Home Reference Source

src/system_storage.js

import { invoke } from './utilities.js'

/** @ignore */
export class SystemStorage {
  /** SystemStorage constructor, needs reference back to world */
  constructor(world) {
    /** World instance */
    this.world = world
    /** List of systems, stored in run-order */
    this.systems = []
    /** Context passed to all systems */
    this.context = { world }
  }

  /** Pushes a system to the list with optional init/constructor args */
  register(systemClass, ...args) {
    // Make sure the system is valid
    if (typeof systemClass !== 'function') {
      throw new Error('System is not a valid function or class.')
    }
    // Create and add the system with context
    const newSystem = new systemClass(...args)
    this._injectContext(newSystem)
    invoke(newSystem, 'init', ...args)
    this.systems.push(newSystem)
  }

  /** Runs a system with optional args */
  run(...args) {
    let status = true
    // Continue rerunning while any systems return true
    while (status) {
      status = undefined
      for (const system of this.systems) {
        // Try to call the "run" method
        const result = invoke(system, 'run', ...args)
        status = status || result
      }
      // Clear args after first run, so re-runs can be identified
      args.length = 0
    }
  }

  /** Update existing systems' context */
  setContext(data) {
    this.context = { ...data, world: this.world }
    for (const system of this.systems) {
      this._injectContext(system)
    }
  }

  /** Injects context into a system based on current context state */
  _injectContext(system) {
    for (const key in this.context) {
      system[key] = this.context[key]
    }
  }
}