SystemStore.js

import { compose } from 'stampit';
import pickBy from 'lodash/pickBy';
import { isFunction } from './helpers';
import System from './System';

/**
 * Centralized place for registering and creating systems.
 *
 * __For internal use only!__
 *
 * @class SystemStore
 * @param {Object}          opts
 * @param {Entropy}         opts.game game instance
 */
const SystemStore = compose({
  init(opts) {
    /**
     * Game instance injected to constructor.
     *
     * @public
     * @memberOf SystemStore#
     * @name game
     * @type Entropy
     */
    this.game = opts.game;

    /**
     * Object with factories for system types.
     *
     * @private
     * @memberOf SystemStore#
     * @name _factories
     * @type Object
     */
    this._factories = {};
  },
  methods: {
    /**
     * Registers system.
     *
     * @public
     * @memberof SystemStore#
     * @method register
     * @param {Object}    descriptor            object describing system
     * @param {String}    descriptor.type       type of system
     * @param {Function}  descriptor.onCreate   method called when system is created
     * @param {Function}  descriptor.onRemove   method called when system is removed
     * @param {Function}  descriptor.onUpdate   method called when system is updated
     */
    register(descriptor) {
      this._factories[descriptor.type] = compose(System, {
        properties: {
          type: descriptor.type,
        },
        methods: pickBy(descriptor, value => isFunction(value)),
      });
    },
    /**
     * Registeres many systems.
     *
     * @public
     * @memberof SystemStore#
     * @method registerMany
     * @param  {Array} descriptiors array of system's descriptors (see {@link SystemStore#register})
     */
    registerMany(descriptors) {
      descriptors.forEach(descriptor => this.register(descriptor));
    },
    /**
     * Creates new entity instance or acquires one from pool.
     *
     * @public
     * @memberof SystemStore#
     * @method create
     * @param  {String} type    type of system to create
     * @param  {...Any} args arguments passed to `onCreate` method
     * @return {System}         new system ready to be added to engine
     */
    create(type, ...args) {
      const system = this._factories[type]({
        game: this.game,
      });
      system.onCreate(...args);
      return system;
    },
  },
});

export default SystemStore;