@daneren2005/shared-memory-ecs 1.5.0 → 1.6.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/README.md +104 -28
- package/dist/actions/build-worker-entity.d.ts +1 -1
- package/dist/actions/create-entity-worker.d.ts +2 -2
- package/dist/actions/kill-entity-worker.d.ts +2 -2
- package/dist/component-definition.d.ts +2 -0
- package/dist/{create-component-worker-CaB32Dgn.js → create-system-worker-BM5E-S92.js} +53 -19
- package/dist/create-system-worker-BM5E-S92.js.map +1 -0
- package/dist/entity.d.ts +1 -0
- package/dist/index.d.ts +10 -7
- package/dist/index.js +199 -94
- package/dist/index.js.map +1 -1
- package/dist/systems/entity-system.d.ts +1 -0
- package/dist/systems/{component-system.d.ts → entity-worker-system.d.ts} +22 -18
- package/dist/systems/iterable-system.d.ts +1 -0
- package/dist/systems/system.d.ts +11 -0
- package/dist/systems/worker-system.d.ts +22 -0
- package/dist/systems/workers/apply-query-delta.d.ts +1 -1
- package/dist/systems/workers/create-entity-system-worker.d.ts +8 -0
- package/dist/systems/workers/create-system-worker.d.ts +9 -0
- package/dist/systems/workers/entity-system-web-worker.d.ts +17 -0
- package/dist/systems/workers/{component-worker-message.d.ts → entity-system-worker-message.d.ts} +10 -4
- package/dist/worker.d.ts +7 -5
- package/dist/worker.js +2 -2
- package/dist/world.d.ts +5 -4
- package/package.json +3 -2
- package/dist/create-component-worker-CaB32Dgn.js.map +0 -1
- package/dist/systems/workers/component-web-worker.d.ts +0 -17
- package/dist/systems/workers/create-component-worker.d.ts +0 -8
package/README.md
CHANGED
|
@@ -14,10 +14,12 @@ fog of war, sub-classed entities, required components, etc).
|
|
|
14
14
|
config to the raw block values) and `attach(entity, memory, index)` (builds the accessor over that block).
|
|
15
15
|
Loading a component is `attach(entity, memory, memory.create(toBlock(config)))`; splitting it this way lets a
|
|
16
16
|
worker build the block off-thread (it calls only `toBlock`) and the main thread wrap it (`attach`) when it
|
|
17
|
-
adopts the entity. Plus an optional `save(component)
|
|
18
|
-
`Config` (defining props supplied up front, e.g. `maxHealth`) and
|
|
19
|
-
e.g. current `health`); `toBlock` sees `Config & Serialization` while
|
|
20
|
-
slice. `free` runs when the component is torn down (see
|
|
17
|
+
adopts the entity. Plus an optional `save(component)`, `free(component)`, and `died(component, entity, world)`.
|
|
18
|
+
A component's data splits into `Config` (defining props supplied up front, e.g. `maxHealth`) and
|
|
19
|
+
`Serialization` (runtime-derived state, e.g. current `health`); `toBlock` sees `Config & Serialization` while
|
|
20
|
+
`save` returns only the `Serialization` slice. `free` runs when the component is torn down (see
|
|
21
|
+
[Freeing extra resources](#freeing-extra-resources)); `died` runs when the entity is killed, with it still
|
|
22
|
+
readable (see [Reacting to death](#reacting-to-death)).
|
|
21
23
|
- **`ComponentRegistry<C>`** – the map of all component definitions for a game.
|
|
22
24
|
- **`EntityFactory<C>`** – maps an entity `type` name to a base (template) config. Loading an entity layers
|
|
23
25
|
the caller's config over its type's template, so shared static data lives in one place and a save only
|
|
@@ -30,8 +32,9 @@ fog of war, sub-classed entities, required components, etc).
|
|
|
30
32
|
direct property accessors and only loads/saves component data. Every entity has an `entity` component
|
|
31
33
|
whose `type` (a plain, worker-invisible string) records the factory template it was built from.
|
|
32
34
|
- **Systems** – `System`, `IterableSystem`, `EntitySystem` (main-thread iteration over entities with a
|
|
33
|
-
given set of components)
|
|
34
|
-
off-thread when Web Workers + `SharedArrayBuffer` are available)
|
|
35
|
+
given set of components), `EntityWorkerSystem` (runs an update function over raw memory blocks,
|
|
36
|
+
off-thread when Web Workers + `SharedArrayBuffer` are available), and `WorkerSystem` (an `EntityWorkerSystem`
|
|
37
|
+
that runs once per tick over its sub-queries instead of once per entity — see [Per-tick systems](#per-tick-systems-workersystem)).
|
|
35
38
|
|
|
36
39
|
## Defining components
|
|
37
40
|
|
|
@@ -132,7 +135,7 @@ resolves that pointer back to the string through the world's cache; a worker can
|
|
|
132
135
|
## Iterating entities
|
|
133
136
|
|
|
134
137
|
`world.entities` is a `Map` keyed by `eid`, not an array, and so is `entities` on `EntitySystem` and
|
|
135
|
-
`
|
|
138
|
+
`EntityWorkerSystem`:
|
|
136
139
|
|
|
137
140
|
```ts
|
|
138
141
|
world.entities.forEach(entity => { ... }); // in the order they were added
|
|
@@ -186,25 +189,25 @@ physics library exports its `*_INDEX` constants.
|
|
|
186
189
|
Reach for this when a profile says to, not by default. A menu, a save, a system that touches a dozen entities:
|
|
187
190
|
use the accessors.
|
|
188
191
|
|
|
189
|
-
##
|
|
192
|
+
## EntityWorkerSystem workers
|
|
190
193
|
|
|
191
|
-
`
|
|
192
|
-
worker entry file calls `
|
|
194
|
+
`EntityWorkerSystem` needs a `getWorker()` that returns a real `Worker`, and an `updateFunction`. Your
|
|
195
|
+
worker entry file calls `createEntitySystemWorker(self, updateFunction)`, importing it from the
|
|
193
196
|
[`/worker` subpath](#importing-in-workers) so the worker bundle stays small. When Web Workers or
|
|
194
197
|
`SharedArrayBuffer` are unavailable it transparently falls back to running the same update function on
|
|
195
198
|
the main thread. Attach any extra per-run data (the equivalent of the old faction/fog-of-war fields)
|
|
196
199
|
by overriding `addDataToWorld(world)`. Declare its shape with the `W` type parameter (an interface
|
|
197
|
-
extending `
|
|
200
|
+
extending `EntityWorkerSystemWorld`) so both `addDataToWorld` and the `updateFunction` see it typed:
|
|
198
201
|
|
|
199
202
|
```ts
|
|
200
|
-
interface DamageWorld extends
|
|
203
|
+
interface DamageWorld extends EntityWorkerSystemWorld {
|
|
201
204
|
damage: number
|
|
202
205
|
}
|
|
203
206
|
|
|
204
207
|
const damageUpdate: EntityUpdateFunction<Components, { health: Int32Array }, DamageWorld> =
|
|
205
208
|
(world, entityId, components) => { components.health[0] -= world.damage; };
|
|
206
209
|
|
|
207
|
-
class DamageSystem extends
|
|
210
|
+
class DamageSystem extends EntityWorkerSystem<Components, { health: Int32Array }, DamageWorld> {
|
|
208
211
|
addDataToWorld(world: DamageWorld) { world.damage = 5; }
|
|
209
212
|
}
|
|
210
213
|
```
|
|
@@ -220,11 +223,11 @@ itself. Both are optional properties on the `EntityUpdateFunction`.
|
|
|
220
223
|
(structured-cloned across the boundary) and returns a `Partial<W>` that is merged onto `world` on every
|
|
221
224
|
subsequent run. Use it for state that must be seeded from the main thread but then persist inside the worker
|
|
222
225
|
— a seeded RNG, a lookup table, a config object — without paying to re-send it each frame. Type the init
|
|
223
|
-
data with the `D` type parameter (the fourth on `EntityUpdateFunction` / `
|
|
226
|
+
data with the `D` type parameter (the fourth on `EntityUpdateFunction` / `EntityWorkerSystem`) so `getInitData`
|
|
224
227
|
and the `init` hook agree on its shape; it defaults to `unknown` when a system has no init data:
|
|
225
228
|
|
|
226
229
|
```ts
|
|
227
|
-
interface DamageWorld extends
|
|
230
|
+
interface DamageWorld extends EntityWorkerSystemWorld {
|
|
228
231
|
damage: number
|
|
229
232
|
}
|
|
230
233
|
interface DamageInitData {
|
|
@@ -238,7 +241,7 @@ const damageUpdate: EntityUpdateFunction<Components, { health: Int32Array }, Dam
|
|
|
238
241
|
// `DamageInitData | undefined` (undefined when the system supplies no getInitData).
|
|
239
242
|
damageUpdate.init = (data) => ({ damage: data?.baseDamage ?? 1 });
|
|
240
243
|
|
|
241
|
-
class DamageSystem extends
|
|
244
|
+
class DamageSystem extends EntityWorkerSystem<Components, { health: Int32Array }, DamageWorld, DamageInitData> {
|
|
242
245
|
constructor(world: BaseWorld<Components>) {
|
|
243
246
|
super(world, {
|
|
244
247
|
name: 'DamageSystem',
|
|
@@ -253,7 +256,7 @@ class DamageSystem extends ComponentSystem<Components, { health: Int32Array }, D
|
|
|
253
256
|
```
|
|
254
257
|
|
|
255
258
|
Unlike `addDataToWorld` (an overridable method on the system), `getInitData` is a config option — it lives in
|
|
256
|
-
the options passed to the `
|
|
259
|
+
the options passed to the `EntityWorkerSystem` constructor, so a system used without a subclass can supply it
|
|
257
260
|
there directly.
|
|
258
261
|
|
|
259
262
|
**`preRun`** runs once per run, before any entity is updated, with the run's `world`, the full entity list,
|
|
@@ -270,31 +273,75 @@ damageUpdate.preRun = (world, entities, queries, callbacks) => {
|
|
|
270
273
|
(An `entityRemoved(world, entityId, callbacks)` hook completes the set — it fires once per entity that left
|
|
271
274
|
the system this run, so a worker can release any per-entity state it was holding.)
|
|
272
275
|
|
|
276
|
+
### Per-tick systems: `WorkerSystem`
|
|
277
|
+
|
|
278
|
+
Some systems have no entities of their own — they run **once per tick** to scan or count other entities, and
|
|
279
|
+
maybe spawn something. A `WorkerSystem` is an `EntityWorkerSystem` whose function is called **once per run** over
|
|
280
|
+
the named sub-queries instead of once per entity. It has no main query, so it runs every interval even with
|
|
281
|
+
zero entities, and it reuses the whole worker/query/`createsEntities`/`addDataToWorld` machinery:
|
|
282
|
+
|
|
283
|
+
```ts
|
|
284
|
+
// once per run: no per-entity loop, just the queries
|
|
285
|
+
const spawnerUpdate: WorkerSystemRunFunction<Components, SpawnerWorld> = (world, queries, callbacks) => {
|
|
286
|
+
const asteroids = queries.asteroids ?? [];
|
|
287
|
+
if(asteroids.length < world.minAsteroids) {
|
|
288
|
+
createEntityWorker(world, { type: 'asteroid', x: 0, y: 0 }, callbacks);
|
|
289
|
+
}
|
|
290
|
+
};
|
|
291
|
+
|
|
292
|
+
class SpawnerSystem extends WorkerSystem<Components, SpawnerWorld> {
|
|
293
|
+
minAsteroids = 20;
|
|
294
|
+
constructor(world: TestWorld) {
|
|
295
|
+
super(world, {
|
|
296
|
+
name: 'Spawner',
|
|
297
|
+
updateFunction: spawnerUpdate,
|
|
298
|
+
createsEntities: true,
|
|
299
|
+
deltaBetweenRuns: 1000,
|
|
300
|
+
getWorker: () => new Worker(SPAWNER_WORKER_URL, { type: 'module' }),
|
|
301
|
+
queries: { asteroids: { required: ['asteroid'] } },
|
|
302
|
+
});
|
|
303
|
+
}
|
|
304
|
+
// Fresh per-run data — structured-cloned to the worker each run, so keep it plain/cloneable.
|
|
305
|
+
addDataToWorld(world: SpawnerWorld) { world.minAsteroids = this.minAsteroids; }
|
|
306
|
+
}
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
Its worker entry uses `createSystemWorker` (the run-function counterpart of `createEntitySystemWorker`),
|
|
310
|
+
passing the registry only when it creates entities:
|
|
311
|
+
|
|
312
|
+
```ts
|
|
313
|
+
import { createSystemWorker } from '@daneren2005/shared-memory-ecs/worker';
|
|
314
|
+
createSystemWorker(self, spawnerUpdate, registry);
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
The run function may carry the same `init` / `entityRemoved` hooks as an `updateFunction`. Everything else —
|
|
318
|
+
callbacks, worker fallback, off-thread creation — behaves exactly as an `EntityWorkerSystem`.
|
|
319
|
+
|
|
273
320
|
### Importing in workers
|
|
274
321
|
|
|
275
322
|
Each worker entry file is bundled on its own, and a single-entry bundle cannot tree-shake this package's
|
|
276
|
-
barrel: importing `
|
|
323
|
+
barrel: importing `createEntitySystemWorker` from `@daneren2005/shared-memory-ecs` drags the whole library -
|
|
277
324
|
`BaseWorld`, every system, their `@daneren2005/shared-memory-objects` dependencies - into the worker, even
|
|
278
325
|
though a worker never runs any of it (easily ~20kb of dead code per worker). Import worker-side helpers from
|
|
279
326
|
the `@daneren2005/shared-memory-ecs/worker` subpath instead. It exposes only what runs in a worker -
|
|
280
|
-
`
|
|
281
|
-
worker-relevant types) - so the bundle stays tiny:
|
|
327
|
+
`createEntitySystemWorker`, `createSystemWorker`, `createEntityWorker`, `killEntityWorker`, `DEAD_INDEX`,
|
|
328
|
+
`TYPE_INDEX` (plus the worker-relevant types) - so the bundle stays tiny:
|
|
282
329
|
|
|
283
330
|
```ts
|
|
284
331
|
// damage.worker.ts - the worker entry file
|
|
285
|
-
import {
|
|
332
|
+
import { createEntitySystemWorker } from '@daneren2005/shared-memory-ecs/worker';
|
|
286
333
|
import { damageUpdate } from './damage-update';
|
|
287
334
|
|
|
288
|
-
|
|
335
|
+
createEntitySystemWorker(self, damageUpdate);
|
|
289
336
|
```
|
|
290
337
|
|
|
291
338
|
The same applies to any module the worker file pulls in: an update function that calls `createEntityWorker`
|
|
292
339
|
or `killEntityWorker` should import them from `/worker` too. Type-only imports (`EntityUpdateFunction`,
|
|
293
|
-
`
|
|
294
|
-
(`
|
|
340
|
+
`EntityWorkerSystemWorld`, ...) can come from either path since types are erased, and main-thread code
|
|
341
|
+
(`EntityWorkerSystem`, `BaseWorld`, `EntityFactory`, ...) keeps importing from the package root.
|
|
295
342
|
|
|
296
343
|
A worker that creates entities (see [Creating entities from a worker](#creating-entities-from-a-worker)) passes
|
|
297
|
-
your component registry as the third argument - `
|
|
344
|
+
your component registry as the third argument - `createEntitySystemWorker(self, shipUpdate, registry)` - so it has
|
|
298
345
|
each component's `toBlock`. Only do this in workers that actually create entities; it pulls the registry (and
|
|
299
346
|
whatever it imports) into that worker's bundle.
|
|
300
347
|
|
|
@@ -314,7 +361,7 @@ const update: EntityUpdateFunction<Components, { entity: Uint32Array }> = (world
|
|
|
314
361
|
// ...branch on type, etc.
|
|
315
362
|
};
|
|
316
363
|
|
|
317
|
-
class TypedSystem extends
|
|
364
|
+
class TypedSystem extends EntityWorkerSystem<Components, { entity: Uint32Array }> {
|
|
318
365
|
constructor(world: BaseWorld<Components>) {
|
|
319
366
|
super(world, { name: 'TypedSystem', required: ['entity'], updateFunction: update, getWorker: () => new Worker(/* ... */) });
|
|
320
367
|
}
|
|
@@ -410,11 +457,11 @@ exists on the following frame, so the system picks it up next run.
|
|
|
410
457
|
Two things make this work, both opt-in so only the workers that create entities pay for them:
|
|
411
458
|
|
|
412
459
|
- Register the system with `createsEntities: true`. That ships the factory templates to its worker on load.
|
|
413
|
-
- In that system's worker entry, pass your component registry to `
|
|
460
|
+
- In that system's worker entry, pass your component registry to `createEntitySystemWorker`, so the worker has
|
|
414
461
|
each component's block builder:
|
|
415
462
|
|
|
416
463
|
```ts
|
|
417
|
-
|
|
464
|
+
createEntitySystemWorker(self, shipUpdate, registry);
|
|
418
465
|
```
|
|
419
466
|
|
|
420
467
|
Every component is already defined as two halves for exactly this — `toBlock(config)` (the block values) and
|
|
@@ -485,6 +532,35 @@ It is deferred to the same safe point as the component's own block (see above),
|
|
|
485
532
|
entity dies — so a system still mid-run over that memory can't see your resource released early. Reload calls
|
|
486
533
|
it without any `death` event, so it is the reliable place to avoid leaks when a world is reused.
|
|
487
534
|
|
|
535
|
+
### Reacting to death
|
|
536
|
+
|
|
537
|
+
To *react* when an entity dies — spawn drops at its position, credit a kill, play an effect — a component
|
|
538
|
+
definition can carry an optional `died(component, entity, world)`. It fires exactly once per death, on the main
|
|
539
|
+
thread, with the dying entity **still fully readable** (its blocks are only *deferred*-freed, never torn down
|
|
540
|
+
before the hook runs), for both a worker kill (`killEntityWorker`) and a main-thread `killEntity`:
|
|
541
|
+
|
|
542
|
+
```ts
|
|
543
|
+
const oreDepositDefinition: ComponentDefinition<OreDeposit, Int32Array, OreDepositConfig> = {
|
|
544
|
+
type: Int32Array,
|
|
545
|
+
size: 3,
|
|
546
|
+
loadProperties: ['oreAmount'],
|
|
547
|
+
toBlock(config) { /* ... */ },
|
|
548
|
+
attach(entity, memory, index) { /* ... */ },
|
|
549
|
+
died(component, entity, world) {
|
|
550
|
+
// The asteroid is still readable here, so spawn its drop where it was.
|
|
551
|
+
const { x, y } = entity.components.position!;
|
|
552
|
+
world.loadEntity({ type: 'Ore', x, y, amount: component.oreAmount });
|
|
553
|
+
},
|
|
554
|
+
};
|
|
555
|
+
```
|
|
556
|
+
|
|
557
|
+
The hook is engine-agnostic: attach death behavior to the component that represents it. A throwing `died` can't
|
|
558
|
+
abort the death — it is caught and surfaced as a `system-error` event (`phase: 'died'`) while the entity is still
|
|
559
|
+
removed. Unlike `free`, `died` fires **only** on a real death, never on `world.load()`/`clear()` teardown.
|
|
560
|
+
|
|
561
|
+
For a non-declarative hook, the world also emits `world.on('entity-died', entity)` at the same point (distinct
|
|
562
|
+
from `entity-removed`, which fires for every removal, reloads included).
|
|
563
|
+
|
|
488
564
|
### Reusing a world: `load` and `clear`
|
|
489
565
|
|
|
490
566
|
A world is meant to be reused rather than rebuilt. `world.load(config)` swaps in a fresh scenario — it removes
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { WorkerAllocator, WorkerCreateEntityConfig, WorkerCreatedEntity } from '../systems/
|
|
1
|
+
import type { WorkerAllocator, WorkerCreateEntityConfig, WorkerCreatedEntity } from '../systems/entity-worker-system';
|
|
2
2
|
export interface WorkerCreatableComponent {
|
|
3
3
|
loadProperties: Array<string>;
|
|
4
4
|
loadInFinishLoading?: boolean;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
export default function createEntityWorker(world:
|
|
1
|
+
import type { EntityWorkerSystemCallbacks, EntityWorkerSystemWorld, WorkerCreateEntityConfig } from '../systems/entity-worker-system';
|
|
2
|
+
export default function createEntityWorker(world: EntityWorkerSystemWorld, config: WorkerCreateEntityConfig, callbacks: EntityWorkerSystemCallbacks): void;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
export default function killEntityWorker(entityId: number, components: EntityUpdateComponents, callbacks:
|
|
1
|
+
import type { EntityWorkerSystemCallbacks, EntityUpdateComponents } from '../systems/entity-worker-system';
|
|
2
|
+
export default function killEntityWorker(entityId: number, components: EntityUpdateComponents, callbacks: EntityWorkerSystemCallbacks): void;
|
|
@@ -2,6 +2,7 @@ import type { TypedArrayConstructor } from '@daneren2005/shared-memory-objects/i
|
|
|
2
2
|
import type MemoryComponent from './memory-component';
|
|
3
3
|
import type { ComponentTypedArray } from './memory-component';
|
|
4
4
|
import type BaseEntity from './entity';
|
|
5
|
+
import type BaseWorld from './world';
|
|
5
6
|
import type { EntityComponent, EntityComponentConfig, EntityComponentSerialization } from './entity-component';
|
|
6
7
|
export interface BaseComponent {
|
|
7
8
|
index: number;
|
|
@@ -17,6 +18,7 @@ export interface ComponentDefinition<Component extends BaseComponent, T extends
|
|
|
17
18
|
attach(entity: BaseEntity, memory: MemoryComponent<T>, index: number): Component;
|
|
18
19
|
save?(component: Component): Serialization;
|
|
19
20
|
free?(component: Component): void;
|
|
21
|
+
died?(component: Component, entity: BaseEntity, world: BaseWorld): void;
|
|
20
22
|
}
|
|
21
23
|
export type RegisteredComponentDefinition<Component extends BaseComponent, T extends ComponentTypedArray = ComponentTypedArray, Config = any, Serialization = object> = ComponentDefinition<Component, T, Config, Serialization> & {
|
|
22
24
|
memoryComponent: MemoryComponent<T>;
|
|
@@ -165,11 +165,11 @@ function m(e, t, n) {
|
|
|
165
165
|
//#endregion
|
|
166
166
|
//#region src/actions/create-entity-worker.ts
|
|
167
167
|
function h(e, t, n) {
|
|
168
|
-
if (!e.buildEntityDescriptor) throw Error("createEntityWorker requires the system to be registered with createsEntities: true and the component registry passed to
|
|
168
|
+
if (!e.buildEntityDescriptor) throw Error("createEntityWorker requires the system to be registered with createsEntities: true and the component registry passed to createEntitySystemWorker");
|
|
169
169
|
n.createEntity(e.buildEntityDescriptor(t));
|
|
170
170
|
}
|
|
171
171
|
//#endregion
|
|
172
|
-
//#region src/systems/workers/create-
|
|
172
|
+
//#region src/systems/workers/create-entity-system-worker.ts
|
|
173
173
|
function g(t, n, r) {
|
|
174
174
|
let c = [], l = {}, u, d, f, p = {}, m, h, g = (e) => f?.getString(e) ?? "";
|
|
175
175
|
t.onmessage = function(v) {
|
|
@@ -191,20 +191,20 @@ function g(t, n, r) {
|
|
|
191
191
|
for (let e of Object.keys(l)) delete l[e];
|
|
192
192
|
u = void 0;
|
|
193
193
|
} else if (y.type === "run") {
|
|
194
|
-
u && Object.assign(y.world, u), y.world.getString = g;
|
|
194
|
+
u && Object.assign(y.world, u), y.world.getString = g, y.world.heap = d;
|
|
195
195
|
let e = {
|
|
196
196
|
allocateEid: () => m ? Atomics.add(m.data, 0, 1) + 1 : 0,
|
|
197
197
|
allocateComponentBlock: (e, t) => p[e].create(t)
|
|
198
198
|
};
|
|
199
199
|
y.world.allocate = e, h && r && (y.world.buildEntityDescriptor = (t) => s(t, h, r, e));
|
|
200
|
-
let i = performance.now(), a = [],
|
|
200
|
+
let i = performance.now(), a = [], f = {}, v = [], b = [];
|
|
201
201
|
c = o(c, y.entities);
|
|
202
|
-
let
|
|
202
|
+
let x = {};
|
|
203
203
|
Object.entries(y.queries).forEach(([e, t]) => {
|
|
204
204
|
let n = o(l[e] ?? [], t);
|
|
205
|
-
l[e] = n,
|
|
205
|
+
l[e] = n, x[e] = n;
|
|
206
206
|
});
|
|
207
|
-
let
|
|
207
|
+
let S = {
|
|
208
208
|
entityComponentChanged(e, t, n, r) {
|
|
209
209
|
a.push({
|
|
210
210
|
entityId: e,
|
|
@@ -224,7 +224,7 @@ function g(t, n, r) {
|
|
|
224
224
|
});
|
|
225
225
|
},
|
|
226
226
|
emitSystemEvent(e, t) {
|
|
227
|
-
(
|
|
227
|
+
(f[e] ?? (f[e] = [])).push(t);
|
|
228
228
|
},
|
|
229
229
|
entityDied(e) {
|
|
230
230
|
a.push({
|
|
@@ -234,22 +234,47 @@ function g(t, n, r) {
|
|
|
234
234
|
});
|
|
235
235
|
},
|
|
236
236
|
createEntity(e) {
|
|
237
|
-
|
|
237
|
+
v.push(e);
|
|
238
|
+
}
|
|
239
|
+
}, C = !1;
|
|
240
|
+
if (n.preRun) try {
|
|
241
|
+
n.preRun(y.world, c, x, S);
|
|
242
|
+
} catch (e) {
|
|
243
|
+
C = !0, b.push({
|
|
244
|
+
error: e,
|
|
245
|
+
phase: "preRun"
|
|
246
|
+
});
|
|
247
|
+
}
|
|
248
|
+
C || c.forEach((e) => {
|
|
249
|
+
try {
|
|
250
|
+
n(y.world, e.entityId, e.components, x, S);
|
|
251
|
+
} catch (t) {
|
|
252
|
+
b.push({
|
|
253
|
+
error: t,
|
|
254
|
+
phase: "update",
|
|
255
|
+
entityId: e.entityId
|
|
256
|
+
});
|
|
238
257
|
}
|
|
239
|
-
};
|
|
240
|
-
n.preRun && n.preRun(y.world, c, v, b), c.forEach((e) => {
|
|
241
|
-
n(y.world, e.entityId, e.components, v, b);
|
|
242
258
|
}), n.entityRemoved && y.entities.removed.forEach((e) => {
|
|
243
|
-
|
|
259
|
+
try {
|
|
260
|
+
n.entityRemoved(y.world, e, S);
|
|
261
|
+
} catch (t) {
|
|
262
|
+
b.push({
|
|
263
|
+
error: t,
|
|
264
|
+
phase: "entityRemoved",
|
|
265
|
+
entityId: e
|
|
266
|
+
});
|
|
267
|
+
}
|
|
244
268
|
});
|
|
245
|
-
let
|
|
269
|
+
let w = performance.now() - i;
|
|
246
270
|
_(t, {
|
|
247
271
|
type: "run-complete",
|
|
248
272
|
generation: y.generation,
|
|
249
|
-
runTime:
|
|
273
|
+
runTime: w,
|
|
250
274
|
events: a,
|
|
251
|
-
systemEvents:
|
|
252
|
-
created:
|
|
275
|
+
systemEvents: f,
|
|
276
|
+
created: v,
|
|
277
|
+
errors: b
|
|
253
278
|
});
|
|
254
279
|
}
|
|
255
280
|
};
|
|
@@ -258,6 +283,15 @@ function _(e, t) {
|
|
|
258
283
|
e.postMessage(t);
|
|
259
284
|
}
|
|
260
285
|
//#endregion
|
|
261
|
-
|
|
286
|
+
//#region src/systems/workers/create-system-worker.ts
|
|
287
|
+
function v(e) {
|
|
288
|
+
let t = (() => {});
|
|
289
|
+
return t.preRun = (t, n, r, i) => e(t, r, i), e.init && (t.init = e.init), e.entityRemoved && (t.entityRemoved = e.entityRemoved), t;
|
|
290
|
+
}
|
|
291
|
+
function y(e, t, n) {
|
|
292
|
+
g(e, v(t), n);
|
|
293
|
+
}
|
|
294
|
+
//#endregion
|
|
295
|
+
export { m as a, d as c, s as d, o as f, h as i, p as l, i as m, v as n, l as o, a as p, g as r, u as s, y as t, c as u };
|
|
262
296
|
|
|
263
|
-
//# sourceMappingURL=create-
|
|
297
|
+
//# sourceMappingURL=create-system-worker-BM5E-S92.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create-system-worker-BM5E-S92.js","names":[],"sources":["../src/memory-component.ts","../src/constant-string-cache.ts","../src/systems/workers/apply-query-delta.ts","../src/actions/build-worker-entity.ts","../src/component.ts","../src/entity-component.ts","../src/actions/kill-entity-worker.ts","../src/actions/create-entity-worker.ts","../src/systems/workers/create-entity-system-worker.ts","../src/systems/workers/create-system-worker.ts"],"sourcesContent":["import SharedPool from '@daneren2005/shared-memory-objects/shared-pool';\nimport type { SharedPoolMemory } from '@daneren2005/shared-memory-objects/shared-pool';\nimport type MemoryHeap from '@daneren2005/shared-memory-objects/memory-heap';\nimport type { TypedArrayConstructor } from '@daneren2005/shared-memory-objects/interfaces/typed-array-constructor';\n\nexport type ComponentTypedArray = Uint32Array | Int32Array | Float32Array | Float64Array;\n\n// Backed by a SharedPool: all bookkeeping lives in the shared heap, so a worker can reconstruct a handle over\n// the same pool (pass the owner's getSharedMemory() as `memory`) and allocate/read blocks off-thread.\nexport default class MemoryComponent<T extends ComponentTypedArray = ComponentTypedArray> {\n\theap: MemoryHeap;\n\tpool: SharedPool<T>;\n\n\tconstructor(heap: MemoryHeap, type: TypedArrayConstructor<T>, dataLength: number, memory?: SharedPoolMemory) {\n\t\tthis.heap = heap;\n\t\tthis.pool = memory\n\t\t\t? new SharedPool<T>(heap, memory)\n\t\t\t: new SharedPool<T>(heap, {\n\t\t\t\ttype,\n\t\t\t\tdataLength,\n\t\t\t});\n\t}\n\n\t// Reconstructs a handle over an existing pool (from the owner's getSharedMemory()) — used in a worker, where the\n\t// pool's type/dataLength are already recorded in the heap header, so no definition is needed.\n\tstatic fromSharedMemory<T extends ComponentTypedArray = ComponentTypedArray>(heap: MemoryHeap, memory: SharedPoolMemory): MemoryComponent<T> {\n\t\treturn new MemoryComponent<T>(heap, Uint32Array as unknown as TypedArrayConstructor<T>, 1, memory);\n\t}\n\n\tgetSharedMemory(): SharedPoolMemory {\n\t\treturn this.pool.getSharedMemory();\n\t}\n\n\tget length() {\n\t\treturn this.pool.length;\n\t}\n\tget rawLength() {\n\t\treturn this.pool.bufferLength;\n\t}\n\n\tcreate(values: Array<number>): number {\n\t\treturn this.pool.push(values);\n\t}\n\n\tgetBlock(index: number): T {\n\t\treturn this.pool.at(index);\n\t}\n\tget(index: number, dataIndex: number): number {\n\t\treturn this.pool.get(index, dataIndex);\n\t}\n\tset(index: number, dataIndex: number, value: number) {\n\t\tlet array = this.pool.at(index);\n\t\tarray[dataIndex] = value;\n\t}\n\n\tdelete(index: number) {\n\t\tthis.pool.deleteIndex(index);\n\t}\n\tclear() {\n\t\tthis.pool.clear();\n\t}\n}\n","import ConstantString from '@daneren2005/shared-memory-objects/constant-string';\nimport { getPointer } from '@daneren2005/shared-memory-objects/utils/pointer';\nimport type MemoryHeap from '@daneren2005/shared-memory-objects/memory-heap';\n\n// Interns immutable strings in the heap and resolves them back from a pointer. Every distinct value is allocated\n// once as a single ConstantString shared by all users (15 \"Space Ship\" entities point at one allocation), and a\n// pointer resolves to its string through a Map hit before ever rebuilding it from memory. Both sides of the\n// worker boundary hold one: the main thread creates + interns; a worker (with a heap reconstructed from the same\n// SharedArrayBuffers) only ever resolves pointers and caches the results.\nexport default class ConstantStringCache {\n\tprivate heap: MemoryHeap;\n\t// value -> the one interned allocation. Only the creating (main) thread populates this; it owns the memory.\n\tprivate byValue = new Map<string, ConstantString>();\n\t// pointer -> value: the fast lookup every thread checks before touching memory.\n\tprivate byPointer = new Map<number, string>();\n\n\tconstructor(heap: MemoryHeap) {\n\t\tthis.heap = heap;\n\t}\n\n\t// Dedupes on value, so repeated types share a single ConstantString. Main-thread only.\n\tgetOrCreate(value: string): ConstantString {\n\t\tlet existing = this.byValue.get(value);\n\t\tif(existing) {\n\t\t\treturn existing;\n\t\t}\n\n\t\tconst string = new ConstantString(this.heap, value);\n\t\tthis.byValue.set(value, string);\n\t\tthis.byPointer.set(string.pointer, value);\n\n\t\treturn string;\n\t}\n\n\t// pointer -> string, checking the cache before rebuilding from memory. A pointer of 0 is the empty string; a\n\t// pointer into a buffer that has not synced to this thread yet returns undefined.\n\tgetString(pointer: number): string | undefined {\n\t\tif(pointer === 0) {\n\t\t\treturn '';\n\t\t}\n\n\t\tlet cached = this.byPointer.get(pointer);\n\t\tif(cached !== undefined) {\n\t\t\treturn cached;\n\t\t}\n\n\t\tconst memory = getPointer(pointer);\n\t\tif(this.heap.buffers[memory.bufferPosition] === undefined) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tconst value = new ConstantString(this.heap, memory).value;\n\t\tthis.byPointer.set(pointer, value);\n\n\t\treturn value;\n\t}\n\n\t// Frees every allocation this cache owns and empties the lookups. A worker's cache owns nothing (it only ever\n\t// resolved views), so this just drops its pointer lookups.\n\tclear() {\n\t\tthis.byValue.forEach(string => string.free());\n\t\tthis.byValue.clear();\n\t\tthis.byPointer.clear();\n\t}\n}\n","import type { EntityUpdateComponents, QueryDelta, UpdateEntityConfigObject } from '../entity-worker-system';\n\n// Applies a run's delta to a query's persistent list: drop the entities that left, upsert those that joined or\n// changed. A steady-state run carries empty arrays and returns the list untouched. Returns the list (removals\n// rebuild it via filter), so callers must store the returned reference back.\nexport function applyQueryDelta<T extends EntityUpdateComponents>(\n\tlist: Array<UpdateEntityConfigObject<T>>,\n\tdelta: QueryDelta<T>,\n): Array<UpdateEntityConfigObject<T>> {\n\tif(delta.removed.length) {\n\t\tconst removedSet = new Set(delta.removed);\n\t\tlist = list.filter(entry => !removedSet.has(entry.entityId));\n\t}\n\n\tif(delta.added.length) {\n\t\t// Index existing members so a re-added entity replaces its entry in place instead of duplicating.\n\t\tconst indexByEid = new Map<number, number>();\n\t\tlist.forEach((entry, index) => indexByEid.set(entry.entityId, index));\n\n\t\tfor(let entity of delta.added) {\n\t\t\tconst existing = indexByEid.get(entity.entityId);\n\t\t\tif(existing !== undefined) {\n\t\t\t\tlist[existing] = entity;\n\t\t\t} else {\n\t\t\t\tindexByEid.set(entity.entityId, list.length);\n\t\t\t\tlist.push(entity);\n\t\t\t}\n\t\t}\n\t}\n\n\treturn list;\n}\n","import type { WorkerAllocator, WorkerCreateEntityConfig, WorkerCreatedEntity } from '../systems/entity-worker-system';\n\n// The slice of a component definition worker-side creation needs. Both the game's ComponentDefinitionMap and the\n// world's RegisteredComponentRegistry satisfy it.\nexport interface WorkerCreatableComponent {\n\tloadProperties: Array<string>\n\tloadInFinishLoading?: boolean\n\ttoBlock(config: Record<string, unknown>): Array<number>\n}\nexport type WorkerCreateRegistry = { [name: string]: WorkerCreatableComponent };\nexport type FactoryConfigs = { [type: string]: Record<string, unknown> };\n\n// Turns a factory-style config ({ type, ...overrides }) into a WorkerCreatedEntity, off-thread: layers the type's\n// factory template under the overrides, mints an id, and allocates + writes each triggered component's block via its\n// toBlock(). The always-present `entity` component is NOT built here - the main thread builds it on adopt (interning\n// the type is main-thread-only), reading `type`/`isStatic` off this descriptor. Shared by the real worker and the\n// main-thread fallback so both behave identically.\nexport function buildWorkerEntity(\n\tconfig: WorkerCreateEntityConfig,\n\tfactoryConfigs: FactoryConfigs,\n\tregistry: WorkerCreateRegistry,\n\tallocator: WorkerAllocator,\n): WorkerCreatedEntity {\n\tconst template = factoryConfigs[config.type] ?? {};\n\tconst merged: Record<string, unknown> = { ...template, ...config };\n\n\tconst eid = allocator.allocateEid();\n\tconst components: { [name: string]: number } = {};\n\tfor(let name of Object.keys(registry)) {\n\t\t// The entity component is always built on the main thread when the descriptor is adopted (interning the type),\n\t\t// never off-thread - skip it here whether or not the registry includes it.\n\t\tif(name === 'entity') {\n\t\t\tcontinue;\n\t\t}\n\t\tconst definition = registry[name];\n\t\t// Deferred components need the whole world (other entities) that a worker doesn't have; skip them.\n\t\tif(definition.loadInFinishLoading) {\n\t\t\tcontinue;\n\t\t}\n\t\tif(definition.loadProperties.some(prop => prop in merged)) {\n\t\t\tcomponents[name] = allocator.allocateComponentBlock(name, definition.toBlock(merged));\n\t\t}\n\t}\n\n\treturn {\n\t\teid,\n\t\ttype: config.type,\n\t\tisStatic: merged.isStatic as boolean | undefined,\n\t\tcomponents,\n\t};\n}\n","import type { ComponentTypedArray } from './memory-component';\nimport type { BaseComponent } from './component-definition';\n\n// Base class for a memory-backed component accessor. Subclass it, declare prototype get/set accessors over\n// `this.block` indexed by the component's exported *_INDEX constants, and return `new YourComponent(block, index)`\n// from `attach`. Because the accessors live on one shared prototype - not fresh closures captured per entity -\n// reads off thousands of entities every frame stay monomorphic and inline, and constructing a component allocates\n// just the instance instead of a closure per accessor. Components that own no extra memory need nothing else; a\n// subclass that does can take more constructor args (the entity, another pool) and store them as fields.\nexport default abstract class Component<T extends ComponentTypedArray = ComponentTypedArray> implements BaseComponent {\n\treadonly index: number;\n\treadonly block: T;\n\n\tconstructor(block: T, index: number) {\n\t\tthis.block = block;\n\t\tthis.index = index;\n\t}\n}\n","import type { ComponentDefinition } from './component-definition';\nimport Component from './component';\nimport type ConstantStringCache from './constant-string-cache';\n\nexport interface EntityComponent {\n\tindex: number\n\ttype: string\n\tdead: boolean\n\tisStatic: boolean\n}\n\nexport interface EntityComponentConfig {\n\ttype: string\n\tisStatic?: boolean\n}\n\nexport interface EntityComponentSerialization {\n\ttype?: string\n\tdead?: boolean\n}\n\nexport const DEAD_INDEX = 0;\nexport const STATIC_INDEX = 1;\nexport const TYPE_INDEX = 2;\n\n// `type` is stored as a pointer to an interned ConstantString, so the accessor needs the world's string cache\n// (passed in, not captured per instance) to resolve it.\nclass EntityComponentImpl extends Component<Uint32Array> implements EntityComponent {\n\tprivate cache: ConstantStringCache;\n\n\tconstructor(block: Uint32Array, index: number, cache: ConstantStringCache) {\n\t\tsuper(block, index);\n\t\tthis.cache = cache;\n\t}\n\n\tget type() {\n\t\treturn this.cache.getString(this.block[TYPE_INDEX]) ?? '';\n\t}\n\tset type(value: string) {\n\t\tthis.block[TYPE_INDEX] = value ? this.cache.getOrCreate(value).pointer : 0;\n\t}\n\tget dead() {\n\t\treturn this.block[DEAD_INDEX] === 1;\n\t}\n\tset dead(value: boolean) {\n\t\tthis.block[DEAD_INDEX] = value ? 1 : 0;\n\t}\n\tget isStatic() {\n\t\treturn this.block[STATIC_INDEX] === 1;\n\t}\n\tset isStatic(value: boolean) {\n\t\tthis.block[STATIC_INDEX] = value ? 1 : 0;\n\t}\n}\n\nexport const entityDefinition: ComponentDefinition<EntityComponent, Uint32Array, EntityComponentConfig, EntityComponentSerialization> = {\n\ttype: Uint32Array,\n\tsize: 3,\n\tloadProperties: ['type', 'isStatic'],\n\t// The only component that reads the entity (never worker-created): it interns its type string through the heap and\n\t// stores the pointer. `entity` is always passed here since loadComponent runs on the main thread.\n\ttoBlock(config, entity) {\n\t\tconst cache = entity!.world.constantStrings;\n\t\tconst typePointer = config.type ? cache.getOrCreate(config.type).pointer : 0;\n\t\treturn [config.dead ? 1 : 0, config.isStatic ? 1 : 0, typePointer];\n\t},\n\tattach(entity, memory, index) {\n\t\treturn new EntityComponentImpl(memory.getBlock(index), index, entity.world.constantStrings);\n\t},\n\tsave(component) {\n\t\tconst config: EntityComponentSerialization = {};\n\t\tif(component.type) {\n\t\t\tconfig.type = component.type;\n\t\t}\n\t\tif(component.dead) {\n\t\t\tconfig.dead = true;\n\t\t}\n\n\t\treturn config;\n\t},\n};\n","import type { ComponentTypedArray } from '../memory-component';\nimport type { EntityWorkerSystemCallbacks, EntityUpdateComponents } from '../systems/entity-worker-system';\nimport { DEAD_INDEX } from '../entity-component';\n\n// Worker-side killEntity: flags the entity dead in its block and reports the death back via callbacks. The\n// entity component must be in the system's query for its block to be available here.\nexport default function killEntityWorker(entityId: number, components: EntityUpdateComponents, callbacks: EntityWorkerSystemCallbacks): void {\n\tconst block = (components as { entity?: ComponentTypedArray }).entity;\n\tif(block) {\n\t\tblock[DEAD_INDEX] = 1;\n\t}\n\n\tcallbacks.entityDied(entityId);\n}\n","import type { EntityWorkerSystemCallbacks, EntityWorkerSystemWorld, WorkerCreateEntityConfig } from '../systems/entity-worker-system';\n\n// Worker-side entity creation from a factory config. Pass `{ type: 'ship', ...overrides }`: the worker merges the\n// ship template shipped from the factory, mints a unique id, and allocates + writes every triggered component's block\n// directly into the shared pools (off-thread) via each component's toBlock(). It reports the descriptor back; the main\n// thread adopts it on run-complete (world.adoptEntity), building the `entity` component there and wrapping the\n// worker-written blocks, so the entity first exists on the following frame.\n//\n// Requires the system to be registered with `createsEntities: true` and its worker entry to pass the component\n// registry to createEntitySystemWorker (so the worker has each component's toBlock).\nexport default function createEntityWorker(world: EntityWorkerSystemWorld, config: WorkerCreateEntityConfig, callbacks: EntityWorkerSystemCallbacks): void {\n\tif(!world.buildEntityDescriptor) {\n\t\tthrow new Error('createEntityWorker requires the system to be registered with createsEntities: true and the component registry passed to createEntitySystemWorker');\n\t}\n\n\tcallbacks.createEntity(world.buildEntityDescriptor(config));\n}\n","import MemoryHeap from '@daneren2005/shared-memory-objects/memory-heap';\nimport type AllocatedMemory from '@daneren2005/shared-memory-objects/allocated-memory';\nimport type EntitySystemWorkerMessage from './entity-system-worker-message';\nimport type { EntityEvent, SystemEvents, WorkerRunError } from './entity-system-worker-message';\nimport ConstantStringCache from '../../constant-string-cache';\nimport MemoryComponent from '../../memory-component';\nimport type { ComponentDefinitionMap, ComponentMap } from '../../component-definition';\nimport type {\n\tEntityWorkerSystemCallbacks, EntityWorkerSystemWorld, EntityQueryComponents, EntityUpdateComponents,\n\tEntityUpdateFunction, QueryDelta, UpdateEntityConfigObject, WorkerCreatedEntity,\n} from '../entity-worker-system';\nimport { buildWorkerEntity, type FactoryConfigs } from '../../actions/build-worker-entity';\nimport { applyQueryDelta } from './apply-query-delta';\n\n// The slice of the worker global scope createEntitySystemWorker touches. Passing `self` explicitly (rather than\n// using the global) lets runners like @vitest/web-worker, which inject `self` as a module local, drive it.\nexport interface EntitySystemWorkerScope {\n\tonmessage: ((e: MessageEvent) => void) | null\n\tpostMessage(message: EntitySystemWorkerMessage): void\n}\n\nexport default function createEntitySystemWorker<\n\tC extends ComponentMap,\n\tT extends EntityUpdateComponents<C>,\n\tW extends EntityWorkerSystemWorld = EntityWorkerSystemWorld,\n\tD = unknown,\n>(scope: EntitySystemWorkerScope, updateFunction: EntityUpdateFunction<C, T, W, D>, definitions?: ComponentDefinitionMap) {\n\t// Persistent lists, carried across runs and mutated by each run's delta (see applyQueryDelta).\n\tlet entities: Array<UpdateEntityConfigObject<T>> = [];\n\tconst queryEntities: { [key: string]: Array<UpdateEntityConfigObject<T>> } = {};\n\t// What updateFunction.init returned: persistent state (e.g. a seeded RNG) merged onto `world` each run.\n\tlet worldExtension: Partial<W> | undefined;\n\tlet heap: MemoryHeap | undefined;\n\tlet stringCache: ConstantStringCache | undefined;\n\t// Reconstructed pool handles over the world's shared state, plus the factory templates - for off-thread entity\n\t// allocation. `definitions` (passed by the game's worker entry) supplies each component's toBlock/loadProperties.\n\tlet pools: { [name: string]: MemoryComponent } = {};\n\tlet eidCounter: AllocatedMemory | undefined;\n\tlet factoryConfigs: FactoryConfigs | undefined;\n\tconst getString = (pointer: number): string => stringCache?.getString(pointer) ?? '';\n\n\tscope.onmessage = function(e) {\n\t\tconst message = e.data as EntitySystemWorkerMessage<W, D>;\n\n\t\tif(message.type === 'init') {\n\t\t\tpostMessageTyped(scope, {\n\t\t\t\ttype: 'init-complete',\n\t\t\t});\n\t\t} else if(message.type === 'load') {\n\t\t\tif(message.heap) {\n\t\t\t\theap = new MemoryHeap(message.heap);\n\t\t\t\tstringCache = new ConstantStringCache(heap);\n\t\t\t\t// Report any buffer this worker grows (while allocating off-thread) back to the main thread, which adopts\n\t\t\t\t// it and fans it out to sibling workers.\n\t\t\t\theap.addOnGrowBufferHandlers(buffer => postMessageTyped(scope, { type: 'grow-buffer-from-worker', buffer }));\n\t\t\t}\n\t\t\tif(heap && message.sharedMemory) {\n\t\t\t\tpools = {};\n\t\t\t\tfor(const name of Object.keys(message.sharedMemory.components)) {\n\t\t\t\t\tpools[name] = MemoryComponent.fromSharedMemory(heap, message.sharedMemory.components[name]);\n\t\t\t\t}\n\t\t\t\teidCounter = heap.getSharedAlloc(message.sharedMemory.eidCounter);\n\t\t\t}\n\t\t\tfactoryConfigs = message.factoryConfigs;\n\t\t\tworldExtension = updateFunction.init?.(message.data) ?? undefined;\n\t\t\tpostMessageTyped(scope, {\n\t\t\t\ttype: 'loaded',\n\t\t\t});\n\t\t} else if(message.type === 'grow-buffer') {\n\t\t\t// Never replace a buffer this worker already holds: the main thread fans a worker-grown buffer back out to\n\t\t\t// every worker (including the one that grew it), and overwriting our own live MemoryBuffer would discard its\n\t\t\t// allocation bookkeeping. The SharedArrayBuffer at that position is already the same one.\n\t\t\tif(heap && heap.buffers[message.buffer.bufferPosition] === undefined) {\n\t\t\t\theap.addSharedBuffer(message.buffer);\n\t\t\t}\n\t\t} else if(message.type === 'reset') {\n\t\t\t// Drop the persistent lists so a reused world starts empty; worldExtension is refreshed by the next load.\n\t\t\tentities = [];\n\t\t\tfor(const key of Object.keys(queryEntities)) {\n\t\t\t\tdelete queryEntities[key];\n\t\t\t}\n\t\t\tworldExtension = undefined;\n\t\t} else if(message.type === 'run') {\n\t\t\tif(worldExtension) {\n\t\t\t\tObject.assign(message.world, worldExtension);\n\t\t\t}\n\t\t\tmessage.world.getString = getString;\n\t\t\tmessage.world.heap = heap;\n\t\t\tconst allocator = {\n\t\t\t\tallocateEid: () => eidCounter ? Atomics.add(eidCounter.data, 0, 1) + 1 : 0,\n\t\t\t\tallocateComponentBlock: (name: string, values: Array<number>) => pools[name].create(values),\n\t\t\t};\n\t\t\tmessage.world.allocate = allocator;\n\t\t\t// Only a system registered with createsEntities (factoryConfigs shipped) whose worker entry passed the\n\t\t\t// component definitions can create entities from a config.\n\t\t\tif(factoryConfigs && definitions) {\n\t\t\t\tmessage.world.buildEntityDescriptor = config => buildWorkerEntity(config, factoryConfigs!, definitions, allocator);\n\t\t\t}\n\t\t\tconst start = performance.now();\n\t\t\tlet entityEvents: Array<EntityEvent> = [];\n\t\t\tlet systemEvents: SystemEvents = {};\n\t\t\tlet createdEntities: Array<WorkerCreatedEntity> = [];\n\t\t\tlet errors: Array<WorkerRunError> = [];\n\n\t\t\tentities = applyQueryDelta(entities, message.entities as QueryDelta<T>);\n\n\t\t\tlet queries: EntityQueryComponents<C> = {};\n\t\t\tObject.entries(message.queries).forEach(([queryKey, delta]) => {\n\t\t\t\tconst list = applyQueryDelta(queryEntities[queryKey] ?? [], delta as QueryDelta<T>);\n\t\t\t\tqueryEntities[queryKey] = list;\n\t\t\t\tqueries[queryKey] = list;\n\t\t\t});\n\n\t\t\tlet callbacks: EntityWorkerSystemCallbacks<C> = {\n\t\t\t\tentityComponentChanged<K extends keyof C, P extends keyof C[K]>(entityId: number, componentName: K, prop: P, value: C[K][P]) {\n\t\t\t\t\tentityEvents.push({\n\t\t\t\t\t\tentityId,\n\t\t\t\t\t\tevent: 'component-property-updated',\n\t\t\t\t\t\targs: [componentName, prop, value],\n\t\t\t\t\t});\n\t\t\t\t},\n\t\t\t\temitEntityEvent(entityId: number, event: string, ...args: Array<unknown>) {\n\t\t\t\t\tentityEvents.push({\n\t\t\t\t\t\tentityId,\n\t\t\t\t\t\tevent,\n\t\t\t\t\t\targs,\n\t\t\t\t\t});\n\t\t\t\t},\n\t\t\t\temitSystemEvent(event: string, entityId: number) {\n\t\t\t\t\t(systemEvents[event] ?? (systemEvents[event] = [])).push(entityId);\n\t\t\t\t},\n\t\t\t\tentityDied(entityId: number) {\n\t\t\t\t\tentityEvents.push({\n\t\t\t\t\t\tentityId,\n\t\t\t\t\t\tevent: 'death',\n\t\t\t\t\t\targs: [],\n\t\t\t\t\t});\n\t\t\t\t},\n\t\t\t\tcreateEntity(entity: WorkerCreatedEntity) {\n\t\t\t\t\tcreatedEntities.push(entity);\n\t\t\t\t},\n\t\t\t};\n\t\t\tlet preRunFailed = false;\n\t\t\tif(updateFunction.preRun) {\n\t\t\t\ttry {\n\t\t\t\t\tupdateFunction.preRun(message.world, entities, queries, callbacks);\n\t\t\t\t} catch(err) {\n\t\t\t\t\tpreRunFailed = true;\n\t\t\t\t\terrors.push({ error: err as Error, phase: 'preRun' });\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// preRun sets up the run's state; if it threw, skip the entity loop rather than run over half-prepared data.\n\t\t\tif(!preRunFailed) {\n\t\t\t\tentities.forEach(entity => {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tupdateFunction(message.world, entity.entityId, entity.components, queries, callbacks);\n\t\t\t\t\t} catch(err) {\n\t\t\t\t\t\t// One entity failing must not stop the rest of the run.\n\t\t\t\t\t\terrors.push({ error: err as Error, phase: 'update', entityId: entity.entityId });\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tif(updateFunction.entityRemoved) {\n\t\t\t\tmessage.entities.removed.forEach(entityId => {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tupdateFunction.entityRemoved!(message.world, entityId, callbacks);\n\t\t\t\t\t} catch(err) {\n\t\t\t\t\t\terrors.push({ error: err as Error, phase: 'entityRemoved', entityId });\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t}\n\t\t\tconst runTime = performance.now() - start;\n\n\t\t\tpostMessageTyped(scope, {\n\t\t\t\ttype: 'run-complete',\n\t\t\t\tgeneration: message.generation,\n\t\t\t\trunTime,\n\t\t\t\tevents: entityEvents,\n\t\t\t\tsystemEvents,\n\t\t\t\tcreated: createdEntities,\n\t\t\t\terrors,\n\t\t\t});\n\t\t}\n\t};\n}\n\nfunction postMessageTyped(scope: EntitySystemWorkerScope, message: EntitySystemWorkerMessage) {\n\tscope.postMessage(message);\n}\n","import createEntitySystemWorker, { type EntitySystemWorkerScope } from './create-entity-system-worker';\nimport type { ComponentDefinitionMap, ComponentMap } from '../../component-definition';\nimport type {\n\tEntityWorkerSystemCallbacks, EntityWorkerSystemWorld, EntityQueryComponents, EntityUpdateComponents,\n\tEntityUpdateFunction, EntityUpdateInitFunction, EntityRemovedFunction,\n} from '../entity-worker-system';\n\n// A WorkerSystem's single per-run function: called once per run over the named sub-queries, not once per entity.\n// Optional `init`/`entityRemoved` mirror EntityUpdateFunction's hooks.\nexport type WorkerSystemRunFunction<\n\tC extends ComponentMap,\n\tW extends EntityWorkerSystemWorld = EntityWorkerSystemWorld,\n\tD = unknown,\n> = ((world: W, queries: EntityQueryComponents<C>, callbacks: EntityWorkerSystemCallbacks<C>) => void) & {\n\tinit?: EntityUpdateInitFunction<W, D>\n\tentityRemoved?: EntityRemovedFunction<C, W>\n};\n\n// A WorkerSystem reuses the EntityWorkerSystem worker machinery: the single run function becomes `preRun` (which runs\n// once with query access) and the per-entity body is a no-op, since a WorkerSystem never populates its main query.\nexport function toEntityUpdateFunction<\n\tC extends ComponentMap,\n\tW extends EntityWorkerSystemWorld = EntityWorkerSystemWorld,\n\tD = unknown,\n>(run: WorkerSystemRunFunction<C, W, D>): EntityUpdateFunction<C, EntityUpdateComponents<C>, W, D> {\n\tconst updateFunction = (() => {}) as EntityUpdateFunction<C, EntityUpdateComponents<C>, W, D>;\n\tupdateFunction.preRun = (world, _entities, queries, callbacks) => run(world, queries, callbacks);\n\tif(run.init) {\n\t\tupdateFunction.init = run.init;\n\t}\n\tif(run.entityRemoved) {\n\t\tupdateFunction.entityRemoved = run.entityRemoved;\n\t}\n\n\treturn updateFunction;\n}\n\n// Worker entry helper for a WorkerSystem (mirrors createEntitySystemWorker). Pass the component registry only for a\n// worker that creates entities.\nexport default function createSystemWorker<\n\tC extends ComponentMap,\n\tW extends EntityWorkerSystemWorld = EntityWorkerSystemWorld,\n\tD = unknown,\n>(scope: EntitySystemWorkerScope, runFunction: WorkerSystemRunFunction<C, W, D>, definitions?: ComponentDefinitionMap) {\n\tcreateEntitySystemWorker(scope, toEntityUpdateFunction(runFunction), definitions);\n}\n"],"mappings":"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"}
|
package/dist/entity.d.ts
CHANGED
|
@@ -6,6 +6,7 @@ export default class BaseEntity<C extends ComponentMap = ComponentMap, Cfg = any
|
|
|
6
6
|
readonly eid: number;
|
|
7
7
|
config?: Cfg;
|
|
8
8
|
world: BaseWorld<ComponentDefinitionMap, C, Cfg>;
|
|
9
|
+
private componentMemoryDeletionScheduled;
|
|
9
10
|
components: Partial<C> & {
|
|
10
11
|
entity: EntityComponent;
|
|
11
12
|
};
|
package/dist/index.d.ts
CHANGED
|
@@ -15,15 +15,18 @@ export type { ComponentTypedArray } from './memory-component';
|
|
|
15
15
|
export { default as Component } from './component';
|
|
16
16
|
export type { BaseComponent, ComponentMap, ComponentDefinition, ComponentDefinitionMap, ComponentRegistry, ComponentsOf, EntityConfigOf, RegisteredComponentDefinition, RegisteredComponentRegistry, } from './component-definition';
|
|
17
17
|
export { default as System } from './systems/system';
|
|
18
|
-
export type { SystemConfig } from './systems/system';
|
|
18
|
+
export type { SystemConfig, SystemError, SystemErrorPhase } from './systems/system';
|
|
19
19
|
export { default as IterableSystem } from './systems/iterable-system';
|
|
20
20
|
export type { IterableSystemConfig } from './systems/iterable-system';
|
|
21
21
|
export { default as EntitySystem } from './systems/entity-system';
|
|
22
22
|
export type { EntitySystemConfig } from './systems/entity-system';
|
|
23
|
-
export { default as
|
|
24
|
-
export
|
|
23
|
+
export { default as EntityWorkerSystem } from './systems/entity-worker-system';
|
|
24
|
+
export { default as WorkerSystem } from './systems/worker-system';
|
|
25
|
+
export type { WorkerSystemConfig, WorkerSystemRunFunction } from './systems/worker-system';
|
|
26
|
+
export type { EntityWorkerSystemConfig, EntityWorkerSystemQuery, EntityWorkerSystemWorld, EntityWorkerSystemCallbacks, WorkerAllocator, WorkerCreateEntityConfig, WorkerCreatedEntity, EntityUpdateComponents, EntityQueryComponents, EntityUpdateFunction, EntityUpdateInitFunction, EntityUpdatePreRunFunction, EntityRemovedFunction, UpdateEntityConfig, UpdateEntityConfigObject, } from './systems/entity-worker-system';
|
|
25
27
|
export { default as WebWorker } from './systems/workers/web-worker';
|
|
26
|
-
export { default as
|
|
27
|
-
export { default as
|
|
28
|
-
export
|
|
29
|
-
export type {
|
|
28
|
+
export { default as EntitySystemWebWorker } from './systems/workers/entity-system-web-worker';
|
|
29
|
+
export { default as createEntitySystemWorker } from './systems/workers/create-entity-system-worker';
|
|
30
|
+
export { default as createSystemWorker } from './systems/workers/create-system-worker';
|
|
31
|
+
export type { default as EntitySystemWorkerMessage } from './systems/workers/entity-system-worker-message';
|
|
32
|
+
export type { EntityEvent, SystemEvents } from './systems/workers/entity-system-worker-message';
|