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(entity, values) { this.createMany([[entity, values]]); } destroy(entity) { this.destroyMany([entity]); } destroyMany(entities) { this.freeMany( entities .map((entity) => { if ('undefined' !== typeof this.map[entity]) { return this.map[entity]; } throw new Error(`can't free for non-existent entity ${entity}`); }), ); for (let i = 0; i < entities.length; i++) { this.map[entities[i]] = undefined; } } static filterDefaults(instance) { const json = {}; for (const [i, {defaultValue}] of this.schema) { if (i in instance && instance[i] !== defaultValue) { json[i] = instance[i]; } } 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 [entity, values] = entities[i]; if (!this.get(entity)) { creating.push([entity, values]); } else { const instance = this.get(entity); for (const i in values) { instance[i] = values[i]; } } } this.createMany(creating); } // eslint-disable-next-line no-unused-vars markChange(entity, components) {} mergeDiff(original, update) { return {...original, ...update}; } sizeOf(entity) { return this.constructor.schema.sizeOf(this.get(entity)); } static wrap(name, ecs) { class WrappedComponent extends this { markChange(entity, key, value) { ecs.markChange(entity, {[name]: {[key]: value}}) } } return new WrappedComponent(); } }