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/filters.js
ADDED
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
import { ensureEntity } from "./entity.js";
|
|
2
|
+
import { fireObserverEvent, registerObserverCallback, unregisterObserverCallback } from "./observer.js";
|
|
3
|
+
// ============================================================================
|
|
4
|
+
// Filter Hashing
|
|
5
|
+
// ============================================================================
|
|
6
|
+
/**
|
|
7
|
+
* Generates a unique hash string for filter terms.
|
|
8
|
+
*
|
|
9
|
+
* @param terms - Filter terms containing include/exclude type arrays
|
|
10
|
+
* @returns Deterministic hash string (e.g., "+1:5:12|-3:7")
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* const hash = hashFilterTerms({ include: [5, 1, 12], exclude: [7, 3] });
|
|
14
|
+
* // Returns "+1:5:12|-3:7" (sorted for consistency)
|
|
15
|
+
*/
|
|
16
|
+
export function hashFilterTerms(terms) {
|
|
17
|
+
// Sort to ensure same terms always produce same hash regardless of input order
|
|
18
|
+
const includeHash = terms.include.toSorted((a, b) => a - b).join(":");
|
|
19
|
+
const excludeHash = terms.exclude.toSorted((a, b) => a - b).join(":");
|
|
20
|
+
return `+${includeHash}|-${excludeHash}`;
|
|
21
|
+
}
|
|
22
|
+
// ============================================================================
|
|
23
|
+
// Archetype Matching
|
|
24
|
+
// ============================================================================
|
|
25
|
+
/**
|
|
26
|
+
* Tests whether an archetype satisfies the given filter terms.
|
|
27
|
+
*
|
|
28
|
+
* @param archetype - Archetype to test against filter
|
|
29
|
+
* @param terms - Filter terms with include/exclude type constraints
|
|
30
|
+
* @returns True if archetype contains ALL included types and NONE of excluded types
|
|
31
|
+
*
|
|
32
|
+
* @example
|
|
33
|
+
* const matches = matchesFilterTerms(archetype, {
|
|
34
|
+
* include: [PositionType, VelocityType],
|
|
35
|
+
* exclude: [DisabledType]
|
|
36
|
+
* });
|
|
37
|
+
*/
|
|
38
|
+
export function matchesFilterTerms(archetype, terms) {
|
|
39
|
+
// Verify ALL required types are present
|
|
40
|
+
for (let i = 0; i < terms.include.length; i++) {
|
|
41
|
+
const typeId = terms.include[i];
|
|
42
|
+
if (!archetype.typesSet.has(typeId)) {
|
|
43
|
+
return false;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
// Verify NONE of excluded types are present
|
|
47
|
+
for (let i = 0; i < terms.exclude.length; i++) {
|
|
48
|
+
const typeId = terms.exclude[i];
|
|
49
|
+
if (archetype.typesSet.has(typeId)) {
|
|
50
|
+
return false;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
return true;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Finds all archetypes matching filter terms using rarest-type optimization.
|
|
57
|
+
*
|
|
58
|
+
* Uses the "rarest type first" strategy: starts with the type that appears in
|
|
59
|
+
* the fewest archetypes, then filters that smaller set. This minimizes the
|
|
60
|
+
* number of archetypes we need to check.
|
|
61
|
+
*
|
|
62
|
+
* @param world - World instance containing archetype registry
|
|
63
|
+
* @param terms - Filter terms with include/exclude type constraints
|
|
64
|
+
* @returns Array of archetypes that match all filter criteria
|
|
65
|
+
*
|
|
66
|
+
* @example
|
|
67
|
+
* const archetypes = findMatchingArchetypes(world, {
|
|
68
|
+
* include: [PositionType, VelocityType],
|
|
69
|
+
* exclude: []
|
|
70
|
+
* });
|
|
71
|
+
*/
|
|
72
|
+
export function findMatchingArchetypes(world, terms) {
|
|
73
|
+
// Empty include list is a degenerate case - return no matches
|
|
74
|
+
if (terms.include.length === 0) {
|
|
75
|
+
return [];
|
|
76
|
+
}
|
|
77
|
+
// Find the rarest type (appears in fewest archetypes) for optimal iteration
|
|
78
|
+
let rarestId = terms.include[0];
|
|
79
|
+
let minCount = Number.POSITIVE_INFINITY;
|
|
80
|
+
for (let i = 0; i < terms.include.length; i++) {
|
|
81
|
+
const typeId = terms.include[i];
|
|
82
|
+
const meta = ensureEntity(world, typeId);
|
|
83
|
+
const count = meta.records.length;
|
|
84
|
+
if (count === 0) {
|
|
85
|
+
// If any required type has zero archetypes, no matches are possible
|
|
86
|
+
return [];
|
|
87
|
+
}
|
|
88
|
+
if (count < minCount) {
|
|
89
|
+
rarestId = typeId;
|
|
90
|
+
minCount = count;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
// Only iterate archetypes containing the rarest type, then filter further
|
|
94
|
+
const rarestMeta = ensureEntity(world, rarestId);
|
|
95
|
+
const archetypes = rarestMeta.records;
|
|
96
|
+
const matches = [];
|
|
97
|
+
for (let a = 0; a < archetypes.length; a++) {
|
|
98
|
+
const archetype = archetypes[a];
|
|
99
|
+
if (matchesFilterTerms(archetype, terms)) {
|
|
100
|
+
matches.push(archetype);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
return matches;
|
|
104
|
+
}
|
|
105
|
+
// ============================================================================
|
|
106
|
+
// Filter Registry
|
|
107
|
+
// ============================================================================
|
|
108
|
+
/**
|
|
109
|
+
* Destroys a filter and cleans up its observer callbacks.
|
|
110
|
+
* Called when a filter's archetype cache becomes empty.
|
|
111
|
+
*/
|
|
112
|
+
function destroyFilter(world, filterId) {
|
|
113
|
+
const filter = world.filters.byId.get(filterId);
|
|
114
|
+
// Unregister callbacks to prevent memory leaks and stale references
|
|
115
|
+
unregisterObserverCallback(world, "archetypeCreated", filter.onArchetypeCreate);
|
|
116
|
+
unregisterObserverCallback(world, "archetypeDestroyed", filter.onArchetypeDelete);
|
|
117
|
+
fireObserverEvent(world, "filterDestroyed", filter);
|
|
118
|
+
world.filters.byId.delete(filterId);
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Gets or creates a filter with observer-based cache invalidation.
|
|
122
|
+
*
|
|
123
|
+
* Filters are cached by their terms hash. When created, observers are registered
|
|
124
|
+
* to automatically update the cached archetype list as archetypes are created
|
|
125
|
+
* or destroyed.
|
|
126
|
+
*
|
|
127
|
+
* @param world - World instance containing filter registry
|
|
128
|
+
* @param terms - Filter terms defining which archetypes to match
|
|
129
|
+
* @returns FilterMeta with cached matching archetypes
|
|
130
|
+
*
|
|
131
|
+
* @example
|
|
132
|
+
* const filter = ensureFilter(world, {
|
|
133
|
+
* include: [PositionType, VelocityType],
|
|
134
|
+
* exclude: [DisabledType]
|
|
135
|
+
* });
|
|
136
|
+
* // filter.archetypes contains all matching archetypes
|
|
137
|
+
*/
|
|
138
|
+
export function ensureFilter(world, terms) {
|
|
139
|
+
const filterId = hashFilterTerms(terms);
|
|
140
|
+
let filterMeta = world.filters.byId.get(filterId);
|
|
141
|
+
if (!filterMeta) {
|
|
142
|
+
// Create new filter with observer callbacks that close over terms and filterMeta
|
|
143
|
+
filterMeta = {
|
|
144
|
+
terms,
|
|
145
|
+
archetypes: findMatchingArchetypes(world, terms),
|
|
146
|
+
// Called when a new archetype is created - add to cache if it matches
|
|
147
|
+
onArchetypeCreate: (archetype) => {
|
|
148
|
+
if (!matchesFilterTerms(archetype, terms)) {
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
filterMeta.archetypes.push(archetype);
|
|
152
|
+
},
|
|
153
|
+
// Called when an archetype is destroyed - remove from cache, cleanup if empty
|
|
154
|
+
onArchetypeDelete: (archetype) => {
|
|
155
|
+
const idx = filterMeta.archetypes.indexOf(archetype);
|
|
156
|
+
if (idx !== -1) {
|
|
157
|
+
filterMeta.archetypes.splice(idx, 1);
|
|
158
|
+
}
|
|
159
|
+
// Auto-cleanup: destroy filter when it has no matching archetypes
|
|
160
|
+
if (filterMeta.archetypes.length === 0) {
|
|
161
|
+
destroyFilter(world, filterId);
|
|
162
|
+
}
|
|
163
|
+
},
|
|
164
|
+
};
|
|
165
|
+
world.filters.byId.set(filterId, filterMeta);
|
|
166
|
+
// Register observers to keep archetype cache in sync
|
|
167
|
+
registerObserverCallback(world, "archetypeCreated", filterMeta.onArchetypeCreate);
|
|
168
|
+
registerObserverCallback(world, "archetypeDestroyed", filterMeta.onArchetypeDelete);
|
|
169
|
+
fireObserverEvent(world, "filterCreated", filterMeta);
|
|
170
|
+
}
|
|
171
|
+
return filterMeta;
|
|
172
|
+
}
|
|
173
|
+
// ============================================================================
|
|
174
|
+
// Filter Iteration
|
|
175
|
+
// ============================================================================
|
|
176
|
+
/**
|
|
177
|
+
* Iterates all entities matching a filter in reverse order.
|
|
178
|
+
*
|
|
179
|
+
* Reverse iteration allows safe entity deletion during iteration without
|
|
180
|
+
* skipping entities or invalidating indices.
|
|
181
|
+
*
|
|
182
|
+
* @param filter - Filter metadata containing cached matching archetypes
|
|
183
|
+
* @returns Generator yielding entity IDs from all matching archetypes
|
|
184
|
+
*
|
|
185
|
+
* @example
|
|
186
|
+
* for (const entity of iterateFilterEntities(filter)) {
|
|
187
|
+
* // Safe to delete entity here due to reverse iteration
|
|
188
|
+
* destroyEntity(world, entity);
|
|
189
|
+
* }
|
|
190
|
+
*/
|
|
191
|
+
export function* iterateFilterEntities(filter) {
|
|
192
|
+
const archetypes = filter.archetypes;
|
|
193
|
+
for (let a = 0; a < archetypes.length; a++) {
|
|
194
|
+
const archetype = archetypes[a];
|
|
195
|
+
const entities = archetype.entities;
|
|
196
|
+
// Reverse iteration enables safe deletion during traversal
|
|
197
|
+
for (let i = entities.length - 1; i >= 0; i--) {
|
|
198
|
+
yield entities[i];
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
//# sourceMappingURL=filters.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"filters.js","sourceRoot":"","sources":["../src/filters.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export { createWorld, resetWorld } from "./world.js";
|
|
2
|
+
export { createEntity, destroyEntity, isEntityAlive } from "./entity.js";
|
|
3
|
+
export { addComponent, emitComponentChanged, getComponentValue, hasComponent, removeComponent, setComponentValue, } from "./component.js";
|
|
4
|
+
export { defineComponent, defineRelation, defineTag, Wildcard } from "./registry.js";
|
|
5
|
+
export { getPairRelation, getPairTarget, getRelationTargets, pair } from "./relation.js";
|
|
6
|
+
export { addResource, getResourceValue, hasResource, removeResource, setResourceValue, } from "./resource.js";
|
|
7
|
+
export { getName, lookupByName, Name, removeName, setName } from "./name.js";
|
|
8
|
+
export { added, changed, destroyQuery, ensureQuery, fetchEntities, fetchEntitiesWithQuery, fetchFirstEntity, not, } from "./query.js";
|
|
9
|
+
export { addSystem, buildSchedule, executeSchedule, executeScheduleAsync, } from "./scheduler.js";
|
|
10
|
+
export type { ActionGetter, ActionInitializer, Actions } from "./actions.js";
|
|
11
|
+
export type { Component, Entity, EntityId, Pair, Relation, RelationTargetId, Tag } from "./encoding.js";
|
|
12
|
+
export type { Event, EventSchema } from "./event.js";
|
|
13
|
+
export type { FilterTerms } from "./filters.js";
|
|
14
|
+
export type { AddedModifier, ChangedModifier, ModifierType, NotModifier, QueryMeta, QueryModifier } from "./query.js";
|
|
15
|
+
export type { ScheduleId, SystemMeta, SystemOptions, SystemRunner } from "./scheduler.js";
|
|
16
|
+
export type { InferSchemaRecord, Schema, SchemaRecord } from "./schema.js";
|
|
17
|
+
export type { World } from "./world.js";
|
|
18
|
+
export { clearEvents, countEvents, defineEvent, EVENT_EXPIRY_TICKS, emitEvent, fetchEvents, fetchLastEvent, hasEvents, } from "./event.js";
|
|
19
|
+
export { removed } from "./removal.js";
|
|
20
|
+
export type { EventPayloads, EventType, Observer, ObserverMeta } from "./observer.js";
|
|
21
|
+
export { registerObserverCallback, unregisterObserverCallback } from "./observer.js";
|
|
22
|
+
export { Type } from "./schema.js";
|
|
23
|
+
export { defineActions } from "./actions.js";
|
|
24
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAMrD,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAMzE,OAAO,EACL,YAAY,EACZ,oBAAoB,EACpB,iBAAiB,EACjB,YAAY,EACZ,eAAe,EACf,iBAAiB,GAClB,MAAM,gBAAgB,CAAC;AAMxB,OAAO,EAAE,eAAe,EAAE,cAAc,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAMrF,OAAO,EAAE,eAAe,EAAE,aAAa,EAAE,kBAAkB,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AAMzF,OAAO,EACL,WAAW,EACX,gBAAgB,EAChB,WAAW,EACX,cAAc,EACd,gBAAgB,GACjB,MAAM,eAAe,CAAC;AAMvB,OAAO,EAAE,OAAO,EAAE,YAAY,EAAE,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAM7E,OAAO,EACL,KAAK,EACL,OAAO,EACP,YAAY,EACZ,WAAW,EACX,aAAa,EACb,sBAAsB,EACtB,gBAAgB,EAChB,GAAG,GACJ,MAAM,YAAY,CAAC;AAMpB,OAAO,EACL,SAAS,EACT,aAAa,EACb,eAAe,EACf,oBAAoB,GACrB,MAAM,gBAAgB,CAAC;AAMxB,YAAY,EAAE,YAAY,EAAE,iBAAiB,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAC7E,YAAY,EAAE,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,QAAQ,EAAE,gBAAgB,EAAE,GAAG,EAAE,MAAM,eAAe,CAAC;AACxG,YAAY,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AACrD,YAAY,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAChD,YAAY,EAAE,aAAa,EAAE,eAAe,EAAE,YAAY,EAAE,WAAW,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AACtH,YAAY,EAAE,UAAU,EAAE,UAAU,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC1F,YAAY,EAAE,iBAAiB,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3E,YAAY,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAMxC,OAAO,EACL,WAAW,EACX,WAAW,EACX,WAAW,EACX,kBAAkB,EAClB,SAAS,EACT,WAAW,EACX,cAAc,EACd,SAAS,GACV,MAAM,YAAY,CAAC;AAMpB,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAMvC,YAAY,EAAE,aAAa,EAAE,SAAS,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AACtF,OAAO,EAAE,wBAAwB,EAAE,0BAA0B,EAAE,MAAM,eAAe,CAAC;AAMrF,OAAO,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AAMnC,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
// ============================================================================
|
|
2
|
+
// World Operations
|
|
3
|
+
// ============================================================================
|
|
4
|
+
export { createWorld, resetWorld } from "./world.js";
|
|
5
|
+
// ============================================================================
|
|
6
|
+
// Entity Operations
|
|
7
|
+
// ============================================================================
|
|
8
|
+
export { createEntity, destroyEntity, isEntityAlive } from "./entity.js";
|
|
9
|
+
// ============================================================================
|
|
10
|
+
// Component Operations
|
|
11
|
+
// ============================================================================
|
|
12
|
+
export { addComponent, emitComponentChanged, getComponentValue, hasComponent, removeComponent, setComponentValue, } from "./component.js";
|
|
13
|
+
// ============================================================================
|
|
14
|
+
// Registry Operations
|
|
15
|
+
// ============================================================================
|
|
16
|
+
export { defineComponent, defineRelation, defineTag, Wildcard } from "./registry.js";
|
|
17
|
+
// ============================================================================
|
|
18
|
+
// Relation Operations
|
|
19
|
+
// ============================================================================
|
|
20
|
+
export { getPairRelation, getPairTarget, getRelationTargets, pair } from "./relation.js";
|
|
21
|
+
// ============================================================================
|
|
22
|
+
// Resource Operations
|
|
23
|
+
// ============================================================================
|
|
24
|
+
export { addResource, getResourceValue, hasResource, removeResource, setResourceValue, } from "./resource.js";
|
|
25
|
+
// ============================================================================
|
|
26
|
+
// Name System
|
|
27
|
+
// ============================================================================
|
|
28
|
+
export { getName, lookupByName, Name, removeName, setName } from "./name.js";
|
|
29
|
+
// ============================================================================
|
|
30
|
+
// Query Operations
|
|
31
|
+
// ============================================================================
|
|
32
|
+
export { added, changed, destroyQuery, ensureQuery, fetchEntities, fetchEntitiesWithQuery, fetchFirstEntity, not, } from "./query.js";
|
|
33
|
+
// ============================================================================
|
|
34
|
+
// System Operations
|
|
35
|
+
// ============================================================================
|
|
36
|
+
export { addSystem, buildSchedule, executeSchedule, executeScheduleAsync, } from "./scheduler.js";
|
|
37
|
+
// ============================================================================
|
|
38
|
+
// Event System
|
|
39
|
+
// ============================================================================
|
|
40
|
+
export { clearEvents, countEvents, defineEvent, EVENT_EXPIRY_TICKS, emitEvent, fetchEvents, fetchLastEvent, hasEvents, } from "./event.js";
|
|
41
|
+
// ============================================================================
|
|
42
|
+
// Removal Detection
|
|
43
|
+
// ============================================================================
|
|
44
|
+
export { removed } from "./removal.js";
|
|
45
|
+
export { registerObserverCallback, unregisterObserverCallback } from "./observer.js";
|
|
46
|
+
// ============================================================================
|
|
47
|
+
// Schema Factories
|
|
48
|
+
// ============================================================================
|
|
49
|
+
export { Type } from "./schema.js";
|
|
50
|
+
// ============================================================================
|
|
51
|
+
// Actions
|
|
52
|
+
// ============================================================================
|
|
53
|
+
export { defineActions } from "./actions.js";
|
|
54
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,mBAAmB;AACnB,+EAA+E;AAE/E,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAErD,+EAA+E;AAC/E,oBAAoB;AACpB,+EAA+E;AAE/E,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAEzE,+EAA+E;AAC/E,uBAAuB;AACvB,+EAA+E;AAE/E,OAAO,EACL,YAAY,EACZ,oBAAoB,EACpB,iBAAiB,EACjB,YAAY,EACZ,eAAe,EACf,iBAAiB,GAClB,MAAM,gBAAgB,CAAC;AAExB,+EAA+E;AAC/E,sBAAsB;AACtB,+EAA+E;AAE/E,OAAO,EAAE,eAAe,EAAE,cAAc,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAErF,+EAA+E;AAC/E,sBAAsB;AACtB,+EAA+E;AAE/E,OAAO,EAAE,eAAe,EAAE,aAAa,EAAE,kBAAkB,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AAEzF,+EAA+E;AAC/E,sBAAsB;AACtB,+EAA+E;AAE/E,OAAO,EACL,WAAW,EACX,gBAAgB,EAChB,WAAW,EACX,cAAc,EACd,gBAAgB,GACjB,MAAM,eAAe,CAAC;AAEvB,+EAA+E;AAC/E,cAAc;AACd,+EAA+E;AAE/E,OAAO,EAAE,OAAO,EAAE,YAAY,EAAE,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAE7E,+EAA+E;AAC/E,mBAAmB;AACnB,+EAA+E;AAE/E,OAAO,EACL,KAAK,EACL,OAAO,EACP,YAAY,EACZ,WAAW,EACX,aAAa,EACb,sBAAsB,EACtB,gBAAgB,EAChB,GAAG,GACJ,MAAM,YAAY,CAAC;AAEpB,+EAA+E;AAC/E,oBAAoB;AACpB,+EAA+E;AAE/E,OAAO,EACL,SAAS,EACT,aAAa,EACb,eAAe,EACf,oBAAoB,GACrB,MAAM,gBAAgB,CAAC;AAexB,+EAA+E;AAC/E,eAAe;AACf,+EAA+E;AAE/E,OAAO,EACL,WAAW,EACX,WAAW,EACX,WAAW,EACX,kBAAkB,EAClB,SAAS,EACT,WAAW,EACX,cAAc,EACd,SAAS,GACV,MAAM,YAAY,CAAC;AAEpB,+EAA+E;AAC/E,oBAAoB;AACpB,+EAA+E;AAE/E,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAOvC,OAAO,EAAE,wBAAwB,EAAE,0BAA0B,EAAE,MAAM,eAAe,CAAC;AAErF,+EAA+E;AAC/E,mBAAmB;AACnB,+EAA+E;AAE/E,OAAO,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AAEnC,+EAA+E;AAC/E,UAAU;AACV,+EAA+E;AAE/E,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC"}
|
package/dist/name.d.ts
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import type { EntityId } from "./encoding.js";
|
|
2
|
+
import type { World } from "./world.js";
|
|
3
|
+
/**
|
|
4
|
+
* Name component for entity identification.
|
|
5
|
+
*
|
|
6
|
+
* Stores a single string value that must be unique within the world.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```typescript
|
|
10
|
+
* addComponent(world, entity, Name, { value: "player-1" });
|
|
11
|
+
* const name = getComponentValue(world, entity, Name, "value");
|
|
12
|
+
* ```
|
|
13
|
+
*/
|
|
14
|
+
export declare const Name: import("./encoding.js").Component<{
|
|
15
|
+
value: import("./schema.js").Schema<string>;
|
|
16
|
+
}>;
|
|
17
|
+
/**
|
|
18
|
+
* Initializes the name system for a world by setting up the dual-index registry
|
|
19
|
+
* and observer callbacks that keep name mappings synchronized with entity lifecycle.
|
|
20
|
+
* Called automatically by createWorld().
|
|
21
|
+
* @internal
|
|
22
|
+
*/
|
|
23
|
+
export declare function initNameSystem(world: World): void;
|
|
24
|
+
/**
|
|
25
|
+
* Gets the name of an entity.
|
|
26
|
+
* @param world - World instance
|
|
27
|
+
* @param entityId - Entity to get name from
|
|
28
|
+
* @returns Entity name or undefined if not named
|
|
29
|
+
* @example
|
|
30
|
+
* ```ts
|
|
31
|
+
* const name = getName(world, entity);
|
|
32
|
+
* ```
|
|
33
|
+
*/
|
|
34
|
+
export declare function getName(world: World, entityId: EntityId): string | undefined;
|
|
35
|
+
/**
|
|
36
|
+
* Sets or updates the name of an entity.
|
|
37
|
+
* @param world - World instance
|
|
38
|
+
* @param entityId - Entity to name
|
|
39
|
+
* @param name - Name to assign (must be unique and non-empty)
|
|
40
|
+
* @throws Error if name is empty or already exists
|
|
41
|
+
* @example
|
|
42
|
+
* ```ts
|
|
43
|
+
* setName(world, player, "player-1");
|
|
44
|
+
* ```
|
|
45
|
+
*/
|
|
46
|
+
export declare function setName(world: World, entityId: EntityId, name: string): void;
|
|
47
|
+
/**
|
|
48
|
+
* Removes the name from an entity.
|
|
49
|
+
* @param world - World instance
|
|
50
|
+
* @param entityId - Entity to remove name from
|
|
51
|
+
* @example
|
|
52
|
+
* ```ts
|
|
53
|
+
* removeName(world, entity);
|
|
54
|
+
* ```
|
|
55
|
+
*/
|
|
56
|
+
export declare function removeName(world: World, entityId: EntityId): void;
|
|
57
|
+
/**
|
|
58
|
+
* Looks up an entity by name, optionally validating required components.
|
|
59
|
+
* @param world - World instance
|
|
60
|
+
* @param name - Name to look up
|
|
61
|
+
* @param components - Optional components to validate presence
|
|
62
|
+
* @returns Entity ID or undefined if not found or missing required components
|
|
63
|
+
* @example
|
|
64
|
+
* ```ts
|
|
65
|
+
* const player = lookupByName(world, "player-1");
|
|
66
|
+
* const player = lookupByName(world, "player-1", Position, Health);
|
|
67
|
+
* ```
|
|
68
|
+
*/
|
|
69
|
+
export declare function lookupByName(world: World, name: string, ...components: EntityId[]): EntityId | undefined;
|
|
70
|
+
//# sourceMappingURL=name.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"name.d.ts","sourceRoot":"","sources":["../src/name.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAK9C,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAMxC;;;;;;;;;;GAUG;AACH,eAAO,MAAM,IAAI;;EAAoD,CAAC;AActE;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI,CA0EjD;AAMD;;;;;;;;;GASG;AACH,wBAAgB,OAAO,CAAC,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,QAAQ,GAAG,MAAM,GAAG,SAAS,CAE5E;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,OAAO,CAAC,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAO5E;AAED;;;;;;;;GAQG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,QAAQ,GAAG,IAAI,CAMjE;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,UAAU,EAAE,QAAQ,EAAE,GAAG,QAAQ,GAAG,SAAS,CAexG"}
|
package/dist/name.js
ADDED
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
import { addComponent, getComponentValue, hasComponent, removeComponent, setComponentValue } from "./component.js";
|
|
2
|
+
import { registerObserverCallback } from "./observer.js";
|
|
3
|
+
import { defineComponent } from "./registry.js";
|
|
4
|
+
import { addResource, getResourceValue } from "./resource.js";
|
|
5
|
+
import { Type } from "./schema.js";
|
|
6
|
+
// ============================================================================
|
|
7
|
+
// Component Definitions
|
|
8
|
+
// ============================================================================
|
|
9
|
+
/**
|
|
10
|
+
* Name component for entity identification.
|
|
11
|
+
*
|
|
12
|
+
* Stores a single string value that must be unique within the world.
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* ```typescript
|
|
16
|
+
* addComponent(world, entity, Name, { value: "player-1" });
|
|
17
|
+
* const name = getComponentValue(world, entity, Name, "value");
|
|
18
|
+
* ```
|
|
19
|
+
*/
|
|
20
|
+
export const Name = defineComponent("Name", { value: Type.string() });
|
|
21
|
+
/**
|
|
22
|
+
* Dual-index registry for O(1) lookups in both directions. Stored as a world resource.
|
|
23
|
+
*/
|
|
24
|
+
const NameRegistry = defineComponent("NameRegistry", {
|
|
25
|
+
nameToEntity: Type.object(),
|
|
26
|
+
entityToName: Type.object(),
|
|
27
|
+
});
|
|
28
|
+
// ============================================================================
|
|
29
|
+
// Initialization
|
|
30
|
+
// ============================================================================
|
|
31
|
+
/**
|
|
32
|
+
* Initializes the name system for a world by setting up the dual-index registry
|
|
33
|
+
* and observer callbacks that keep name mappings synchronized with entity lifecycle.
|
|
34
|
+
* Called automatically by createWorld().
|
|
35
|
+
* @internal
|
|
36
|
+
*/
|
|
37
|
+
export function initNameSystem(world) {
|
|
38
|
+
addResource(world, NameRegistry, {
|
|
39
|
+
nameToEntity: new Map(),
|
|
40
|
+
entityToName: new Map(),
|
|
41
|
+
});
|
|
42
|
+
// Clean up registry when Name component is removed from an entity
|
|
43
|
+
registerObserverCallback(world, "componentRemoved", (componentId, entityId) => {
|
|
44
|
+
if (componentId !== Name) {
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
const nameToEntity = getResourceValue(world, NameRegistry, "nameToEntity");
|
|
48
|
+
const entityToName = getResourceValue(world, NameRegistry, "entityToName");
|
|
49
|
+
const name = entityToName.get(entityId);
|
|
50
|
+
nameToEntity.delete(name);
|
|
51
|
+
entityToName.delete(entityId);
|
|
52
|
+
});
|
|
53
|
+
// Sync registry when Name component is added or its value changes.
|
|
54
|
+
// Validates uniqueness and non-empty constraints before updating mappings.
|
|
55
|
+
registerObserverCallback(world, "componentChanged", (componentId, entityId) => {
|
|
56
|
+
if (componentId !== Name) {
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
const nameToEntity = getResourceValue(world, NameRegistry, "nameToEntity");
|
|
60
|
+
const entityToName = getResourceValue(world, NameRegistry, "entityToName");
|
|
61
|
+
const previous = entityToName.get(entityId);
|
|
62
|
+
const current = getComponentValue(world, entityId, Name, "value");
|
|
63
|
+
if (previous === current) {
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
if (!current) {
|
|
67
|
+
throw new Error("Name cannot be empty");
|
|
68
|
+
}
|
|
69
|
+
if (nameToEntity.has(current)) {
|
|
70
|
+
throw new Error(`Name "${current}" already exists`);
|
|
71
|
+
}
|
|
72
|
+
// Remove old mapping if renaming an entity
|
|
73
|
+
if (previous !== undefined) {
|
|
74
|
+
nameToEntity.delete(previous);
|
|
75
|
+
}
|
|
76
|
+
nameToEntity.set(current, entityId);
|
|
77
|
+
entityToName.set(entityId, current);
|
|
78
|
+
});
|
|
79
|
+
// Clean up registry when a named entity is destroyed
|
|
80
|
+
registerObserverCallback(world, "entityDestroyed", (entityId) => {
|
|
81
|
+
const nameToEntity = getResourceValue(world, NameRegistry, "nameToEntity");
|
|
82
|
+
const entityToName = getResourceValue(world, NameRegistry, "entityToName");
|
|
83
|
+
const name = entityToName.get(entityId);
|
|
84
|
+
if (name === undefined) {
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
nameToEntity.delete(name);
|
|
88
|
+
entityToName.delete(entityId);
|
|
89
|
+
});
|
|
90
|
+
// Recreate fresh registry when world is reset
|
|
91
|
+
registerObserverCallback(world, "worldReset", () => {
|
|
92
|
+
addResource(world, NameRegistry, {
|
|
93
|
+
nameToEntity: new Map(),
|
|
94
|
+
entityToName: new Map(),
|
|
95
|
+
});
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
// ============================================================================
|
|
99
|
+
// Public API
|
|
100
|
+
// ============================================================================
|
|
101
|
+
/**
|
|
102
|
+
* Gets the name of an entity.
|
|
103
|
+
* @param world - World instance
|
|
104
|
+
* @param entityId - Entity to get name from
|
|
105
|
+
* @returns Entity name or undefined if not named
|
|
106
|
+
* @example
|
|
107
|
+
* ```ts
|
|
108
|
+
* const name = getName(world, entity);
|
|
109
|
+
* ```
|
|
110
|
+
*/
|
|
111
|
+
export function getName(world, entityId) {
|
|
112
|
+
return getComponentValue(world, entityId, Name, "value");
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Sets or updates the name of an entity.
|
|
116
|
+
* @param world - World instance
|
|
117
|
+
* @param entityId - Entity to name
|
|
118
|
+
* @param name - Name to assign (must be unique and non-empty)
|
|
119
|
+
* @throws Error if name is empty or already exists
|
|
120
|
+
* @example
|
|
121
|
+
* ```ts
|
|
122
|
+
* setName(world, player, "player-1");
|
|
123
|
+
* ```
|
|
124
|
+
*/
|
|
125
|
+
export function setName(world, entityId, name) {
|
|
126
|
+
if (!hasComponent(world, entityId, Name)) {
|
|
127
|
+
addComponent(world, entityId, Name, { value: name });
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
setComponentValue(world, entityId, Name, "value", name);
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Removes the name from an entity.
|
|
134
|
+
* @param world - World instance
|
|
135
|
+
* @param entityId - Entity to remove name from
|
|
136
|
+
* @example
|
|
137
|
+
* ```ts
|
|
138
|
+
* removeName(world, entity);
|
|
139
|
+
* ```
|
|
140
|
+
*/
|
|
141
|
+
export function removeName(world, entityId) {
|
|
142
|
+
if (!hasComponent(world, entityId, Name)) {
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
removeComponent(world, entityId, Name);
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Looks up an entity by name, optionally validating required components.
|
|
149
|
+
* @param world - World instance
|
|
150
|
+
* @param name - Name to look up
|
|
151
|
+
* @param components - Optional components to validate presence
|
|
152
|
+
* @returns Entity ID or undefined if not found or missing required components
|
|
153
|
+
* @example
|
|
154
|
+
* ```ts
|
|
155
|
+
* const player = lookupByName(world, "player-1");
|
|
156
|
+
* const player = lookupByName(world, "player-1", Position, Health);
|
|
157
|
+
* ```
|
|
158
|
+
*/
|
|
159
|
+
export function lookupByName(world, name, ...components) {
|
|
160
|
+
const nameToEntity = getResourceValue(world, NameRegistry, "nameToEntity");
|
|
161
|
+
const entityId = nameToEntity.get(name);
|
|
162
|
+
if (!entityId) {
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
for (const component of components) {
|
|
166
|
+
if (!hasComponent(world, entityId, component)) {
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
return entityId;
|
|
171
|
+
}
|
|
172
|
+
//# sourceMappingURL=name.js.map
|
package/dist/name.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"name.js","sourceRoot":"","sources":["../src/name.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import type { Archetype } from "./archetype.js";
|
|
2
|
+
import type { Entity, EntityId } from "./encoding.js";
|
|
3
|
+
import type { FilterMeta } from "./filters.js";
|
|
4
|
+
import type { World } from "./world.js";
|
|
5
|
+
/**
|
|
6
|
+
* Event payload type mapping.
|
|
7
|
+
*
|
|
8
|
+
* Maps event names to argument tuples for type-safe observer callbacks.
|
|
9
|
+
*/
|
|
10
|
+
export type EventPayloads = {
|
|
11
|
+
archetypeCreated: [archetype: Archetype];
|
|
12
|
+
archetypeDestroyed: [archetype: Archetype];
|
|
13
|
+
filterCreated: [filter: FilterMeta];
|
|
14
|
+
filterDestroyed: [filter: FilterMeta];
|
|
15
|
+
entityCreated: [entityId: Entity];
|
|
16
|
+
entityDestroyed: [entityId: EntityId];
|
|
17
|
+
componentAdded: [componentId: EntityId, entityId: EntityId];
|
|
18
|
+
componentRemoved: [componentId: EntityId, entityId: EntityId];
|
|
19
|
+
componentChanged: [componentId: EntityId, entityId: EntityId];
|
|
20
|
+
worldReset: [world: World];
|
|
21
|
+
};
|
|
22
|
+
/**
|
|
23
|
+
* Event type keys.
|
|
24
|
+
*/
|
|
25
|
+
export type EventType = keyof EventPayloads;
|
|
26
|
+
/**
|
|
27
|
+
* Observer callback function.
|
|
28
|
+
*/
|
|
29
|
+
export type Observer<T extends EventType> = (...args: EventPayloads[T]) => void;
|
|
30
|
+
/**
|
|
31
|
+
* Observer metadata for single event type.
|
|
32
|
+
*/
|
|
33
|
+
export type ObserverMeta<T extends EventType> = {
|
|
34
|
+
/**
|
|
35
|
+
* Callbacks fired on event.
|
|
36
|
+
*/
|
|
37
|
+
callbacks: Observer<T>[];
|
|
38
|
+
};
|
|
39
|
+
/**
|
|
40
|
+
* Registers a callback to be invoked when an event of the specified type is fired.
|
|
41
|
+
*
|
|
42
|
+
* @param world - The world instance containing observer state
|
|
43
|
+
* @param eventType - The event type to listen for
|
|
44
|
+
* @param callback - Function to invoke when the event fires
|
|
45
|
+
*
|
|
46
|
+
* @example
|
|
47
|
+
* ```ts
|
|
48
|
+
* registerObserverCallback(world, "onAdd", (entity, componentId, value) => {
|
|
49
|
+
* console.log(`Component ${componentId} added to entity ${entity}`);
|
|
50
|
+
* });
|
|
51
|
+
* ```
|
|
52
|
+
*/
|
|
53
|
+
export declare function registerObserverCallback<T extends EventType>(world: World, eventType: T, callback: Observer<T>): void;
|
|
54
|
+
/**
|
|
55
|
+
* Removes a previously registered callback for the specified event type.
|
|
56
|
+
*
|
|
57
|
+
* @param world - The world instance containing observer state
|
|
58
|
+
* @param eventType - The event type to stop listening for
|
|
59
|
+
* @param callback - The exact callback reference to remove
|
|
60
|
+
*
|
|
61
|
+
* @example
|
|
62
|
+
* ```ts
|
|
63
|
+
* const handler = (entity, componentId, value) => { ... };
|
|
64
|
+
* registerObserverCallback(world, "onAdd", handler);
|
|
65
|
+
* // Later:
|
|
66
|
+
* unregisterObserverCallback(world, "onAdd", handler);
|
|
67
|
+
* ```
|
|
68
|
+
*/
|
|
69
|
+
export declare function unregisterObserverCallback<T extends EventType>(world: World, eventType: T, callback: Observer<T>): void;
|
|
70
|
+
/**
|
|
71
|
+
* Dispatches an event to all registered callbacks for the specified event type.
|
|
72
|
+
*
|
|
73
|
+
* @param world - The world instance containing observer state
|
|
74
|
+
* @param eventType - The event type to dispatch
|
|
75
|
+
* @param args - Arguments to pass to each callback (varies by event type)
|
|
76
|
+
*
|
|
77
|
+
* @example
|
|
78
|
+
* ```ts
|
|
79
|
+
* fireObserverEvent(world, "onAdd", entity, componentId, componentValue);
|
|
80
|
+
* ```
|
|
81
|
+
*/
|
|
82
|
+
export declare function fireObserverEvent<T extends EventType>(world: World, eventType: T, ...args: EventPayloads[T]): void;
|
|
83
|
+
//# sourceMappingURL=observer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"observer.d.ts","sourceRoot":"","sources":["../src/observer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAChD,OAAO,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACtD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAMxC;;;;GAIG;AACH,MAAM,MAAM,aAAa,GAAG;IAC1B,gBAAgB,EAAE,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC;IACzC,kBAAkB,EAAE,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC;IAC3C,aAAa,EAAE,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IACpC,eAAe,EAAE,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IACtC,aAAa,EAAE,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;IAClC,eAAe,EAAE,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;IACtC,cAAc,EAAE,CAAC,WAAW,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAC;IAC5D,gBAAgB,EAAE,CAAC,WAAW,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAC;IAC9D,gBAAgB,EAAE,CAAC,WAAW,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAC;IAC9D,UAAU,EAAE,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;CAC5B,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,SAAS,GAAG,MAAM,aAAa,CAAC;AAE5C;;GAEG;AACH,MAAM,MAAM,QAAQ,CAAC,CAAC,SAAS,SAAS,IAAI,CAAC,GAAG,IAAI,EAAE,aAAa,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC;AAEhF;;GAEG;AACH,MAAM,MAAM,YAAY,CAAC,CAAC,SAAS,SAAS,IAAI;IAC9C;;OAEG;IACH,SAAS,EAAE,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC;CAC1B,CAAC;AAMF;;;;;;;;;;;;;GAaG;AACH,wBAAgB,wBAAwB,CAAC,CAAC,SAAS,SAAS,EAAE,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAC,CAAC,GAAG,IAAI,CAErH;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,0BAA0B,CAAC,CAAC,SAAS,SAAS,EAC5D,KAAK,EAAE,KAAK,EACZ,SAAS,EAAE,CAAC,EACZ,QAAQ,EAAE,QAAQ,CAAC,CAAC,CAAC,GACpB,IAAI,CAON;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,iBAAiB,CAAC,CAAC,SAAS,SAAS,EAAE,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC,EAAE,GAAG,IAAI,EAAE,aAAa,CAAC,CAAC,CAAC,GAAG,IAAI,CAOlH"}
|