UNPKG

@javelin/ecs

Version:

241 lines 8.21 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.createWorld = exports.DeferredOpType = void 0; const core_1 = require("@javelin/core"); const component_1 = require("./component"); const internal_1 = require("./internal"); const storage_1 = require("./storage"); const $systemId = Symbol("javelin_system_id"); var DeferredOpType; (function (DeferredOpType) { DeferredOpType[DeferredOpType["Create"] = 0] = "Create"; DeferredOpType[DeferredOpType["Attach"] = 1] = "Attach"; DeferredOpType[DeferredOpType["Detach"] = 2] = "Detach"; DeferredOpType[DeferredOpType["Destroy"] = 3] = "Destroy"; })(DeferredOpType = exports.DeferredOpType || (exports.DeferredOpType = {})); /** * Create a world. * @param options WorldOptions * @returns World */ function createWorld(options = {}) { var _a, _b; const { topics = [] } = options; const systems = []; const deferredOps = []; const destroyed = new Set(); const storage = storage_1.createStorage({ snapshot: (_a = options.snapshot) === null || _a === void 0 ? void 0 : _a.storage }); let entityIds = 0; let systemIds = 0; (_b = options.systems) === null || _b === void 0 ? void 0 : _b.forEach(addSystem); function createDeferredOp(...args) { const deferred = []; for (let i = 0; i < args.length; i++) { deferred[i] = args[i]; } return deferred; } function maybeReleaseComponent(component) { const pool = internal_1.UNSAFE_internals.schemaPools.get(component_1.getSchemaId(component)); if (pool && Reflect.get(component, component_1.$pool)) { pool.release(component); } } function addSystem(system) { systems.push(system); system[$systemId] = systemIds++; } function removeSystem(system) { const index = systems.indexOf(system); if (index > -1) { systems.splice(index, 1); } } function addTopic(topic) { topics.push(topic); } function removeTopic(topic) { const index = topics.indexOf(topic); if (index > -1) { topics.splice(index, 1); } } function create(...components) { const entity = entityIds++; if (components.length > 0) { deferredOps.push(createDeferredOp(DeferredOpType.Attach, entity, components)); } return entity; } function attach(entity, ...components) { deferredOps.push(createDeferredOp(DeferredOpType.Attach, entity, components)); } function attachImmediate(entity, components) { storage.attachComponents(entity, components); } function detach(entity, ...components) { if (components.length === 0) { return; } const schemaIds = components.map(c => { var _a; return typeof c === "number" ? c : (_a = internal_1.UNSAFE_internals.schemaIndex.get(c)) !== null && _a !== void 0 ? _a : component_1.getSchemaId(c); }); deferredOps.push(createDeferredOp(DeferredOpType.Detach, entity, schemaIds)); } function detachImmediate(entity, schemaIds) { const components = []; for (let i = 0; i < schemaIds.length; i++) { const schemaId = schemaIds[i]; const component = storage.getComponentBySchemaId(entity, schemaId); core_1.assert(component !== null, `Failed to detach component: entity does not have component of type ${schemaId}`); components.push(component); } storage.detachBySchemaId(entity, schemaIds); components.forEach(maybeReleaseComponent); } function destroy(entity) { if (destroyed.has(entity)) { return; } deferredOps.push(createDeferredOp(DeferredOpType.Destroy, entity)); destroyed.add(entity); } function destroyImmediate(entity) { storage.clearComponents(entity); } function has(entity, schema) { component_1.registerSchema(schema); return storage.hasComponentOfSchema(entity, schema); } function get(entity, schema) { component_1.registerSchema(schema); const component = storage.getComponentBySchema(entity, schema); if (component === null) { throw new Error("Failed to get component: entity does not have component"); } return component; } function tryGet(entity, schema) { try { component_1.registerSchema(schema); return storage.getComponentBySchema(entity, schema); } catch (error) { return null; } } function reset() { destroyed.clear(); // clear deferred ops core_1.mutableEmpty(deferredOps); // remove all systems core_1.mutableEmpty(systems); // remove all topics topics.forEach(topic => topic.clear()); core_1.mutableEmpty(topics); // reset entity id counter entityIds = 0; // reset step data world.latestTick = -1; world.latestTickData = null; world.latestSystemId = -1; // release components for (let i = 0; i < storage.archetypes.length; i++) { const archetype = storage.archetypes[i]; for (let j = 0; j < archetype.type.length; j++) { const column = archetype.table[j]; const componentPool = internal_1.UNSAFE_internals.schemaPools.get(archetype.type[j]); for (let k = 0; k < column.length; k++) { const component = column[k]; componentPool === null || componentPool === void 0 ? void 0 : componentPool.release(component); } } } // reset entity-component storage storage.clear(); } function createSnapshot() { return { storage: storage.createSnapshot(), }; } function applyAttachOp(op) { const [, entity, components] = op; attachImmediate(entity, components); } function applyDetachOp(op) { const [, entity, schemaIds] = op; detachImmediate(entity, schemaIds); } function applyDestroyOp(op) { const [, entity] = op; destroyImmediate(entity); } function applyDeferredOp(deferred) { switch (deferred[0]) { case DeferredOpType.Attach: applyAttachOp(deferred); break; case DeferredOpType.Detach: applyDetachOp(deferred); break; case DeferredOpType.Destroy: applyDestroyOp(deferred); break; } } function step(data) { let prevWorld = internal_1.UNSAFE_internals.currentWorldId; internal_1.UNSAFE_internals.currentWorldId = id; world.latestTickData = data; for (let i = 0; i < deferredOps.length; i++) { applyDeferredOp(deferredOps[i]); } core_1.mutableEmpty(deferredOps); // flush topics for (let i = 0; i < topics.length; i++) { topics[i].flush(); } // execute systems for (let i = 0; i < systems.length; i++) { const system = systems[i]; world.latestSystemId = system[$systemId]; system(world); } destroyed.clear(); world.latestTick++; internal_1.UNSAFE_internals.currentWorldId = prevWorld; } const id = internal_1.UNSAFE_internals.worldIds++; const world = { id, storage, latestTick: -1, latestTickData: null, latestSystemId: -1, attach, attachImmediate, addSystem, addTopic, create, destroy, destroyImmediate, get, createSnapshot, has, detach, detachImmediate, removeSystem, removeTopic, reset, step, tryGet, }; internal_1.UNSAFE_internals.worlds.push(world); return world; } exports.createWorld = createWorld; //# sourceMappingURL=world.js.map