@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/dist/config.js
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
// WorldOptions, canonical defaults, and fail-fast resolution/validation.
|
|
2
|
+
// All feature knobs are nested under their feature key ( nesting rule).
|
|
3
|
+
/** Thrown synchronously at construction for any invalid configuration. */
|
|
4
|
+
export class ConfigError extends Error {
|
|
5
|
+
name = 'ConfigError';
|
|
6
|
+
constructor(message) {
|
|
7
|
+
super(message);
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
const isPositiveInt = (n) => Number.isInteger(n) && n > 0;
|
|
11
|
+
export function resolveOptions(options = {}) {
|
|
12
|
+
const generationBits = options.generationBits ?? 10;
|
|
13
|
+
if (!Number.isInteger(generationBits) || generationBits < 0 || generationBits > 31) {
|
|
14
|
+
throw new ConfigError(`generationBits must be an integer in [0, 31] (so indexBits = 32 - generationBits is valid); got ${generationBits}`);
|
|
15
|
+
}
|
|
16
|
+
const indexBits = 32 - generationBits;
|
|
17
|
+
const threaded = options.threaded ?? false;
|
|
18
|
+
// Generations are the worker stale-handle detection mechanism; 0 is unsafe under threading.
|
|
19
|
+
if (generationBits === 0 && threaded) {
|
|
20
|
+
throw new ConfigError('generationBits must be > 0 when threaded === true (worker stale-handle detection)');
|
|
21
|
+
}
|
|
22
|
+
const maxEntities = options.maxEntities ?? 1 << 20;
|
|
23
|
+
if (!isPositiveInt(maxEntities)) {
|
|
24
|
+
throw new ConfigError(`maxEntities must be a positive integer; got ${maxEntities}`);
|
|
25
|
+
}
|
|
26
|
+
const maxIndex = 2 ** indexBits;
|
|
27
|
+
if (maxEntities > maxIndex) {
|
|
28
|
+
throw new ConfigError(`maxEntities (${maxEntities}) exceeds the index space 2^${indexBits} = ${maxIndex} for generationBits=${generationBits}`);
|
|
29
|
+
}
|
|
30
|
+
const maxHotArchetypes = options.maxHotArchetypes ?? Math.max(256, maxEntities >>> 8);
|
|
31
|
+
if (!isPositiveInt(maxHotArchetypes)) {
|
|
32
|
+
throw new ConfigError(`maxHotArchetypes must be a positive integer; got ${maxHotArchetypes}`);
|
|
33
|
+
}
|
|
34
|
+
const relations = options.relations ?? [];
|
|
35
|
+
const r = options.reactivity ?? {};
|
|
36
|
+
const maxWritesPerFrame = r.maxWritesPerFrame ?? maxEntities * 4;
|
|
37
|
+
const maxShapeChangesPerFrame = r.maxShapeChangesPerFrame ?? maxEntities * 2;
|
|
38
|
+
if (!isPositiveInt(maxWritesPerFrame)) {
|
|
39
|
+
throw new ConfigError(`reactivity.maxWritesPerFrame must be a positive integer; got ${maxWritesPerFrame}`);
|
|
40
|
+
}
|
|
41
|
+
if (!isPositiveInt(maxShapeChangesPerFrame)) {
|
|
42
|
+
throw new ConfigError(`reactivity.maxShapeChangesPerFrame must be a positive integer; got ${maxShapeChangesPerFrame}`);
|
|
43
|
+
}
|
|
44
|
+
// Two-word log entries when any relation is registered ( C2).
|
|
45
|
+
const logEntryWords = r.logEntryWords ?? (relations.length > 0 ? 2 : 1);
|
|
46
|
+
const workers = options.scheduler?.workers ?? 0;
|
|
47
|
+
if (typeof workers === 'number' && (!Number.isInteger(workers) || workers < 0)) {
|
|
48
|
+
throw new ConfigError(`scheduler.workers must be a non-negative integer or 'no-sab'; got ${workers}`);
|
|
49
|
+
}
|
|
50
|
+
return {
|
|
51
|
+
components: options.components ?? [],
|
|
52
|
+
relations,
|
|
53
|
+
systems: options.systems ?? [],
|
|
54
|
+
maxEntities,
|
|
55
|
+
generationBits,
|
|
56
|
+
indexBits,
|
|
57
|
+
threaded,
|
|
58
|
+
maxHotArchetypes,
|
|
59
|
+
reactivity: {
|
|
60
|
+
maxWritesPerFrame,
|
|
61
|
+
maxShapeChangesPerFrame,
|
|
62
|
+
observerCadence: r.observerCadence ?? 'frame-end',
|
|
63
|
+
changeTrackingDefault: r.changeTrackingDefault ?? 'component',
|
|
64
|
+
logEntryWords,
|
|
65
|
+
shrinkRings: r.shrinkRings ?? false,
|
|
66
|
+
},
|
|
67
|
+
scheduler: { workers },
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import type { EntityHandle as SchemaEntityHandle, EntityIndex as SchemaEntityIndex } from '@ecsia/schema';
|
|
2
|
+
/** A packed u32: [generation: generationBits][index: indexBits], generation in the HIGH bits. */
|
|
3
|
+
export type EntityHandle = SchemaEntityHandle;
|
|
4
|
+
/** The low-bits index portion — the slot in the dense/sparse arrays. */
|
|
5
|
+
export type EntityIndex = SchemaEntityIndex;
|
|
6
|
+
/** The generation (version) counter for a slot. */
|
|
7
|
+
export type EntityGeneration = number & {
|
|
8
|
+
readonly __ecsiaEntityGeneration: unique symbol;
|
|
9
|
+
};
|
|
10
|
+
export interface HandleLayout {
|
|
11
|
+
readonly indexBits: number;
|
|
12
|
+
readonly generationBits: number;
|
|
13
|
+
/** Low-bits mask isolating the index. */
|
|
14
|
+
readonly indexMask: number;
|
|
15
|
+
/** Unshifted generation mask (`(1 << generationBits) - 1`). */
|
|
16
|
+
readonly generationMask: number;
|
|
17
|
+
/** `=== indexBits`. */
|
|
18
|
+
readonly generationShift: number;
|
|
19
|
+
/** Largest valid index (`indexMask`). */
|
|
20
|
+
readonly maxIndex: number;
|
|
21
|
+
/** Generation value just before wrap to 0 (`generationMask`). */
|
|
22
|
+
readonly maxGeneration: number;
|
|
23
|
+
/** Number of addressable slots (`maxIndex + 1`). */
|
|
24
|
+
readonly capacity: number;
|
|
25
|
+
}
|
|
26
|
+
/** Sentinel for "no entity" in eid fields and APIs that may return absent. NOT a live handle. */
|
|
27
|
+
export declare const NO_ENTITY: EntityHandle;
|
|
28
|
+
/** Alias of {@link NO_ENTITY} for call sites that prefer the "null handle" spelling. */
|
|
29
|
+
export declare const NULL_ENTITY: SchemaEntityHandle;
|
|
30
|
+
/**
|
|
31
|
+
* True when `handle` is the {@link NO_ENTITY} sentinel (an absent / null handle). Use this to
|
|
32
|
+
* discriminate handles returned from APIs that may yield "no entity" without comparing against the
|
|
33
|
+
* raw `0xffffffff` literal: `if (isNoEntity(h)) { ... }`.
|
|
34
|
+
*/
|
|
35
|
+
export declare function isNoEntity(handle: EntityHandle): boolean;
|
|
36
|
+
/**
|
|
37
|
+
* Build the immutable handle layout from a generation-bit split. `indexBits = 32 -
|
|
38
|
+
* generationBits`. `1 << 32` is 1 in JS (shift is mod-32), so the all-ones index mask is
|
|
39
|
+
* special-cased for `generationBits === 0`.
|
|
40
|
+
*/
|
|
41
|
+
export declare function makeHandleLayout(generationBits: number): HandleLayout;
|
|
42
|
+
export declare function makeHandle(index: number, generation: number, layout: HandleLayout): EntityHandle;
|
|
43
|
+
export declare function handleIndex(handle: EntityHandle, layout: HandleLayout): EntityIndex;
|
|
44
|
+
export declare function handleGeneration(handle: EntityHandle, layout: HandleLayout): EntityGeneration;
|
|
45
|
+
//# sourceMappingURL=codec.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"codec.d.ts","sourceRoot":"","sources":["../../src/entity/codec.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,YAAY,IAAI,kBAAkB,EAAE,WAAW,IAAI,iBAAiB,EAAE,MAAM,eAAe,CAAA;AAGzG,iGAAiG;AACjG,MAAM,MAAM,YAAY,GAAG,kBAAkB,CAAA;AAE7C,wEAAwE;AACxE,MAAM,MAAM,WAAW,GAAG,iBAAiB,CAAA;AAE3C,mDAAmD;AACnD,MAAM,MAAM,gBAAgB,GAAG,MAAM,GAAG;IAAE,QAAQ,CAAC,uBAAuB,EAAE,OAAO,MAAM,CAAA;CAAE,CAAA;AAE3F,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;IAC1B,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAA;IAC/B,yCAAyC;IACzC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;IAC1B,+DAA+D;IAC/D,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAA;IAC/B,uBAAuB;IACvB,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAA;IAChC,yCAAyC;IACzC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IACzB,iEAAiE;IACjE,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAA;IAC9B,oDAAoD;IACpD,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;CAC1B;AAED,iGAAiG;AACjG,eAAO,MAAM,SAAS,EAAiB,YAAY,CAAA;AAEnD,wFAAwF;AACxF,eAAO,MAAM,WAAW,oBAAY,CAAA;AAEpC;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE,YAAY,GAAG,OAAO,CAExD;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,cAAc,EAAE,MAAM,GAAG,YAAY,CAiBrE;AAED,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,YAAY,GAAG,YAAY,CAOhG;AAED,wBAAgB,WAAW,CAAC,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,YAAY,GAAG,WAAW,CAEnF;AAED,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,YAAY,GAAG,gBAAgB,CAE7F"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
// The generational handle: a packed u32 [generation: high][index: low].
|
|
2
|
+
// Encode/decode are pure, branch-free bit ops; the brand is erased at runtime.
|
|
3
|
+
import { IS_DEV } from '../env.js';
|
|
4
|
+
/** Sentinel for "no entity" in eid fields and APIs that may return absent. NOT a live handle. */
|
|
5
|
+
export const NO_ENTITY = 0xffffffff;
|
|
6
|
+
/** Alias of {@link NO_ENTITY} for call sites that prefer the "null handle" spelling. */
|
|
7
|
+
export const NULL_ENTITY = NO_ENTITY;
|
|
8
|
+
/**
|
|
9
|
+
* True when `handle` is the {@link NO_ENTITY} sentinel (an absent / null handle). Use this to
|
|
10
|
+
* discriminate handles returned from APIs that may yield "no entity" without comparing against the
|
|
11
|
+
* raw `0xffffffff` literal: `if (isNoEntity(h)) { ... }`.
|
|
12
|
+
*/
|
|
13
|
+
export function isNoEntity(handle) {
|
|
14
|
+
return handle === NO_ENTITY;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Build the immutable handle layout from a generation-bit split. `indexBits = 32 -
|
|
18
|
+
* generationBits`. `1 << 32` is 1 in JS (shift is mod-32), so the all-ones index mask is
|
|
19
|
+
* special-cased for `generationBits === 0`.
|
|
20
|
+
*/
|
|
21
|
+
export function makeHandleLayout(generationBits) {
|
|
22
|
+
if (!Number.isInteger(generationBits) || generationBits < 0 || generationBits > 31) {
|
|
23
|
+
throw new RangeError(`generationBits must be an integer in [0, 31]; got ${generationBits}`);
|
|
24
|
+
}
|
|
25
|
+
const indexBits = 32 - generationBits;
|
|
26
|
+
const indexMask = generationBits === 0 ? 0xffffffff : ((1 << indexBits) - 1) >>> 0;
|
|
27
|
+
const generationMask = generationBits === 0 ? 0 : ((1 << generationBits) - 1) >>> 0;
|
|
28
|
+
return Object.freeze({
|
|
29
|
+
indexBits,
|
|
30
|
+
generationBits,
|
|
31
|
+
indexMask,
|
|
32
|
+
generationMask,
|
|
33
|
+
generationShift: indexBits,
|
|
34
|
+
maxIndex: indexMask,
|
|
35
|
+
maxGeneration: generationMask,
|
|
36
|
+
capacity: indexMask + 1,
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
export function makeHandle(index, generation, layout) {
|
|
40
|
+
// Dev-mode guard: a generation above maxGeneration would overflow the
|
|
41
|
+
// generation field and silently alias another slot's handle. Stripped in production builds.
|
|
42
|
+
if (IS_DEV && generation > layout.maxGeneration) {
|
|
43
|
+
throw new RangeError(`makeHandle: generation ${generation} exceeds maxGeneration ${layout.maxGeneration}`);
|
|
44
|
+
}
|
|
45
|
+
return (((generation << layout.generationShift) | index) >>> 0);
|
|
46
|
+
}
|
|
47
|
+
export function handleIndex(handle, layout) {
|
|
48
|
+
return ((handle & layout.indexMask) >>> 0);
|
|
49
|
+
}
|
|
50
|
+
export function handleGeneration(handle, layout) {
|
|
51
|
+
return ((handle >>> layout.generationShift) & layout.generationMask);
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=codec.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"codec.js","sourceRoot":"","sources":["../../src/entity/codec.ts"],"names":[],"mappings":"AAAA,wEAAwE;AACxE,+EAA+E;AAK/E,OAAO,EAAE,MAAM,EAAE,MAAM,WAAW,CAAA;AA4BlC,iGAAiG;AACjG,MAAM,CAAC,MAAM,SAAS,GAAG,UAA0B,CAAA;AAEnD,wFAAwF;AACxF,MAAM,CAAC,MAAM,WAAW,GAAG,SAAS,CAAA;AAEpC;;;;GAIG;AACH,MAAM,UAAU,UAAU,CAAC,MAAoB;IAC7C,OAAQ,MAAiB,KAAM,SAAoB,CAAA;AACrD,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,gBAAgB,CAAC,cAAsB;IACrD,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,cAAc,CAAC,IAAI,cAAc,GAAG,CAAC,IAAI,cAAc,GAAG,EAAE,EAAE,CAAC;QACnF,MAAM,IAAI,UAAU,CAAC,qDAAqD,cAAc,EAAE,CAAC,CAAA;IAC7F,CAAC;IACD,MAAM,SAAS,GAAG,EAAE,GAAG,cAAc,CAAA;IACrC,MAAM,SAAS,GAAG,cAAc,KAAK,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,SAAS,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAA;IAClF,MAAM,cAAc,GAAG,cAAc,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,cAAc,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAA;IACnF,OAAO,MAAM,CAAC,MAAM,CAAC;QACnB,SAAS;QACT,cAAc;QACd,SAAS;QACT,cAAc;QACd,eAAe,EAAE,SAAS;QAC1B,QAAQ,EAAE,SAAS;QACnB,aAAa,EAAE,cAAc;QAC7B,QAAQ,EAAE,SAAS,GAAG,CAAC;KACxB,CAAC,CAAA;AACJ,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,KAAa,EAAE,UAAkB,EAAE,MAAoB;IAChF,sEAAsE;IACtE,4FAA4F;IAC5F,IAAI,MAAM,IAAI,UAAU,GAAG,MAAM,CAAC,aAAa,EAAE,CAAC;QAChD,MAAM,IAAI,UAAU,CAAC,0BAA0B,UAAU,0BAA0B,MAAM,CAAC,aAAa,EAAE,CAAC,CAAA;IAC5G,CAAC;IACD,OAAO,CAAC,CAAC,CAAC,UAAU,IAAI,MAAM,CAAC,eAAe,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC,CAAiB,CAAA;AACjF,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,MAAoB,EAAE,MAAoB;IACpE,OAAO,CAAC,CAAC,MAAM,GAAG,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,CAAgB,CAAA;AAC3D,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,MAAoB,EAAE,MAAoB;IACzE,OAAO,CAAC,CAAC,MAAM,KAAK,MAAM,CAAC,eAAe,CAAC,GAAG,MAAM,CAAC,cAAc,CAAqB,CAAA;AAC1F,CAAC"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import type { EntityHandle, HandleLayout } from './codec.js';
|
|
2
|
+
export declare class CapacityExceeded extends Error {
|
|
3
|
+
readonly name = "CapacityExceeded";
|
|
4
|
+
constructor(capacity: number, aliveCount: number);
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Asked of the store when a brand-new index would exceed the currently-addressable array
|
|
8
|
+
* length. Returns the new addressable length after growth; returns the
|
|
9
|
+
* unchanged length when growth is impossible, which makes `allocEntity` throw CapacityExceeded.
|
|
10
|
+
*/
|
|
11
|
+
export type GrowHook = (need: number) => number;
|
|
12
|
+
export interface EntityIndexArrays {
|
|
13
|
+
/** sparse[index] = position of `index` within `dense`. */
|
|
14
|
+
readonly sparse: Uint32Array;
|
|
15
|
+
/** dense[pos] = a full EntityHandle; [0, aliveCount) alive, [aliveCount, denseLen) parked-free. */
|
|
16
|
+
readonly dense: Uint32Array;
|
|
17
|
+
/** Per-slot generation, addressed by index (only low generationBits used). */
|
|
18
|
+
readonly generation: Uint32Array;
|
|
19
|
+
}
|
|
20
|
+
/** Tuning for the mint-time bounds: how many indices are addressable now vs. ever allowed. */
|
|
21
|
+
export interface EntityIndexBounds {
|
|
22
|
+
/** Current addressable array length (grows via the GrowHook up to `ceiling`). */
|
|
23
|
+
readonly addressable: number;
|
|
24
|
+
/**
|
|
25
|
+
* Hard mint ceiling: the largest number of distinct indices that may ever be minted. The
|
|
26
|
+
* allocator throws CapacityExceeded once denseLen reaches this with no free slot. Typically
|
|
27
|
+
* `min(maxEntities, maxIndex + 1)`, minus one when threaded to reserve `maxIndex` for the
|
|
28
|
+
* NO_ENTITY sentinel.
|
|
29
|
+
*/
|
|
30
|
+
readonly ceiling: number;
|
|
31
|
+
}
|
|
32
|
+
export declare class EntityIndex {
|
|
33
|
+
#private;
|
|
34
|
+
constructor(layout: HandleLayout, arrays: EntityIndexArrays, bounds?: EntityIndexBounds, grow?: GrowHook);
|
|
35
|
+
/** Re-publish the backing arrays after a growth; positions/cursors are unchanged. */
|
|
36
|
+
rebind(arrays: EntityIndexArrays, addressable: number): void;
|
|
37
|
+
get aliveCount(): number;
|
|
38
|
+
get denseLen(): number;
|
|
39
|
+
get wrapped(): boolean;
|
|
40
|
+
allocEntity(): EntityHandle;
|
|
41
|
+
freeEntity(handle: EntityHandle): void;
|
|
42
|
+
/** The full (generational) handle currently occupying `index`, or NO_ENTITY-equivalent if dead. */
|
|
43
|
+
handleOfIndex(index: number): EntityHandle;
|
|
44
|
+
isAlive(handle: EntityHandle): boolean;
|
|
45
|
+
}
|
|
46
|
+
//# sourceMappingURL=index-allocator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index-allocator.d.ts","sourceRoot":"","sources":["../../src/entity/index-allocator.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AAE5D,qBAAa,gBAAiB,SAAQ,KAAK;IACzC,SAAkB,IAAI,sBAAqB;gBAC/B,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM;CAKjD;AAED;;;;GAIG;AACH,MAAM,MAAM,QAAQ,GAAG,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAA;AAE/C,MAAM,WAAW,iBAAiB;IAChC,0DAA0D;IAC1D,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAA;IAC5B,mGAAmG;IACnG,QAAQ,CAAC,KAAK,EAAE,WAAW,CAAA;IAC3B,8EAA8E;IAC9E,QAAQ,CAAC,UAAU,EAAE,WAAW,CAAA;CACjC;AAOD,8FAA8F;AAC9F,MAAM,WAAW,iBAAiB;IAChC,iFAAiF;IACjF,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;IAC5B;;;;;OAKG;IACH,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;CACzB;AAED,qBAAa,WAAW;;gBAUV,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,iBAAiB,EAAE,MAAM,CAAC,EAAE,iBAAiB,EAAE,IAAI,CAAC,EAAE,QAAQ;IAaxG,qFAAqF;IACrF,MAAM,CAAC,MAAM,EAAE,iBAAiB,EAAE,WAAW,EAAE,MAAM,GAAG,IAAI;IAK5D,IAAI,UAAU,IAAI,MAAM,CAEvB;IAED,IAAI,QAAQ,IAAI,MAAM,CAErB;IAED,IAAI,OAAO,IAAI,OAAO,CAErB;IAED,WAAW,IAAI,YAAY;IAqC3B,UAAU,CAAC,MAAM,EAAE,YAAY,GAAG,IAAI;IAwBtC,mGAAmG;IACnG,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,YAAY;IAM1C,OAAO,CAAC,MAAM,EAAE,YAAY,GAAG,OAAO;CAOvC"}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
// The dense/sparse swap-and-move free-list: the authoritative registry of
|
|
2
|
+
// which index slots are alive and at which generation. All mutation here is single-writer
|
|
3
|
+
// (main-thread, serial phase). `dense` stores full handles (index ⊕ generation) so recycling
|
|
4
|
+
// can reissue the bumped handle with a single read.
|
|
5
|
+
import { handleIndex, makeHandle } from './codec.js';
|
|
6
|
+
export class CapacityExceeded extends Error {
|
|
7
|
+
name = 'CapacityExceeded';
|
|
8
|
+
constructor(capacity, aliveCount) {
|
|
9
|
+
super(`entity index space exhausted: ${aliveCount} alive at capacity ${capacity}; raise indexBits (lower generationBits) or maxEntities`);
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
export class EntityIndex {
|
|
13
|
+
#layout;
|
|
14
|
+
#arrays;
|
|
15
|
+
#cursors = { aliveCount: 0, denseLen: 0 };
|
|
16
|
+
/** Set once on the first generation wrap of any slot, for the dev-mode warning. */
|
|
17
|
+
#wrapped = false;
|
|
18
|
+
#addressable;
|
|
19
|
+
#ceiling;
|
|
20
|
+
#grow;
|
|
21
|
+
constructor(layout, arrays, bounds, grow) {
|
|
22
|
+
this.#layout = layout;
|
|
23
|
+
this.#arrays = arrays;
|
|
24
|
+
const len = arrays.dense.length;
|
|
25
|
+
this.#addressable = bounds?.addressable ?? len;
|
|
26
|
+
// Without an explicit ceiling the allocator can only address what it was handed: cap mints
|
|
27
|
+
// at the array length (still never beyond the index space).
|
|
28
|
+
this.#ceiling = bounds?.ceiling ?? Math.min(len, this.#layout.maxIndex + 1);
|
|
29
|
+
// Default hook: no growth — minting past `addressable` is impossible, so it stays put and
|
|
30
|
+
// the ceiling guard throws.
|
|
31
|
+
this.#grow = grow ?? (() => this.#addressable);
|
|
32
|
+
}
|
|
33
|
+
/** Re-publish the backing arrays after a growth; positions/cursors are unchanged. */
|
|
34
|
+
rebind(arrays, addressable) {
|
|
35
|
+
this.#arrays = arrays;
|
|
36
|
+
this.#addressable = addressable;
|
|
37
|
+
}
|
|
38
|
+
get aliveCount() {
|
|
39
|
+
return this.#cursors.aliveCount;
|
|
40
|
+
}
|
|
41
|
+
get denseLen() {
|
|
42
|
+
return this.#cursors.denseLen;
|
|
43
|
+
}
|
|
44
|
+
get wrapped() {
|
|
45
|
+
return this.#wrapped;
|
|
46
|
+
}
|
|
47
|
+
allocEntity() {
|
|
48
|
+
const c = this.#cursors;
|
|
49
|
+
{
|
|
50
|
+
const { sparse, dense } = this.#arrays;
|
|
51
|
+
if (c.aliveCount < c.denseLen) {
|
|
52
|
+
const pos = c.aliveCount;
|
|
53
|
+
const handle = dense[pos];
|
|
54
|
+
const index = handleIndex(handle, this.#layout);
|
|
55
|
+
sparse[index] = pos;
|
|
56
|
+
c.aliveCount += 1;
|
|
57
|
+
return handle;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
// Mint a brand-new index. The ceiling is the real, addressable bound (the backing-array
|
|
61
|
+
// length, capped by the index space); never mint an index we cannot store.
|
|
62
|
+
if (c.denseLen >= this.#ceiling) {
|
|
63
|
+
throw new CapacityExceeded(this.#ceiling, c.aliveCount);
|
|
64
|
+
}
|
|
65
|
+
if (c.denseLen >= this.#addressable) {
|
|
66
|
+
// Ask the store to grow the backing arrays and re-publish via rebind(); if it cannot,
|
|
67
|
+
// addressable is unchanged and we are genuinely exhausted.
|
|
68
|
+
const grown = this.#grow(c.denseLen + 1);
|
|
69
|
+
if (c.denseLen >= grown) {
|
|
70
|
+
throw new CapacityExceeded(this.#ceiling, c.aliveCount);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
const { sparse, dense, generation } = this.#arrays;
|
|
74
|
+
const index = c.denseLen;
|
|
75
|
+
generation[index] = 0;
|
|
76
|
+
const handle = makeHandle(index, 0, this.#layout);
|
|
77
|
+
dense[index] = handle;
|
|
78
|
+
sparse[index] = index;
|
|
79
|
+
c.denseLen += 1;
|
|
80
|
+
c.aliveCount += 1;
|
|
81
|
+
return handle;
|
|
82
|
+
}
|
|
83
|
+
freeEntity(handle) {
|
|
84
|
+
const { sparse, dense, generation } = this.#arrays;
|
|
85
|
+
const c = this.#cursors;
|
|
86
|
+
const layout = this.#layout;
|
|
87
|
+
const index = handleIndex(handle, layout);
|
|
88
|
+
const pos = sparse[index];
|
|
89
|
+
const lastAlive = c.aliveCount - 1;
|
|
90
|
+
const lastHandle = dense[lastAlive];
|
|
91
|
+
const lastIndex = handleIndex(lastHandle, layout);
|
|
92
|
+
dense[pos] = lastHandle;
|
|
93
|
+
sparse[lastIndex] = pos;
|
|
94
|
+
const prevGen = generation[index];
|
|
95
|
+
const nextGen = (prevGen + 1) & layout.generationMask;
|
|
96
|
+
if (nextGen < prevGen)
|
|
97
|
+
this.#wrapped = true;
|
|
98
|
+
generation[index] = nextGen;
|
|
99
|
+
const newHandle = makeHandle(index, nextGen, layout);
|
|
100
|
+
dense[lastAlive] = newHandle;
|
|
101
|
+
sparse[index] = lastAlive;
|
|
102
|
+
c.aliveCount = lastAlive;
|
|
103
|
+
}
|
|
104
|
+
/** The full (generational) handle currently occupying `index`, or NO_ENTITY-equivalent if dead. */
|
|
105
|
+
handleOfIndex(index) {
|
|
106
|
+
if (index >= this.#cursors.denseLen)
|
|
107
|
+
return 0xffffffff;
|
|
108
|
+
const gen = this.#arrays.generation[index];
|
|
109
|
+
return makeHandle(index, gen, this.#layout);
|
|
110
|
+
}
|
|
111
|
+
isAlive(handle) {
|
|
112
|
+
const index = handleIndex(handle, this.#layout);
|
|
113
|
+
if (index >= this.#cursors.denseLen)
|
|
114
|
+
return false;
|
|
115
|
+
const pos = this.#arrays.sparse[index];
|
|
116
|
+
if (pos >= this.#cursors.aliveCount)
|
|
117
|
+
return false;
|
|
118
|
+
return this.#arrays.dense[pos] === handle;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
//# sourceMappingURL=index-allocator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index-allocator.js","sourceRoot":"","sources":["../../src/entity/index-allocator.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export { makeHandle, handleIndex, handleGeneration, makeHandleLayout, NO_ENTITY, NULL_ENTITY, isNoEntity } from './codec.js';
|
|
2
|
+
export type { EntityHandle, EntityIndex, EntityGeneration, HandleLayout } from './codec.js';
|
|
3
|
+
export { EntityIndex as EntityIndexAllocator, CapacityExceeded } from './index-allocator.js';
|
|
4
|
+
export type { EntityIndexArrays } from './index-allocator.js';
|
|
5
|
+
export { EntityRecord, ARCHETYPE_NONE } from './record.js';
|
|
6
|
+
export type { EntityRecordArrays, EntityLocation } from './record.js';
|
|
7
|
+
export { EntityRef } from './ref.js';
|
|
8
|
+
export type { EntityAccessors, AccessorResolver } from './ref.js';
|
|
9
|
+
export { reserveEntityBlock, returnReservedIds } from './reservation.js';
|
|
10
|
+
export type { EntityReservation } from './reservation.js';
|
|
11
|
+
export { EntityStore } from './store.js';
|
|
12
|
+
export type { EntityStoreConfig, HandleStats } from './store.js';
|
|
13
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/entity/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,SAAS,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA;AAC5H,YAAY,EAAE,YAAY,EAAE,WAAW,EAAE,gBAAgB,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AAE3F,OAAO,EAAE,WAAW,IAAI,oBAAoB,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAA;AAC5F,YAAY,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAA;AAE7D,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AAC1D,YAAY,EAAE,kBAAkB,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AAErE,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAA;AACpC,YAAY,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAA;AAEjE,OAAO,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAA;AACxE,YAAY,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAA;AAEzD,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA;AACxC,YAAY,EAAE,iBAAiB,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { makeHandle, handleIndex, handleGeneration, makeHandleLayout, NO_ENTITY, NULL_ENTITY, isNoEntity } from './codec.js';
|
|
2
|
+
export { EntityIndex as EntityIndexAllocator, CapacityExceeded } from './index-allocator.js';
|
|
3
|
+
export { EntityRecord, ARCHETYPE_NONE } from './record.js';
|
|
4
|
+
export { EntityRef } from './ref.js';
|
|
5
|
+
export { reserveEntityBlock, returnReservedIds } from './reservation.js';
|
|
6
|
+
export { EntityStore } from './store.js';
|
|
7
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/entity/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,SAAS,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA;AAG5H,OAAO,EAAE,WAAW,IAAI,oBAAoB,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAA;AAG5F,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AAG1D,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAA;AAGpC,OAAO,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAA;AAGxE,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { EntityHandle, HandleLayout } from './codec.js';
|
|
2
|
+
/**
|
|
3
|
+
* Record sentinel for an index not yet placed into any archetype. Normatively owned by
|
|
4
|
+
* declared here as the value the record arrays carry pre-placement.
|
|
5
|
+
*/
|
|
6
|
+
export declare const ARCHETYPE_NONE = 4294967295;
|
|
7
|
+
export interface EntityRecordArrays {
|
|
8
|
+
/** recordArchetypeId[index] = the ArchetypeId the entity currently lives in. */
|
|
9
|
+
readonly recordArchetypeId: Uint32Array;
|
|
10
|
+
/** recordArchetypeRow[index] = the row within that archetype's SoA columns. */
|
|
11
|
+
readonly recordArchetypeRow: Uint32Array;
|
|
12
|
+
}
|
|
13
|
+
export interface EntityLocation {
|
|
14
|
+
readonly archetypeId: number;
|
|
15
|
+
readonly row: number;
|
|
16
|
+
}
|
|
17
|
+
export declare class EntityRecord {
|
|
18
|
+
#private;
|
|
19
|
+
constructor(layout: HandleLayout, arrays: EntityRecordArrays);
|
|
20
|
+
rebind(arrays: EntityRecordArrays): void;
|
|
21
|
+
commitRecord(index: number, archetypeId: number, row: number): void;
|
|
22
|
+
resolveLocation(handle: EntityHandle): EntityLocation;
|
|
23
|
+
/** The archetype id of an entity by its (already-decoded) index — the storage RecordSurface. */
|
|
24
|
+
archetypeIdOf(index: number): number;
|
|
25
|
+
/** The row of an entity within its archetype by its index — the storage RecordSurface. */
|
|
26
|
+
rowOf(index: number): number;
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=record.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"record.d.ts","sourceRoot":"","sources":["../../src/entity/record.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AAE5D;;;GAGG;AACH,eAAO,MAAM,cAAc,aAAa,CAAA;AAExC,MAAM,WAAW,kBAAkB;IACjC,gFAAgF;IAChF,QAAQ,CAAC,iBAAiB,EAAE,WAAW,CAAA;IACvC,+EAA+E;IAC/E,QAAQ,CAAC,kBAAkB,EAAE,WAAW,CAAA;CACzC;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;IAC5B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;CACrB;AAED,qBAAa,YAAY;;gBAIX,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,kBAAkB;IAK5D,MAAM,CAAC,MAAM,EAAE,kBAAkB,GAAG,IAAI;IAKxC,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI;IAKnE,eAAe,CAAC,MAAM,EAAE,YAAY,GAAG,cAAc;IAQrD,gGAAgG;IAChG,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM;IAIpC,0FAA0F;IAC1F,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM;CAG7B"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
// The two-word entity record: two parallel flat arrays addressed by the
|
|
2
|
+
// handle's index. Writing both words is the structural commit point (INVARIANT C1). The
|
|
3
|
+
// commit is wrapped in `commitRecord` so a future v2 can swap the two plain stores for an
|
|
4
|
+
// Atomics pair without touching callers.
|
|
5
|
+
import { handleIndex } from './codec.js';
|
|
6
|
+
/**
|
|
7
|
+
* Record sentinel for an index not yet placed into any archetype. Normatively owned by
|
|
8
|
+
* declared here as the value the record arrays carry pre-placement.
|
|
9
|
+
*/
|
|
10
|
+
export const ARCHETYPE_NONE = 0xffffffff;
|
|
11
|
+
export class EntityRecord {
|
|
12
|
+
#layout;
|
|
13
|
+
#arrays;
|
|
14
|
+
constructor(layout, arrays) {
|
|
15
|
+
this.#layout = layout;
|
|
16
|
+
this.#arrays = arrays;
|
|
17
|
+
}
|
|
18
|
+
rebind(arrays) {
|
|
19
|
+
this.#arrays = arrays;
|
|
20
|
+
}
|
|
21
|
+
// Row word first, id word second; v1 stores are plain.
|
|
22
|
+
commitRecord(index, archetypeId, row) {
|
|
23
|
+
this.#arrays.recordArchetypeRow[index] = row;
|
|
24
|
+
this.#arrays.recordArchetypeId[index] = archetypeId;
|
|
25
|
+
}
|
|
26
|
+
resolveLocation(handle) {
|
|
27
|
+
const index = handleIndex(handle, this.#layout);
|
|
28
|
+
return {
|
|
29
|
+
archetypeId: this.#arrays.recordArchetypeId[index],
|
|
30
|
+
row: this.#arrays.recordArchetypeRow[index],
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
/** The archetype id of an entity by its (already-decoded) index — the storage RecordSurface. */
|
|
34
|
+
archetypeIdOf(index) {
|
|
35
|
+
return this.#arrays.recordArchetypeId[index];
|
|
36
|
+
}
|
|
37
|
+
/** The row of an entity within its archetype by its index — the storage RecordSurface. */
|
|
38
|
+
rowOf(index) {
|
|
39
|
+
return this.#arrays.recordArchetypeRow[index];
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=record.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"record.js","sourceRoot":"","sources":["../../src/entity/record.ts"],"names":[],"mappings":"AAAA,wEAAwE;AACxE,wFAAwF;AACxF,0FAA0F;AAC1F,yCAAyC;AAEzC,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA;AAGxC;;;GAGG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG,UAAU,CAAA;AAcxC,MAAM,OAAO,YAAY;IACd,OAAO,CAAc;IAC9B,OAAO,CAAoB;IAE3B,YAAY,MAAoB,EAAE,MAA0B;QAC1D,IAAI,CAAC,OAAO,GAAG,MAAM,CAAA;QACrB,IAAI,CAAC,OAAO,GAAG,MAAM,CAAA;IACvB,CAAC;IAED,MAAM,CAAC,MAA0B;QAC/B,IAAI,CAAC,OAAO,GAAG,MAAM,CAAA;IACvB,CAAC;IAED,uDAAuD;IACvD,YAAY,CAAC,KAAa,EAAE,WAAmB,EAAE,GAAW;QAC1D,IAAI,CAAC,OAAO,CAAC,kBAAkB,CAAC,KAAK,CAAC,GAAG,GAAG,CAAA;QAC5C,IAAI,CAAC,OAAO,CAAC,iBAAiB,CAAC,KAAK,CAAC,GAAG,WAAW,CAAA;IACrD,CAAC;IAED,eAAe,CAAC,MAAoB;QAClC,MAAM,KAAK,GAAG,WAAW,CAAC,MAAM,EAAE,IAAI,CAAC,OAAO,CAAC,CAAA;QAC/C,OAAO;YACL,WAAW,EAAE,IAAI,CAAC,OAAO,CAAC,iBAAiB,CAAC,KAAK,CAAW;YAC5D,GAAG,EAAE,IAAI,CAAC,OAAO,CAAC,kBAAkB,CAAC,KAAK,CAAW;SACtD,CAAA;IACH,CAAC;IAED,gGAAgG;IAChG,aAAa,CAAC,KAAa;QACzB,OAAO,IAAI,CAAC,OAAO,CAAC,iBAAiB,CAAC,KAAK,CAAW,CAAA;IACxD,CAAC;IAED,0FAA0F;IAC1F,KAAK,CAAC,KAAa;QACjB,OAAO,IAAI,CAAC,OAAO,CAAC,kBAAkB,CAAC,KAAK,CAAW,CAAA;IACzD,CAAC;CACF"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import type { EntityHandle } from './codec.js';
|
|
2
|
+
import type { EntityRecord } from './record.js';
|
|
3
|
+
import type { ComponentDef, ReadOf, Schema, WriteOf } from '@ecsia/schema';
|
|
4
|
+
/**
|
|
5
|
+
* Resolves the (archetype, component) accessor singleton for an entity, pokes its row/handle, and
|
|
6
|
+
* returns it. The world installs one resolver per world; binds against a directly-allocated
|
|
7
|
+
* column set, binds against the entity's real archetype (the archetype-binding seam).
|
|
8
|
+
*/
|
|
9
|
+
export interface AccessorResolver {
|
|
10
|
+
resolveRead(handle: EntityHandle, archetypeId: number, row: number, def: unknown): unknown;
|
|
11
|
+
resolveWrite(handle: EntityHandle, archetypeId: number, row: number, def: unknown): unknown;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* The accessor surface installed on `EntityRef`. The bare `entity.<comp>` getter shorthand
|
|
15
|
+
* resolves to `read()` and is Readonly; `write()` returns the mutable singleton whose
|
|
16
|
+
* setters call world.trackWrite.
|
|
17
|
+
*/
|
|
18
|
+
export interface EntityAccessors {
|
|
19
|
+
read(def: unknown): unknown;
|
|
20
|
+
write(def: unknown): unknown;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* EntityRef is a POOLED SINGLETON: there is exactly ONE instance per world, and `world.entity(h)`
|
|
24
|
+
* re-points (rebinds) that one object at `h` and returns it — it does NOT allocate a fresh ref per
|
|
25
|
+
* call. The pooling contract is therefore:
|
|
26
|
+
*
|
|
27
|
+
* - The handle you bind is valid only until the NEXT `world.entity(...)` call, or until the bound
|
|
28
|
+
* entity is despawned / structurally moved. A reference captured in a local and used across
|
|
29
|
+
* either event aliases the wrong row.
|
|
30
|
+
* - Do NOT hold the ref across a `world.entity()` call. Re-resolve with `world.entity(h)` at the
|
|
31
|
+
* point of use, or extract the plain field values you need into locals first.
|
|
32
|
+
*
|
|
33
|
+
* To turn the classic silent-corruption footgun into a loud failure, the RANDOM-ACCESS read()/write()
|
|
34
|
+
* accessors verify on every call that the currently-bound handle is still alive and still occupies the
|
|
35
|
+
* location this ref cached at bind time; a stale/recycled/moved binding THROWS instead of reading or
|
|
36
|
+
* writing the wrong entity's row. (Query-iteration element accessors are a separate, hot path and are
|
|
37
|
+
* intentionally NOT guarded here.)
|
|
38
|
+
*/
|
|
39
|
+
export declare class EntityRef {
|
|
40
|
+
#private;
|
|
41
|
+
__handle: EntityHandle;
|
|
42
|
+
__archetypeId: number;
|
|
43
|
+
__row: number;
|
|
44
|
+
/** Set when bound via `{ lenient: true }` (e.g. an onRemove observer resolving a just-despawned entity). */
|
|
45
|
+
__lenient: boolean;
|
|
46
|
+
constructor(records: EntityRecord);
|
|
47
|
+
/** Public, frozen-surface accessor for the bound handle (the non-`__` form referenced by ). */
|
|
48
|
+
get handle(): EntityHandle;
|
|
49
|
+
/** Inject the world's accessor resolver (world wiring). */
|
|
50
|
+
__setResolver(resolver: AccessorResolver): void;
|
|
51
|
+
/** Inject the world's liveness probe so random-access read/write can fail loud on a stale binding. */
|
|
52
|
+
__setLiveness(isAlive: (handle: EntityHandle) => boolean): void;
|
|
53
|
+
/** Re-point this pooled ref at a (validated-alive) handle and resolve its location. */
|
|
54
|
+
__bind(handle: EntityHandle, lenient?: boolean): this;
|
|
55
|
+
/**
|
|
56
|
+
* Deeply-`Readonly` view of `def`'s fields for this entity.
|
|
57
|
+
* The `const C` parameter recovers the inferred `ReadOf<C>` so a random-access read is typed without
|
|
58
|
+
* caller casts; assignment through it is a TS2540 compile error. RANDOM-ACCESS path: guarded against a
|
|
59
|
+
* stale/recycled/moved pooled binding (see class jsdoc).
|
|
60
|
+
*/
|
|
61
|
+
read<const C extends ComponentDef<Schema>>(def: C): ReadOf<C>;
|
|
62
|
+
/**
|
|
63
|
+
* Mutable, write-tracked `WriteView<S>` of `def`'s fields for this entity. The `const C` parameter
|
|
64
|
+
* recovers the inferred `WriteOf<C>` so a random-access write is typed without caller casts; every
|
|
65
|
+
* setter additionally drives the write log (the only tracked-mutation path). RANDOM-ACCESS path:
|
|
66
|
+
* guarded against a stale/recycled/moved pooled binding (see class jsdoc).
|
|
67
|
+
*/
|
|
68
|
+
write<const C extends ComponentDef<Schema>>(def: C): WriteOf<C>;
|
|
69
|
+
}
|
|
70
|
+
//# sourceMappingURL=ref.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ref.d.ts","sourceRoot":"","sources":["../../src/entity/ref.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AAE9C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAC/C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,eAAe,CAAA;AAE1E;;;;GAIG;AACH,MAAM,WAAW,gBAAgB;IAC/B,WAAW,CAAC,MAAM,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,OAAO,GAAG,OAAO,CAAA;IAC1F,YAAY,CAAC,MAAM,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,OAAO,GAAG,OAAO,CAAA;CAC5F;AAED;;;;GAIG;AACH,MAAM,WAAW,eAAe;IAC9B,IAAI,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAAA;IAC3B,KAAK,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAAA;CAC7B;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,qBAAa,SAAS;;IAKpB,QAAQ,EAAE,YAAY,CAAY;IAClC,aAAa,EAAE,MAAM,CAAiB;IACtC,KAAK,SAAI;IACT,4GAA4G;IAC5G,SAAS,UAAQ;gBAEL,OAAO,EAAE,YAAY;IAIjC,+FAA+F;IAC/F,IAAI,MAAM,IAAI,YAAY,CAEzB;IAED,2DAA2D;IAC3D,aAAa,CAAC,QAAQ,EAAE,gBAAgB,GAAG,IAAI;IAI/C,sGAAsG;IACtG,aAAa,CAAC,OAAO,EAAE,CAAC,MAAM,EAAE,YAAY,KAAK,OAAO,GAAG,IAAI;IAI/D,uFAAuF;IACvF,MAAM,CAAC,MAAM,EAAE,YAAY,EAAE,OAAO,UAAQ,GAAG,IAAI;IAkCnD;;;;;OAKG;IACH,IAAI,CAAC,KAAK,CAAC,CAAC,SAAS,YAAY,CAAC,MAAM,CAAC,EAAE,GAAG,EAAE,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC;IAM7D;;;;;OAKG;IACH,KAAK,CAAC,KAAK,CAAC,CAAC,SAAS,YAAY,CAAC,MAAM,CAAC,EAAE,GAAG,EAAE,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;CAKhE"}
|