diff --git a/src/index.ts b/src/index.ts index 0f1ff04..c6749fa 100644 --- a/src/index.ts +++ b/src/index.ts @@ -11,6 +11,8 @@ export { makeEntity, entityIndex, entityGeneration } from "./entity"; export { SparseSet } from "./storage/sparse-set"; export type { WorldEvent, + EntityEvent, + RelEvent, QueryUpdate, RelationshipUpdate, } from "./observable/events"; diff --git a/src/observable/events.ts b/src/observable/events.ts index 594c2c5..895ad52 100644 --- a/src/observable/events.ts +++ b/src/observable/events.ts @@ -4,17 +4,25 @@ import type { Entity } from "../entity"; // ── World Events ────────────────────────────────────── /** - * Discriminated union of all world-level events. - * Emitted via `world.events$`. + * Events that carry an `entity` field — component and lifecycle events. */ -export type WorldEvent = +export type EntityEvent = | SpawnedEvent | DestroyedEvent | ComponentAddedEvent | ComponentRemovedEvent - | ComponentChangedEvent - | RelAddedEvent - | RelRemovedEvent; + | ComponentChangedEvent; + +/** + * Events that carry `source`/`target` fields — relationship events. + */ +export type RelEvent = RelAddedEvent | RelRemovedEvent; + +/** + * Discriminated union of all world-level events. + * Emitted via `world.events$`. + */ +export type WorldEvent = EntityEvent | RelEvent; export interface SpawnedEvent { type: "spawned"; diff --git a/src/observable/observe.ts b/src/observable/observe.ts index 6001016..6b413d1 100644 --- a/src/observable/observe.ts +++ b/src/observable/observe.ts @@ -1,7 +1,12 @@ import { Subject } from "rxjs"; import type { Query } from "../query"; import type { Entity } from "../entity"; -import type { WorldEvent, QueryUpdate, RelationshipUpdate } from "./events"; +import type { + WorldEvent, + EntityEvent, + QueryUpdate, + RelationshipUpdate, +} from "./events"; import type { RelationshipDef } from "../relationship"; import type { ComponentDef } from "../component"; @@ -143,21 +148,21 @@ export class ObservableLayer { queryMatches: (query: Query, e: Entity) => boolean, ): void { if (!("entity" in event)) return; + const entityEvent = event as EntityEvent; // Determine which component keys are relevant let keys: symbol[] = []; - switch (event.type) { + switch (entityEvent.type) { case "spawned": case "destroyed": - // Check all observers (via the ANY_KEY set) keys = [ANY_KEY]; break; case "componentAdded": case "componentRemoved": case "componentChanged": - keys = [event.component._key]; + keys = [entityEvent.component._key]; break; } @@ -169,7 +174,8 @@ export class ObservableLayer { for (const o of set) { if (!seen.has(o)) { seen.add(o); - this._updateObserver(o, event, queryMatches); + // event is entity-bearing after the in-guard above + this._updateObserver(o, entityEvent, queryMatches); } } } @@ -179,10 +185,10 @@ export class ObservableLayer { private _updateObserver( obs: QueryObserverState, - event: WorldEvent, + event: EntityEvent, queryMatches: (query: Query, e: Entity) => boolean, ): void { - const e = event.entity!; + const e = event.entity; const wasMatched = obs.matched.has(e); const nowMatches = queryMatches(obs.query, e);