@forgeax/engine-ecs 0.1.26 → 0.1.27
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 +94 -35
- package/dist/__tests__/world-read.unit.test.d.ts +2 -0
- package/dist/__tests__/world-read.unit.test.d.ts.map +1 -0
- package/dist/commands.d.ts +2 -0
- package/dist/commands.d.ts.map +1 -1
- package/dist/index.mjs +3471 -4263
- package/dist/index.mjs.map +1 -1
- package/dist/internal.d.ts +2 -3
- package/dist/internal.d.ts.map +1 -1
- package/dist/internal.mjs +3 -333
- package/dist/internal.mjs.map +1 -1
- package/dist/projection/index.mjs.map +1 -1
- package/dist/shared.mjs.map +1 -1
- package/dist/world-entity-lifecycle.d.ts +3 -14
- package/dist/world-entity-lifecycle.d.ts.map +1 -1
- package/dist/world-internal.d.ts +65 -5
- package/dist/world-internal.d.ts.map +1 -1
- package/dist/world-read.d.ts +16 -0
- package/dist/world-read.d.ts.map +1 -0
- package/dist/world-read.mjs +8 -0
- package/dist/world-read.mjs.map +1 -0
- package/dist/world-scheduling.d.ts +0 -4
- package/dist/world-scheduling.d.ts.map +1 -1
- package/dist/world-storage-primitives.d.ts +26 -0
- package/dist/world-storage-primitives.d.ts.map +1 -0
- package/dist/world.d.ts +352 -157
- package/dist/world.d.ts.map +1 -1
- package/package.json +8 -4
- package/src/__tests__/command-buffer.test.ts +29 -3
- package/src/__tests__/hierarchy.unit.test.ts +3 -3
- package/src/__tests__/world-health.contract.test.ts +195 -2
- package/src/__tests__/world-read.unit.test.ts +30 -0
- package/src/commands.ts +22 -9
- package/src/internal.ts +5 -3
- package/src/world-entity-lifecycle.ts +23 -252
- package/src/world-internal-augmentation.d.ts +11 -0
- package/src/world-internal.ts +114 -63
- package/src/world-read.ts +38 -0
- package/src/world-scheduling.ts +0 -26
- package/src/world-storage-primitives.ts +179 -0
- package/src/world.ts +2590 -509
- package/dist/world-component-access.d.ts +0 -311
- package/dist/world-component-access.d.ts.map +0 -1
- package/dist/world-component-storage.d.ts +0 -298
- package/dist/world-component-storage.d.ts.map +0 -1
- package/dist/world-core.d.ts +0 -39
- package/dist/world-core.d.ts.map +0 -1
- package/src/world-component-access.ts +0 -1769
- package/src/world-component-storage.ts +0 -1264
- package/src/world-core.ts +0 -74
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
import { fieldTypeToMetaKey, type ManagedArrayElementType, TYPE_METADATA } from './component';
|
|
2
|
+
|
|
3
|
+
/** Freeze the detached POD produced by World.inspect(). */
|
|
4
|
+
export function detachWorldInspection<T extends object>(snapshot: T): Readonly<T> {
|
|
5
|
+
return freezeInspection(snapshot);
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
function freezeInspection<T>(value: T): Readonly<T> {
|
|
9
|
+
if (value === null || (typeof value !== 'object' && typeof value !== 'function')) {
|
|
10
|
+
return value as Readonly<T>;
|
|
11
|
+
}
|
|
12
|
+
for (const key of Reflect.ownKeys(value as object)) {
|
|
13
|
+
const child = (value as Record<PropertyKey, unknown>)[key];
|
|
14
|
+
if (child !== null && (typeof child === 'object' || typeof child === 'function')) {
|
|
15
|
+
freezeInspection(child);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
return Object.freeze(value) as Readonly<T>;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Element-byte-width for a managed-array element type, read off the global
|
|
23
|
+
* TYPE_METADATA table (single SSOT). `entity` stores as `u32` (4 bytes); every
|
|
24
|
+
* scalar maps to its own key. `fieldTypeToMetaKey` always resolves a key for a
|
|
25
|
+
* ManagedArrayElementType, and every such row carries a concrete `byteSize`.
|
|
26
|
+
*/
|
|
27
|
+
export function elementByteSize(elementType: ManagedArrayElementType): number {
|
|
28
|
+
const key = fieldTypeToMetaKey(elementType);
|
|
29
|
+
// biome-ignore lint/style/noNonNullAssertion: every ManagedArrayElementType resolves to a row with a concrete byteSize
|
|
30
|
+
return TYPE_METADATA[key!]!.byteSize!;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export function reinterpretSlotBytes(
|
|
34
|
+
bytes: Uint8Array,
|
|
35
|
+
elementType: ManagedArrayElementType,
|
|
36
|
+
elementCount: number,
|
|
37
|
+
): ReturnType<typeof reinterpretBufferRegion> {
|
|
38
|
+
return reinterpretBufferRegion(bytes.buffer, bytes.byteOffset, elementType, elementCount);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export function reinterpretBufferRegion(
|
|
42
|
+
buffer: ArrayBufferLike,
|
|
43
|
+
byteOffset: number,
|
|
44
|
+
elementType: ManagedArrayElementType,
|
|
45
|
+
elementCount: number,
|
|
46
|
+
):
|
|
47
|
+
| Float32Array
|
|
48
|
+
| Float64Array
|
|
49
|
+
| Int32Array
|
|
50
|
+
| Uint32Array
|
|
51
|
+
| Int16Array
|
|
52
|
+
| Uint16Array
|
|
53
|
+
| Int8Array
|
|
54
|
+
| Uint8Array {
|
|
55
|
+
// shared<X> template literals: column-stored as u32 handles, reinterpret
|
|
56
|
+
// as Uint32Array. The brand is applied at the FieldValueType level;
|
|
57
|
+
// runtime storage is plain u32 (feat-20260614 M5; replaces the retired
|
|
58
|
+
// 'handle<X>' arm).
|
|
59
|
+
if (elementType.startsWith('shared<')) {
|
|
60
|
+
return new Uint32Array(buffer, byteOffset, elementCount);
|
|
61
|
+
}
|
|
62
|
+
switch (elementType) {
|
|
63
|
+
case 'f32':
|
|
64
|
+
return new Float32Array(buffer, byteOffset, elementCount);
|
|
65
|
+
case 'f64':
|
|
66
|
+
return new Float64Array(buffer, byteOffset, elementCount);
|
|
67
|
+
case 'i32':
|
|
68
|
+
return new Int32Array(buffer, byteOffset, elementCount);
|
|
69
|
+
case 'u32':
|
|
70
|
+
case 'enum':
|
|
71
|
+
case 'ref':
|
|
72
|
+
case 'entity':
|
|
73
|
+
return new Uint32Array(buffer, byteOffset, elementCount);
|
|
74
|
+
case 'i16':
|
|
75
|
+
return new Int16Array(buffer, byteOffset, elementCount);
|
|
76
|
+
case 'u16':
|
|
77
|
+
return new Uint16Array(buffer, byteOffset, elementCount);
|
|
78
|
+
case 'i8':
|
|
79
|
+
return new Int8Array(buffer, byteOffset, elementCount);
|
|
80
|
+
case 'u8':
|
|
81
|
+
case 'bool':
|
|
82
|
+
return new Uint8Array(buffer, byteOffset, elementCount);
|
|
83
|
+
}
|
|
84
|
+
// Exhaustiveness fallthrough: TypeScript template-literal type
|
|
85
|
+
// (`shared<${string}>`) is structurally not narrowed away by the
|
|
86
|
+
// `startsWith` guard above, so this branch is unreachable yet TS still
|
|
87
|
+
// requires a return path.
|
|
88
|
+
return new Uint32Array(buffer, byteOffset, elementCount);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Reinterpret `bytes` as the typed view for `elementType` and write `value`
|
|
93
|
+
* at element index `idx`. Mirrors the `array<T>` storage law (4/8/2/1-byte
|
|
94
|
+
* element widths per TYPE_METADATA.byteSize) and is used by `world.push`
|
|
95
|
+
* to land a new tail element into BufferPool slot bytes after a `grow`.
|
|
96
|
+
*/
|
|
97
|
+
export function writeArrayElementAt(
|
|
98
|
+
bytes: Uint8Array,
|
|
99
|
+
idx: number,
|
|
100
|
+
elementType: ManagedArrayElementType,
|
|
101
|
+
value: number,
|
|
102
|
+
): void {
|
|
103
|
+
const buf = bytes.buffer;
|
|
104
|
+
const offset = bytes.byteOffset;
|
|
105
|
+
const byteLen = bytes.byteLength;
|
|
106
|
+
switch (elementType) {
|
|
107
|
+
case 'f32':
|
|
108
|
+
new Float32Array(buf, offset, byteLen >>> 2)[idx] = value;
|
|
109
|
+
return;
|
|
110
|
+
case 'f64':
|
|
111
|
+
new Float64Array(buf, offset, byteLen >>> 3)[idx] = value;
|
|
112
|
+
return;
|
|
113
|
+
case 'i32':
|
|
114
|
+
new Int32Array(buf, offset, byteLen >>> 2)[idx] = value;
|
|
115
|
+
return;
|
|
116
|
+
case 'u32':
|
|
117
|
+
case 'enum':
|
|
118
|
+
case 'ref':
|
|
119
|
+
case 'entity':
|
|
120
|
+
new Uint32Array(buf, offset, byteLen >>> 2)[idx] = value;
|
|
121
|
+
return;
|
|
122
|
+
case 'i16':
|
|
123
|
+
new Int16Array(buf, offset, byteLen >>> 1)[idx] = value;
|
|
124
|
+
return;
|
|
125
|
+
case 'u16':
|
|
126
|
+
new Uint16Array(buf, offset, byteLen >>> 1)[idx] = value;
|
|
127
|
+
return;
|
|
128
|
+
case 'i8':
|
|
129
|
+
new Int8Array(buf, offset, byteLen)[idx] = value;
|
|
130
|
+
return;
|
|
131
|
+
case 'u8':
|
|
132
|
+
case 'bool':
|
|
133
|
+
new Uint8Array(buf, offset, byteLen)[idx] = value;
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Reinterpret `bytes` as the typed view for `elementType` and read element
|
|
140
|
+
* `idx`. Mirrors `writeArrayElementAt` -- consumed by `world.pop` to materialise
|
|
141
|
+
* the tail value before the count is decremented.
|
|
142
|
+
*/
|
|
143
|
+
export function readArrayElementAt(
|
|
144
|
+
bytes: Uint8Array,
|
|
145
|
+
idx: number,
|
|
146
|
+
elementType: ManagedArrayElementType,
|
|
147
|
+
): number {
|
|
148
|
+
const buf = bytes.buffer;
|
|
149
|
+
const offset = bytes.byteOffset;
|
|
150
|
+
const byteLen = bytes.byteLength;
|
|
151
|
+
// shared<X> template literals: column-stored as u32 handles, read as
|
|
152
|
+
// Uint32Array. (feat-20260614 M5; replaces retired 'handle<X>' arm.)
|
|
153
|
+
if (elementType.startsWith('shared<')) {
|
|
154
|
+
return new Uint32Array(buf, offset, byteLen >>> 2)[idx] ?? 0;
|
|
155
|
+
}
|
|
156
|
+
switch (elementType) {
|
|
157
|
+
case 'f32':
|
|
158
|
+
return new Float32Array(buf, offset, byteLen >>> 2)[idx] ?? 0;
|
|
159
|
+
case 'f64':
|
|
160
|
+
return new Float64Array(buf, offset, byteLen >>> 3)[idx] ?? 0;
|
|
161
|
+
case 'i32':
|
|
162
|
+
return new Int32Array(buf, offset, byteLen >>> 2)[idx] ?? 0;
|
|
163
|
+
case 'u32':
|
|
164
|
+
case 'enum':
|
|
165
|
+
case 'ref':
|
|
166
|
+
case 'entity':
|
|
167
|
+
return new Uint32Array(buf, offset, byteLen >>> 2)[idx] ?? 0;
|
|
168
|
+
case 'i16':
|
|
169
|
+
return new Int16Array(buf, offset, byteLen >>> 1)[idx] ?? 0;
|
|
170
|
+
case 'u16':
|
|
171
|
+
return new Uint16Array(buf, offset, byteLen >>> 1)[idx] ?? 0;
|
|
172
|
+
case 'i8':
|
|
173
|
+
return new Int8Array(buf, offset, byteLen)[idx] ?? 0;
|
|
174
|
+
case 'u8':
|
|
175
|
+
case 'bool':
|
|
176
|
+
return new Uint8Array(buf, offset, byteLen)[idx] ?? 0;
|
|
177
|
+
}
|
|
178
|
+
return 0;
|
|
179
|
+
}
|