@ecsia/core 0.1.0
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/LICENSE +21 -0
- package/README.md +29 -0
- package/dist/bitmask/bitmask.d.ts +21 -0
- package/dist/bitmask/bitmask.d.ts.map +1 -0
- package/dist/bitmask/bitmask.js +103 -0
- package/dist/bitmask/bitmask.js.map +1 -0
- package/dist/bitmask/index.d.ts +3 -0
- package/dist/bitmask/index.d.ts.map +1 -0
- package/dist/bitmask/index.js +2 -0
- package/dist/bitmask/index.js.map +1 -0
- package/dist/component/accessor.d.ts +40 -0
- package/dist/component/accessor.d.ts.map +1 -0
- package/dist/component/accessor.js +220 -0
- package/dist/component/accessor.js.map +1 -0
- package/dist/component/column-set.d.ts +20 -0
- package/dist/component/column-set.d.ts.map +1 -0
- package/dist/component/column-set.js +60 -0
- package/dist/component/column-set.js.map +1 -0
- package/dist/component/define.d.ts +23 -0
- package/dist/component/define.d.ts.map +1 -0
- package/dist/component/define.js +155 -0
- package/dist/component/define.js.map +1 -0
- package/dist/component/descriptors.d.ts +3 -0
- package/dist/component/descriptors.d.ts.map +1 -0
- package/dist/component/descriptors.js +147 -0
- package/dist/component/descriptors.js.map +1 -0
- package/dist/component/index.d.ts +10 -0
- package/dist/component/index.d.ts.map +1 -0
- package/dist/component/index.js +6 -0
- package/dist/component/index.js.map +1 -0
- package/dist/component/sidecar.d.ts +58 -0
- package/dist/component/sidecar.d.ts.map +1 -0
- package/dist/component/sidecar.js +136 -0
- package/dist/component/sidecar.js.map +1 -0
- package/dist/config.d.ts +55 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +70 -0
- package/dist/config.js.map +1 -0
- package/dist/entity/codec.d.ts +45 -0
- package/dist/entity/codec.d.ts.map +1 -0
- package/dist/entity/codec.js +53 -0
- package/dist/entity/codec.js.map +1 -0
- package/dist/entity/index-allocator.d.ts +46 -0
- package/dist/entity/index-allocator.d.ts.map +1 -0
- package/dist/entity/index-allocator.js +121 -0
- package/dist/entity/index-allocator.js.map +1 -0
- package/dist/entity/index.d.ts +13 -0
- package/dist/entity/index.d.ts.map +1 -0
- package/dist/entity/index.js +7 -0
- package/dist/entity/index.js.map +1 -0
- package/dist/entity/record.d.ts +28 -0
- package/dist/entity/record.d.ts.map +1 -0
- package/dist/entity/record.js +42 -0
- package/dist/entity/record.js.map +1 -0
- package/dist/entity/ref.d.ts +70 -0
- package/dist/entity/ref.d.ts.map +1 -0
- package/dist/entity/ref.js +104 -0
- package/dist/entity/ref.js.map +1 -0
- package/dist/entity/reservation.d.ts +12 -0
- package/dist/entity/reservation.d.ts.map +1 -0
- package/dist/entity/reservation.js +28 -0
- package/dist/entity/reservation.js.map +1 -0
- package/dist/entity/store.d.ts +60 -0
- package/dist/entity/store.d.ts.map +1 -0
- package/dist/entity/store.js +193 -0
- package/dist/entity/store.js.map +1 -0
- package/dist/env.d.ts +2 -0
- package/dist/env.d.ts.map +1 -0
- package/dist/env.js +12 -0
- package/dist/env.js.map +1 -0
- package/dist/ids.d.ts +9 -0
- package/dist/ids.d.ts.map +1 -0
- package/dist/ids.js +8 -0
- package/dist/ids.js.map +1 -0
- package/dist/index.d.ts +29 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +33 -0
- package/dist/index.js.map +1 -0
- package/dist/inspect-surface.d.ts +27 -0
- package/dist/inspect-surface.d.ts.map +1 -0
- package/dist/inspect-surface.js +14 -0
- package/dist/inspect-surface.js.map +1 -0
- package/dist/internal.d.ts +19 -0
- package/dist/internal.d.ts.map +1 -0
- package/dist/internal.js +19 -0
- package/dist/internal.js.map +1 -0
- package/dist/memory/allocU32.d.ts +25 -0
- package/dist/memory/allocU32.d.ts.map +1 -0
- package/dist/memory/allocU32.js +95 -0
- package/dist/memory/allocU32.js.map +1 -0
- package/dist/memory/buffers.d.ts +94 -0
- package/dist/memory/buffers.d.ts.map +1 -0
- package/dist/memory/buffers.js +308 -0
- package/dist/memory/buffers.js.map +1 -0
- package/dist/memory/index.d.ts +7 -0
- package/dist/memory/index.d.ts.map +1 -0
- package/dist/memory/index.js +4 -0
- package/dist/memory/index.js.map +1 -0
- package/dist/memory/layout.d.ts +37 -0
- package/dist/memory/layout.d.ts.map +1 -0
- package/dist/memory/layout.js +116 -0
- package/dist/memory/layout.js.map +1 -0
- package/dist/query/compile.d.ts +73 -0
- package/dist/query/compile.d.ts.map +1 -0
- package/dist/query/compile.js +158 -0
- package/dist/query/compile.js.map +1 -0
- package/dist/query/engine.d.ts +48 -0
- package/dist/query/engine.d.ts.map +1 -0
- package/dist/query/engine.js +230 -0
- package/dist/query/engine.js.map +1 -0
- package/dist/query/index.d.ts +8 -0
- package/dist/query/index.d.ts.map +1 -0
- package/dist/query/index.js +10 -0
- package/dist/query/index.js.map +1 -0
- package/dist/query/live-query.d.ts +122 -0
- package/dist/query/live-query.d.ts.map +1 -0
- package/dist/query/live-query.js +543 -0
- package/dist/query/live-query.js.map +1 -0
- package/dist/query/sparse-set.d.ts +18 -0
- package/dist/query/sparse-set.d.ts.map +1 -0
- package/dist/query/sparse-set.js +126 -0
- package/dist/query/sparse-set.js.map +1 -0
- package/dist/reactivity/change-version.d.ts +19 -0
- package/dist/reactivity/change-version.d.ts.map +1 -0
- package/dist/reactivity/change-version.js +76 -0
- package/dist/reactivity/change-version.js.map +1 -0
- package/dist/reactivity/index.d.ts +12 -0
- package/dist/reactivity/index.d.ts.map +1 -0
- package/dist/reactivity/index.js +12 -0
- package/dist/reactivity/index.js.map +1 -0
- package/dist/reactivity/log.d.ts +83 -0
- package/dist/reactivity/log.d.ts.map +1 -0
- package/dist/reactivity/log.js +260 -0
- package/dist/reactivity/log.js.map +1 -0
- package/dist/reactivity/observer-commands.d.ts +40 -0
- package/dist/reactivity/observer-commands.d.ts.map +1 -0
- package/dist/reactivity/observer-commands.js +111 -0
- package/dist/reactivity/observer-commands.js.map +1 -0
- package/dist/reactivity/observers.d.ts +50 -0
- package/dist/reactivity/observers.d.ts.map +1 -0
- package/dist/reactivity/observers.js +127 -0
- package/dist/reactivity/observers.js.map +1 -0
- package/dist/reactivity/reactivity.d.ts +141 -0
- package/dist/reactivity/reactivity.d.ts.map +1 -0
- package/dist/reactivity/reactivity.js +479 -0
- package/dist/reactivity/reactivity.js.map +1 -0
- package/dist/reactivity/structural-journal.d.ts +30 -0
- package/dist/reactivity/structural-journal.d.ts.map +1 -0
- package/dist/reactivity/structural-journal.js +77 -0
- package/dist/reactivity/structural-journal.js.map +1 -0
- package/dist/registry.d.ts +26 -0
- package/dist/registry.d.ts.map +1 -0
- package/dist/registry.js +58 -0
- package/dist/registry.js.map +1 -0
- package/dist/serialize-surface.d.ts +170 -0
- package/dist/serialize-surface.d.ts.map +1 -0
- package/dist/serialize-surface.js +6 -0
- package/dist/serialize-surface.js.map +1 -0
- package/dist/storage/archetype.d.ts +38 -0
- package/dist/storage/archetype.d.ts.map +1 -0
- package/dist/storage/archetype.js +47 -0
- package/dist/storage/archetype.js.map +1 -0
- package/dist/storage/cold-store.d.ts +41 -0
- package/dist/storage/cold-store.d.ts.map +1 -0
- package/dist/storage/cold-store.js +100 -0
- package/dist/storage/cold-store.js.map +1 -0
- package/dist/storage/index.d.ts +10 -0
- package/dist/storage/index.d.ts.map +1 -0
- package/dist/storage/index.js +5 -0
- package/dist/storage/index.js.map +1 -0
- package/dist/storage/signature.d.ts +27 -0
- package/dist/storage/signature.d.ts.map +1 -0
- package/dist/storage/signature.js +115 -0
- package/dist/storage/signature.js.map +1 -0
- package/dist/storage/storage.d.ts +72 -0
- package/dist/storage/storage.d.ts.map +1 -0
- package/dist/storage/storage.js +192 -0
- package/dist/storage/storage.js.map +1 -0
- package/dist/storage/store.d.ts +88 -0
- package/dist/storage/store.d.ts.map +1 -0
- package/dist/storage/store.js +473 -0
- package/dist/storage/store.js.map +1 -0
- package/dist/util/stable-index.d.ts +29 -0
- package/dist/util/stable-index.d.ts.map +1 -0
- package/dist/util/stable-index.js +51 -0
- package/dist/util/stable-index.js.map +1 -0
- package/dist/world.d.ts +262 -0
- package/dist/world.d.ts.map +1 -0
- package/dist/world.js +831 -0
- package/dist/world.js.map +1 -0
- package/package.json +52 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Andy Aragon
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# @ecsia/core
|
|
2
|
+
|
|
3
|
+
The single-threaded kernel of [**ecsia**](https://github.com/andymai/ecsia) — a fast,
|
|
4
|
+
type-safe Entity Component System for TypeScript.
|
|
5
|
+
|
|
6
|
+
`@ecsia/core` provides archetype/SoA tables, a serial-only per-entity bitmask membership
|
|
7
|
+
index, monomorphic typed accessors, live queries, and reactivity. It runs standalone; the
|
|
8
|
+
opt-in `@ecsia/scheduler`, `@ecsia/relations`, and `@ecsia/serialization` layers attach to a
|
|
9
|
+
world through injected seams (the dependency graph is acyclic).
|
|
10
|
+
|
|
11
|
+
> **Status:** 0.1.0, unpublished. Most users want the umbrella package
|
|
12
|
+
> [`ecsia`](https://www.npmjs.com/package/ecsia), which re-exports the whole cohesive
|
|
13
|
+
> surface and tree-shakes what you don't touch. Reach for `@ecsia/core` directly only when
|
|
14
|
+
> you want the kernel without the scheduler/serialization layers.
|
|
15
|
+
|
|
16
|
+
## Install
|
|
17
|
+
|
|
18
|
+
```sh
|
|
19
|
+
pnpm add @ecsia/core # not yet published — local workspace for now
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Links
|
|
23
|
+
|
|
24
|
+
- Repository & full docs: https://github.com/andymai/ecsia
|
|
25
|
+
- Umbrella package: [`ecsia`](https://github.com/andymai/ecsia)
|
|
26
|
+
|
|
27
|
+
## License
|
|
28
|
+
|
|
29
|
+
[MIT](./LICENSE) © Andy Aragon
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { ComponentId } from '@ecsia/schema';
|
|
2
|
+
import type { Buffers } from '../memory/index.js';
|
|
3
|
+
import type { Signature } from '../storage/signature.js';
|
|
4
|
+
/** Main-thread / serial-phase gate. Workers establish membership from the archetype signature. */
|
|
5
|
+
export type PhaseGate = () => 'serial' | 'wave';
|
|
6
|
+
export declare class Bitmask {
|
|
7
|
+
#private;
|
|
8
|
+
constructor(buffers: Buffers, componentCount: number, maxEntities: number, phase: PhaseGate);
|
|
9
|
+
get stride(): number;
|
|
10
|
+
/** O(1) membership point test for a single entity index. */
|
|
11
|
+
bitmaskHas(index: number, c: ComponentId): boolean;
|
|
12
|
+
/** Coherence with the table: set added bits, clear removed bits, after a serial migration. */
|
|
13
|
+
bitmaskApplyDelta(index: number, fromSig: Signature, toSig: Signature): void;
|
|
14
|
+
/** Clear all of an entity's membership words on despawn. O(stride). */
|
|
15
|
+
bitmaskClear(index: number): void;
|
|
16
|
+
/** Zero-copy view of one entity's fixed-stride shape words (for the single-entity matcher ). */
|
|
17
|
+
entityShapeWords(index: number): Uint32Array;
|
|
18
|
+
/** Re-publish the region view after a fallback grow (the region length-tracks on the primary path). */
|
|
19
|
+
rebind(): void;
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=bitmask.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bitmask.d.ts","sourceRoot":"","sources":["../../src/bitmask/bitmask.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAA;AAChD,OAAO,KAAK,EAAE,OAAO,EAAqB,MAAM,oBAAoB,CAAA;AACpE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAA;AAKxD,kGAAkG;AAClG,MAAM,MAAM,SAAS,GAAG,MAAM,QAAQ,GAAG,MAAM,CAAA;AAE/C,qBAAa,OAAO;;gBAUN,OAAO,EAAE,OAAO,EAAE,cAAc,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS;IAe3F,IAAI,MAAM,IAAI,MAAM,CAEnB;IAWD,4DAA4D;IAC5D,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,CAAC,EAAE,WAAW,GAAG,OAAO;IAOlD,8FAA8F;IAC9F,iBAAiB,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,SAAS,GAAG,IAAI;IAsB5E,uEAAuE;IACvE,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAOjC,gGAAgG;IAChG,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,WAAW;IAK5C,uGAAuG;IACvG,MAAM,IAAI,IAAI;CAYf"}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
// The per-entity bitmask membership index. MAIN-THREAD / SERIAL-ONLY:
|
|
2
|
+
// every read and write asserts world.phase === 'serial' (Invariant). It is the
|
|
3
|
+
// O(1) entity.has(C) point-test substrate and the single-entity incremental query matcher — NOT
|
|
4
|
+
// the iteration path (that is per-archetype). Coherence with the archetype tables is one-way:
|
|
5
|
+
// bitmaskApplyDelta refreshes it immediately after each serial migration commit.
|
|
6
|
+
//
|
|
7
|
+
// Layout: bitmask.words is a u32 region of length capacity*stride, addressed by ENTITY INDEX (low
|
|
8
|
+
// handle bits, stable across swap-pop). stride = ceil(N/32) where N = registered component-type
|
|
9
|
+
// count ( C4). Pair ids beyond the fixed stride live in a lazily-grown sparse vector.
|
|
10
|
+
import { sigHas } from '../storage/signature.js';
|
|
11
|
+
const BITMASK_REGION_KEY = 'bitmask.words';
|
|
12
|
+
export class Bitmask {
|
|
13
|
+
#region;
|
|
14
|
+
#words;
|
|
15
|
+
#stride;
|
|
16
|
+
/** Fixed bit count covered by the dense words; ids at/above this use the sparse vector. */
|
|
17
|
+
#fixedBitCount;
|
|
18
|
+
#phase;
|
|
19
|
+
/** Out-of-stride pair bits, lazily grown per entity index (unbounded pair-id space). */
|
|
20
|
+
#sparse = new Map();
|
|
21
|
+
constructor(buffers, componentCount, maxEntities, phase) {
|
|
22
|
+
// stride = ceil(N/32) exactly per ( C4). N (registered component count) is always >= 1
|
|
23
|
+
// (FIRST_USER_COMPONENT_ID), so this is >= 1 without a max(1,...) floor; ids beyond fixedBitCount
|
|
24
|
+
// fall through to the sparse vector. The backing region reserves at least one word so a
|
|
25
|
+
// degenerate N=0 world still has a valid (length-tracking) allocation.
|
|
26
|
+
this.#stride = Math.ceil(componentCount / 32);
|
|
27
|
+
this.#fixedBitCount = this.#stride * 32;
|
|
28
|
+
this.#phase = phase;
|
|
29
|
+
const regionWords = Math.max(1, maxEntities * this.#stride);
|
|
30
|
+
this.#region = buffers.region(BITMASK_REGION_KEY, 'u32', regionWords, {
|
|
31
|
+
maxLength: regionWords,
|
|
32
|
+
});
|
|
33
|
+
this.#words = this.#region.view;
|
|
34
|
+
}
|
|
35
|
+
get stride() {
|
|
36
|
+
return this.#stride;
|
|
37
|
+
}
|
|
38
|
+
#assertSerial() {
|
|
39
|
+
if (this.#phase() !== 'serial') {
|
|
40
|
+
throw new Error('component bitmask access is main-thread / serial-phase only; perform structural reads or mutations ' +
|
|
41
|
+
'outside worker waves (before scheduler.update() or in a serial system), not from a worker-wave system');
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
/** O(1) membership point test for a single entity index. */
|
|
45
|
+
bitmaskHas(index, c) {
|
|
46
|
+
this.#assertSerial();
|
|
47
|
+
const cid = c;
|
|
48
|
+
if (cid >= this.#fixedBitCount)
|
|
49
|
+
return this.#sparse.get(index)?.has(cid) ?? false;
|
|
50
|
+
return (this.#words[index * this.#stride + (cid >>> 5)] & (1 << (cid & 31))) !== 0;
|
|
51
|
+
}
|
|
52
|
+
/** Coherence with the table: set added bits, clear removed bits, after a serial migration. */
|
|
53
|
+
bitmaskApplyDelta(index, fromSig, toSig) {
|
|
54
|
+
this.#assertSerial();
|
|
55
|
+
const base = index * this.#stride;
|
|
56
|
+
for (let i = 0; i < toSig.length; i++) {
|
|
57
|
+
const c = toSig[i];
|
|
58
|
+
if (c < this.#fixedBitCount) {
|
|
59
|
+
this.#words[base + (c >>> 5)] = (this.#words[base + (c >>> 5)] | (1 << (c & 31))) >>> 0;
|
|
60
|
+
}
|
|
61
|
+
else {
|
|
62
|
+
this.#sparseSet(index, c);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
for (let i = 0; i < fromSig.length; i++) {
|
|
66
|
+
const c = fromSig[i];
|
|
67
|
+
if (sigHas(toSig, c))
|
|
68
|
+
continue;
|
|
69
|
+
if (c < this.#fixedBitCount) {
|
|
70
|
+
this.#words[base + (c >>> 5)] = (this.#words[base + (c >>> 5)] & ~(1 << (c & 31))) >>> 0;
|
|
71
|
+
}
|
|
72
|
+
else {
|
|
73
|
+
this.#sparse.get(index)?.delete(c);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
/** Clear all of an entity's membership words on despawn. O(stride). */
|
|
78
|
+
bitmaskClear(index) {
|
|
79
|
+
this.#assertSerial();
|
|
80
|
+
const base = index * this.#stride;
|
|
81
|
+
for (let w = 0; w < this.#stride; w++)
|
|
82
|
+
this.#words[base + w] = 0;
|
|
83
|
+
this.#sparse.delete(index);
|
|
84
|
+
}
|
|
85
|
+
/** Zero-copy view of one entity's fixed-stride shape words (for the single-entity matcher ). */
|
|
86
|
+
entityShapeWords(index) {
|
|
87
|
+
this.#assertSerial();
|
|
88
|
+
return this.#words.subarray(index * this.#stride, index * this.#stride + this.#stride);
|
|
89
|
+
}
|
|
90
|
+
/** Re-publish the region view after a fallback grow (the region length-tracks on the primary path). */
|
|
91
|
+
rebind() {
|
|
92
|
+
this.#words = this.#region.view;
|
|
93
|
+
}
|
|
94
|
+
#sparseSet(index, c) {
|
|
95
|
+
let s = this.#sparse.get(index);
|
|
96
|
+
if (s === undefined) {
|
|
97
|
+
s = new Set();
|
|
98
|
+
this.#sparse.set(index, s);
|
|
99
|
+
}
|
|
100
|
+
s.add(c);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
//# sourceMappingURL=bitmask.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bitmask.js","sourceRoot":"","sources":["../../src/bitmask/bitmask.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/bitmask/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AACtC,YAAY,EAAE,SAAS,EAAE,MAAM,cAAc,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/bitmask/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { AccessorFactory, ColumnBinding, ComponentDef, ComponentId, EntityHandle, Schema } from '@ecsia/schema';
|
|
2
|
+
import type { Backing, ColumnLayout, TypedArray } from '../memory/index.js';
|
|
3
|
+
import { columnKey } from '../memory/index.js';
|
|
4
|
+
import type { SidecarKey } from './sidecar.js';
|
|
5
|
+
export interface AccessorWorld {
|
|
6
|
+
trackWrite(index: number, componentId: ComponentId, fieldIndex?: number): void;
|
|
7
|
+
handleIndex(handle: EntityHandle): number;
|
|
8
|
+
readonly tracking: {
|
|
9
|
+
readonly active: boolean;
|
|
10
|
+
};
|
|
11
|
+
sidecarRead(key: SidecarKey, index: number, gen: number): unknown;
|
|
12
|
+
sidecarWrite(key: SidecarKey, index: number, gen: number, value: unknown): void;
|
|
13
|
+
/** Low generationBits of the live handle at `index` — the RF-HYGIENE stamp source. */
|
|
14
|
+
generationOf(index: number): number;
|
|
15
|
+
}
|
|
16
|
+
export interface AccessorBinding {
|
|
17
|
+
readonly world: AccessorWorld;
|
|
18
|
+
readonly componentId: ComponentId;
|
|
19
|
+
}
|
|
20
|
+
export interface AccessorInstanceBase {
|
|
21
|
+
__idx: number;
|
|
22
|
+
__eid: EntityHandle;
|
|
23
|
+
__binding: AccessorBinding | null;
|
|
24
|
+
__rebind(newBacking: Backing): void;
|
|
25
|
+
/**
|
|
26
|
+
* Fallback-grow rebind for ONE column. Each column-bearing field owns a SEPARATE backing buffer
|
|
27
|
+
* (one `buffers.column` per field), so a fallback grow re-points exactly that field's view. A
|
|
28
|
+
* whole-instance `__rebind` would alias every field onto the single grown backing (corrupting the
|
|
29
|
+
* other fields' columns); the buffers layer always targets the field that actually grew.
|
|
30
|
+
*/
|
|
31
|
+
__rebindField(fieldIndex: number, newBacking: Backing): void;
|
|
32
|
+
}
|
|
33
|
+
export declare function bindingsFor(columns: ReadonlyArray<{
|
|
34
|
+
view: TypedArray;
|
|
35
|
+
layout: ColumnLayout;
|
|
36
|
+
}>): ColumnBinding[];
|
|
37
|
+
export declare function makeAccessorFactory<S extends Schema>(def: ComponentDef<S>): AccessorFactory<S>;
|
|
38
|
+
export { columnKey };
|
|
39
|
+
export type { ColumnKey } from '../memory/index.js';
|
|
40
|
+
//# sourceMappingURL=accessor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"accessor.d.ts","sourceRoot":"","sources":["../../src/component/accessor.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EACV,eAAe,EACf,aAAa,EACb,YAAY,EACZ,WAAW,EACX,YAAY,EAEZ,MAAM,EACP,MAAM,eAAe,CAAA;AACtB,OAAO,KAAK,EAAE,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAA;AAC3E,OAAO,EAAE,SAAS,EAAe,MAAM,oBAAoB,CAAA;AAG3D,OAAO,KAAK,EAAY,UAAU,EAAE,MAAM,cAAc,CAAA;AAIxD,MAAM,WAAW,aAAa;IAC5B,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,WAAW,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAC9E,WAAW,CAAC,MAAM,EAAE,YAAY,GAAG,MAAM,CAAA;IAOzC,QAAQ,CAAC,QAAQ,EAAE;QAAE,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAA;KAAE,CAAA;IAG/C,WAAW,CAAC,GAAG,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;IACjE,YAAY,CAAC,GAAG,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,IAAI,CAAA;IAC/E,sFAAsF;IACtF,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAAA;CACpC;AAID,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,KAAK,EAAE,aAAa,CAAA;IAC7B,QAAQ,CAAC,WAAW,EAAE,WAAW,CAAA;CAClC;AAID,MAAM,WAAW,oBAAoB;IACnC,KAAK,EAAE,MAAM,CAAA;IACb,KAAK,EAAE,YAAY,CAAA;IACnB,SAAS,EAAE,eAAe,GAAG,IAAI,CAAA;IACjC,QAAQ,CAAC,UAAU,EAAE,OAAO,GAAG,IAAI,CAAA;IACnC;;;;;OAKG;IACH,aAAa,CAAC,UAAU,EAAE,MAAM,EAAE,UAAU,EAAE,OAAO,GAAG,IAAI,CAAA;CAC7D;AAgED,wBAAgB,WAAW,CACzB,OAAO,EAAE,aAAa,CAAC;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,MAAM,EAAE,YAAY,CAAA;CAAE,CAAC,GACjE,aAAa,EAAE,CAMjB;AAID,wBAAgB,mBAAmB,CAAC,CAAC,SAAS,MAAM,EAAE,GAAG,EAAE,YAAY,CAAC,CAAC,CAAC,GAAG,eAAe,CAAC,CAAC,CAAC,CA2H9F;AAuCD,OAAO,EAAE,SAAS,EAAE,CAAA;AACpB,YAAY,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAA"}
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
// The factory-closure accessor class. ONE hidden
|
|
2
|
+
// class per (archetype, component), closing over the column views and reading a mutable __idx.
|
|
3
|
+
// This is NOT an ES Proxy on the accessor itself and NOT new Function() — it is a parameterised
|
|
4
|
+
// closure returning a plain JS class (the permitted technique).
|
|
5
|
+
//
|
|
6
|
+
// Each instance is the single monomorphic singleton for its (archetype, component): read()/the
|
|
7
|
+
// shorthand return it typed Readonly, write() returns it mutable. A getter reads the
|
|
8
|
+
// captured view at __idx; a setter writes the slot AND calls world.trackWrite. On the primary
|
|
9
|
+
// grow path captured views auto-widen (no rebind call); on the fallback path __rebind rebuilds
|
|
10
|
+
// them from the new backing.
|
|
11
|
+
import { columnKey, elementCtor } from '../memory/index.js';
|
|
12
|
+
import { sidecarKey } from './sidecar.js';
|
|
13
|
+
function columnElementOf(f) {
|
|
14
|
+
const ctor = f.ctor;
|
|
15
|
+
if (ctor === Float32Array)
|
|
16
|
+
return 'f32';
|
|
17
|
+
if (ctor === Float64Array)
|
|
18
|
+
return 'f64';
|
|
19
|
+
if (ctor === Int8Array)
|
|
20
|
+
return 'i8';
|
|
21
|
+
if (ctor === Uint8Array)
|
|
22
|
+
return 'u8';
|
|
23
|
+
if (ctor === Uint8ClampedArray)
|
|
24
|
+
return 'u8c';
|
|
25
|
+
if (ctor === Int16Array)
|
|
26
|
+
return 'i16';
|
|
27
|
+
if (ctor === Uint16Array)
|
|
28
|
+
return 'u16';
|
|
29
|
+
if (ctor === Int32Array)
|
|
30
|
+
return 'i32';
|
|
31
|
+
if (ctor === Uint32Array)
|
|
32
|
+
return 'u32';
|
|
33
|
+
throw new Error('unsupported column element ctor');
|
|
34
|
+
}
|
|
35
|
+
function planFields(def) {
|
|
36
|
+
const columnPlans = [];
|
|
37
|
+
const richPlans = [];
|
|
38
|
+
const componentId = def.id;
|
|
39
|
+
let fieldIndex = 0;
|
|
40
|
+
for (const f of def.fields) {
|
|
41
|
+
if (f.ctor !== null) {
|
|
42
|
+
columnPlans.push({
|
|
43
|
+
fieldIndex,
|
|
44
|
+
name: f.name,
|
|
45
|
+
stride: f.stride,
|
|
46
|
+
element: columnElementOf(f),
|
|
47
|
+
encode: f.encode,
|
|
48
|
+
decode: f.decode,
|
|
49
|
+
isVec: f.stride > 1,
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
else if (f.rich !== undefined) {
|
|
53
|
+
// Rich (sidecar-backed) field: gets a getter/setter pair targeting the sidecar. Its field
|
|
54
|
+
// index is still consumed so column keys stay stable across the field set.
|
|
55
|
+
richPlans.push({ fieldIndex, name: f.name, rich: f.rich, sidecarKey: sidecarKey(componentId, fieldIndex) });
|
|
56
|
+
}
|
|
57
|
+
fieldIndex += 1;
|
|
58
|
+
}
|
|
59
|
+
return { columnPlans, richPlans };
|
|
60
|
+
}
|
|
61
|
+
// Build the per-(archetype, component) ColumnBinding[] for a column set the caller allocated. The
|
|
62
|
+
// archetype-binding seam will produce these from a real archetype's columns; for the
|
|
63
|
+
// caller passes the freshly-allocated columns directly.
|
|
64
|
+
export function bindingsFor(columns) {
|
|
65
|
+
return columns.map((c) => ({
|
|
66
|
+
view: c.view,
|
|
67
|
+
byteOffset: c.view.byteOffset,
|
|
68
|
+
element: c.layout.element,
|
|
69
|
+
}));
|
|
70
|
+
}
|
|
71
|
+
const AXIS_NAMES = ['x', 'y', 'z', 'w'];
|
|
72
|
+
export function makeAccessorFactory(def) {
|
|
73
|
+
const { columnPlans: plans, richPlans } = planFields(def);
|
|
74
|
+
const componentId = def.id;
|
|
75
|
+
return ((columns) => {
|
|
76
|
+
// The assert counts ONLY column-bearing plans: a rich-only or mixed
|
|
77
|
+
// component binds against its column subset, and the rich getters install independently below.
|
|
78
|
+
if (columns.length !== plans.length) {
|
|
79
|
+
throw new Error(`accessor factory for '${def.name}': expected ${plans.length} columns, got ${columns.length}`);
|
|
80
|
+
}
|
|
81
|
+
// Captured per-field state, closed over by every getter/setter. `views` is mutated in place on
|
|
82
|
+
// a fallback rebind so the closures keep seeing the live view without regeneration.
|
|
83
|
+
const views = columns.map((c) => c.view);
|
|
84
|
+
const offsets = columns.map((c) => c.byteOffset);
|
|
85
|
+
const elements = columns.map((c) => c.element);
|
|
86
|
+
// One reusable VecView per vec field (no allocation on read). Lazily built on first get
|
|
87
|
+
// and cached here, then re-returned for every subsequent get; it reads owner.__idx lazily so it
|
|
88
|
+
// stays correct as __idx is re-poked, and resolves the live view from `views[i]` so a fallback
|
|
89
|
+
// rebind is transparent.
|
|
90
|
+
const vecViews = plans.map(() => undefined);
|
|
91
|
+
class Accessor {
|
|
92
|
+
__idx = 0;
|
|
93
|
+
__eid = 0;
|
|
94
|
+
__binding = null;
|
|
95
|
+
__rebind(newBacking) {
|
|
96
|
+
for (let i = 0; i < views.length; i++)
|
|
97
|
+
this.__rebindField(i, newBacking);
|
|
98
|
+
}
|
|
99
|
+
__rebindField(fieldIndex, newBacking) {
|
|
100
|
+
const Ctor = elementCtor(elements[fieldIndex]);
|
|
101
|
+
// No length argument: rebuild the length-tracking view at the captured byteOffset.
|
|
102
|
+
views[fieldIndex] = new Ctor(newBacking, offsets[fieldIndex]);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
plans.forEach((plan, i) => {
|
|
106
|
+
const stride = plan.stride;
|
|
107
|
+
const decode = plan.decode;
|
|
108
|
+
const encode = plan.encode;
|
|
109
|
+
const fieldIndex = plan.fieldIndex;
|
|
110
|
+
// fieldIndex is forwarded ONLY by field-granular setters. There is no changeTracking
|
|
111
|
+
// surface, so vec setters pass withField=true unconditionally. TODO: gate withField on the
|
|
112
|
+
// per-component changeTrackingDefault when reactivity config lands, so component-granular
|
|
113
|
+
// components omit fieldIndex.
|
|
114
|
+
const track = (self, withField) => {
|
|
115
|
+
const b = self.__binding;
|
|
116
|
+
if (b === null)
|
|
117
|
+
return;
|
|
118
|
+
// Fast-out: no write consumer ⇒ trackWrite is a no-op anyway, so skip the handleIndex decode
|
|
119
|
+
// and the two closure hops entirely ( write-path gate). See AccessorWorld.tracking.
|
|
120
|
+
if (!b.world.tracking.active)
|
|
121
|
+
return;
|
|
122
|
+
if (withField)
|
|
123
|
+
b.world.trackWrite(b.world.handleIndex(self.__eid), componentId, fieldIndex);
|
|
124
|
+
else
|
|
125
|
+
b.world.trackWrite(b.world.handleIndex(self.__eid), componentId);
|
|
126
|
+
};
|
|
127
|
+
if (plan.isVec) {
|
|
128
|
+
Object.defineProperty(Accessor.prototype, plan.name, {
|
|
129
|
+
enumerable: true,
|
|
130
|
+
configurable: true,
|
|
131
|
+
get() {
|
|
132
|
+
let v = vecViews[i];
|
|
133
|
+
if (v === undefined) {
|
|
134
|
+
v = makeVecView(views, i, stride, this, decode, encode, () => track(this, true));
|
|
135
|
+
vecViews[i] = v;
|
|
136
|
+
}
|
|
137
|
+
return v;
|
|
138
|
+
},
|
|
139
|
+
set(value) {
|
|
140
|
+
const view = views[i];
|
|
141
|
+
const base = this.__idx * stride;
|
|
142
|
+
for (let a = 0; a < stride; a++)
|
|
143
|
+
view[base + a] = encode(value[a]);
|
|
144
|
+
track(this, true);
|
|
145
|
+
},
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
else {
|
|
149
|
+
Object.defineProperty(Accessor.prototype, plan.name, {
|
|
150
|
+
enumerable: true,
|
|
151
|
+
configurable: true,
|
|
152
|
+
get() {
|
|
153
|
+
const view = views[i];
|
|
154
|
+
return decode(view[this.__idx]);
|
|
155
|
+
},
|
|
156
|
+
set(value) {
|
|
157
|
+
const view = views[i];
|
|
158
|
+
view[this.__idx] = encode(value);
|
|
159
|
+
track(this, false);
|
|
160
|
+
},
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
});
|
|
164
|
+
// Rich (sidecar-backed) getters/setters. The getter returns the live JS
|
|
165
|
+
// reference (string primitive / object<T>); the setter writes the sidecar slot AND routes through
|
|
166
|
+
// the SAME field-granular trackWrite numeric setters use, so Changed/observers fire identically
|
|
167
|
+
// (RF-CHANGED). In-place mutation of an object<T> reference is NOT tracked — only re-assignment is.
|
|
168
|
+
richPlans.forEach((plan) => {
|
|
169
|
+
const key = plan.sidecarKey;
|
|
170
|
+
const fieldIndex = plan.fieldIndex;
|
|
171
|
+
Object.defineProperty(Accessor.prototype, plan.name, {
|
|
172
|
+
enumerable: true,
|
|
173
|
+
configurable: true,
|
|
174
|
+
get() {
|
|
175
|
+
const b = this.__binding;
|
|
176
|
+
if (b === null)
|
|
177
|
+
return undefined;
|
|
178
|
+
const idx = b.world.handleIndex(this.__eid);
|
|
179
|
+
return b.world.sidecarRead(key, idx, b.world.generationOf(idx));
|
|
180
|
+
},
|
|
181
|
+
set(value) {
|
|
182
|
+
const b = this.__binding;
|
|
183
|
+
if (b === null)
|
|
184
|
+
return;
|
|
185
|
+
const idx = b.world.handleIndex(this.__eid);
|
|
186
|
+
b.world.sidecarWrite(key, idx, b.world.generationOf(idx), value);
|
|
187
|
+
b.world.trackWrite(idx, componentId, fieldIndex);
|
|
188
|
+
},
|
|
189
|
+
});
|
|
190
|
+
});
|
|
191
|
+
return Accessor;
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
// A thin vec view, built ONCE per (accessor, vec field) and reused across gets (no allocation
|
|
195
|
+
// on read). It reads `owner.__idx` lazily so the single cached wrapper stays correct as __idx is
|
|
196
|
+
// re-poked, and resolves the live view from `views[viewIndex]` so a fallback rebind is transparent.
|
|
197
|
+
// Indexed/named axis reads decode; writes encode + report a field-granular write.
|
|
198
|
+
function makeVecView(views, viewIndex, stride, owner, decode, encode, trackWrite) {
|
|
199
|
+
const read = (axis) => decode(views[viewIndex][owner.__idx * stride + axis]);
|
|
200
|
+
const write = (axis, value) => {
|
|
201
|
+
;
|
|
202
|
+
views[viewIndex][owner.__idx * stride + axis] = encode(value);
|
|
203
|
+
trackWrite();
|
|
204
|
+
};
|
|
205
|
+
const obj = { length: stride };
|
|
206
|
+
for (let a = 0; a < stride; a++) {
|
|
207
|
+
const axis = a;
|
|
208
|
+
const def = {
|
|
209
|
+
enumerable: true,
|
|
210
|
+
get: () => read(axis),
|
|
211
|
+
set: (v) => write(axis, v),
|
|
212
|
+
};
|
|
213
|
+
Object.defineProperty(obj, axis, def);
|
|
214
|
+
if (axis < AXIS_NAMES.length)
|
|
215
|
+
Object.defineProperty(obj, AXIS_NAMES[axis], def);
|
|
216
|
+
}
|
|
217
|
+
return obj;
|
|
218
|
+
}
|
|
219
|
+
export { columnKey };
|
|
220
|
+
//# sourceMappingURL=accessor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"accessor.js","sourceRoot":"","sources":["../../src/component/accessor.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { ComponentDef, ComponentId, EntityHandle, Schema } from '@ecsia/schema';
|
|
2
|
+
import type { Buffers, Column } from '../memory/index.js';
|
|
3
|
+
import type { AccessorInstanceBase, AccessorWorld } from './accessor.js';
|
|
4
|
+
export interface ColumnSet {
|
|
5
|
+
readonly archetypeId: number;
|
|
6
|
+
readonly componentId: ComponentId;
|
|
7
|
+
readonly columns: readonly Column[];
|
|
8
|
+
/** The monomorphic accessor singleton for this (archetype, component). */
|
|
9
|
+
readonly accessor: AccessorInstanceBase;
|
|
10
|
+
}
|
|
11
|
+
export interface BuildColumnSetParams {
|
|
12
|
+
readonly buffers: Buffers;
|
|
13
|
+
readonly archetypeId: number;
|
|
14
|
+
readonly def: ComponentDef<Schema>;
|
|
15
|
+
readonly world: AccessorWorld;
|
|
16
|
+
readonly initialCapacity: number;
|
|
17
|
+
}
|
|
18
|
+
export declare function buildColumnSet(params: BuildColumnSetParams): ColumnSet;
|
|
19
|
+
export declare function bindAccessorRow(set: ColumnSet, row: number, eid: EntityHandle): AccessorInstanceBase;
|
|
20
|
+
//# sourceMappingURL=column-set.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"column-set.d.ts","sourceRoot":"","sources":["../../src/component/column-set.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,YAAY,EAAmB,MAAM,EAAE,MAAM,eAAe,CAAA;AACrG,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAA;AAGzD,OAAO,KAAK,EAAmB,oBAAoB,EAAE,aAAa,EAAE,MAAM,eAAe,CAAA;AAGzF,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;IAC5B,QAAQ,CAAC,WAAW,EAAE,WAAW,CAAA;IACjC,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAA;IACnC,0EAA0E;IAC1E,QAAQ,CAAC,QAAQ,EAAE,oBAAoB,CAAA;CACxC;AAED,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAA;IACzB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;IAC5B,QAAQ,CAAC,GAAG,EAAE,YAAY,CAAC,MAAM,CAAC,CAAA;IAClC,QAAQ,CAAC,KAAK,EAAE,aAAa,CAAA;IAC7B,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAA;CACjC;AAED,wBAAgB,cAAc,CAAC,MAAM,EAAE,oBAAoB,GAAG,SAAS,CA0CtE;AAID,wBAAgB,eAAe,CAAC,GAAG,EAAE,SAAS,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,YAAY,GAAG,oBAAoB,CAKpG"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
// The (archetype, component) ColumnSet allocation + accessor instantiation.
|
|
2
|
+
// This is the binding seam: it allocates one column per column-backed field
|
|
3
|
+
// through Buffers.column, instantiates the component's accessor singleton over those columns, and
|
|
4
|
+
// registers the singleton as a ViewHolder for the fallback grow path.
|
|
5
|
+
//
|
|
6
|
+
// ARCHETYPE-BINDING SEAM: storage owns producing this from a real archetype's row store. For
|
|
7
|
+
// the caller passes any archetypeId (e.g. a single test/empty archetype) and the columns are
|
|
8
|
+
// allocated directly so the read/write paths are exercisable now.
|
|
9
|
+
import { columnKey } from '../memory/index.js';
|
|
10
|
+
import { bindingsFor } from './accessor.js';
|
|
11
|
+
export function buildColumnSet(params) {
|
|
12
|
+
const { buffers, archetypeId, def, world, initialCapacity } = params;
|
|
13
|
+
const rt = def;
|
|
14
|
+
const componentId = def.id;
|
|
15
|
+
if (componentId < 0) {
|
|
16
|
+
throw new Error(`buildColumnSet: component '${def.name}' has no id (register it with a world first)`);
|
|
17
|
+
}
|
|
18
|
+
const columns = [];
|
|
19
|
+
let fieldIndex = 0;
|
|
20
|
+
let layoutIndex = 0;
|
|
21
|
+
for (const f of def.fields) {
|
|
22
|
+
if (f.ctor !== null) {
|
|
23
|
+
const layout = rt.columnLayouts[layoutIndex];
|
|
24
|
+
if (layout === undefined)
|
|
25
|
+
throw new Error(`buildColumnSet: missing layout for field '${f.name}'`);
|
|
26
|
+
const key = columnKey(archetypeId, componentId, fieldIndex);
|
|
27
|
+
columns.push(buffers.column(key, layout, initialCapacity));
|
|
28
|
+
layoutIndex += 1;
|
|
29
|
+
}
|
|
30
|
+
fieldIndex += 1;
|
|
31
|
+
}
|
|
32
|
+
const factory = rt.accessorFactory;
|
|
33
|
+
if (factory === null)
|
|
34
|
+
throw new Error(`buildColumnSet: component '${def.name}' has no accessor factory`);
|
|
35
|
+
const AccessorClass = factory(bindingsFor(columns));
|
|
36
|
+
const accessor = new AccessorClass();
|
|
37
|
+
const binding = { world, componentId };
|
|
38
|
+
accessor.__binding = binding;
|
|
39
|
+
// Register one ViewHolder PER column so a fallback grow re-binds exactly that field's view.
|
|
40
|
+
// Each column owns a separate backing; a whole-instance rebind would alias every field onto the
|
|
41
|
+
// single grown backing. `columns` is in accessor field-order, so the index is the rebind target.
|
|
42
|
+
for (let i = 0; i < columns.length; i++) {
|
|
43
|
+
const fieldIndex = i;
|
|
44
|
+
buffers.registerAccessor(columns[i].key, {
|
|
45
|
+
__rebind(newBacking) {
|
|
46
|
+
accessor.__rebindField(fieldIndex, newBacking);
|
|
47
|
+
},
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
return { archetypeId, componentId, columns, accessor };
|
|
51
|
+
}
|
|
52
|
+
// Point a column set's accessor singleton at a (row, entity). 's query/iteration loop pokes
|
|
53
|
+
// __idx; the entity read/write path pokes both before handing the view out.
|
|
54
|
+
export function bindAccessorRow(set, row, eid) {
|
|
55
|
+
const a = set.accessor;
|
|
56
|
+
a.__idx = row;
|
|
57
|
+
a.__eid = eid;
|
|
58
|
+
return a;
|
|
59
|
+
}
|
|
60
|
+
//# sourceMappingURL=column-set.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"column-set.js","sourceRoot":"","sources":["../../src/component/column-set.ts"],"names":[],"mappings":"AAAA,4EAA4E;AAC5E,4EAA4E;AAC5E,kGAAkG;AAClG,sEAAsE;AACtE,EAAE;AACF,6FAA6F;AAC7F,6FAA6F;AAC7F,kEAAkE;AAIlE,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAA;AAC9C,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAA;AAoB3C,MAAM,UAAU,cAAc,CAAC,MAA4B;IACzD,MAAM,EAAE,OAAO,EAAE,WAAW,EAAE,GAAG,EAAE,KAAK,EAAE,eAAe,EAAE,GAAG,MAAM,CAAA;IACpE,MAAM,EAAE,GAAG,GAA+B,CAAA;IAC1C,MAAM,WAAW,GAAG,GAAG,CAAC,EAAiB,CAAA;IACzC,IAAK,WAAsB,GAAG,CAAC,EAAE,CAAC;QAChC,MAAM,IAAI,KAAK,CAAC,8BAA8B,GAAG,CAAC,IAAI,8CAA8C,CAAC,CAAA;IACvG,CAAC;IAED,MAAM,OAAO,GAAa,EAAE,CAAA;IAC5B,IAAI,UAAU,GAAG,CAAC,CAAA;IAClB,IAAI,WAAW,GAAG,CAAC,CAAA;IACnB,KAAK,MAAM,CAAC,IAAI,GAAG,CAAC,MAAoC,EAAE,CAAC;QACzD,IAAI,CAAC,CAAC,IAAI,KAAK,IAAI,EAAE,CAAC;YACpB,MAAM,MAAM,GAAG,EAAE,CAAC,aAAa,CAAC,WAAW,CAAC,CAAA;YAC5C,IAAI,MAAM,KAAK,SAAS;gBAAE,MAAM,IAAI,KAAK,CAAC,6CAA6C,CAAC,CAAC,IAAI,GAAG,CAAC,CAAA;YACjG,MAAM,GAAG,GAAG,SAAS,CAAC,WAAW,EAAE,WAAqB,EAAE,UAAU,CAAC,CAAA;YACrE,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,EAAE,MAAM,EAAE,eAAe,CAAC,CAAC,CAAA;YAC1D,WAAW,IAAI,CAAC,CAAA;QAClB,CAAC;QACD,UAAU,IAAI,CAAC,CAAA;IACjB,CAAC;IAED,MAAM,OAAO,GAAG,EAAE,CAAC,eAAe,CAAA;IAClC,IAAI,OAAO,KAAK,IAAI;QAAE,MAAM,IAAI,KAAK,CAAC,8BAA8B,GAAG,CAAC,IAAI,2BAA2B,CAAC,CAAA;IACxG,MAAM,aAAa,GAAG,OAAO,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC,CAAA;IACnD,MAAM,QAAQ,GAAG,IAAI,aAAa,EAAqC,CAAA;IACvE,MAAM,OAAO,GAAoB,EAAE,KAAK,EAAE,WAAW,EAAE,CAAA;IACvD,QAAQ,CAAC,SAAS,GAAG,OAAO,CAAA;IAE5B,4FAA4F;IAC5F,gGAAgG;IAChG,iGAAiG;IACjG,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACxC,MAAM,UAAU,GAAG,CAAC,CAAA;QACpB,OAAO,CAAC,gBAAgB,CAAE,OAAO,CAAC,CAAC,CAAY,CAAC,GAAG,EAAE;YACnD,QAAQ,CAAC,UAAU;gBACjB,QAAQ,CAAC,aAAa,CAAC,UAAU,EAAE,UAAU,CAAC,CAAA;YAChD,CAAC;SACF,CAAC,CAAA;IACJ,CAAC;IAED,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAA;AACxD,CAAC;AAED,4FAA4F;AAC5F,4EAA4E;AAC5E,MAAM,UAAU,eAAe,CAAC,GAAc,EAAE,GAAW,EAAE,GAAiB;IAC5E,MAAM,CAAC,GAAG,GAAG,CAAC,QAAQ,CAAA;IACtB,CAAC,CAAC,KAAK,GAAG,GAAG,CAAA;IACb,CAAC,CAAC,KAAK,GAAG,GAAG,CAAA;IACb,OAAO,CAAC,CAAA;AACV,CAAC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { AccessorFactory, ComponentDef, ComponentId, ComponentOptions, Schema } from '@ecsia/schema';
|
|
2
|
+
import type { ColumnLayout } from '../memory/index.js';
|
|
3
|
+
export declare const UNREGISTERED: ComponentId;
|
|
4
|
+
export type DefKind = 'component' | 'relation-presence' | 'relation-overflow';
|
|
5
|
+
export interface ComponentRuntime<S extends Schema> extends ComponentDef<S> {
|
|
6
|
+
id: ComponentId;
|
|
7
|
+
accessorFactory: AccessorFactory<S> | null;
|
|
8
|
+
readonly columnLayouts: readonly ColumnLayout[];
|
|
9
|
+
readonly defKind: DefKind;
|
|
10
|
+
readonly restrictedToMainThread: boolean;
|
|
11
|
+
/** True iff the component carries >=1 rich (sidecar-backed) field. */
|
|
12
|
+
readonly hasRichFields: boolean;
|
|
13
|
+
}
|
|
14
|
+
export declare function defineComponent<const S extends Schema, const B extends string = never, const N extends string = never>(schema: S, options: ComponentOptions & ({
|
|
15
|
+
readonly name: N;
|
|
16
|
+
readonly brand?: B;
|
|
17
|
+
} | {
|
|
18
|
+
readonly brand: B;
|
|
19
|
+
readonly name?: N;
|
|
20
|
+
})): ComponentDef<S, [B] extends [never] ? N : B>;
|
|
21
|
+
export declare function defineTag<const N extends string>(name: N): ComponentDef<Record<never, never>, N>;
|
|
22
|
+
export declare function registerComponentId<S extends Schema>(def: ComponentDef<S>, id: ComponentId): void;
|
|
23
|
+
//# sourceMappingURL=define.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"define.d.ts","sourceRoot":"","sources":["../../src/component/define.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EACV,eAAe,EACf,YAAY,EACZ,WAAW,EACX,gBAAgB,EAGhB,MAAM,EACP,MAAM,eAAe,CAAA;AACtB,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AAKtD,eAAO,MAAM,YAAY,EAAS,WAAW,CAAA;AAE7C,MAAM,MAAM,OAAO,GAAG,WAAW,GAAG,mBAAmB,GAAG,mBAAmB,CAAA;AAK7E,MAAM,WAAW,gBAAgB,CAAC,CAAC,SAAS,MAAM,CAAE,SAAQ,YAAY,CAAC,CAAC,CAAC;IACzE,EAAE,EAAE,WAAW,CAAA;IACf,eAAe,EAAE,eAAe,CAAC,CAAC,CAAC,GAAG,IAAI,CAAA;IAC1C,QAAQ,CAAC,aAAa,EAAE,SAAS,YAAY,EAAE,CAAA;IAC/C,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAA;IACzB,QAAQ,CAAC,sBAAsB,EAAE,OAAO,CAAA;IACxC,sEAAsE;IACtE,QAAQ,CAAC,aAAa,EAAE,OAAO,CAAA;CAChC;AAwED,wBAAgB,eAAe,CAC7B,KAAK,CAAC,CAAC,SAAS,MAAM,EACtB,KAAK,CAAC,CAAC,SAAS,MAAM,GAAG,KAAK,EAC9B,KAAK,CAAC,CAAC,SAAS,MAAM,GAAG,KAAK,EAE9B,MAAM,EAAE,CAAC,EACT,OAAO,EAAE,gBAAgB,GAAG,CAAC;IAAE,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC;IAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC,CAAA;CAAE,GAAG;IAAE,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAC;IAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;CAAE,CAAC,GAChH,YAAY,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CA0D9C;AAID,wBAAgB,SAAS,CAAC,KAAK,CAAC,CAAC,SAAS,MAAM,EAAE,IAAI,EAAE,CAAC,GAAG,YAAY,CAAC,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,EAAE,CAAC,CAAC,CAKhG;AAKD,wBAAgB,mBAAmB,CAAC,CAAC,SAAS,MAAM,EAAE,GAAG,EAAE,YAAY,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,WAAW,GAAG,IAAI,CAOjG"}
|