UNPKG

blueshell

Version:

A Behavior Tree implementation in modern Javascript

202 lines 6.2 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.Condition = exports.Action = exports.Base = void 0; /** * Created by josh on 1/10/16. */ const uuid_1 = require("uuid"); const models_1 = require("../models"); const utils_1 = require("../utils"); /** * Base class of all Nodes. * @author Joshua Chaitin-Pollak */ class Base { static registerTreePublisher(publisher) { Base.treePublisher = publisher; } static registerNodeForDebug(node) { utils_1.NodeManager.getInstance().addNode(node); } static unregisterNodeForDebug(node) { utils_1.NodeManager.getInstance().removeNode(node); } /** * @constructor * @param name The name of the Node. If no name is given, the name of the Class will be used. */ constructor(name = '') { this.name = name; this._id = ''; if (!this.name) { this.name = this.constructor.name; } this._parent = ''; } /** * Handles the Event, and invokes `onEvent(state, event)` * @param state The state when the event occured. * @param event The event to handle. * @protected */ handleEvent(state, event) { this._beforeEvent(state, event); const passed = this.precondition(state, event); if (!passed) { return models_1.rc.FAILURE; } try { Base.treePublisher.publishResult(state, event, false); const result = this.onEvent(state, event); return this._afterEvent(result, state, event); } catch (err) { state.errorReason = err; if (this.getDebug(state)) { console.error('Error: ', err.stack); // eslint-disable-line no-console } return models_1.rc.ERROR; } } /** * Return an empty object * @ignore * @param state * @param event */ // eslint-disable-next-line @typescript-eslint/no-unused-vars _beforeEvent(state, event) { const pStorage = this._privateStorage(state); const nodeStorage = this.getNodeStorage(state); // If this is the root node, increment the event counter if (!this._parent) { pStorage.eventCounter = ++pStorage.eventCounter || 1; } // Reset the lastResult unless it was previously RUNNING and we're not a parent if (nodeStorage.lastResult !== models_1.rc.RUNNING || (0, models_1.isParentNode)(this)) { nodeStorage.lastResult = ''; } // Record the last event we've seen // console.log('%s: incrementing event counter %s, %s', // this.path, nodeStorage.lastEventSeen, pStorage.eventCounter); nodeStorage.lastEventSeen = pStorage.eventCounter; return {}; } /** * Logging * @ignore * @param res * @param state * @param event */ _afterEvent(res, state, event) { if (this.getDebug(state)) { console.log(this.path, ' => ', event, ' => ', res); // eslint-disable-line no-console } const storage = this.getNodeStorage(state); // Cache our results for the next iteration storage.lastResult = res; return res; } /** * Return true if this Node should proceed handling the event. false otherwise. * @param state * @param event */ // eslint-disable-next-line @typescript-eslint/no-unused-vars precondition(state, event) { return true; } /** * Invoked when there is a new event. * @param state * @param event * @return Result. Must be rc.SUCCESS, rc.FAILURE, or rc.RUNNING */ // eslint-disable-next-line @typescript-eslint/no-unused-vars onEvent(state, event) { return models_1.rc.SUCCESS; } set parent(path) { this._parent = path; } get parent() { return this._parent; } get id() { if (!this._id) { this._id = `n${(0, uuid_1.v4)().replace(/\-/g, '')}`; } return this._id; } get path() { return (!!this._parent ? `${this._parent}_` : '') + this.name; } /** * Returns storage unique to this Node, keyed on the Node's path. * @param state */ getNodeStorage(state) { const path = this.path; const blueshell = this._privateStorage(state); blueshell[path] = blueshell[path] || {}; return blueshell[path]; } /** * Resets the storage unique to this Node, via the Node's path. * If this node is a parent, then also reset all children. * @param state */ resetNodeStorage(state) { if ((0, models_1.isParentNode)(this)) { for (const child of this.getChildren()) { child.resetNodeStorage(state); } } const path = this.path; const blueshell = this._privateStorage(state); blueshell[path] = {}; return blueshell[path]; } /** * @ignore * @param state */ _privateStorage(state) { state.__blueshell = state.__blueshell || {}; return state.__blueshell; } getDebug(state) { return this._privateStorage(state).debug; } getTreeEventCounter(state) { return this._privateStorage(state).eventCounter; } /** * Getter for the previous event seen. * @param state */ getLastEventSeen(state) { return this.getNodeStorage(state).lastEventSeen; } /** * Getter for the result of the last handled Event. * @param state */ getLastResult(state) { return this.getNodeStorage(state).lastResult; } get symbol() { return ''; } } exports.Base = Base; exports.Action = Base; exports.Condition = Base; // Hard to properly type this since the static can't // inherit the types from this generic class. This static is // here because it's difficult to inject this functionality // into blueshell in the current form, but this is maybe // marginally better than a global Base.treePublisher = new utils_1.TreeNonPublisher(); //# sourceMappingURL=Base.js.map