UNPKG

darker-engine

Version:
598 lines (597 loc) 28.9 kB
var __asyncValues = (this && this.__asyncValues) || function (o) { if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined."); var m = o[Symbol.asyncIterator], i; return m ? m.call(o) : (o = typeof __values === "function" ? __values(o) : o[Symbol.iterator](), i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i); function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; } function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); } }; import { uid, UIDKey } from './uid.js'; export const engine = () => { let rawSystems = []; // TODO: remove?? let systems = []; let entityList = []; let typeEntityMap = {}; let entityComponentMap = {}; // Contains which components/data has every entity let entityDataMap = []; // Contains which entities has every system let systemEntitiesMap = []; const { getUID } = uid(() => entityList); const setSystems = async (..._systems) => { var _a, e_1, _b, _c; var _d; rawSystems = [..._systems]; systems = []; systemEntitiesMap = []; try { for (var _e = true, _systems_1 = __asyncValues(_systems), _systems_1_1; _systems_1_1 = await _systems_1.next(), _a = _systems_1_1.done, !_a;) { _c = _systems_1_1.value; _e = false; try { const system = _c; const _system = (await system()); _system.name = system.name; _system.id = (_d = _system.id) !== null && _d !== void 0 ? _d : getUID(UIDKey.SYSTEM); systemEntitiesMap[_system.id] = []; systems[_system.id] = _system; } finally { _e = true; } } } catch (e_1_1) { e_1 = { error: e_1_1 }; } finally { try { if (!_e && !_a && (_b = _systems_1.return)) await _b.call(_systems_1); } finally { if (e_1) throw e_1.error; } } }; const _entity_removeComponent = async (entityId, component) => { var _a, e_2, _b, _c; var _d, _e; const entity = getEntity(entityId); if (!entity) { return console.warn(`Warning "removeComponent::(${entityId},${component})" undefined`); } entityComponentMap[entityId] = entityComponentMap[entityId].filter((_component) => _component !== component); const systemList = systems .filter((system) => { var _a; const entities = systemEntitiesMap[system.id]; return (_a = entities === null || entities === void 0 ? void 0 : entities.includes(entityId)) !== null && _a !== void 0 ? _a : false; }) .filter((system) => !system.components.every((_component) => { var _a; return (_a = entityComponentMap[entityId]) === null || _a === void 0 ? void 0 : _a.includes(_component); })) .reverse(); try { for (var _f = true, systemList_1 = __asyncValues(systemList), systemList_1_1; systemList_1_1 = await systemList_1.next(), _a = systemList_1_1.done, !_a;) { _c = systemList_1_1.value; _f = false; try { const system = _c; const entities = systemEntitiesMap[system.id]; systemEntitiesMap[system.id] = (_d = entities === null || entities === void 0 ? void 0 : entities.filter((_id) => _id !== entityId)) !== null && _d !== void 0 ? _d : []; try { await ((_e = system === null || system === void 0 ? void 0 : system.onRemove) === null || _e === void 0 ? void 0 : _e.call(system, entityId)); } catch (e) { console.warn(`Error catch system::${system.id} "onRemove(${entityId})"`); console.error(e); } } finally { _f = true; } } } catch (e_2_1) { e_2 = { error: e_2_1 }; } finally { try { if (!_f && !_a && (_b = systemList_1.return)) await _b.call(systemList_1); } finally { if (e_2) throw e_2.error; } } return; }; const _entity_updateComponent = async (entityId, component, data) => { var _a, e_3, _b, _c; var _d, _e; const entity = getEntity(entityId); if (!entity) { console.warn(`Warning "updateComponent::(${entityId},${component})" undefined`); return entity; } if (!((_d = entityComponentMap[entityId]) === null || _d === void 0 ? void 0 : _d.includes(component))) { return await _entity_addComponent(entityId, component, data); } const currentData = entityDataMap[entity.id]; entityDataMap[entity.id] = Object.assign(Object.assign({}, currentData), { [component]: Object.assign(Object.assign({}, (currentData[component] || {})), data) }); const systemList = systems //Only filters the current updated component .filter((system) => system.components.includes(component)) .filter((system) => { var _a; const entities = systemEntitiesMap[system.id]; return (_a = entities === null || entities === void 0 ? void 0 : entities.includes(entityId)) !== null && _a !== void 0 ? _a : false; }); try { for (var _f = true, systemList_2 = __asyncValues(systemList), systemList_2_1; systemList_2_1 = await systemList_2.next(), _a = systemList_2_1.done, !_a;) { _c = systemList_2_1.value; _f = false; try { const system = _c; try { await ((_e = system === null || system === void 0 ? void 0 : system.onUpdate) === null || _e === void 0 ? void 0 : _e.call(system, entityId, component)); } catch (e) { console.warn(`Error catch system::${system.id} "onUpdate(${entityId}, ${component})"`); console.error(e); } } finally { _f = true; } } } catch (e_3_1) { e_3 = { error: e_3_1 }; } finally { try { if (!_f && !_a && (_b = systemList_2.return)) await _b.call(systemList_2); } finally { if (e_3) throw e_3.error; } } return entity; }; const _entity_addComponent = async (entityId, component, data = {}) => { var _a, e_4, _b, _c; var _d; const entity = getEntity(entityId); if (!entity) { console.warn(`Warning "addComponent::(${entityId},${component})" undefined`); return entity; } entityComponentMap[entity.id].push(component); entityDataMap[entity.id] = Object.assign(Object.assign({}, entityDataMap[entity.id]), { [component]: data }); const systemList = systems .filter((system) => system.components.includes(component)) // Cuando los sistemas no contengan la entidad actual .filter((system) => { var _a; const entities = systemEntitiesMap[system.id]; return (_a = !(entities === null || entities === void 0 ? void 0 : entities.includes(entityId))) !== null && _a !== void 0 ? _a : true; }) // Cuando la entidad tenga los componentes correspondientes a ese sistema .filter((system) => system.components.every((_component) => { var _a; return (_a = entityComponentMap[entityId]) === null || _a === void 0 ? void 0 : _a.includes(_component); })); try { for (var _e = true, systemList_3 = __asyncValues(systemList), systemList_3_1; systemList_3_1 = await systemList_3.next(), _a = systemList_3_1.done, !_a;) { _c = systemList_3_1.value; _e = false; try { const system = _c; const entities = systemEntitiesMap[system.id]; systemEntitiesMap[system.id] = [...(entities !== null && entities !== void 0 ? entities : []), entityId]; try { await ((_d = system === null || system === void 0 ? void 0 : system.onAdd) === null || _d === void 0 ? void 0 : _d.call(system, entityId)); } catch (e) { console.warn(`Error catch system::${system.id} "onAdd(${entityId})"`); console.error(e); } } finally { _e = true; } } } catch (e_4_1) { e_4 = { error: e_4_1 }; } finally { try { if (!_e && !_a && (_b = systemList_3.return)) await _b.call(systemList_3); } finally { if (e_4) throw e_4.error; } } return entity; }; // TODO: maintain original order, not this shit const _entity_getComponentTypes = (entityId) => entityComponentMap[entityId]; const _entity_getComponent = (entityId, component, deepClone = false) => { const entityData = entityDataMap[entityId]; return entityData && entityData[component] ? deepClone ? structuredClone(entityData[component]) : Object.assign({}, entityData[component]) : {}; }; const _entity_getComponents = (entityId, components, deepClone = false) => { const entityData = entityDataMap[entityId]; return components.reduce((acc, component) => { const data = entityData[component]; if (!data) return acc; acc[component] = deepClone ? structuredClone(data) : data; return acc; }, {}); }; const _entity_hasComponent = (entityId, component) => { var _a; return (_a = entityComponentMap[entityId]) === null || _a === void 0 ? void 0 : _a.includes(component); }; const _entity_getData = (entityId) => structuredClone(entityDataMap[entityId]); const getEntityList = () => Object.values(entityList) || []; const getEntityListByType = (type) => { var _a; return ((_a = typeEntityMap[type]) === null || _a === void 0 ? void 0 : _a.map((entityId) => entityList[entityId])) || []; }; const getEntityListByComponents = (...componentList) => { return entityList .reduce((list, entity) => { const entityComponents = entityComponentMap[entity.id]; if (componentList.length === 0 || componentList.every((component) => entityComponents.includes(component))) { return [...list, entity]; } return list; }, Array()) .filter(Boolean); }; const getEntity = (entityId) => { const entity = entityList[entityId]; if (!entity) { console.warn(`Warning "internal::getEntity(${entityId})" undefined`); } return entity; }; const addEntity = async (...rawEntities) => { var _a, e_5, _b, _c, _d, e_6, _e, _f; var _g; const date = Date.now(); const entities = rawEntities.map((rawEntity) => { var _a, _b, _c; const entity = rawEntity; entity.id = (_a = entity.id) !== null && _a !== void 0 ? _a : getUID(UIDKey.ENTITY, entity.safe); entity.getData = () => _entity_getData(entity.id); entity.getComponent = (component, deepClone) => _entity_getComponent(entity.id, component, deepClone); entity.getComponentTypes = () => _entity_getComponentTypes(entity.id); entity.getComponents = (components, deepClone) => _entity_getComponents(entity.id, components, deepClone); entity.hasComponent = (component) => _entity_hasComponent(entity.id, component); entity.removeComponent = (component) => _entity_removeComponent(entity.id, component); entity.updateComponent = (component, data) => _entity_updateComponent(entity.id, component, data); if (!typeEntityMap[entity.type]) { typeEntityMap[entity.type] = []; } typeEntityMap[entity.type].push(entity.id); entityComponentMap[entity.id] = entity.components; entityDataMap[entity.id] = (_c = (_b = entity === null || entity === void 0 ? void 0 : entity.getComponentTypes) === null || _b === void 0 ? void 0 : _b.call(entity).reduce((acc, b) => (Object.assign(Object.assign({}, acc), { [b]: acc[b] || {} })), entity.data)) !== null && _c !== void 0 ? _c : {}; entityList[entity.id] = entity; return entity; }); try { for (var _h = true, entities_1 = __asyncValues(entities), entities_1_1; entities_1_1 = await entities_1.next(), _a = entities_1_1.done, !_a;) { _c = entities_1_1.value; _h = false; try { const entity = _c; // Calculate points from component order. const componentMapPoint = entity.components.reduce((obj, com, ind) => (Object.assign(Object.assign({}, obj), { [com]: ind ** 2 })), {}); const systemList = systems .map((system) => ({ system, // Assign system by component points order points: system.components.reduce((points, component) => componentMapPoint[component] + points, 0), })) .filter((system) => !isNaN(system.points)) .sort((systemA, systemB) => systemB.points > systemA.points ? -1 : systemB.points === systemA.points ? 0 : 1) .map(({ system }) => system); try { for (var _j = true, systemList_4 = (e_6 = void 0, __asyncValues(systemList)), systemList_4_1; systemList_4_1 = await systemList_4.next(), _d = systemList_4_1.done, !_d;) { _f = systemList_4_1.value; _j = false; try { const system = _f; const systemEntities = systemEntitiesMap[system.id]; systemEntitiesMap[system.id] = [...(systemEntities !== null && systemEntities !== void 0 ? systemEntities : []), entity.id]; try { await ((_g = system === null || system === void 0 ? void 0 : system.onAdd) === null || _g === void 0 ? void 0 : _g.call(system, entity.id)); } catch (e) { console.warn(`Error catch system::${system.id} "onUpdate(${entity.id})"`); console.error(e); } } finally { _j = true; } } } catch (e_6_1) { e_6 = { error: e_6_1 }; } finally { try { if (!_j && !_d && (_e = systemList_4.return)) await _e.call(systemList_4); } finally { if (e_6) throw e_6.error; } } } finally { _h = true; } } } catch (e_5_1) { e_5 = { error: e_5_1 }; } finally { try { if (!_h && !_a && (_b = entities_1.return)) await _b.call(entities_1); } finally { if (e_5) throw e_5.error; } } const ms = Date.now() - date; if (ms > 500) { console.warn(`addEntity ${ms}ms addedEntities:${entities.length} totalEntities:${entityList.length}`); } return entities; }; const removeEntity = async (...entityIdList) => { var _a, e_7, _b, _c, _d, e_8, _e, _f; var _g, _h, _j; const _entityList = entityIdList.map((entityId) => entityList[entityId]); try { for (var _k = true, _entityList_1 = __asyncValues(_entityList), _entityList_1_1; _entityList_1_1 = await _entityList_1.next(), _a = _entityList_1_1.done, !_a;) { _c = _entityList_1_1.value; _k = false; try { const entity = _c; if (!entity) return; const componentEntityList = (_g = entity === null || entity === void 0 ? void 0 : entity.getComponentTypes) === null || _g === void 0 ? void 0 : _g.call(entity); if (!componentEntityList) return; // Calculate points from component order. const componentMapPoint = componentEntityList.reduce((obj, com, ind) => (Object.assign(Object.assign({}, obj), { [com]: ind ** 2 })), {}); const systemList = systems .map((system) => ({ system, // Assign system by component points order points: system.components.reduce((points, component) => componentMapPoint[component] + points, 0), })) .filter((system) => !isNaN(system.points)) .sort((systemA, systemB) => systemB.points > systemA.points ? 1 : systemB.points === systemA.points ? 0 : -1) .map(({ system }) => system); try { for (var _l = true, systemList_5 = (e_8 = void 0, __asyncValues(systemList)), systemList_5_1; systemList_5_1 = await systemList_5.next(), _d = systemList_5_1.done, !_d;) { _f = systemList_5_1.value; _l = false; try { const system = _f; try { await ((_h = system === null || system === void 0 ? void 0 : system.onRemove) === null || _h === void 0 ? void 0 : _h.call(system, entity.id)); } catch (e) { console.warn(`Error catch system::${system.id} "onRemove(${entity.id})"`); console.error(e); } const systemEntities = systemEntitiesMap[system.id]; systemEntitiesMap[system.id] = (_j = systemEntities === null || systemEntities === void 0 ? void 0 : systemEntities.filter((_id) => _id !== entity.id)) !== null && _j !== void 0 ? _j : []; } finally { _l = true; } } } catch (e_8_1) { e_8 = { error: e_8_1 }; } finally { try { if (!_l && !_d && (_e = systemList_5.return)) await _e.call(systemList_5); } finally { if (e_8) throw e_8.error; } } delete entityList[entity.id]; delete entityComponentMap[entity.id]; typeEntityMap[entity.type] = typeEntityMap[entity.type].filter((entityId) => entity.id !== entityId); } finally { _k = true; } } } catch (e_7_1) { e_7 = { error: e_7_1 }; } finally { try { if (!_k && !_a && (_b = _entityList_1.return)) await _b.call(_entityList_1); } finally { if (e_7) throw e_7.error; } } }; const getSystem = (id) => systems[id]; const clear = () => { systems = []; entityList = []; typeEntityMap = {}; entityComponentMap = []; entityDataMap = []; systemEntitiesMap = []; }; const load = async () => { var _a, e_9, _b, _c; var _d; try { for (var _e = true, systems_1 = __asyncValues(systems), systems_1_1; systems_1_1 = await systems_1.next(), _a = systems_1_1.done, !_a;) { _c = systems_1_1.value; _e = false; try { const system = _c; await ((_d = system === null || system === void 0 ? void 0 : system.onLoad) === null || _d === void 0 ? void 0 : _d.call(system)); } finally { _e = true; } } } catch (e_9_1) { e_9 = { error: e_9_1 }; } finally { try { if (!_e && !_a && (_b = systems_1.return)) await _b.call(systems_1); } finally { if (e_9) throw e_9.error; } } }; const hardReload = async () => { var _a, e_10, _b, _c, _d, e_11, _e, _f, _g, e_12, _h, _j, _k, e_13, _l, _m; try { for (var _o = true, _p = __asyncValues([...systems].reverse().filter(Boolean)), _q; _q = await _p.next(), _a = _q.done, !_a;) { _c = _q.value; _o = false; try { const system = _c; const entities = systemEntitiesMap[system.id]; try { for (var _r = true, _s = (e_11 = void 0, __asyncValues([...entities].reverse())), _t; _t = await _s.next(), _d = _t.done, !_d;) { _f = _t.value; _r = false; try { const entityId = _f; (system === null || system === void 0 ? void 0 : system.onRemove) && (await (system === null || system === void 0 ? void 0 : system.onRemove(entityId))); } finally { _r = true; } } } catch (e_11_1) { e_11 = { error: e_11_1 }; } finally { try { if (!_r && !_d && (_e = _s.return)) await _e.call(_s); } finally { if (e_11) throw e_11.error; } } (system === null || system === void 0 ? void 0 : system.onDestroy) && (await (system === null || system === void 0 ? void 0 : system.onDestroy())); } finally { _o = true; } } } catch (e_10_1) { e_10 = { error: e_10_1 }; } finally { try { if (!_o && !_a && (_b = _p.return)) await _b.call(_p); } finally { if (e_10) throw e_10.error; } } try { for (var _u = true, _v = __asyncValues([...systems].filter(Boolean)), _w; _w = await _v.next(), _g = _w.done, !_g;) { _j = _w.value; _u = false; try { const system = _j; (system === null || system === void 0 ? void 0 : system.onLoad) && (await (system === null || system === void 0 ? void 0 : system.onLoad())); const entities = systemEntitiesMap[system.id]; try { for (var _x = true, _y = (e_13 = void 0, __asyncValues([...entities])), _z; _z = await _y.next(), _k = _z.done, !_k;) { _m = _z.value; _x = false; try { const entityId = _m; (system === null || system === void 0 ? void 0 : system.onAdd) && (await (system === null || system === void 0 ? void 0 : system.onAdd(entityId))); } finally { _x = true; } } } catch (e_13_1) { e_13 = { error: e_13_1 }; } finally { try { if (!_x && !_k && (_l = _y.return)) await _l.call(_y); } finally { if (e_13) throw e_13.error; } } } finally { _u = true; } } } catch (e_12_1) { e_12 = { error: e_12_1 }; } finally { try { if (!_u && !_g && (_h = _v.return)) await _h.call(_v); } finally { if (e_12) throw e_12.error; } } }; const debug = () => { const swapSystem = async (systemId, system) => { var _a, e_14, _b, _c, _d, e_15, _e, _f; var _g, _h; const currentSystem = systems[systemId]; const entities = systemEntitiesMap[systemId]; // Remove current entities from system if (currentSystem.onRemove) { try { for (var _j = true, _k = __asyncValues([...entities].reverse()), _l; _l = await _k.next(), _a = _l.done, !_a;) { _c = _l.value; _j = false; try { const entityId = _c; await currentSystem.onRemove(entityId); } finally { _j = true; } } } catch (e_14_1) { e_14 = { error: e_14_1 }; } finally { try { if (!_j && !_a && (_b = _k.return)) await _b.call(_k); } finally { if (e_14) throw e_14.error; } } } // Destroy current system if (currentSystem.onDestroy) await currentSystem.onDestroy(); const swappedSystem = (await system()); swappedSystem.id = currentSystem.id; swappedSystem.name = currentSystem.name; systems[systemId] = swappedSystem; // Load current system if (currentSystem === null || currentSystem === void 0 ? void 0 : currentSystem.onLoad) await ((_g = swappedSystem.onLoad) === null || _g === void 0 ? void 0 : _g.call(swappedSystem)); // Add current entities to swapped system if (currentSystem.onAdd) { try { for (var _m = true, _o = __asyncValues([...entities]), _p; _p = await _o.next(), _d = _p.done, !_d;) { _f = _p.value; _m = false; try { const entityId = _f; await ((_h = swappedSystem.onAdd) === null || _h === void 0 ? void 0 : _h.call(swappedSystem, entityId)); } finally { _m = true; } } } catch (e_15_1) { e_15 = { error: e_15_1 }; } finally { try { if (!_m && !_d && (_e = _o.return)) await _e.call(_o); } finally { if (e_15) throw e_15.error; } } } }; const getSystem = (name) => Object.values(systems).find((system) => system.name === name); return { swapSystem, getSystem, }; }; return { setSystems, getEntityList, getEntityListByType, getEntityListByComponents, getEntity, addEntity, removeEntity, getSystem, clear, load, hardReload, __debug__: debug(), }; };