iris-ecs 0.0.1
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 +721 -0
- package/dist/actions.d.ts +43 -0
- package/dist/actions.d.ts.map +1 -0
- package/dist/actions.js +35 -0
- package/dist/actions.js.map +1 -0
- package/dist/archetype.d.ts +194 -0
- package/dist/archetype.d.ts.map +1 -0
- package/dist/archetype.js +412 -0
- package/dist/archetype.js.map +1 -0
- package/dist/component.d.ts +89 -0
- package/dist/component.d.ts.map +1 -0
- package/dist/component.js +237 -0
- package/dist/component.js.map +1 -0
- package/dist/encoding.d.ts +204 -0
- package/dist/encoding.d.ts.map +1 -0
- package/dist/encoding.js +215 -0
- package/dist/encoding.js.map +1 -0
- package/dist/entity.d.ts +129 -0
- package/dist/entity.d.ts.map +1 -0
- package/dist/entity.js +243 -0
- package/dist/entity.js.map +1 -0
- package/dist/event.d.ts +237 -0
- package/dist/event.d.ts.map +1 -0
- package/dist/event.js +293 -0
- package/dist/event.js.map +1 -0
- package/dist/filters.d.ts +121 -0
- package/dist/filters.d.ts.map +1 -0
- package/dist/filters.js +202 -0
- package/dist/filters.js.map +1 -0
- package/dist/index.d.ts +24 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +54 -0
- package/dist/index.js.map +1 -0
- package/dist/name.d.ts +70 -0
- package/dist/name.d.ts.map +1 -0
- package/dist/name.js +172 -0
- package/dist/name.js.map +1 -0
- package/dist/observer.d.ts +83 -0
- package/dist/observer.d.ts.map +1 -0
- package/dist/observer.js +62 -0
- package/dist/observer.js.map +1 -0
- package/dist/query.d.ts +198 -0
- package/dist/query.d.ts.map +1 -0
- package/dist/query.js +299 -0
- package/dist/query.js.map +1 -0
- package/dist/registry.d.ts +118 -0
- package/dist/registry.d.ts.map +1 -0
- package/dist/registry.js +112 -0
- package/dist/registry.js.map +1 -0
- package/dist/relation.d.ts +60 -0
- package/dist/relation.d.ts.map +1 -0
- package/dist/relation.js +171 -0
- package/dist/relation.js.map +1 -0
- package/dist/removal.d.ts +27 -0
- package/dist/removal.d.ts.map +1 -0
- package/dist/removal.js +66 -0
- package/dist/removal.js.map +1 -0
- package/dist/resource.d.ts +78 -0
- package/dist/resource.d.ts.map +1 -0
- package/dist/resource.js +86 -0
- package/dist/resource.js.map +1 -0
- package/dist/scheduler.d.ts +106 -0
- package/dist/scheduler.d.ts.map +1 -0
- package/dist/scheduler.js +204 -0
- package/dist/scheduler.js.map +1 -0
- package/dist/schema.d.ts +117 -0
- package/dist/schema.d.ts.map +1 -0
- package/dist/schema.js +113 -0
- package/dist/schema.js.map +1 -0
- package/dist/world.d.ts +172 -0
- package/dist/world.d.ts.map +1 -0
- package/dist/world.js +127 -0
- package/dist/world.js.map +1 -0
- package/package.json +52 -0
package/dist/event.d.ts
ADDED
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
import type { Schema, SchemaRecord } from "./schema.js";
|
|
2
|
+
import type { World } from "./world.js";
|
|
3
|
+
/**
|
|
4
|
+
* Event ID brand for nominal typing.
|
|
5
|
+
*/
|
|
6
|
+
declare const EVENT_BRAND: unique symbol;
|
|
7
|
+
/**
|
|
8
|
+
* Event schema brand for carrying schema type in Event.
|
|
9
|
+
*/
|
|
10
|
+
declare const EVENT_SCHEMA_BRAND: unique symbol;
|
|
11
|
+
/**
|
|
12
|
+
* Event schema type.
|
|
13
|
+
*
|
|
14
|
+
* Maps field names to their schema definitions (same as component schema).
|
|
15
|
+
*/
|
|
16
|
+
export type EventSchema = SchemaRecord;
|
|
17
|
+
/**
|
|
18
|
+
* Event data type inference.
|
|
19
|
+
*
|
|
20
|
+
* - Empty schema {} -> undefined (tag event)
|
|
21
|
+
* - Non-empty schema -> resolved data object
|
|
22
|
+
*/
|
|
23
|
+
export type EventData<T extends EventSchema> = keyof T extends never ? undefined : {
|
|
24
|
+
[K in keyof T]: T[K] extends Schema<infer U> ? U : never;
|
|
25
|
+
};
|
|
26
|
+
/**
|
|
27
|
+
* Event ID (branded type).
|
|
28
|
+
*
|
|
29
|
+
* Nominal type for events defined via defineEvent().
|
|
30
|
+
*/
|
|
31
|
+
export type EventId<S extends EventSchema = EventSchema> = number & {
|
|
32
|
+
[EVENT_BRAND]: true;
|
|
33
|
+
[EVENT_SCHEMA_BRAND]: S;
|
|
34
|
+
};
|
|
35
|
+
/**
|
|
36
|
+
* Event definition.
|
|
37
|
+
*
|
|
38
|
+
* Global event definition with schema for type-safe event data.
|
|
39
|
+
*/
|
|
40
|
+
export type Event<S extends EventSchema = EventSchema> = {
|
|
41
|
+
/**
|
|
42
|
+
* Unique event ID.
|
|
43
|
+
*/
|
|
44
|
+
readonly id: EventId<S>;
|
|
45
|
+
/**
|
|
46
|
+
* Event name (user-defined).
|
|
47
|
+
*/
|
|
48
|
+
readonly name: string;
|
|
49
|
+
/**
|
|
50
|
+
* Field schemas for event data (empty for tag events).
|
|
51
|
+
*/
|
|
52
|
+
readonly schema: S;
|
|
53
|
+
};
|
|
54
|
+
/**
|
|
55
|
+
* Internal event entry with tick.
|
|
56
|
+
*
|
|
57
|
+
* Stores event data along with the tick it was emitted at.
|
|
58
|
+
*/
|
|
59
|
+
export type EventEntry<T extends EventSchema = EventSchema> = {
|
|
60
|
+
/**
|
|
61
|
+
* Event data (undefined for tag events).
|
|
62
|
+
*/
|
|
63
|
+
data: EventData<T>;
|
|
64
|
+
/**
|
|
65
|
+
* Tick when event was emitted.
|
|
66
|
+
*/
|
|
67
|
+
tick: number;
|
|
68
|
+
};
|
|
69
|
+
/**
|
|
70
|
+
* Per-world event queue metadata.
|
|
71
|
+
*/
|
|
72
|
+
export type EventQueueMeta<T extends EventSchema = EventSchema> = {
|
|
73
|
+
/**
|
|
74
|
+
* Event definition reference.
|
|
75
|
+
*/
|
|
76
|
+
event: Event<T>;
|
|
77
|
+
/**
|
|
78
|
+
* Queue of event entries.
|
|
79
|
+
*/
|
|
80
|
+
events: EventEntry<T>[];
|
|
81
|
+
/**
|
|
82
|
+
* Execution tick tracking for event consumption.
|
|
83
|
+
*/
|
|
84
|
+
lastTick: {
|
|
85
|
+
/**
|
|
86
|
+
* Tick when events last consumed outside any system.
|
|
87
|
+
*/
|
|
88
|
+
self: number;
|
|
89
|
+
/**
|
|
90
|
+
* Per-system consumption ticks: systemId -> tick
|
|
91
|
+
*/
|
|
92
|
+
bySystemId: Map<string, number>;
|
|
93
|
+
};
|
|
94
|
+
};
|
|
95
|
+
/**
|
|
96
|
+
* Number of ticks before events expire.
|
|
97
|
+
*
|
|
98
|
+
* Events persist for this many ticks to ensure systems can read regardless
|
|
99
|
+
* of execution order.
|
|
100
|
+
*/
|
|
101
|
+
export declare const EVENT_EXPIRY_TICKS = 2;
|
|
102
|
+
/**
|
|
103
|
+
* Define event type.
|
|
104
|
+
*
|
|
105
|
+
* Allocates unique event ID with optional schema for type-safe event data.
|
|
106
|
+
* Tag events (no schema) use void for data type - emit() requires no data argument.
|
|
107
|
+
*
|
|
108
|
+
* @param name - Event name for debugging
|
|
109
|
+
* @param schema - Optional field schema record (omit for tag events)
|
|
110
|
+
* @returns Event definition
|
|
111
|
+
*
|
|
112
|
+
* @example
|
|
113
|
+
* ```typescript
|
|
114
|
+
* // Tag event (no data)
|
|
115
|
+
* const GameStarted = defineEvent("GameStarted");
|
|
116
|
+
* emit(world, GameStarted); // No data argument
|
|
117
|
+
*
|
|
118
|
+
* // Data event
|
|
119
|
+
* const DamageDealt = defineEvent("DamageDealt", {
|
|
120
|
+
* target: Type.u32(),
|
|
121
|
+
* amount: Type.f32(),
|
|
122
|
+
* });
|
|
123
|
+
* emit(world, DamageDealt, { target: enemy, amount: 25 });
|
|
124
|
+
* ```
|
|
125
|
+
*/
|
|
126
|
+
export declare function defineEvent<S extends EventSchema = Record<never, never>>(name: string, schema?: S): Event<S>;
|
|
127
|
+
/**
|
|
128
|
+
* Ensure event queue exists for given event in world.
|
|
129
|
+
*
|
|
130
|
+
* Creates queue lazily on first access (emit or fetch).
|
|
131
|
+
*
|
|
132
|
+
* @param world - World instance
|
|
133
|
+
* @param event - Event definition
|
|
134
|
+
* @returns Event queue metadata
|
|
135
|
+
*/
|
|
136
|
+
export declare function ensureEventQueue<S extends EventSchema>(world: World, event: Event<S>): EventQueueMeta<S>;
|
|
137
|
+
/**
|
|
138
|
+
* Emit event to world.
|
|
139
|
+
*
|
|
140
|
+
* Tag events (empty schema) require no data argument.
|
|
141
|
+
* Data events require data matching the schema.
|
|
142
|
+
*
|
|
143
|
+
* @param world - World instance
|
|
144
|
+
* @param event - Event definition
|
|
145
|
+
* @param args - Event data (only for data events)
|
|
146
|
+
*/
|
|
147
|
+
export declare function emitEvent<S extends EventSchema>(world: World, event: Event<S>, ...args: keyof S extends never ? [] : [data: EventData<S>]): void;
|
|
148
|
+
/**
|
|
149
|
+
* Fetch events emitted since last call.
|
|
150
|
+
*
|
|
151
|
+
* Per-system isolated: each system has independent tracking of which events
|
|
152
|
+
* it has consumed. Multiple systems can consume the same events independently.
|
|
153
|
+
*
|
|
154
|
+
* @param world - World instance
|
|
155
|
+
* @param event - Event definition
|
|
156
|
+
* @returns Generator yielding event data
|
|
157
|
+
*
|
|
158
|
+
* @example
|
|
159
|
+
* ```typescript
|
|
160
|
+
* for (const event of fetchEvents(world, DamageDealt)) {
|
|
161
|
+
* applyDamage(event.target, event.amount);
|
|
162
|
+
* }
|
|
163
|
+
* ```
|
|
164
|
+
*/
|
|
165
|
+
export declare function fetchEvents<S extends EventSchema>(world: World, event: Event<S>): Generator<EventData<S>>;
|
|
166
|
+
/**
|
|
167
|
+
* Check if there are unread events for current context.
|
|
168
|
+
*
|
|
169
|
+
* Does not mark events as read or trigger cleanup.
|
|
170
|
+
*
|
|
171
|
+
* @param world - World instance
|
|
172
|
+
* @param event - Event definition
|
|
173
|
+
* @returns True if unread events exist
|
|
174
|
+
*
|
|
175
|
+
* @example
|
|
176
|
+
* ```typescript
|
|
177
|
+
* if (hasEvents(world, DamageDealt)) {
|
|
178
|
+
* // Process damage events
|
|
179
|
+
* }
|
|
180
|
+
* ```
|
|
181
|
+
*/
|
|
182
|
+
export declare function hasEvents<S extends EventSchema>(world: World, event: Event<S>): boolean;
|
|
183
|
+
/**
|
|
184
|
+
* Count unread events for current context.
|
|
185
|
+
*
|
|
186
|
+
* Does not mark events as read or trigger cleanup.
|
|
187
|
+
*
|
|
188
|
+
* @param world - World instance
|
|
189
|
+
* @param event - Event definition
|
|
190
|
+
* @returns Number of unread events
|
|
191
|
+
*
|
|
192
|
+
* @example
|
|
193
|
+
* ```typescript
|
|
194
|
+
* const damageCount = countEvents(world, DamageDealt);
|
|
195
|
+
* console.log(`${damageCount} damage events this tick`);
|
|
196
|
+
* ```
|
|
197
|
+
*/
|
|
198
|
+
export declare function countEvents<S extends EventSchema>(world: World, event: Event<S>): number;
|
|
199
|
+
/**
|
|
200
|
+
* Fetch only the most recent event, marking all as read.
|
|
201
|
+
*
|
|
202
|
+
* Useful when only the latest state matters (e.g., input, config changes).
|
|
203
|
+
*
|
|
204
|
+
* @param world - World instance
|
|
205
|
+
* @param event - Event definition
|
|
206
|
+
* @returns Most recent event data, or undefined if no unread events
|
|
207
|
+
*
|
|
208
|
+
* @example
|
|
209
|
+
* ```typescript
|
|
210
|
+
* // Only care about the latest input state
|
|
211
|
+
* const input = fetchLastEvent(world, InputChanged);
|
|
212
|
+
* if (input) {
|
|
213
|
+
* updatePlayerDirection(input.direction);
|
|
214
|
+
* }
|
|
215
|
+
* ```
|
|
216
|
+
*/
|
|
217
|
+
export declare function fetchLastEvent<S extends EventSchema>(world: World, event: Event<S>): EventData<S> | undefined;
|
|
218
|
+
/**
|
|
219
|
+
* Clear events (mark as read without processing).
|
|
220
|
+
*
|
|
221
|
+
* Useful when a system needs to skip events under certain conditions.
|
|
222
|
+
*
|
|
223
|
+
* @param world - World instance
|
|
224
|
+
* @param event - Event definition
|
|
225
|
+
*
|
|
226
|
+
* @example
|
|
227
|
+
* ```typescript
|
|
228
|
+
* if (isPaused) {
|
|
229
|
+
* // Skip damage events while paused
|
|
230
|
+
* clearEvents(world, DamageDealt);
|
|
231
|
+
* return;
|
|
232
|
+
* }
|
|
233
|
+
* ```
|
|
234
|
+
*/
|
|
235
|
+
export declare function clearEvents<S extends EventSchema>(world: World, event: Event<S>): void;
|
|
236
|
+
export {};
|
|
237
|
+
//# sourceMappingURL=event.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"event.d.ts","sourceRoot":"","sources":["../src/event.ts"],"names":[],"mappings":"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"}
|
package/dist/event.js
ADDED
|
@@ -0,0 +1,293 @@
|
|
|
1
|
+
// ============================================================================
|
|
2
|
+
// Constants
|
|
3
|
+
// ============================================================================
|
|
4
|
+
/**
|
|
5
|
+
* Number of ticks before events expire.
|
|
6
|
+
*
|
|
7
|
+
* Events persist for this many ticks to ensure systems can read regardless
|
|
8
|
+
* of execution order.
|
|
9
|
+
*/
|
|
10
|
+
export const EVENT_EXPIRY_TICKS = 2;
|
|
11
|
+
/**
|
|
12
|
+
* Global event registry singleton.
|
|
13
|
+
*/
|
|
14
|
+
const EVENT_REGISTRY = {
|
|
15
|
+
byId: new Map(),
|
|
16
|
+
nextId: 0,
|
|
17
|
+
};
|
|
18
|
+
// ============================================================================
|
|
19
|
+
// Event Definition
|
|
20
|
+
// ============================================================================
|
|
21
|
+
/**
|
|
22
|
+
* Define event type.
|
|
23
|
+
*
|
|
24
|
+
* Allocates unique event ID with optional schema for type-safe event data.
|
|
25
|
+
* Tag events (no schema) use void for data type - emit() requires no data argument.
|
|
26
|
+
*
|
|
27
|
+
* @param name - Event name for debugging
|
|
28
|
+
* @param schema - Optional field schema record (omit for tag events)
|
|
29
|
+
* @returns Event definition
|
|
30
|
+
*
|
|
31
|
+
* @example
|
|
32
|
+
* ```typescript
|
|
33
|
+
* // Tag event (no data)
|
|
34
|
+
* const GameStarted = defineEvent("GameStarted");
|
|
35
|
+
* emit(world, GameStarted); // No data argument
|
|
36
|
+
*
|
|
37
|
+
* // Data event
|
|
38
|
+
* const DamageDealt = defineEvent("DamageDealt", {
|
|
39
|
+
* target: Type.u32(),
|
|
40
|
+
* amount: Type.f32(),
|
|
41
|
+
* });
|
|
42
|
+
* emit(world, DamageDealt, { target: enemy, amount: 25 });
|
|
43
|
+
* ```
|
|
44
|
+
*/
|
|
45
|
+
export function defineEvent(name, schema) {
|
|
46
|
+
const id = EVENT_REGISTRY.nextId++;
|
|
47
|
+
const event = {
|
|
48
|
+
id,
|
|
49
|
+
name,
|
|
50
|
+
schema: schema ?? {},
|
|
51
|
+
};
|
|
52
|
+
EVENT_REGISTRY.byId.set(id, event);
|
|
53
|
+
return event;
|
|
54
|
+
}
|
|
55
|
+
// ============================================================================
|
|
56
|
+
// Per-World Event Queue Management
|
|
57
|
+
// ============================================================================
|
|
58
|
+
/**
|
|
59
|
+
* Ensure event queue exists for given event in world.
|
|
60
|
+
*
|
|
61
|
+
* Creates queue lazily on first access (emit or fetch).
|
|
62
|
+
*
|
|
63
|
+
* @param world - World instance
|
|
64
|
+
* @param event - Event definition
|
|
65
|
+
* @returns Event queue metadata
|
|
66
|
+
*/
|
|
67
|
+
export function ensureEventQueue(world, event) {
|
|
68
|
+
let queue = world.events.byId.get(event.id);
|
|
69
|
+
if (!queue) {
|
|
70
|
+
queue = {
|
|
71
|
+
event: event,
|
|
72
|
+
events: [],
|
|
73
|
+
lastTick: {
|
|
74
|
+
self: 0,
|
|
75
|
+
bySystemId: new Map(),
|
|
76
|
+
},
|
|
77
|
+
};
|
|
78
|
+
world.events.byId.set(event.id, queue);
|
|
79
|
+
}
|
|
80
|
+
return queue;
|
|
81
|
+
}
|
|
82
|
+
// ============================================================================
|
|
83
|
+
// Event Emission
|
|
84
|
+
// ============================================================================
|
|
85
|
+
/**
|
|
86
|
+
* Emit event to world.
|
|
87
|
+
*
|
|
88
|
+
* Tag events (empty schema) require no data argument.
|
|
89
|
+
* Data events require data matching the schema.
|
|
90
|
+
*
|
|
91
|
+
* @param world - World instance
|
|
92
|
+
* @param event - Event definition
|
|
93
|
+
* @param args - Event data (only for data events)
|
|
94
|
+
*/
|
|
95
|
+
export function emitEvent(world, event, ...args) {
|
|
96
|
+
const queue = ensureEventQueue(world, event);
|
|
97
|
+
const data = args[0];
|
|
98
|
+
const tick = world.execution.tick;
|
|
99
|
+
queue.events.push({ data, tick });
|
|
100
|
+
}
|
|
101
|
+
// ============================================================================
|
|
102
|
+
// Event Reading
|
|
103
|
+
// ============================================================================
|
|
104
|
+
/**
|
|
105
|
+
* Update lastTick for current execution context.
|
|
106
|
+
*
|
|
107
|
+
* Internal helper shared by fetchEvents, fetchLastEvent, and clearEvents.
|
|
108
|
+
*
|
|
109
|
+
* @param world - World instance
|
|
110
|
+
* @param queue - Event queue metadata
|
|
111
|
+
*/
|
|
112
|
+
function markEventsRead(world, queue) {
|
|
113
|
+
const { systemId, tick } = world.execution;
|
|
114
|
+
if (systemId === null) {
|
|
115
|
+
queue.lastTick.self = tick;
|
|
116
|
+
}
|
|
117
|
+
else {
|
|
118
|
+
queue.lastTick.bySystemId.set(systemId, tick);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Remove expired events from queue.
|
|
123
|
+
*
|
|
124
|
+
* Events older than EVENT_EXPIRY_TICKS are removed to prevent unbounded growth.
|
|
125
|
+
*
|
|
126
|
+
* @param world - World instance
|
|
127
|
+
* @param queue - Event queue metadata
|
|
128
|
+
*/
|
|
129
|
+
function cleanupExpiredEvents(world, queue) {
|
|
130
|
+
const expiryTick = world.execution.tick - EVENT_EXPIRY_TICKS;
|
|
131
|
+
// Find first non-expired index
|
|
132
|
+
let firstValidIndex = 0;
|
|
133
|
+
while (firstValidIndex < queue.events.length && queue.events[firstValidIndex].tick <= expiryTick) {
|
|
134
|
+
firstValidIndex++;
|
|
135
|
+
}
|
|
136
|
+
// Remove expired events from front
|
|
137
|
+
if (firstValidIndex > 0) {
|
|
138
|
+
queue.events.splice(0, firstValidIndex);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Fetch events emitted since last call.
|
|
143
|
+
*
|
|
144
|
+
* Per-system isolated: each system has independent tracking of which events
|
|
145
|
+
* it has consumed. Multiple systems can consume the same events independently.
|
|
146
|
+
*
|
|
147
|
+
* @param world - World instance
|
|
148
|
+
* @param event - Event definition
|
|
149
|
+
* @returns Generator yielding event data
|
|
150
|
+
*
|
|
151
|
+
* @example
|
|
152
|
+
* ```typescript
|
|
153
|
+
* for (const event of fetchEvents(world, DamageDealt)) {
|
|
154
|
+
* applyDamage(event.target, event.amount);
|
|
155
|
+
* }
|
|
156
|
+
* ```
|
|
157
|
+
*/
|
|
158
|
+
export function* fetchEvents(world, event) {
|
|
159
|
+
const queue = ensureEventQueue(world, event);
|
|
160
|
+
const { systemId, tick } = world.execution;
|
|
161
|
+
// Get lastTick for this execution context
|
|
162
|
+
const lastTick = systemId === null ? queue.lastTick.self : (queue.lastTick.bySystemId.get(systemId) ?? 0);
|
|
163
|
+
try {
|
|
164
|
+
for (let i = 0; i < queue.events.length; i++) {
|
|
165
|
+
const entry = queue.events[i];
|
|
166
|
+
// Event must have been emitted AFTER lastTick but AT or BEFORE current tick
|
|
167
|
+
if (entry.tick > lastTick && entry.tick <= tick) {
|
|
168
|
+
yield entry.data;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
finally {
|
|
173
|
+
markEventsRead(world, queue);
|
|
174
|
+
cleanupExpiredEvents(world, queue);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
// ============================================================================
|
|
178
|
+
// Utility Functions
|
|
179
|
+
// ============================================================================
|
|
180
|
+
/**
|
|
181
|
+
* Check if there are unread events for current context.
|
|
182
|
+
*
|
|
183
|
+
* Does not mark events as read or trigger cleanup.
|
|
184
|
+
*
|
|
185
|
+
* @param world - World instance
|
|
186
|
+
* @param event - Event definition
|
|
187
|
+
* @returns True if unread events exist
|
|
188
|
+
*
|
|
189
|
+
* @example
|
|
190
|
+
* ```typescript
|
|
191
|
+
* if (hasEvents(world, DamageDealt)) {
|
|
192
|
+
* // Process damage events
|
|
193
|
+
* }
|
|
194
|
+
* ```
|
|
195
|
+
*/
|
|
196
|
+
export function hasEvents(world, event) {
|
|
197
|
+
const queue = ensureEventQueue(world, event);
|
|
198
|
+
const { systemId, tick } = world.execution;
|
|
199
|
+
const lastTick = systemId === null ? queue.lastTick.self : (queue.lastTick.bySystemId.get(systemId) ?? 0);
|
|
200
|
+
for (let i = 0; i < queue.events.length; i++) {
|
|
201
|
+
const entry = queue.events[i];
|
|
202
|
+
if (entry.tick > lastTick && entry.tick <= tick) {
|
|
203
|
+
return true;
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
return false;
|
|
207
|
+
}
|
|
208
|
+
/**
|
|
209
|
+
* Count unread events for current context.
|
|
210
|
+
*
|
|
211
|
+
* Does not mark events as read or trigger cleanup.
|
|
212
|
+
*
|
|
213
|
+
* @param world - World instance
|
|
214
|
+
* @param event - Event definition
|
|
215
|
+
* @returns Number of unread events
|
|
216
|
+
*
|
|
217
|
+
* @example
|
|
218
|
+
* ```typescript
|
|
219
|
+
* const damageCount = countEvents(world, DamageDealt);
|
|
220
|
+
* console.log(`${damageCount} damage events this tick`);
|
|
221
|
+
* ```
|
|
222
|
+
*/
|
|
223
|
+
export function countEvents(world, event) {
|
|
224
|
+
const queue = ensureEventQueue(world, event);
|
|
225
|
+
const { systemId, tick } = world.execution;
|
|
226
|
+
const lastTick = systemId === null ? queue.lastTick.self : (queue.lastTick.bySystemId.get(systemId) ?? 0);
|
|
227
|
+
let count = 0;
|
|
228
|
+
for (let i = 0; i < queue.events.length; i++) {
|
|
229
|
+
const entry = queue.events[i];
|
|
230
|
+
if (entry.tick > lastTick && entry.tick <= tick) {
|
|
231
|
+
count++;
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
return count;
|
|
235
|
+
}
|
|
236
|
+
/**
|
|
237
|
+
* Fetch only the most recent event, marking all as read.
|
|
238
|
+
*
|
|
239
|
+
* Useful when only the latest state matters (e.g., input, config changes).
|
|
240
|
+
*
|
|
241
|
+
* @param world - World instance
|
|
242
|
+
* @param event - Event definition
|
|
243
|
+
* @returns Most recent event data, or undefined if no unread events
|
|
244
|
+
*
|
|
245
|
+
* @example
|
|
246
|
+
* ```typescript
|
|
247
|
+
* // Only care about the latest input state
|
|
248
|
+
* const input = fetchLastEvent(world, InputChanged);
|
|
249
|
+
* if (input) {
|
|
250
|
+
* updatePlayerDirection(input.direction);
|
|
251
|
+
* }
|
|
252
|
+
* ```
|
|
253
|
+
*/
|
|
254
|
+
export function fetchLastEvent(world, event) {
|
|
255
|
+
const queue = ensureEventQueue(world, event);
|
|
256
|
+
const { systemId, tick } = world.execution;
|
|
257
|
+
const lastTick = systemId === null ? queue.lastTick.self : (queue.lastTick.bySystemId.get(systemId) ?? 0);
|
|
258
|
+
// Find last matching event (iterate backwards, break early)
|
|
259
|
+
let result;
|
|
260
|
+
for (let i = queue.events.length - 1; i >= 0; i--) {
|
|
261
|
+
const entry = queue.events[i];
|
|
262
|
+
if (entry.tick > lastTick && entry.tick <= tick) {
|
|
263
|
+
result = entry.data;
|
|
264
|
+
break;
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
markEventsRead(world, queue);
|
|
268
|
+
cleanupExpiredEvents(world, queue);
|
|
269
|
+
return result;
|
|
270
|
+
}
|
|
271
|
+
/**
|
|
272
|
+
* Clear events (mark as read without processing).
|
|
273
|
+
*
|
|
274
|
+
* Useful when a system needs to skip events under certain conditions.
|
|
275
|
+
*
|
|
276
|
+
* @param world - World instance
|
|
277
|
+
* @param event - Event definition
|
|
278
|
+
*
|
|
279
|
+
* @example
|
|
280
|
+
* ```typescript
|
|
281
|
+
* if (isPaused) {
|
|
282
|
+
* // Skip damage events while paused
|
|
283
|
+
* clearEvents(world, DamageDealt);
|
|
284
|
+
* return;
|
|
285
|
+
* }
|
|
286
|
+
* ```
|
|
287
|
+
*/
|
|
288
|
+
export function clearEvents(world, event) {
|
|
289
|
+
const queue = ensureEventQueue(world, event);
|
|
290
|
+
markEventsRead(world, queue);
|
|
291
|
+
cleanupExpiredEvents(world, queue);
|
|
292
|
+
}
|
|
293
|
+
//# sourceMappingURL=event.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"event.js","sourceRoot":"","sources":["../src/event.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import type { Archetype } from "./archetype.js";
|
|
2
|
+
import type { EntityId } from "./encoding.js";
|
|
3
|
+
import type { Observer } from "./observer.js";
|
|
4
|
+
import type { World } from "./world.js";
|
|
5
|
+
/**
|
|
6
|
+
* Filter terms for archetype matching.
|
|
7
|
+
*
|
|
8
|
+
* Specifies inclusion and exclusion constraints for archetype selection.
|
|
9
|
+
*/
|
|
10
|
+
export type FilterTerms = {
|
|
11
|
+
/**
|
|
12
|
+
* Required component IDs (all must be present).
|
|
13
|
+
*/
|
|
14
|
+
include: EntityId[];
|
|
15
|
+
/**
|
|
16
|
+
* Excluded component IDs (none must be present).
|
|
17
|
+
*/
|
|
18
|
+
exclude: EntityId[];
|
|
19
|
+
};
|
|
20
|
+
/**
|
|
21
|
+
* Filter metadata for registry caching.
|
|
22
|
+
*
|
|
23
|
+
* Stores filter terms, matched archetypes, and observer callbacks.
|
|
24
|
+
*/
|
|
25
|
+
export type FilterMeta = {
|
|
26
|
+
/**
|
|
27
|
+
* Filter terms (include/exclude constraints).
|
|
28
|
+
*/
|
|
29
|
+
terms: FilterTerms;
|
|
30
|
+
/**
|
|
31
|
+
* Matched archetypes (cached result of findMatchingArchetypes).
|
|
32
|
+
*/
|
|
33
|
+
archetypes: Archetype[];
|
|
34
|
+
/**
|
|
35
|
+
* Observer callback for archetype creation.
|
|
36
|
+
*/
|
|
37
|
+
onArchetypeCreate: Observer<"archetypeCreated">;
|
|
38
|
+
/**
|
|
39
|
+
* Observer callback for archetype destruction.
|
|
40
|
+
*/
|
|
41
|
+
onArchetypeDelete: Observer<"archetypeDestroyed">;
|
|
42
|
+
};
|
|
43
|
+
/**
|
|
44
|
+
* Generates a unique hash string for filter terms.
|
|
45
|
+
*
|
|
46
|
+
* @param terms - Filter terms containing include/exclude type arrays
|
|
47
|
+
* @returns Deterministic hash string (e.g., "+1:5:12|-3:7")
|
|
48
|
+
*
|
|
49
|
+
* @example
|
|
50
|
+
* const hash = hashFilterTerms({ include: [5, 1, 12], exclude: [7, 3] });
|
|
51
|
+
* // Returns "+1:5:12|-3:7" (sorted for consistency)
|
|
52
|
+
*/
|
|
53
|
+
export declare function hashFilterTerms(terms: FilterTerms): string;
|
|
54
|
+
/**
|
|
55
|
+
* Tests whether an archetype satisfies the given filter terms.
|
|
56
|
+
*
|
|
57
|
+
* @param archetype - Archetype to test against filter
|
|
58
|
+
* @param terms - Filter terms with include/exclude type constraints
|
|
59
|
+
* @returns True if archetype contains ALL included types and NONE of excluded types
|
|
60
|
+
*
|
|
61
|
+
* @example
|
|
62
|
+
* const matches = matchesFilterTerms(archetype, {
|
|
63
|
+
* include: [PositionType, VelocityType],
|
|
64
|
+
* exclude: [DisabledType]
|
|
65
|
+
* });
|
|
66
|
+
*/
|
|
67
|
+
export declare function matchesFilterTerms(archetype: Archetype, terms: FilterTerms): boolean;
|
|
68
|
+
/**
|
|
69
|
+
* Finds all archetypes matching filter terms using rarest-type optimization.
|
|
70
|
+
*
|
|
71
|
+
* Uses the "rarest type first" strategy: starts with the type that appears in
|
|
72
|
+
* the fewest archetypes, then filters that smaller set. This minimizes the
|
|
73
|
+
* number of archetypes we need to check.
|
|
74
|
+
*
|
|
75
|
+
* @param world - World instance containing archetype registry
|
|
76
|
+
* @param terms - Filter terms with include/exclude type constraints
|
|
77
|
+
* @returns Array of archetypes that match all filter criteria
|
|
78
|
+
*
|
|
79
|
+
* @example
|
|
80
|
+
* const archetypes = findMatchingArchetypes(world, {
|
|
81
|
+
* include: [PositionType, VelocityType],
|
|
82
|
+
* exclude: []
|
|
83
|
+
* });
|
|
84
|
+
*/
|
|
85
|
+
export declare function findMatchingArchetypes(world: World, terms: FilterTerms): Archetype[];
|
|
86
|
+
/**
|
|
87
|
+
* Gets or creates a filter with observer-based cache invalidation.
|
|
88
|
+
*
|
|
89
|
+
* Filters are cached by their terms hash. When created, observers are registered
|
|
90
|
+
* to automatically update the cached archetype list as archetypes are created
|
|
91
|
+
* or destroyed.
|
|
92
|
+
*
|
|
93
|
+
* @param world - World instance containing filter registry
|
|
94
|
+
* @param terms - Filter terms defining which archetypes to match
|
|
95
|
+
* @returns FilterMeta with cached matching archetypes
|
|
96
|
+
*
|
|
97
|
+
* @example
|
|
98
|
+
* const filter = ensureFilter(world, {
|
|
99
|
+
* include: [PositionType, VelocityType],
|
|
100
|
+
* exclude: [DisabledType]
|
|
101
|
+
* });
|
|
102
|
+
* // filter.archetypes contains all matching archetypes
|
|
103
|
+
*/
|
|
104
|
+
export declare function ensureFilter(world: World, terms: FilterTerms): FilterMeta;
|
|
105
|
+
/**
|
|
106
|
+
* Iterates all entities matching a filter in reverse order.
|
|
107
|
+
*
|
|
108
|
+
* Reverse iteration allows safe entity deletion during iteration without
|
|
109
|
+
* skipping entities or invalidating indices.
|
|
110
|
+
*
|
|
111
|
+
* @param filter - Filter metadata containing cached matching archetypes
|
|
112
|
+
* @returns Generator yielding entity IDs from all matching archetypes
|
|
113
|
+
*
|
|
114
|
+
* @example
|
|
115
|
+
* for (const entity of iterateFilterEntities(filter)) {
|
|
116
|
+
* // Safe to delete entity here due to reverse iteration
|
|
117
|
+
* destroyEntity(world, entity);
|
|
118
|
+
* }
|
|
119
|
+
*/
|
|
120
|
+
export declare function iterateFilterEntities(filter: FilterMeta): IterableIterator<EntityId>;
|
|
121
|
+
//# sourceMappingURL=filters.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"filters.d.ts","sourceRoot":"","sources":["../src/filters.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAChD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAE9C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAE9C,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAMxC;;;;GAIG;AACH,MAAM,MAAM,WAAW,GAAG;IACxB;;OAEG;IACH,OAAO,EAAE,QAAQ,EAAE,CAAC;IACpB;;OAEG;IACH,OAAO,EAAE,QAAQ,EAAE,CAAC;CACrB,CAAC;AAEF;;;;GAIG;AACH,MAAM,MAAM,UAAU,GAAG;IACvB;;OAEG;IACH,KAAK,EAAE,WAAW,CAAC;IACnB;;OAEG;IACH,UAAU,EAAE,SAAS,EAAE,CAAC;IACxB;;OAEG;IACH,iBAAiB,EAAE,QAAQ,CAAC,kBAAkB,CAAC,CAAC;IAChD;;OAEG;IACH,iBAAiB,EAAE,QAAQ,CAAC,oBAAoB,CAAC,CAAC;CACnD,CAAC;AAMF;;;;;;;;;GASG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,WAAW,GAAG,MAAM,CAK1D;AAMD;;;;;;;;;;;;GAYG;AACH,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,SAAS,EAAE,KAAK,EAAE,WAAW,GAAG,OAAO,CAkBpF;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,WAAW,GAAG,SAAS,EAAE,CAwCpF;AAqBD;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,WAAW,GAAG,UAAU,CAyCzE;AAMD;;;;;;;;;;;;;;GAcG;AACH,wBAAiB,qBAAqB,CAAC,MAAM,EAAE,UAAU,GAAG,gBAAgB,CAAC,QAAQ,CAAC,CAYrF"}
|