aiecsjs 0.5.6 → 0.5.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +50 -926
- package/README_ZHTW.md +51 -936
- package/api.json +23 -0
- package/dist/chunk-3FV6UMUS.cjs +2 -0
- package/dist/chunk-3FV6UMUS.cjs.map +1 -0
- package/dist/chunk-3ZLNR4JX.cjs +2 -0
- package/dist/chunk-3ZLNR4JX.cjs.map +1 -0
- package/dist/chunk-N5OETPTK.js +2 -0
- package/dist/chunk-N5OETPTK.js.map +1 -0
- package/dist/chunk-TNZMD7E5.js +2 -0
- package/dist/chunk-TNZMD7E5.js.map +1 -0
- package/dist/chunk-YFTCD2UG.js +2 -0
- package/dist/chunk-YFTCD2UG.js.map +1 -0
- package/dist/chunk-ZIZSWIHW.cjs +2 -0
- package/dist/chunk-ZIZSWIHW.cjs.map +1 -0
- package/dist/commands.cjs +1 -1
- package/dist/commands.cjs.map +1 -1
- package/dist/commands.d.cts +1 -1
- package/dist/commands.d.ts +1 -1
- package/dist/commands.js +1 -1
- package/dist/commands.js.map +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +49 -4
- package/dist/index.d.ts +49 -4
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/observers.cjs +1 -1
- package/dist/observers.d.cts +1 -1
- package/dist/observers.d.ts +1 -1
- package/dist/observers.js +1 -1
- package/dist/observers.js.map +1 -1
- package/dist/relations.cjs +1 -1
- package/dist/relations.cjs.map +1 -1
- package/dist/relations.d.cts +1 -1
- package/dist/relations.d.ts +1 -1
- package/dist/relations.js +1 -1
- package/dist/relations.js.map +1 -1
- package/dist/serialize.cjs +1 -1
- package/dist/serialize.d.cts +1 -1
- package/dist/serialize.d.ts +1 -1
- package/dist/serialize.js +1 -1
- package/dist/{types-BGEeHad-.d.cts → types-BeVLA7xG.d.cts} +11 -1
- package/dist/{types-BGEeHad-.d.ts → types-BeVLA7xG.d.ts} +11 -1
- package/dist/worker.cjs +1 -1
- package/dist/worker.cjs.map +1 -1
- package/dist/worker.d.cts +2 -2
- package/dist/worker.d.ts +2 -2
- package/dist/worker.js +1 -1
- package/dist/worker.js.map +1 -1
- package/llms-full.txt +109 -1500
- package/llms.txt +8 -29
- package/package.json +7 -2
- package/dist/chunk-FZ5DSL4K.cjs +0 -2
- package/dist/chunk-FZ5DSL4K.cjs.map +0 -1
- package/dist/chunk-H3E365XN.cjs +0 -2
- package/dist/chunk-H3E365XN.cjs.map +0 -1
- package/dist/chunk-IFA7MVBB.js +0 -2
- package/dist/chunk-IFA7MVBB.js.map +0 -1
- package/dist/chunk-L3H4HVUJ.cjs +0 -2
- package/dist/chunk-L3H4HVUJ.cjs.map +0 -1
- package/dist/chunk-R67UJPKI.js +0 -2
- package/dist/chunk-R67UJPKI.js.map +0 -1
- package/dist/chunk-TKDLUVJR.js +0 -2
- package/dist/chunk-TKDLUVJR.js.map +0 -1
package/dist/relations.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/relations.ts"],"names":["nextRelationId","defineRelation","options","ChildOf","getOrCreateStorage","state","rel","storage","addRelation","world","source","target","data","getWorldState","src","tgt","next","prevTgt","prevInner","list","inner","removeRelation","idx","getRelationTargets","gen","packEid","tIdx","getRelationData","registerRelationsCleanup","eid","e","i"],"mappings":"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","file":"relations.cjs","sourcesContent":["// aiecsjs/relations — entity-to-entity relations (experimental in 0.1).\n\nimport { packEid, registerRelationsCleanup } from './internal/entity.js'\nimport type { EntityId, Relation, RelationStorage, World, WorldState } from './internal/types.js'\nimport { getWorldState } from './internal/world.js'\n\nlet nextRelationId = 1\n\nexport function defineRelation<T = void>(options?: { exclusive?: boolean }): Relation<T> {\n const id = nextRelationId++\n return {\n __kind: 'relation',\n __id: id,\n __exclusive: options?.exclusive ?? false,\n __hasData: false,\n } as Relation<T>\n}\n\nexport const ChildOf: Relation = defineRelation({ exclusive: true })\n\nfunction getOrCreateStorage(state: WorldState, rel: Relation<any>): RelationStorage {\n let storage = state.relationStorage.get(rel.__id)\n if (storage) return storage\n storage = {\n rel,\n exclusive: rel.__exclusive ? new Int32Array(state.capacity).fill(-1) : null,\n outgoing: new Map<number, number[]>(),\n data: new Map<number, Map<number, unknown>>(),\n }\n state.relationStorage.set(rel.__id, storage)\n return storage\n}\n\nexport function addRelation<T>(\n world: World,\n source: EntityId,\n rel: Relation<T>,\n target: EntityId,\n data?: T,\n): void {\n const state = getWorldState(world)\n if (state.readOnly) throw new Error('aiecsjs: cannot mutate a read-only world')\n const storage = getOrCreateStorage(state, rel as Relation<any>)\n // Use raw idx as keys in relation storage so slot reuse invalidation is consistent\n const src = (source as number) & state.options.indexMask\n const tgt = (target as number) & state.options.indexMask\n\n if (storage.exclusive) {\n if (src >= storage.exclusive.length) {\n const next = new Int32Array(Math.max(src + 1, storage.exclusive.length * 2)).fill(-1)\n next.set(storage.exclusive)\n storage.exclusive = next\n }\n // Exclusive redirect: if this source already pointed at a different target,\n // drop that previous target's data entry so getRelationData stays consistent\n // with getRelationTargets, which reports only the current exclusive target.\n const prevTgt = storage.exclusive[src] ?? -1\n if (prevTgt >= 0 && prevTgt !== tgt) {\n const prevInner = storage.data.get(src)\n prevInner?.delete(prevTgt)\n if (prevInner && prevInner.size === 0) storage.data.delete(src)\n }\n storage.exclusive[src] = tgt\n } else {\n let list = storage.outgoing.get(src)\n if (!list) {\n list = []\n storage.outgoing.set(src, list)\n }\n if (!list.includes(tgt)) list.push(tgt)\n }\n\n if (data !== undefined) {\n let inner = storage.data.get(src)\n if (!inner) {\n inner = new Map<number, unknown>()\n storage.data.set(src, inner)\n }\n inner.set(tgt, data)\n }\n}\n\nexport function removeRelation(\n world: World,\n source: EntityId,\n rel: Relation,\n target: EntityId,\n): void {\n const state = getWorldState(world)\n if (state.readOnly) throw new Error('aiecsjs: cannot mutate a read-only world')\n const storage = state.relationStorage.get(rel.__id)\n if (!storage) return\n const src = (source as number) & state.options.indexMask\n const tgt = (target as number) & state.options.indexMask\n if (storage.exclusive) {\n if (src < storage.exclusive.length && storage.exclusive[src] === tgt) {\n storage.exclusive[src] = -1\n }\n } else {\n const list = storage.outgoing.get(src)\n if (list) {\n const idx = list.indexOf(tgt)\n if (idx >= 0) list.splice(idx, 1)\n if (list.length === 0) storage.outgoing.delete(src)\n }\n }\n const inner = storage.data.get(src)\n if (inner) {\n inner.delete(tgt)\n if (inner.size === 0) storage.data.delete(src)\n }\n}\n\nexport function getRelationTargets(\n world: World,\n source: EntityId,\n rel: Relation,\n): readonly EntityId[] {\n const state = getWorldState(world)\n const storage = state.relationStorage.get(rel.__id)\n if (!storage) return []\n const src = (source as number) & state.options.indexMask\n if (storage.exclusive) {\n if (src < storage.exclusive.length) {\n const tgt = storage.exclusive[src] ?? -1\n if (tgt >= 0) {\n const gen = state.generations[tgt] ?? 0\n return [packEid(tgt, gen, state.options)]\n }\n }\n return []\n }\n const list = storage.outgoing.get(src)\n if (!list) return []\n return list.map((tIdx) => {\n const gen = state.generations[tIdx] ?? 0\n return packEid(tIdx, gen, state.options)\n })\n}\n\n/**\n * Read the data payload attached to a relation edge.\n *\n * Returns the `data` value that was supplied to {@link addRelation} for the\n * `(source, rel, target)` triple, or `undefined` when:\n * - the relation has never been stored for this world,\n * - no edge from `source` to `target` via `rel` exists, or\n * - the edge was added without a data argument.\n *\n * **Slot-keying semantic (ABA caveat):** relation storage keys edges by raw\n * entity slot index (`entityId & indexMask`), not by the full packed EntityId\n * that includes the generation counter. This means that if entity A is\n * destroyed and a *different* entity B is later created in the same slot, B\n * will inherit any edges that A had — unless the destroy cleanup hook ran\n * (which it does when `destroyEntity` is called). Callers that cache a\n * source/target EntityId should validate liveness with `entityExists` before\n * calling `getRelationData` if slot recycling is a concern.\n */\nexport function getRelationData<T>(\n world: World,\n source: EntityId,\n rel: Relation<T>,\n target: EntityId,\n): T | undefined {\n const state = getWorldState(world)\n const storage = state.relationStorage.get(rel.__id)\n if (!storage) return undefined\n const src = (source as number) & state.options.indexMask\n const tgt = (target as number) & state.options.indexMask\n return storage.data.get(src)?.get(tgt) as T | undefined\n}\n\n// Cleanup hook: when an entity is destroyed, remove all relations involving it.\nregisterRelationsCleanup((state: WorldState, eid: EntityId) => {\n const e = (eid as number) & state.options.indexMask\n for (const storage of state.relationStorage.values()) {\n if (storage.exclusive) {\n if (e < storage.exclusive.length) storage.exclusive[e] = -1\n // Also clear any references TO this entity as target\n for (let i = 0; i < storage.exclusive.length; i++) {\n if (storage.exclusive[i] === e) storage.exclusive[i] = -1\n }\n }\n storage.outgoing.delete(e)\n for (const [src, list] of storage.outgoing) {\n const idx = list.indexOf(e)\n if (idx >= 0) {\n list.splice(idx, 1)\n if (list.length === 0) storage.outgoing.delete(src)\n }\n }\n // Clear data entries involving this entity. The outer key is the source\n // eid; entries whose source IS this entity drop entirely. Entries that\n // reference this entity as a target are pruned from each inner map.\n storage.data.delete(e)\n for (const [src, inner] of storage.data) {\n inner.delete(e)\n if (inner.size === 0) storage.data.delete(src)\n }\n }\n})\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/relations.ts"],"names":["nextRelationId","defineRelation","options","ChildOf","getOrCreateStorage","state","rel","storage","linkIncoming","src","tgt","incoming","set","unlinkIncoming","addRelation","world","source","target","data","getWorldState","next","prevTgt","prevInner","list","inner","removeRelation","idx","getRelationTargets","gen","packEid","tIdx","getRelationData","registerRelationsCleanup","eid","e","cur","incomingSet"],"mappings":"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","file":"relations.cjs","sourcesContent":["// aiecsjs/relations — entity-to-entity relations (experimental in 0.1).\n\nimport { packEid, registerRelationsCleanup } from './internal/entity.js'\nimport type { EntityId, Relation, RelationStorage, World, WorldState } from './internal/types.js'\nimport { getWorldState } from './internal/world.js'\n\nlet nextRelationId = 1\n\nexport function defineRelation<T = void>(options?: { exclusive?: boolean }): Relation<T> {\n const id = nextRelationId++\n return {\n __kind: 'relation',\n __id: id,\n __exclusive: options?.exclusive ?? false,\n __hasData: false,\n } as Relation<T>\n}\n\nexport const ChildOf: Relation = defineRelation({ exclusive: true })\n\nfunction getOrCreateStorage(state: WorldState, rel: Relation<unknown>): RelationStorage {\n let storage = state.relationStorage.get(rel.__id)\n if (storage) return storage\n storage = {\n rel,\n exclusive: rel.__exclusive ? new Int32Array(state.capacity).fill(-1) : null,\n incoming: rel.__exclusive ? new Map<number, Set<number>>() : null,\n outgoing: new Map<number, number[]>(),\n data: new Map<number, Map<number, unknown>>(),\n }\n state.relationStorage.set(rel.__id, storage)\n return storage\n}\n\n// --- Exclusive reverse-index (incoming) helpers ---\n// `incoming` mirrors the `exclusive` array: incoming.get(tgt) is the set of\n// source slots whose exclusive[src] === tgt. Every place that writes a non-`-1`\n// value into `exclusive` must call `linkIncoming`, and every place that clears a\n// slot (sets it back to -1) must call `unlinkIncoming`, so the reverse index\n// never drifts from the forward array.\n\nfunction linkIncoming(storage: RelationStorage, src: number, tgt: number): void {\n const incoming = storage.incoming\n if (!incoming) return\n let set = incoming.get(tgt)\n if (!set) {\n set = new Set<number>()\n incoming.set(tgt, set)\n }\n set.add(src)\n}\n\nfunction unlinkIncoming(storage: RelationStorage, src: number, tgt: number): void {\n const incoming = storage.incoming\n if (!incoming) return\n const set = incoming.get(tgt)\n if (!set) return\n set.delete(src)\n if (set.size === 0) incoming.delete(tgt)\n}\n\nexport function addRelation<T>(\n world: World,\n source: EntityId,\n rel: Relation<T>,\n target: EntityId,\n data?: T,\n): void {\n const state = getWorldState(world)\n if (state.readOnly) throw new Error('aiecsjs: cannot mutate a read-only world')\n const storage = getOrCreateStorage(state, rel as Relation<unknown>)\n // Use raw idx as keys in relation storage so slot reuse invalidation is consistent\n const src = (source as number) & state.options.indexMask\n const tgt = (target as number) & state.options.indexMask\n\n if (storage.exclusive) {\n if (src >= storage.exclusive.length) {\n const next = new Int32Array(Math.max(src + 1, storage.exclusive.length * 2)).fill(-1)\n next.set(storage.exclusive)\n storage.exclusive = next\n }\n // Exclusive redirect: if this source already pointed at a different target,\n // drop that previous target's data entry so getRelationData stays consistent\n // with getRelationTargets, which reports only the current exclusive target.\n const prevTgt = storage.exclusive[src] ?? -1\n if (prevTgt >= 0 && prevTgt !== tgt) {\n const prevInner = storage.data.get(src)\n prevInner?.delete(prevTgt)\n if (prevInner && prevInner.size === 0) storage.data.delete(src)\n unlinkIncoming(storage, src, prevTgt)\n }\n storage.exclusive[src] = tgt\n if (prevTgt !== tgt) linkIncoming(storage, src, tgt)\n } else {\n let list = storage.outgoing.get(src)\n if (!list) {\n list = []\n storage.outgoing.set(src, list)\n }\n if (!list.includes(tgt)) list.push(tgt)\n }\n\n if (data !== undefined) {\n let inner = storage.data.get(src)\n if (!inner) {\n inner = new Map<number, unknown>()\n storage.data.set(src, inner)\n }\n inner.set(tgt, data)\n }\n}\n\nexport function removeRelation(\n world: World,\n source: EntityId,\n rel: Relation,\n target: EntityId,\n): void {\n const state = getWorldState(world)\n if (state.readOnly) throw new Error('aiecsjs: cannot mutate a read-only world')\n const storage = state.relationStorage.get(rel.__id)\n if (!storage) return\n const src = (source as number) & state.options.indexMask\n const tgt = (target as number) & state.options.indexMask\n if (storage.exclusive) {\n if (src < storage.exclusive.length && storage.exclusive[src] === tgt) {\n storage.exclusive[src] = -1\n unlinkIncoming(storage, src, tgt)\n }\n } else {\n const list = storage.outgoing.get(src)\n if (list) {\n const idx = list.indexOf(tgt)\n if (idx >= 0) list.splice(idx, 1)\n if (list.length === 0) storage.outgoing.delete(src)\n }\n }\n const inner = storage.data.get(src)\n if (inner) {\n inner.delete(tgt)\n if (inner.size === 0) storage.data.delete(src)\n }\n}\n\nexport function getRelationTargets(\n world: World,\n source: EntityId,\n rel: Relation,\n): readonly EntityId[] {\n const state = getWorldState(world)\n const storage = state.relationStorage.get(rel.__id)\n if (!storage) return []\n const src = (source as number) & state.options.indexMask\n if (storage.exclusive) {\n if (src < storage.exclusive.length) {\n const tgt = storage.exclusive[src] ?? -1\n if (tgt >= 0) {\n const gen = state.generations[tgt] ?? 0\n return [packEid(tgt, gen, state.options)]\n }\n }\n return []\n }\n const list = storage.outgoing.get(src)\n if (!list) return []\n return list.map((tIdx) => {\n const gen = state.generations[tIdx] ?? 0\n return packEid(tIdx, gen, state.options)\n })\n}\n\n/**\n * Read the data payload attached to a relation edge.\n *\n * Returns the `data` value that was supplied to {@link addRelation} for the\n * `(source, rel, target)` triple, or `undefined` when:\n * - the relation has never been stored for this world,\n * - no edge from `source` to `target` via `rel` exists, or\n * - the edge was added without a data argument.\n *\n * **Slot-keying semantic (ABA caveat):** relation storage keys edges by raw\n * entity slot index (`entityId & indexMask`), not by the full packed EntityId\n * that includes the generation counter. This means that if entity A is\n * destroyed and a *different* entity B is later created in the same slot, B\n * will inherit any edges that A had — unless the destroy cleanup hook ran\n * (which it does when `destroyEntity` is called). Callers that cache a\n * source/target EntityId should validate liveness with `entityExists` before\n * calling `getRelationData` if slot recycling is a concern.\n */\nexport function getRelationData<T>(\n world: World,\n source: EntityId,\n rel: Relation<T>,\n target: EntityId,\n): T | undefined {\n const state = getWorldState(world)\n const storage = state.relationStorage.get(rel.__id)\n if (!storage) return undefined\n const src = (source as number) & state.options.indexMask\n const tgt = (target as number) & state.options.indexMask\n return storage.data.get(src)?.get(tgt) as T | undefined\n}\n\n// Cleanup hook: when an entity is destroyed, remove all relations involving it.\nregisterRelationsCleanup((state: WorldState, eid: EntityId) => {\n const e = (eid as number) & state.options.indexMask\n for (const storage of state.relationStorage.values()) {\n if (storage.exclusive) {\n // `e` as a SOURCE: clear its own exclusive slot and unlink it from whatever\n // target it currently points at, so the reverse index stays consistent.\n if (e < storage.exclusive.length) {\n const cur = storage.exclusive[e] ?? -1\n if (cur >= 0) unlinkIncoming(storage, e, cur)\n storage.exclusive[e] = -1\n }\n // `e` as a TARGET: clear every source that points at it. Use the reverse\n // index to touch only the actual incoming sources (O(incoming)) instead of\n // scanning the entire `exclusive` capacity (O(capacity)) — the bounded-cost\n // path for large sparse relation tables. Behaviour is identical to the old\n // full scan: every src with exclusive[src] === e is reset to -1.\n const incomingSet = storage.incoming?.get(e)\n if (incomingSet) {\n for (const src of incomingSet) {\n if (src < storage.exclusive.length) storage.exclusive[src] = -1\n }\n storage.incoming?.delete(e)\n }\n }\n storage.outgoing.delete(e)\n for (const [src, list] of storage.outgoing) {\n const idx = list.indexOf(e)\n if (idx >= 0) {\n list.splice(idx, 1)\n if (list.length === 0) storage.outgoing.delete(src)\n }\n }\n // Clear data entries involving this entity. The outer key is the source\n // eid; entries whose source IS this entity drop entirely. Entries that\n // reference this entity as a target are pruned from each inner map.\n storage.data.delete(e)\n for (const [src, inner] of storage.data) {\n inner.delete(e)\n if (inner.size === 0) storage.data.delete(src)\n }\n }\n})\n"]}
|
package/dist/relations.d.cts
CHANGED
package/dist/relations.d.ts
CHANGED
package/dist/relations.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {F,j,s}from'./chunk-YFTCD2UG.js';var m=1;function v(a){return {__kind:"relation",__id:m++,__exclusive:a?.exclusive??false,__hasData:false}}var y=v({exclusive:true});function p(a,l){let o=a.relationStorage.get(l.__id);return o||(o={rel:l,exclusive:l.__exclusive?new Int32Array(a.capacity).fill(-1):null,incoming:l.__exclusive?new Map:null,outgoing:new Map,data:new Map},a.relationStorage.set(l.__id,o),o)}function _(a,l,o){let e=a.incoming;if(!e)return;let n=e.get(o);n||(n=new Set,e.set(o,n)),n.add(l);}function f(a,l,o){let e=a.incoming;if(!e)return;let n=e.get(o);n&&(n.delete(l),n.size===0&&e.delete(o));}function S(a,l,o,e,n){let t=j(a);if(t.readOnly)throw new Error("aiecsjs: cannot mutate a read-only world");let i=p(t,o),s=l&t.options.indexMask,c=e&t.options.indexMask;if(i.exclusive){if(s>=i.exclusive.length){let u=new Int32Array(Math.max(s+1,i.exclusive.length*2)).fill(-1);u.set(i.exclusive),i.exclusive=u;}let r=i.exclusive[s]??-1;if(r>=0&&r!==c){let u=i.data.get(s);u?.delete(r),u&&u.size===0&&i.data.delete(s),f(i,s,r);}i.exclusive[s]=c,r!==c&&_(i,s,c);}else {let r=i.outgoing.get(s);r||(r=[],i.outgoing.set(s,r)),r.includes(c)||r.push(c);}if(n!==void 0){let r=i.data.get(s);r||(r=new Map,i.data.set(s,r)),r.set(c,n);}}function w(a,l,o,e){let n=j(a);if(n.readOnly)throw new Error("aiecsjs: cannot mutate a read-only world");let t=n.relationStorage.get(o.__id);if(!t)return;let i=l&n.options.indexMask,s=e&n.options.indexMask;if(t.exclusive)i<t.exclusive.length&&t.exclusive[i]===s&&(t.exclusive[i]=-1,f(t,i,s));else {let r=t.outgoing.get(i);if(r){let u=r.indexOf(s);u>=0&&r.splice(u,1),r.length===0&&t.outgoing.delete(i);}}let c=t.data.get(i);c&&(c.delete(s),c.size===0&&t.data.delete(i));}function k(a,l,o){let e=j(a),n=e.relationStorage.get(o.__id);if(!n)return [];let t=l&e.options.indexMask;if(n.exclusive){if(t<n.exclusive.length){let s$1=n.exclusive[t]??-1;if(s$1>=0){let c=e.generations[s$1]??0;return [s(s$1,c,e.options)]}}return []}let i=n.outgoing.get(t);return i?i.map(s$1=>{let c=e.generations[s$1]??0;return s(s$1,c,e.options)}):[]}function I(a,l,o,e){let n=j(a),t=n.relationStorage.get(o.__id);if(!t)return;let i=l&n.options.indexMask,s=e&n.options.indexMask;return t.data.get(i)?.get(s)}F((a,l)=>{let o=l&a.options.indexMask;for(let e of a.relationStorage.values()){if(e.exclusive){if(o<e.exclusive.length){let t=e.exclusive[o]??-1;t>=0&&f(e,o,t),e.exclusive[o]=-1;}let n=e.incoming?.get(o);if(n){for(let t of n)t<e.exclusive.length&&(e.exclusive[t]=-1);e.incoming?.delete(o);}}e.outgoing.delete(o);for(let[n,t]of e.outgoing){let i=t.indexOf(o);i>=0&&(t.splice(i,1),t.length===0&&e.outgoing.delete(n));}e.data.delete(o);for(let[n,t]of e.data)t.delete(o),t.size===0&&e.data.delete(n);}});export{y as ChildOf,S as addRelation,v as defineRelation,I as getRelationData,k as getRelationTargets,w as removeRelation};//# sourceMappingURL=relations.js.map
|
|
2
2
|
//# sourceMappingURL=relations.js.map
|
package/dist/relations.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/relations.ts"],"names":["nextRelationId","defineRelation","options","ChildOf","getOrCreateStorage","state","rel","storage","addRelation","world","source","target","data","getWorldState","src","tgt","next","prevTgt","prevInner","list","inner","removeRelation","idx","getRelationTargets","gen","packEid","tIdx","getRelationData","registerRelationsCleanup","eid","e","i"],"mappings":"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","file":"relations.js","sourcesContent":["// aiecsjs/relations — entity-to-entity relations (experimental in 0.1).\n\nimport { packEid, registerRelationsCleanup } from './internal/entity.js'\nimport type { EntityId, Relation, RelationStorage, World, WorldState } from './internal/types.js'\nimport { getWorldState } from './internal/world.js'\n\nlet nextRelationId = 1\n\nexport function defineRelation<T = void>(options?: { exclusive?: boolean }): Relation<T> {\n const id = nextRelationId++\n return {\n __kind: 'relation',\n __id: id,\n __exclusive: options?.exclusive ?? false,\n __hasData: false,\n } as Relation<T>\n}\n\nexport const ChildOf: Relation = defineRelation({ exclusive: true })\n\nfunction getOrCreateStorage(state: WorldState, rel: Relation<any>): RelationStorage {\n let storage = state.relationStorage.get(rel.__id)\n if (storage) return storage\n storage = {\n rel,\n exclusive: rel.__exclusive ? new Int32Array(state.capacity).fill(-1) : null,\n outgoing: new Map<number, number[]>(),\n data: new Map<number, Map<number, unknown>>(),\n }\n state.relationStorage.set(rel.__id, storage)\n return storage\n}\n\nexport function addRelation<T>(\n world: World,\n source: EntityId,\n rel: Relation<T>,\n target: EntityId,\n data?: T,\n): void {\n const state = getWorldState(world)\n if (state.readOnly) throw new Error('aiecsjs: cannot mutate a read-only world')\n const storage = getOrCreateStorage(state, rel as Relation<any>)\n // Use raw idx as keys in relation storage so slot reuse invalidation is consistent\n const src = (source as number) & state.options.indexMask\n const tgt = (target as number) & state.options.indexMask\n\n if (storage.exclusive) {\n if (src >= storage.exclusive.length) {\n const next = new Int32Array(Math.max(src + 1, storage.exclusive.length * 2)).fill(-1)\n next.set(storage.exclusive)\n storage.exclusive = next\n }\n // Exclusive redirect: if this source already pointed at a different target,\n // drop that previous target's data entry so getRelationData stays consistent\n // with getRelationTargets, which reports only the current exclusive target.\n const prevTgt = storage.exclusive[src] ?? -1\n if (prevTgt >= 0 && prevTgt !== tgt) {\n const prevInner = storage.data.get(src)\n prevInner?.delete(prevTgt)\n if (prevInner && prevInner.size === 0) storage.data.delete(src)\n }\n storage.exclusive[src] = tgt\n } else {\n let list = storage.outgoing.get(src)\n if (!list) {\n list = []\n storage.outgoing.set(src, list)\n }\n if (!list.includes(tgt)) list.push(tgt)\n }\n\n if (data !== undefined) {\n let inner = storage.data.get(src)\n if (!inner) {\n inner = new Map<number, unknown>()\n storage.data.set(src, inner)\n }\n inner.set(tgt, data)\n }\n}\n\nexport function removeRelation(\n world: World,\n source: EntityId,\n rel: Relation,\n target: EntityId,\n): void {\n const state = getWorldState(world)\n if (state.readOnly) throw new Error('aiecsjs: cannot mutate a read-only world')\n const storage = state.relationStorage.get(rel.__id)\n if (!storage) return\n const src = (source as number) & state.options.indexMask\n const tgt = (target as number) & state.options.indexMask\n if (storage.exclusive) {\n if (src < storage.exclusive.length && storage.exclusive[src] === tgt) {\n storage.exclusive[src] = -1\n }\n } else {\n const list = storage.outgoing.get(src)\n if (list) {\n const idx = list.indexOf(tgt)\n if (idx >= 0) list.splice(idx, 1)\n if (list.length === 0) storage.outgoing.delete(src)\n }\n }\n const inner = storage.data.get(src)\n if (inner) {\n inner.delete(tgt)\n if (inner.size === 0) storage.data.delete(src)\n }\n}\n\nexport function getRelationTargets(\n world: World,\n source: EntityId,\n rel: Relation,\n): readonly EntityId[] {\n const state = getWorldState(world)\n const storage = state.relationStorage.get(rel.__id)\n if (!storage) return []\n const src = (source as number) & state.options.indexMask\n if (storage.exclusive) {\n if (src < storage.exclusive.length) {\n const tgt = storage.exclusive[src] ?? -1\n if (tgt >= 0) {\n const gen = state.generations[tgt] ?? 0\n return [packEid(tgt, gen, state.options)]\n }\n }\n return []\n }\n const list = storage.outgoing.get(src)\n if (!list) return []\n return list.map((tIdx) => {\n const gen = state.generations[tIdx] ?? 0\n return packEid(tIdx, gen, state.options)\n })\n}\n\n/**\n * Read the data payload attached to a relation edge.\n *\n * Returns the `data` value that was supplied to {@link addRelation} for the\n * `(source, rel, target)` triple, or `undefined` when:\n * - the relation has never been stored for this world,\n * - no edge from `source` to `target` via `rel` exists, or\n * - the edge was added without a data argument.\n *\n * **Slot-keying semantic (ABA caveat):** relation storage keys edges by raw\n * entity slot index (`entityId & indexMask`), not by the full packed EntityId\n * that includes the generation counter. This means that if entity A is\n * destroyed and a *different* entity B is later created in the same slot, B\n * will inherit any edges that A had — unless the destroy cleanup hook ran\n * (which it does when `destroyEntity` is called). Callers that cache a\n * source/target EntityId should validate liveness with `entityExists` before\n * calling `getRelationData` if slot recycling is a concern.\n */\nexport function getRelationData<T>(\n world: World,\n source: EntityId,\n rel: Relation<T>,\n target: EntityId,\n): T | undefined {\n const state = getWorldState(world)\n const storage = state.relationStorage.get(rel.__id)\n if (!storage) return undefined\n const src = (source as number) & state.options.indexMask\n const tgt = (target as number) & state.options.indexMask\n return storage.data.get(src)?.get(tgt) as T | undefined\n}\n\n// Cleanup hook: when an entity is destroyed, remove all relations involving it.\nregisterRelationsCleanup((state: WorldState, eid: EntityId) => {\n const e = (eid as number) & state.options.indexMask\n for (const storage of state.relationStorage.values()) {\n if (storage.exclusive) {\n if (e < storage.exclusive.length) storage.exclusive[e] = -1\n // Also clear any references TO this entity as target\n for (let i = 0; i < storage.exclusive.length; i++) {\n if (storage.exclusive[i] === e) storage.exclusive[i] = -1\n }\n }\n storage.outgoing.delete(e)\n for (const [src, list] of storage.outgoing) {\n const idx = list.indexOf(e)\n if (idx >= 0) {\n list.splice(idx, 1)\n if (list.length === 0) storage.outgoing.delete(src)\n }\n }\n // Clear data entries involving this entity. The outer key is the source\n // eid; entries whose source IS this entity drop entirely. Entries that\n // reference this entity as a target are pruned from each inner map.\n storage.data.delete(e)\n for (const [src, inner] of storage.data) {\n inner.delete(e)\n if (inner.size === 0) storage.data.delete(src)\n }\n }\n})\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/relations.ts"],"names":["nextRelationId","defineRelation","options","ChildOf","getOrCreateStorage","state","rel","storage","linkIncoming","src","tgt","incoming","set","unlinkIncoming","addRelation","world","source","target","data","getWorldState","next","prevTgt","prevInner","list","inner","removeRelation","idx","getRelationTargets","gen","packEid","tIdx","getRelationData","registerRelationsCleanup","eid","e","cur","incomingSet"],"mappings":"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","file":"relations.js","sourcesContent":["// aiecsjs/relations — entity-to-entity relations (experimental in 0.1).\n\nimport { packEid, registerRelationsCleanup } from './internal/entity.js'\nimport type { EntityId, Relation, RelationStorage, World, WorldState } from './internal/types.js'\nimport { getWorldState } from './internal/world.js'\n\nlet nextRelationId = 1\n\nexport function defineRelation<T = void>(options?: { exclusive?: boolean }): Relation<T> {\n const id = nextRelationId++\n return {\n __kind: 'relation',\n __id: id,\n __exclusive: options?.exclusive ?? false,\n __hasData: false,\n } as Relation<T>\n}\n\nexport const ChildOf: Relation = defineRelation({ exclusive: true })\n\nfunction getOrCreateStorage(state: WorldState, rel: Relation<unknown>): RelationStorage {\n let storage = state.relationStorage.get(rel.__id)\n if (storage) return storage\n storage = {\n rel,\n exclusive: rel.__exclusive ? new Int32Array(state.capacity).fill(-1) : null,\n incoming: rel.__exclusive ? new Map<number, Set<number>>() : null,\n outgoing: new Map<number, number[]>(),\n data: new Map<number, Map<number, unknown>>(),\n }\n state.relationStorage.set(rel.__id, storage)\n return storage\n}\n\n// --- Exclusive reverse-index (incoming) helpers ---\n// `incoming` mirrors the `exclusive` array: incoming.get(tgt) is the set of\n// source slots whose exclusive[src] === tgt. Every place that writes a non-`-1`\n// value into `exclusive` must call `linkIncoming`, and every place that clears a\n// slot (sets it back to -1) must call `unlinkIncoming`, so the reverse index\n// never drifts from the forward array.\n\nfunction linkIncoming(storage: RelationStorage, src: number, tgt: number): void {\n const incoming = storage.incoming\n if (!incoming) return\n let set = incoming.get(tgt)\n if (!set) {\n set = new Set<number>()\n incoming.set(tgt, set)\n }\n set.add(src)\n}\n\nfunction unlinkIncoming(storage: RelationStorage, src: number, tgt: number): void {\n const incoming = storage.incoming\n if (!incoming) return\n const set = incoming.get(tgt)\n if (!set) return\n set.delete(src)\n if (set.size === 0) incoming.delete(tgt)\n}\n\nexport function addRelation<T>(\n world: World,\n source: EntityId,\n rel: Relation<T>,\n target: EntityId,\n data?: T,\n): void {\n const state = getWorldState(world)\n if (state.readOnly) throw new Error('aiecsjs: cannot mutate a read-only world')\n const storage = getOrCreateStorage(state, rel as Relation<unknown>)\n // Use raw idx as keys in relation storage so slot reuse invalidation is consistent\n const src = (source as number) & state.options.indexMask\n const tgt = (target as number) & state.options.indexMask\n\n if (storage.exclusive) {\n if (src >= storage.exclusive.length) {\n const next = new Int32Array(Math.max(src + 1, storage.exclusive.length * 2)).fill(-1)\n next.set(storage.exclusive)\n storage.exclusive = next\n }\n // Exclusive redirect: if this source already pointed at a different target,\n // drop that previous target's data entry so getRelationData stays consistent\n // with getRelationTargets, which reports only the current exclusive target.\n const prevTgt = storage.exclusive[src] ?? -1\n if (prevTgt >= 0 && prevTgt !== tgt) {\n const prevInner = storage.data.get(src)\n prevInner?.delete(prevTgt)\n if (prevInner && prevInner.size === 0) storage.data.delete(src)\n unlinkIncoming(storage, src, prevTgt)\n }\n storage.exclusive[src] = tgt\n if (prevTgt !== tgt) linkIncoming(storage, src, tgt)\n } else {\n let list = storage.outgoing.get(src)\n if (!list) {\n list = []\n storage.outgoing.set(src, list)\n }\n if (!list.includes(tgt)) list.push(tgt)\n }\n\n if (data !== undefined) {\n let inner = storage.data.get(src)\n if (!inner) {\n inner = new Map<number, unknown>()\n storage.data.set(src, inner)\n }\n inner.set(tgt, data)\n }\n}\n\nexport function removeRelation(\n world: World,\n source: EntityId,\n rel: Relation,\n target: EntityId,\n): void {\n const state = getWorldState(world)\n if (state.readOnly) throw new Error('aiecsjs: cannot mutate a read-only world')\n const storage = state.relationStorage.get(rel.__id)\n if (!storage) return\n const src = (source as number) & state.options.indexMask\n const tgt = (target as number) & state.options.indexMask\n if (storage.exclusive) {\n if (src < storage.exclusive.length && storage.exclusive[src] === tgt) {\n storage.exclusive[src] = -1\n unlinkIncoming(storage, src, tgt)\n }\n } else {\n const list = storage.outgoing.get(src)\n if (list) {\n const idx = list.indexOf(tgt)\n if (idx >= 0) list.splice(idx, 1)\n if (list.length === 0) storage.outgoing.delete(src)\n }\n }\n const inner = storage.data.get(src)\n if (inner) {\n inner.delete(tgt)\n if (inner.size === 0) storage.data.delete(src)\n }\n}\n\nexport function getRelationTargets(\n world: World,\n source: EntityId,\n rel: Relation,\n): readonly EntityId[] {\n const state = getWorldState(world)\n const storage = state.relationStorage.get(rel.__id)\n if (!storage) return []\n const src = (source as number) & state.options.indexMask\n if (storage.exclusive) {\n if (src < storage.exclusive.length) {\n const tgt = storage.exclusive[src] ?? -1\n if (tgt >= 0) {\n const gen = state.generations[tgt] ?? 0\n return [packEid(tgt, gen, state.options)]\n }\n }\n return []\n }\n const list = storage.outgoing.get(src)\n if (!list) return []\n return list.map((tIdx) => {\n const gen = state.generations[tIdx] ?? 0\n return packEid(tIdx, gen, state.options)\n })\n}\n\n/**\n * Read the data payload attached to a relation edge.\n *\n * Returns the `data` value that was supplied to {@link addRelation} for the\n * `(source, rel, target)` triple, or `undefined` when:\n * - the relation has never been stored for this world,\n * - no edge from `source` to `target` via `rel` exists, or\n * - the edge was added without a data argument.\n *\n * **Slot-keying semantic (ABA caveat):** relation storage keys edges by raw\n * entity slot index (`entityId & indexMask`), not by the full packed EntityId\n * that includes the generation counter. This means that if entity A is\n * destroyed and a *different* entity B is later created in the same slot, B\n * will inherit any edges that A had — unless the destroy cleanup hook ran\n * (which it does when `destroyEntity` is called). Callers that cache a\n * source/target EntityId should validate liveness with `entityExists` before\n * calling `getRelationData` if slot recycling is a concern.\n */\nexport function getRelationData<T>(\n world: World,\n source: EntityId,\n rel: Relation<T>,\n target: EntityId,\n): T | undefined {\n const state = getWorldState(world)\n const storage = state.relationStorage.get(rel.__id)\n if (!storage) return undefined\n const src = (source as number) & state.options.indexMask\n const tgt = (target as number) & state.options.indexMask\n return storage.data.get(src)?.get(tgt) as T | undefined\n}\n\n// Cleanup hook: when an entity is destroyed, remove all relations involving it.\nregisterRelationsCleanup((state: WorldState, eid: EntityId) => {\n const e = (eid as number) & state.options.indexMask\n for (const storage of state.relationStorage.values()) {\n if (storage.exclusive) {\n // `e` as a SOURCE: clear its own exclusive slot and unlink it from whatever\n // target it currently points at, so the reverse index stays consistent.\n if (e < storage.exclusive.length) {\n const cur = storage.exclusive[e] ?? -1\n if (cur >= 0) unlinkIncoming(storage, e, cur)\n storage.exclusive[e] = -1\n }\n // `e` as a TARGET: clear every source that points at it. Use the reverse\n // index to touch only the actual incoming sources (O(incoming)) instead of\n // scanning the entire `exclusive` capacity (O(capacity)) — the bounded-cost\n // path for large sparse relation tables. Behaviour is identical to the old\n // full scan: every src with exclusive[src] === e is reset to -1.\n const incomingSet = storage.incoming?.get(e)\n if (incomingSet) {\n for (const src of incomingSet) {\n if (src < storage.exclusive.length) storage.exclusive[src] = -1\n }\n storage.incoming?.delete(e)\n }\n }\n storage.outgoing.delete(e)\n for (const [src, list] of storage.outgoing) {\n const idx = list.indexOf(e)\n if (idx >= 0) {\n list.splice(idx, 1)\n if (list.length === 0) storage.outgoing.delete(src)\n }\n }\n // Clear data entries involving this entity. The outer key is the source\n // eid; entries whose source IS this entity drop entirely. Entries that\n // reference this entity as a target are pruned from each inner map.\n storage.data.delete(e)\n for (const [src, inner] of storage.data) {\n inner.delete(e)\n if (inner.size === 0) storage.data.delete(src)\n }\n }\n})\n"]}
|
package/dist/serialize.cjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
'use strict';var
|
|
1
|
+
'use strict';var chunk3FV6UMUS_cjs=require('./chunk-3FV6UMUS.cjs');require('./chunk-ZIZSWIHW.cjs');Object.defineProperty(exports,"createDeltaSerializer",{enumerable:true,get:function(){return chunk3FV6UMUS_cjs.e}});Object.defineProperty(exports,"deserializeWorld",{enumerable:true,get:function(){return chunk3FV6UMUS_cjs.b}});Object.defineProperty(exports,"fromJSON",{enumerable:true,get:function(){return chunk3FV6UMUS_cjs.d}});Object.defineProperty(exports,"serializeWorld",{enumerable:true,get:function(){return chunk3FV6UMUS_cjs.a}});Object.defineProperty(exports,"toJSON",{enumerable:true,get:function(){return chunk3FV6UMUS_cjs.c}});//# sourceMappingURL=serialize.cjs.map
|
|
2
2
|
//# sourceMappingURL=serialize.cjs.map
|
package/dist/serialize.d.cts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { W as World, S as SerializeOptions, D as DeltaSerializer, e as DeserializeOptions, p as WorldSnapshot } from './types-
|
|
1
|
+
import { W as World, S as SerializeOptions, D as DeltaSerializer, e as DeserializeOptions, p as WorldSnapshot } from './types-BeVLA7xG.cjs';
|
|
2
2
|
|
|
3
3
|
declare function serializeWorld(world: World, options?: SerializeOptions): Uint8Array;
|
|
4
4
|
declare function deserializeWorld(bytes: Uint8Array, options?: DeserializeOptions): World;
|
package/dist/serialize.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { W as World, S as SerializeOptions, D as DeltaSerializer, e as DeserializeOptions, p as WorldSnapshot } from './types-
|
|
1
|
+
import { W as World, S as SerializeOptions, D as DeltaSerializer, e as DeserializeOptions, p as WorldSnapshot } from './types-BeVLA7xG.js';
|
|
2
2
|
|
|
3
3
|
declare function serializeWorld(world: World, options?: SerializeOptions): Uint8Array;
|
|
4
4
|
declare function deserializeWorld(bytes: Uint8Array, options?: DeserializeOptions): World;
|
package/dist/serialize.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export{e as createDeltaSerializer,b as deserializeWorld,d as fromJSON,a as serializeWorld,c as toJSON}from'./chunk-
|
|
1
|
+
export{e as createDeltaSerializer,b as deserializeWorld,d as fromJSON,a as serializeWorld,c as toJSON}from'./chunk-TNZMD7E5.js';import'./chunk-YFTCD2UG.js';//# sourceMappingURL=serialize.js.map
|
|
2
2
|
//# sourceMappingURL=serialize.js.map
|
|
@@ -56,7 +56,17 @@ interface WorldOptions {
|
|
|
56
56
|
maxEntities?: number;
|
|
57
57
|
indexBits?: number;
|
|
58
58
|
generationBits?: number;
|
|
59
|
+
/**
|
|
60
|
+
* RESERVED / UNIMPLEMENTED (0.x). Setting this has **no effect** today: the
|
|
61
|
+
* world always allocates its own column storage and never reads or writes a
|
|
62
|
+
* caller-supplied SAB. The 0.x Worker handoff is a snapshot-copy transport —
|
|
63
|
+
* post `transferableSnapshot(world)` and rebuild via `adoptSnapshot` from
|
|
64
|
+
* `aiecsjs/worker`; do not pre-allocate a SAB here. The field is kept so the
|
|
65
|
+
* shape is forward-compatible with the true shared-column backing targeted
|
|
66
|
+
* for 0.3+ (see STABILITY.md, `aiecsjs/worker`).
|
|
67
|
+
*/
|
|
59
68
|
buffer?: SharedArrayBuffer;
|
|
69
|
+
/** RESERVED / UNIMPLEMENTED (0.x). Paired with {@link WorldOptions.buffer}; no effect today. */
|
|
60
70
|
bufferByteOffset?: number;
|
|
61
71
|
}
|
|
62
72
|
interface World {
|
|
@@ -88,7 +98,7 @@ interface WorldMeta {
|
|
|
88
98
|
}>;
|
|
89
99
|
}
|
|
90
100
|
interface TransferableSnapshot {
|
|
91
|
-
buffer: SharedArrayBuffer;
|
|
101
|
+
buffer: SharedArrayBuffer | ArrayBuffer;
|
|
92
102
|
meta: WorldMeta;
|
|
93
103
|
}
|
|
94
104
|
interface SerializeOptions {
|
|
@@ -56,7 +56,17 @@ interface WorldOptions {
|
|
|
56
56
|
maxEntities?: number;
|
|
57
57
|
indexBits?: number;
|
|
58
58
|
generationBits?: number;
|
|
59
|
+
/**
|
|
60
|
+
* RESERVED / UNIMPLEMENTED (0.x). Setting this has **no effect** today: the
|
|
61
|
+
* world always allocates its own column storage and never reads or writes a
|
|
62
|
+
* caller-supplied SAB. The 0.x Worker handoff is a snapshot-copy transport —
|
|
63
|
+
* post `transferableSnapshot(world)` and rebuild via `adoptSnapshot` from
|
|
64
|
+
* `aiecsjs/worker`; do not pre-allocate a SAB here. The field is kept so the
|
|
65
|
+
* shape is forward-compatible with the true shared-column backing targeted
|
|
66
|
+
* for 0.3+ (see STABILITY.md, `aiecsjs/worker`).
|
|
67
|
+
*/
|
|
59
68
|
buffer?: SharedArrayBuffer;
|
|
69
|
+
/** RESERVED / UNIMPLEMENTED (0.x). Paired with {@link WorldOptions.buffer}; no effect today. */
|
|
60
70
|
bufferByteOffset?: number;
|
|
61
71
|
}
|
|
62
72
|
interface World {
|
|
@@ -88,7 +98,7 @@ interface WorldMeta {
|
|
|
88
98
|
}>;
|
|
89
99
|
}
|
|
90
100
|
interface TransferableSnapshot {
|
|
91
|
-
buffer: SharedArrayBuffer;
|
|
101
|
+
buffer: SharedArrayBuffer | ArrayBuffer;
|
|
92
102
|
meta: WorldMeta;
|
|
93
103
|
}
|
|
94
104
|
interface SerializeOptions {
|
package/dist/worker.cjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
'use strict';var
|
|
1
|
+
'use strict';var chunk3FV6UMUS_cjs=require('./chunk-3FV6UMUS.cjs'),chunkZIZSWIHW_cjs=require('./chunk-ZIZSWIHW.cjs');var l=1095320899;function W(r){let e=chunkZIZSWIHW_cjs.j(r),o=chunk3FV6UMUS_cjs.a(r);if(typeof SharedArrayBuffer>"u"){let n=new ArrayBuffer(o.byteLength);return new Uint8Array(n).set(o),{buffer:n,meta:p(e)}}let t=new SharedArrayBuffer(o.byteLength);return new Uint8Array(t).set(o),{buffer:t,meta:p(e)}}function b(r){m(r.meta);let e=new Uint8Array(r.buffer);return chunk3FV6UMUS_cjs.b(e)}function S(r,e){let o=new Uint8Array(r),t=chunk3FV6UMUS_cjs.b(o);if(e?.readOnly){let n=chunkZIZSWIHW_cjs.j(t);n.readOnly=true;}return t}function B(r){chunkZIZSWIHW_cjs.k(r.id)&&chunkZIZSWIHW_cjs.m(r);}function p(r){let e=[];for(let o of r.componentInfoByBit)o&&e.push({id:o.id,kind:o.kind,schema:o.schema});return {magic:l,formatVersion:1,aiecsjsVersion:chunkZIZSWIHW_cjs.a,indexBits:r.options.indexBits,generationBits:r.options.generationBits,maxComponents:r.options.maxComponents,maskWordCount:r.options.maskWordCount,capacity:r.capacity,componentSchemas:e}}function m(r){if(r.magic!==l)throw new Error("aiecsjs: invalid snapshot meta (wrong magic)");if(r.formatVersion!==1)throw new Error(`aiecsjs: unsupported snapshot format version ${r.formatVersion}`)}exports.adoptSnapshot=b;exports.attachWorld=S;exports.detachWorld=B;exports.transferableSnapshot=W;//# sourceMappingURL=worker.cjs.map
|
|
2
2
|
//# sourceMappingURL=worker.cjs.map
|
package/dist/worker.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/worker.ts"],"names":["MAGIC","transferableSnapshot","world","state","getWorldState","bytes","serializeWorld","ab","buildMeta","sab","adoptSnapshot","snap","validateMeta","deserializeWorld","attachWorld","buffer","options","detachWorld","isWorldRegistered","destroyWorld","componentSchemas","info","VERSION","meta"],"mappings":"qHAkBA,IAAMA,CAAAA,CAAQ,WAEP,SAASC,CAAAA,CAAqBC,EAAoC,CACvE,IAAMC,CAAAA,CAAQC,mBAAAA,CAAcF,CAAK,CAAA,CAC3BG,EAAQC,mBAAAA,CAAeJ,CAAK,EAElC,GAAI,OAAO,kBAAsB,GAAA,CAAa,
|
|
1
|
+
{"version":3,"sources":["../src/worker.ts"],"names":["MAGIC","transferableSnapshot","world","state","getWorldState","bytes","serializeWorld","ab","buildMeta","sab","adoptSnapshot","snap","validateMeta","deserializeWorld","attachWorld","buffer","options","detachWorld","isWorldRegistered","destroyWorld","componentSchemas","info","VERSION","meta"],"mappings":"qHAkBA,IAAMA,CAAAA,CAAQ,WAEP,SAASC,CAAAA,CAAqBC,EAAoC,CACvE,IAAMC,CAAAA,CAAQC,mBAAAA,CAAcF,CAAK,CAAA,CAC3BG,EAAQC,mBAAAA,CAAeJ,CAAK,EAElC,GAAI,OAAO,kBAAsB,GAAA,CAAa,CAI5C,IAAMK,CAAAA,CAAK,IAAI,WAAA,CAAYF,EAAM,UAAU,CAAA,CAC3C,WAAI,UAAA,CAAWE,CAAE,EAAE,GAAA,CAAIF,CAAK,CAAA,CACrB,CACL,MAAA,CAAQE,CAAAA,CACR,KAAMC,CAAAA,CAAUL,CAAK,CACvB,CACF,CAEA,IAAMM,EAAM,IAAI,iBAAA,CAAkBJ,CAAAA,CAAM,UAAU,CAAA,CAClD,OAAA,IAAI,WAAWI,CAAG,CAAA,CAAE,IAAIJ,CAAK,CAAA,CACtB,CAAE,MAAA,CAAQI,CAAAA,CAAK,IAAA,CAAMD,CAAAA,CAAUL,CAAK,CAAE,CAC/C,CAaO,SAASO,CAAAA,CAAcC,CAAAA,CAAmC,CAC/DC,CAAAA,CAAaD,EAAK,IAAI,CAAA,CACtB,IAAMN,CAAAA,CAAQ,IAAI,UAAA,CAAWM,EAAK,MAAM,CAAA,CACxC,OAAOE,mBAAAA,CAAiBR,CAAK,CAC/B,CAaO,SAASS,CAAAA,CACdC,CAAAA,CACAC,CAAAA,CACO,CACP,IAAMX,CAAAA,CAAQ,IAAI,UAAA,CAAWU,CAAM,CAAA,CAC7Bb,CAAAA,CAAQW,oBAAiBR,CAAK,CAAA,CACpC,GAAIW,CAAAA,EAAS,QAAA,CAAU,CACrB,IAAMb,CAAAA,CAAQC,mBAAAA,CAAcF,CAAK,CAAA,CACjCC,CAAAA,CAAM,SAAW,KACnB,CACA,OAAOD,CACT,CAEO,SAASe,EAAYf,CAAAA,CAAoB,CAC1CgB,mBAAAA,CAAkBhB,CAAAA,CAAM,EAAE,CAAA,EAC5BiB,oBAAajB,CAAK,EAEtB,CAEA,SAASM,CAAAA,CAAUL,CAAAA,CAA8B,CAC/C,IAAMiB,CAAAA,CAAkD,EAAC,CACzD,IAAA,IAAWC,KAAQlB,CAAAA,CAAM,kBAAA,CAClBkB,CAAAA,EACLD,CAAAA,CAAiB,IAAA,CAAK,CAAE,GAAIC,CAAAA,CAAK,EAAA,CAAI,IAAA,CAAMA,CAAAA,CAAK,IAAA,CAAM,MAAA,CAAQA,EAAK,MAAO,CAAC,CAAA,CAE7E,OAAO,CACL,KAAA,CAAOrB,EACP,aAAA,CAAe,CAAA,CACf,eAAgBsB,mBAAAA,CAChB,SAAA,CAAWnB,EAAM,OAAA,CAAQ,SAAA,CACzB,cAAA,CAAgBA,CAAAA,CAAM,OAAA,CAAQ,cAAA,CAC9B,cAAeA,CAAAA,CAAM,OAAA,CAAQ,aAAA,CAC7B,aAAA,CAAeA,CAAAA,CAAM,OAAA,CAAQ,cAC7B,QAAA,CAAUA,CAAAA,CAAM,QAAA,CAChB,gBAAA,CAAAiB,CACF,CACF,CAEA,SAASR,CAAAA,CAAaW,EAAuB,CAC3C,GAAIA,EAAK,KAAA,GAAUvB,CAAAA,CACjB,MAAM,IAAI,KAAA,CAAM,8CAA8C,EAEhE,GAAIuB,CAAAA,CAAK,aAAA,GAAkB,CAAA,CACzB,MAAM,IAAI,MAAM,CAAA,6CAAA,EAAgDA,CAAAA,CAAK,aAAa,CAAA,CAAE,CAExF","file":"worker.cjs","sourcesContent":["// aiecsjs/worker — SharedArrayBuffer helpers (experimental, snapshot-copy).\n//\n// Note: 0.x implements SAB as a transferable snapshot pattern rather than true\n// shared-memory aliasing. The world is serialized into the SAB, and the worker\n// reconstructs a fresh world from those bytes via adoptSnapshot/attachWorld.\n// True shared-column memory is targeted for a future stable release.\n// The API matches the documented contract and survives postMessage cleanly.\n//\n// EntityRef is in-memory only — not preserved across worker boundaries.\n// Generation counters reset on adoptSnapshot/attachWorld. Pass `EntityRef.id`\n// (the packed EntityId) across the worker boundary only if you understand that\n// the generation portion will be stale after a round-trip snapshot.\n\nimport type { TransferableSnapshot, World, WorldMeta, WorldState } from './internal/types.js'\nimport { destroyWorld, getWorldState, isWorldRegistered } from './internal/world.js'\nimport { deserializeWorld, serializeWorld } from './serialize.js'\nimport { VERSION } from './version.js'\n\nconst MAGIC = 0x41494543 // 'AIEC' little-endian as uint32\n\nexport function transferableSnapshot(world: World): TransferableSnapshot {\n const state = getWorldState(world)\n const bytes = serializeWorld(world)\n\n if (typeof SharedArrayBuffer === 'undefined') {\n // Fallback: a plain ArrayBuffer. TransferableSnapshot.buffer is typed\n // `SharedArrayBuffer | ArrayBuffer`, so this needs no cast — the type tells\n // the truth instead of pretending the fallback is a SAB.\n const ab = new ArrayBuffer(bytes.byteLength)\n new Uint8Array(ab).set(bytes)\n return {\n buffer: ab,\n meta: buildMeta(state),\n }\n }\n\n const sab = new SharedArrayBuffer(bytes.byteLength)\n new Uint8Array(sab).set(bytes)\n return { buffer: sab, meta: buildMeta(state) }\n}\n\n/**\n * Adopt a snapshot previously produced by `transferableSnapshot`.\n *\n * SECURITY: same trust expectation as `attachWorld` — the sender of the\n * `TransferableSnapshot` (typically a Web Worker) must be trusted. The\n * function runs `validateMeta` and `deserializeWorld`, which enforce magic\n * + format version + length bounds on the binary header; but the inner\n * JSON payload, once decoded, is fed to `addComponent` and reaches AoS\n * components. For untrusted senders, use `aibridgejs` + `toJSON(world)` at\n * the application boundary instead.\n */\nexport function adoptSnapshot(snap: TransferableSnapshot): World {\n validateMeta(snap.meta)\n const bytes = new Uint8Array(snap.buffer)\n return deserializeWorld(bytes)\n}\n\n/**\n * Adopt a SharedArrayBuffer-backed snapshot produced by `transferableSnapshot`.\n *\n * SECURITY: the SAB sender must be trusted. `attachWorld` performs the same\n * magic + version + length-bounds checks as `deserializeWorld`, but the JSON\n * payload itself is deserialised into AoS components via `addComponent`. If\n * the sender is untrusted (e.g. a third-party Web Worker that you do not\n * audit), prefer the higher-level `aibridgejs` channel + `toJSON(world)`\n * pattern, which lets you validate the shape at the application boundary\n * before constructing entities.\n */\nexport function attachWorld(\n buffer: SharedArrayBuffer | ArrayBuffer,\n options?: { readOnly?: boolean },\n): World {\n const bytes = new Uint8Array(buffer)\n const world = deserializeWorld(bytes)\n if (options?.readOnly) {\n const state = getWorldState(world)\n state.readOnly = true\n }\n return world\n}\n\nexport function detachWorld(world: World): void {\n if (isWorldRegistered(world.id)) {\n destroyWorld(world)\n }\n}\n\nfunction buildMeta(state: WorldState): WorldMeta {\n const componentSchemas: WorldMeta['componentSchemas'] = []\n for (const info of state.componentInfoByBit) {\n if (!info) continue\n componentSchemas.push({ id: info.id, kind: info.kind, schema: info.schema })\n }\n return {\n magic: MAGIC,\n formatVersion: 1,\n aiecsjsVersion: VERSION,\n indexBits: state.options.indexBits,\n generationBits: state.options.generationBits,\n maxComponents: state.options.maxComponents,\n maskWordCount: state.options.maskWordCount,\n capacity: state.capacity,\n componentSchemas,\n }\n}\n\nfunction validateMeta(meta: WorldMeta): void {\n if (meta.magic !== MAGIC) {\n throw new Error('aiecsjs: invalid snapshot meta (wrong magic)')\n }\n if (meta.formatVersion !== 1) {\n throw new Error(`aiecsjs: unsupported snapshot format version ${meta.formatVersion}`)\n }\n}\n"]}
|
package/dist/worker.d.cts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { m as TransferableSnapshot, W as World } from './types-
|
|
1
|
+
import { m as TransferableSnapshot, W as World } from './types-BeVLA7xG.cjs';
|
|
2
2
|
|
|
3
3
|
declare function transferableSnapshot(world: World): TransferableSnapshot;
|
|
4
4
|
/**
|
|
@@ -24,7 +24,7 @@ declare function adoptSnapshot(snap: TransferableSnapshot): World;
|
|
|
24
24
|
* pattern, which lets you validate the shape at the application boundary
|
|
25
25
|
* before constructing entities.
|
|
26
26
|
*/
|
|
27
|
-
declare function attachWorld(buffer: SharedArrayBuffer, options?: {
|
|
27
|
+
declare function attachWorld(buffer: SharedArrayBuffer | ArrayBuffer, options?: {
|
|
28
28
|
readOnly?: boolean;
|
|
29
29
|
}): World;
|
|
30
30
|
declare function detachWorld(world: World): void;
|
package/dist/worker.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { m as TransferableSnapshot, W as World } from './types-
|
|
1
|
+
import { m as TransferableSnapshot, W as World } from './types-BeVLA7xG.js';
|
|
2
2
|
|
|
3
3
|
declare function transferableSnapshot(world: World): TransferableSnapshot;
|
|
4
4
|
/**
|
|
@@ -24,7 +24,7 @@ declare function adoptSnapshot(snap: TransferableSnapshot): World;
|
|
|
24
24
|
* pattern, which lets you validate the shape at the application boundary
|
|
25
25
|
* before constructing entities.
|
|
26
26
|
*/
|
|
27
|
-
declare function attachWorld(buffer: SharedArrayBuffer, options?: {
|
|
27
|
+
declare function attachWorld(buffer: SharedArrayBuffer | ArrayBuffer, options?: {
|
|
28
28
|
readOnly?: boolean;
|
|
29
29
|
}): World;
|
|
30
30
|
declare function detachWorld(world: World): void;
|
package/dist/worker.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import {a,b as b$1}from'./chunk-
|
|
1
|
+
import {a,b as b$1}from'./chunk-TNZMD7E5.js';import {j,k,m as m$1,a as a$1}from'./chunk-YFTCD2UG.js';var l=1095320899;function W(r){let e=j(r),o=a(r);if(typeof SharedArrayBuffer>"u"){let n=new ArrayBuffer(o.byteLength);return new Uint8Array(n).set(o),{buffer:n,meta:p(e)}}let t=new SharedArrayBuffer(o.byteLength);return new Uint8Array(t).set(o),{buffer:t,meta:p(e)}}function b(r){m(r.meta);let e=new Uint8Array(r.buffer);return b$1(e)}function S(r,e){let o=new Uint8Array(r),t=b$1(o);if(e?.readOnly){let n=j(t);n.readOnly=true;}return t}function B(r){k(r.id)&&m$1(r);}function p(r){let e=[];for(let o of r.componentInfoByBit)o&&e.push({id:o.id,kind:o.kind,schema:o.schema});return {magic:l,formatVersion:1,aiecsjsVersion:a$1,indexBits:r.options.indexBits,generationBits:r.options.generationBits,maxComponents:r.options.maxComponents,maskWordCount:r.options.maskWordCount,capacity:r.capacity,componentSchemas:e}}function m(r){if(r.magic!==l)throw new Error("aiecsjs: invalid snapshot meta (wrong magic)");if(r.formatVersion!==1)throw new Error(`aiecsjs: unsupported snapshot format version ${r.formatVersion}`)}export{b as adoptSnapshot,S as attachWorld,B as detachWorld,W as transferableSnapshot};//# sourceMappingURL=worker.js.map
|
|
2
2
|
//# sourceMappingURL=worker.js.map
|
package/dist/worker.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/worker.ts"],"names":["MAGIC","transferableSnapshot","world","state","getWorldState","bytes","serializeWorld","ab","buildMeta","sab","adoptSnapshot","snap","validateMeta","deserializeWorld","attachWorld","buffer","options","detachWorld","isWorldRegistered","destroyWorld","componentSchemas","info","VERSION","meta"],"mappings":"qGAkBA,IAAMA,CAAAA,CAAQ,WAEP,SAASC,CAAAA,CAAqBC,EAAoC,CACvE,IAAMC,CAAAA,CAAQC,CAAAA,CAAcF,CAAK,CAAA,CAC3BG,EAAQC,CAAAA,CAAeJ,CAAK,EAElC,GAAI,OAAO,kBAAsB,GAAA,CAAa,
|
|
1
|
+
{"version":3,"sources":["../src/worker.ts"],"names":["MAGIC","transferableSnapshot","world","state","getWorldState","bytes","serializeWorld","ab","buildMeta","sab","adoptSnapshot","snap","validateMeta","deserializeWorld","attachWorld","buffer","options","detachWorld","isWorldRegistered","destroyWorld","componentSchemas","info","VERSION","meta"],"mappings":"qGAkBA,IAAMA,CAAAA,CAAQ,WAEP,SAASC,CAAAA,CAAqBC,EAAoC,CACvE,IAAMC,CAAAA,CAAQC,CAAAA,CAAcF,CAAK,CAAA,CAC3BG,EAAQC,CAAAA,CAAeJ,CAAK,EAElC,GAAI,OAAO,kBAAsB,GAAA,CAAa,CAI5C,IAAMK,CAAAA,CAAK,IAAI,WAAA,CAAYF,EAAM,UAAU,CAAA,CAC3C,WAAI,UAAA,CAAWE,CAAE,EAAE,GAAA,CAAIF,CAAK,CAAA,CACrB,CACL,MAAA,CAAQE,CAAAA,CACR,KAAMC,CAAAA,CAAUL,CAAK,CACvB,CACF,CAEA,IAAMM,EAAM,IAAI,iBAAA,CAAkBJ,CAAAA,CAAM,UAAU,CAAA,CAClD,OAAA,IAAI,WAAWI,CAAG,CAAA,CAAE,IAAIJ,CAAK,CAAA,CACtB,CAAE,MAAA,CAAQI,CAAAA,CAAK,IAAA,CAAMD,CAAAA,CAAUL,CAAK,CAAE,CAC/C,CAaO,SAASO,CAAAA,CAAcC,CAAAA,CAAmC,CAC/DC,CAAAA,CAAaD,EAAK,IAAI,CAAA,CACtB,IAAMN,CAAAA,CAAQ,IAAI,UAAA,CAAWM,EAAK,MAAM,CAAA,CACxC,OAAOE,GAAAA,CAAiBR,CAAK,CAC/B,CAaO,SAASS,CAAAA,CACdC,CAAAA,CACAC,CAAAA,CACO,CACP,IAAMX,CAAAA,CAAQ,IAAI,UAAA,CAAWU,CAAM,CAAA,CAC7Bb,CAAAA,CAAQW,IAAiBR,CAAK,CAAA,CACpC,GAAIW,CAAAA,EAAS,QAAA,CAAU,CACrB,IAAMb,CAAAA,CAAQC,CAAAA,CAAcF,CAAK,CAAA,CACjCC,CAAAA,CAAM,SAAW,KACnB,CACA,OAAOD,CACT,CAEO,SAASe,EAAYf,CAAAA,CAAoB,CAC1CgB,CAAAA,CAAkBhB,CAAAA,CAAM,EAAE,CAAA,EAC5BiB,IAAajB,CAAK,EAEtB,CAEA,SAASM,CAAAA,CAAUL,CAAAA,CAA8B,CAC/C,IAAMiB,CAAAA,CAAkD,EAAC,CACzD,IAAA,IAAWC,KAAQlB,CAAAA,CAAM,kBAAA,CAClBkB,CAAAA,EACLD,CAAAA,CAAiB,IAAA,CAAK,CAAE,GAAIC,CAAAA,CAAK,EAAA,CAAI,IAAA,CAAMA,CAAAA,CAAK,IAAA,CAAM,MAAA,CAAQA,EAAK,MAAO,CAAC,CAAA,CAE7E,OAAO,CACL,KAAA,CAAOrB,EACP,aAAA,CAAe,CAAA,CACf,eAAgBsB,GAAAA,CAChB,SAAA,CAAWnB,EAAM,OAAA,CAAQ,SAAA,CACzB,cAAA,CAAgBA,CAAAA,CAAM,OAAA,CAAQ,cAAA,CAC9B,cAAeA,CAAAA,CAAM,OAAA,CAAQ,aAAA,CAC7B,aAAA,CAAeA,CAAAA,CAAM,OAAA,CAAQ,cAC7B,QAAA,CAAUA,CAAAA,CAAM,QAAA,CAChB,gBAAA,CAAAiB,CACF,CACF,CAEA,SAASR,CAAAA,CAAaW,EAAuB,CAC3C,GAAIA,EAAK,KAAA,GAAUvB,CAAAA,CACjB,MAAM,IAAI,KAAA,CAAM,8CAA8C,EAEhE,GAAIuB,CAAAA,CAAK,aAAA,GAAkB,CAAA,CACzB,MAAM,IAAI,MAAM,CAAA,6CAAA,EAAgDA,CAAAA,CAAK,aAAa,CAAA,CAAE,CAExF","file":"worker.js","sourcesContent":["// aiecsjs/worker — SharedArrayBuffer helpers (experimental, snapshot-copy).\n//\n// Note: 0.x implements SAB as a transferable snapshot pattern rather than true\n// shared-memory aliasing. The world is serialized into the SAB, and the worker\n// reconstructs a fresh world from those bytes via adoptSnapshot/attachWorld.\n// True shared-column memory is targeted for a future stable release.\n// The API matches the documented contract and survives postMessage cleanly.\n//\n// EntityRef is in-memory only — not preserved across worker boundaries.\n// Generation counters reset on adoptSnapshot/attachWorld. Pass `EntityRef.id`\n// (the packed EntityId) across the worker boundary only if you understand that\n// the generation portion will be stale after a round-trip snapshot.\n\nimport type { TransferableSnapshot, World, WorldMeta, WorldState } from './internal/types.js'\nimport { destroyWorld, getWorldState, isWorldRegistered } from './internal/world.js'\nimport { deserializeWorld, serializeWorld } from './serialize.js'\nimport { VERSION } from './version.js'\n\nconst MAGIC = 0x41494543 // 'AIEC' little-endian as uint32\n\nexport function transferableSnapshot(world: World): TransferableSnapshot {\n const state = getWorldState(world)\n const bytes = serializeWorld(world)\n\n if (typeof SharedArrayBuffer === 'undefined') {\n // Fallback: a plain ArrayBuffer. TransferableSnapshot.buffer is typed\n // `SharedArrayBuffer | ArrayBuffer`, so this needs no cast — the type tells\n // the truth instead of pretending the fallback is a SAB.\n const ab = new ArrayBuffer(bytes.byteLength)\n new Uint8Array(ab).set(bytes)\n return {\n buffer: ab,\n meta: buildMeta(state),\n }\n }\n\n const sab = new SharedArrayBuffer(bytes.byteLength)\n new Uint8Array(sab).set(bytes)\n return { buffer: sab, meta: buildMeta(state) }\n}\n\n/**\n * Adopt a snapshot previously produced by `transferableSnapshot`.\n *\n * SECURITY: same trust expectation as `attachWorld` — the sender of the\n * `TransferableSnapshot` (typically a Web Worker) must be trusted. The\n * function runs `validateMeta` and `deserializeWorld`, which enforce magic\n * + format version + length bounds on the binary header; but the inner\n * JSON payload, once decoded, is fed to `addComponent` and reaches AoS\n * components. For untrusted senders, use `aibridgejs` + `toJSON(world)` at\n * the application boundary instead.\n */\nexport function adoptSnapshot(snap: TransferableSnapshot): World {\n validateMeta(snap.meta)\n const bytes = new Uint8Array(snap.buffer)\n return deserializeWorld(bytes)\n}\n\n/**\n * Adopt a SharedArrayBuffer-backed snapshot produced by `transferableSnapshot`.\n *\n * SECURITY: the SAB sender must be trusted. `attachWorld` performs the same\n * magic + version + length-bounds checks as `deserializeWorld`, but the JSON\n * payload itself is deserialised into AoS components via `addComponent`. If\n * the sender is untrusted (e.g. a third-party Web Worker that you do not\n * audit), prefer the higher-level `aibridgejs` channel + `toJSON(world)`\n * pattern, which lets you validate the shape at the application boundary\n * before constructing entities.\n */\nexport function attachWorld(\n buffer: SharedArrayBuffer | ArrayBuffer,\n options?: { readOnly?: boolean },\n): World {\n const bytes = new Uint8Array(buffer)\n const world = deserializeWorld(bytes)\n if (options?.readOnly) {\n const state = getWorldState(world)\n state.readOnly = true\n }\n return world\n}\n\nexport function detachWorld(world: World): void {\n if (isWorldRegistered(world.id)) {\n destroyWorld(world)\n }\n}\n\nfunction buildMeta(state: WorldState): WorldMeta {\n const componentSchemas: WorldMeta['componentSchemas'] = []\n for (const info of state.componentInfoByBit) {\n if (!info) continue\n componentSchemas.push({ id: info.id, kind: info.kind, schema: info.schema })\n }\n return {\n magic: MAGIC,\n formatVersion: 1,\n aiecsjsVersion: VERSION,\n indexBits: state.options.indexBits,\n generationBits: state.options.generationBits,\n maxComponents: state.options.maxComponents,\n maskWordCount: state.options.maskWordCount,\n capacity: state.capacity,\n componentSchemas,\n }\n}\n\nfunction validateMeta(meta: WorldMeta): void {\n if (meta.magic !== MAGIC) {\n throw new Error('aiecsjs: invalid snapshot meta (wrong magic)')\n }\n if (meta.formatVersion !== 1) {\n throw new Error(`aiecsjs: unsupported snapshot format version ${meta.formatVersion}`)\n }\n}\n"]}
|