Skip to content

Commit

Permalink
actiond and condition specs
Browse files Browse the repository at this point in the history
  • Loading branch information
Nikolas Howard committed Feb 26, 2024
1 parent e47bf25 commit c1dd5d3
Show file tree
Hide file tree
Showing 10 changed files with 726 additions and 195 deletions.
8 changes: 4 additions & 4 deletions dist/BehaviourTreeDefinition.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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[];
}
Expand All @@ -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[];
}
Expand Down
30 changes: 23 additions & 7 deletions dist/bundle.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions dist/bundle.js.map

Large diffs are not rendered by default.

30 changes: 23 additions & 7 deletions dist/index.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions dist/index.js.map

Large diffs are not rendered by default.

8 changes: 4 additions & 4 deletions src/BehaviourTreeDefinition.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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[];
}
Expand All @@ -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[];
}
Expand Down
35 changes: 22 additions & 13 deletions src/nodes/leaf/Action.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<CompleteState>;

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<CompleteState>;
} 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) {
Expand All @@ -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}'`);
}
);

Expand All @@ -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);
}
}

Expand Down
21 changes: 19 additions & 2 deletions src/nodes/leaf/Condition.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

/**
Expand Down
Loading

0 comments on commit c1dd5d3

Please sign in to comment.