export default class Base { map = []; pool = []; static schema; allocateMany(count) { const results = []; while (count-- > 0 && this.pool.length > 0) { results.push(this.pool.pop()); } return results; } create(entityId, values) { this.createMany([[entityId, values]]); } destroy(entityId) { this.destroyMany([entityId]); } destroyMany(entities) { this.freeMany( entities .map((entityId) => { if ('undefined' !== typeof this.map[entityId]) { return this.map[entityId]; } throw new Error(`can't free for non-existent id ${entityId}`); }), ); for (let i = 0; i < entities.length; i++) { this.map[entities[i]] = undefined; } } static filterDefaults(instance) { const json = {}; for (const key in this.properties) { const {defaultValue} = this.properties[key]; if (key in instance && instance[key] !== defaultValue) { json[key] = instance[key]; } } return json; } freeMany(indices) { for (let i = 0; i < indices.length; ++i) { this.pool.push(indices[i]); } } insertMany(entities) { const creating = []; for (let i = 0; i < entities.length; i++) { const [entityId, values] = entities[i]; if (!this.get(entityId)) { creating.push([entityId, values]); } else { const instance = this.get(entityId); for (const i in values) { instance[i] = values[i]; } } } this.createMany(creating); } // eslint-disable-next-line no-unused-vars markChange(entityId, components) {} mergeDiff(original, update) { return {...original, ...update}; } static get properties() { return this.schema.specification.properties; } sizeOf(entityId) { return this.constructor.schema.sizeOf(this.get(entityId)); } static wrap(name, ecs) { class WrappedComponent extends this { markChange(entityId, key, value) { ecs.markChange(entityId, {[name]: {[key]: value}}) } } return new WrappedComponent(); } }