UNPKG

sam-ecs

Version:

A specialized entity component system

382 lines (325 loc) 11.9 kB
'use strict'; var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } //ActionManager.js// /** * @description - Manages the current actions in the ECS manager, * along with reducers that act on those actions * @author - Sam Faulkner */ //node imports var Dict = require('collections/dict.js'); var SortedArray = require('collections/sorted-array.js'); //constants var MAXIMUM_BUFFER_LENGTH = 8; var ActionManager = function () { function ActionManager(bufferSize) { _classCallCheck(this, ActionManager); this._actionQueues = new Array(); this._actionQueues.push(new Array()); this._actionQueues.push(new Array()); this._actionQueueIndex = 0; this._reducers = new Dict(); this._actionBuffer = new SortedArray([], function (first, second) { return first.tick == second.tick; }, function (first, second) { return first.tick - second.tick; }); this._maxBufferSize = bufferSize || MAXIMUM_BUFFER_LENGTH; } _createClass(ActionManager, [{ key: 'setMaxBufferSize', value: function setMaxBufferSize(value) { this._maxBufferSize = value; } /** * @description - Adds a reducer that will reduce actions of * the given type * @param {Function} reducer - the function that will be called with * the given action * @param {Array} actionTypes - the types of action that this reducer * will be called with */ }, { key: 'addReducer', value: function addReducer(reducer, actionTypes) { var _iteratorNormalCompletion = true; var _didIteratorError = false; var _iteratorError = undefined; try { for (var _iterator = actionTypes[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { var actionType = _step.value; if (!this._reducers.has(actionType)) { this._reducers.set(actionType, new Array()); } this._reducers.get(actionType).push(reducer); } } catch (err) { _didIteratorError = true; _iteratorError = err; } finally { try { if (!_iteratorNormalCompletion && _iterator.return) { _iterator.return(); } } finally { if (_didIteratorError) { throw _iteratorError; } } } } /** * @description - Removes the reducer from the given action types * @param {Function} reducer - the function to remove * @param {Array} actionTypes - the types of actions to remove it from */ }, { key: 'removeReducer', value: function removeReducer(reducer, actionTypes) { var _iteratorNormalCompletion2 = true; var _didIteratorError2 = false; var _iteratorError2 = undefined; try { for (var _iterator2 = actionTypes[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) { var actionType = _step2.value; //should I throw an error here? if (!this._reducers.has(actionType)) { continue; } var reducerArray = this._reducers.get(actionType); if (!reducerArray.includes(reducer)) { throw new TypeError("Given reducer can't be removed from type: " + actionType); } reducerArray.splice(reducerArray.indexOf(reducer), 1); } } catch (err) { _didIteratorError2 = true; _iteratorError2 = err; } finally { try { if (!_iteratorNormalCompletion2 && _iterator2.return) { _iterator2.return(); } } finally { if (_didIteratorError2) { throw _iteratorError2; } } } } /** * @description - dispatches all queued actions to * the respective reducers * @param {StateManager} stateManager - the state manager * that is passed to reducers */ }, { key: 'update', value: function update(stateManager, currentTick) { var activeActionQueue = this._actionQueues[this._actionQueueIndex]; this._actionQueueIndex += 1; this._actionQueueIndex %= this._actionQueues.length; this.bufferActions(activeActionQueue, currentTick); var _iteratorNormalCompletion3 = true; var _didIteratorError3 = false; var _iteratorError3 = undefined; try { for (var _iterator3 = activeActionQueue[Symbol.iterator](), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) { var action = _step3.value; this.dispatchNow(action, stateManager); } } catch (err) { _didIteratorError3 = true; _iteratorError3 = err; } finally { try { if (!_iteratorNormalCompletion3 && _iterator3.return) { _iterator3.return(); } } finally { if (_didIteratorError3) { throw _iteratorError3; } } } activeActionQueue.length = 0; } /** * @description - Calls the reducers associated with * the given action. Does NOT do any error checking * if the action is valid * @param {Object} action - the action to be dispatched */ }, { key: 'dispatchNow', value: function dispatchNow(action, stateManager) { var reducerArray = this.getReducers(action.type); if (reducerArray) { var _iteratorNormalCompletion4 = true; var _didIteratorError4 = false; var _iteratorError4 = undefined; try { for (var _iterator4 = reducerArray[Symbol.iterator](), _step4; !(_iteratorNormalCompletion4 = (_step4 = _iterator4.next()).done); _iteratorNormalCompletion4 = true) { var reducer = _step4.value; reducer(action, stateManager, this); } } catch (err) { _didIteratorError4 = true; _iteratorError4 = err; } finally { try { if (!_iteratorNormalCompletion4 && _iterator4.return) { _iterator4.return(); } } finally { if (_didIteratorError4) { throw _iteratorError4; } } } } } /** * @description - Reapplies all the actions from the given tick * @param {Number} tick - the tick to re apply the actions from in time * @param {StateManager} stateManager - the stateManager to pass to the reducers */ }, { key: 'reApplyFrom', value: function reApplyFrom(tick, stateManager) { var actionBuffer = this.getActionBuffer(tick); if (!actionBuffer) { actionBuffer = this._actionBuffer.min(); if (!actionBuffer) throw new RangeError("Tick: '" + tick.toString() + "' is out of range!"); actionBuffer = actionBuffer.actions; } while (actionBuffer) { var _iteratorNormalCompletion5 = true; var _didIteratorError5 = false; var _iteratorError5 = undefined; try { for (var _iterator5 = actionBuffer[Symbol.iterator](), _step5; !(_iteratorNormalCompletion5 = (_step5 = _iterator5.next()).done); _iteratorNormalCompletion5 = true) { var action = _step5.value; this.dispatchNow(action, stateManager); } //increase the tick until we get to the newest in the buffer } catch (err) { _didIteratorError5 = true; _iteratorError5 = err; } finally { try { if (!_iteratorNormalCompletion5 && _iterator5.return) { _iterator5.return(); } } finally { if (_didIteratorError5) { throw _iteratorError5; } } } actionBuffer = this.getActionBuffer(++tick); } } /** * @description - Takes the given action queue and adds it to the * array of buffered actions * @param {Array} actionQueue - queue of actions to buffer * @param {Number} currentTick - the current tick to store with the * queue to keep track of the actions */ }, { key: 'bufferActions', value: function bufferActions(actionQueue, currentTick) { while (this._actionBuffer.length >= this._maxBufferSize) { this._actionBuffer.shift(); } var replicatedActionQueue = []; actionQueue.forEach(function (value, index, array) { replicatedActionQueue.push(Object.assign({}, value)); }); this._actionBuffer.push({ 'tick': currentTick, 'actions': replicatedActionQueue }); } /** * @description - Returns the actions dispatched within the given tick * @param {Number} tick - the tick to retrieve the actions from * @returns {Array} the buffered action array */ }, { key: 'getActionBuffer', value: function getActionBuffer(tick) { var _iteratorNormalCompletion6 = true; var _didIteratorError6 = false; var _iteratorError6 = undefined; try { for (var _iterator6 = this._actionBuffer.toArray()[Symbol.iterator](), _step6; !(_iteratorNormalCompletion6 = (_step6 = _iterator6.next()).done); _iteratorNormalCompletion6 = true) { var buffer = _step6.value; if (buffer.tick == tick) { return buffer.actions; } } } catch (err) { _didIteratorError6 = true; _iteratorError6 = err; } finally { try { if (!_iteratorNormalCompletion6 && _iterator6.return) { _iterator6.return(); } } finally { if (_didIteratorError6) { throw _iteratorError6; } } } } /** * @description - Returns the entire array of action buffers * @returns {Array} the entire buffer of action arrays */ }, { key: '_getActionBuffer', value: function _getActionBuffer() { return this._actionBuffer; } /** * @description - Returns the array of reducers associated with * the given action type * @param {String} actionType - the type of action to return the reducers for */ }, { key: 'getReducers', value: function getReducers(actionType) { if (this._reducers.has(actionType)) { return this._reducers.get(actionType); } } /** * @description - Queues an action to be sent out * next update * @param {Object} action - the action to be queued */ }, { key: 'dispatch', value: function dispatch(action) { if (!action || !action.type) { throw new TypeError("Action must be defined and have a type!"); } this._actionQueues[this._actionQueueIndex].push(action); } /** * @description - Returns the currently queued actions * @returns {Array} the list of actions currently queued */ }, { key: 'getQueuedActions', value: function getQueuedActions() { return this._actionQueues[this._actionQueueIndex]; } }]); return ActionManager; }(); module.exports = ActionManager;