@vworlds/vecs 1.0.15 → 1.0.16

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.
Files changed (181) hide show
  1. package/README.md +249 -119
  2. package/dist/component.d.ts +52 -76
  3. package/dist/component.js +60 -45
  4. package/dist/component.js.map +1 -1
  5. package/dist/component_meta.d.ts +98 -0
  6. package/dist/component_meta.js +65 -0
  7. package/dist/component_meta.js.map +1 -0
  8. package/dist/dsl.d.ts +46 -34
  9. package/dist/dsl.js +459 -61
  10. package/dist/dsl.js.map +1 -1
  11. package/dist/entity/entity.base.d.ts +57 -0
  12. package/dist/entity/entity.base.js +81 -0
  13. package/dist/entity/entity.base.js.map +1 -0
  14. package/dist/entity/entity.components.d.ts +117 -0
  15. package/dist/entity/entity.components.js +244 -0
  16. package/dist/entity/entity.components.js.map +1 -0
  17. package/dist/entity/entity.d.ts +35 -0
  18. package/dist/entity/entity.identity.d.ts +8 -0
  19. package/dist/entity/entity.identity.js +15 -0
  20. package/dist/entity/entity.identity.js.map +1 -0
  21. package/dist/entity/entity.js +33 -0
  22. package/dist/entity/entity.js.map +1 -0
  23. package/dist/entity/entity.lifecycle.d.ts +12 -0
  24. package/dist/entity/entity.lifecycle.js +111 -0
  25. package/dist/entity/entity.lifecycle.js.map +1 -0
  26. package/dist/entity/entity.queries.d.ts +3 -0
  27. package/dist/entity/entity.queries.js +33 -0
  28. package/dist/entity/entity.queries.js.map +1 -0
  29. package/dist/entity/entity.relationships.d.ts +9 -0
  30. package/dist/entity/entity.relationships.js +74 -0
  31. package/dist/entity/entity.relationships.js.map +1 -0
  32. package/dist/entity/index.d.ts +2 -0
  33. package/dist/entity/index.js +3 -0
  34. package/dist/entity/index.js.map +1 -0
  35. package/dist/filter.d.ts +27 -8
  36. package/dist/filter.js +33 -18
  37. package/dist/filter.js.map +1 -1
  38. package/dist/index.d.ts +13 -5
  39. package/dist/index.js +12 -2
  40. package/dist/index.js.map +1 -1
  41. package/dist/inject.d.ts +80 -0
  42. package/dist/inject.js +270 -0
  43. package/dist/inject.js.map +1 -0
  44. package/dist/module.d.ts +23 -0
  45. package/dist/module.js +17 -0
  46. package/dist/module.js.map +1 -0
  47. package/dist/modules/identity.d.ts +15 -0
  48. package/dist/modules/identity.js +41 -0
  49. package/dist/modules/identity.js.map +1 -0
  50. package/dist/modules/singleton.d.ts +26 -0
  51. package/dist/modules/singleton.js +41 -0
  52. package/dist/modules/singleton.js.map +1 -0
  53. package/dist/package.json +12 -1
  54. package/dist/phase.d.ts +2 -2
  55. package/dist/query/index.d.ts +6 -0
  56. package/dist/query/index.js +5 -0
  57. package/dist/query/index.js.map +1 -0
  58. package/dist/query/query.00.base.d.ts +23 -0
  59. package/dist/query/query.00.base.js +77 -0
  60. package/dist/query/query.00.base.js.map +1 -0
  61. package/dist/query/query.01.reactive.d.ts +7 -0
  62. package/dist/query/query.01.reactive.js +58 -0
  63. package/dist/query/query.01.reactive.js.map +1 -0
  64. package/dist/query/query.02.lifecycle.d.ts +6 -0
  65. package/dist/query/query.02.lifecycle.js +63 -0
  66. package/dist/query/query.02.lifecycle.js.map +1 -0
  67. package/dist/query/query.03.tracking.d.ts +15 -0
  68. package/dist/query/query.03.tracking.js +31 -0
  69. package/dist/query/query.03.tracking.js.map +1 -0
  70. package/dist/query/query.04.callbacks.d.ts +14 -0
  71. package/dist/query/query.04.callbacks.js +65 -0
  72. package/dist/query/query.04.callbacks.js.map +1 -0
  73. package/dist/query/query.05.updates.d.ts +14 -0
  74. package/dist/query/query.05.updates.js +81 -0
  75. package/dist/query/query.05.updates.js.map +1 -0
  76. package/dist/query/query.06.predicate.d.ts +13 -0
  77. package/dist/query/query.06.predicate.js +40 -0
  78. package/dist/query/query.06.predicate.js.map +1 -0
  79. package/dist/query/query.07.groups.d.ts +41 -0
  80. package/dist/query/query.07.groups.js +110 -0
  81. package/dist/query/query.07.groups.js.map +1 -0
  82. package/dist/query/query.d.ts +53 -0
  83. package/dist/query/query.js +138 -0
  84. package/dist/query/query.js.map +1 -0
  85. package/dist/relationship.d.ts +19 -0
  86. package/dist/relationship.js +18 -0
  87. package/dist/relationship.js.map +1 -0
  88. package/dist/system.d.ts +37 -23
  89. package/dist/system.js +80 -64
  90. package/dist/system.js.map +1 -1
  91. package/dist/terms/all_term.d.ts +32 -0
  92. package/dist/terms/all_term.js +41 -0
  93. package/dist/terms/all_term.js.map +1 -0
  94. package/dist/terms/any_term.d.ts +33 -0
  95. package/dist/terms/any_term.js +42 -0
  96. package/dist/terms/any_term.js.map +1 -0
  97. package/dist/terms/build.d.ts +62 -0
  98. package/dist/terms/build.js +382 -0
  99. package/dist/terms/build.js.map +1 -0
  100. package/dist/terms/component_term.d.ts +37 -0
  101. package/dist/terms/component_term.js +49 -0
  102. package/dist/terms/component_term.js.map +1 -0
  103. package/dist/terms/empty_term.d.ts +6 -0
  104. package/dist/terms/empty_term.js +12 -0
  105. package/dist/terms/empty_term.js.map +1 -0
  106. package/dist/terms/index.d.ts +11 -0
  107. package/dist/terms/index.js +12 -0
  108. package/dist/terms/index.js.map +1 -0
  109. package/dist/terms/not_term.d.ts +35 -0
  110. package/dist/terms/not_term.js +47 -0
  111. package/dist/terms/not_term.js.map +1 -0
  112. package/dist/terms/only_term.d.ts +47 -0
  113. package/dist/terms/only_term.js +79 -0
  114. package/dist/terms/only_term.js.map +1 -0
  115. package/dist/terms/predicate_term.d.ts +80 -0
  116. package/dist/terms/predicate_term.js +109 -0
  117. package/dist/terms/predicate_term.js.map +1 -0
  118. package/dist/terms/target_term.d.ts +43 -0
  119. package/dist/terms/target_term.js +87 -0
  120. package/dist/terms/target_term.js.map +1 -0
  121. package/dist/terms/term.d.ts +94 -0
  122. package/dist/terms/term.js +202 -0
  123. package/dist/terms/term.js.map +1 -0
  124. package/dist/terms/world_term.d.ts +68 -0
  125. package/dist/terms/world_term.js +99 -0
  126. package/dist/terms/world_term.js.map +1 -0
  127. package/dist/timer.js +2 -2
  128. package/dist/timer.js.map +1 -1
  129. package/dist/util/array_map.js +12 -0
  130. package/dist/util/array_map.js.map +1 -1
  131. package/dist/util/bitset.js +107 -22
  132. package/dist/util/bitset.js.map +1 -1
  133. package/dist/util/dense_set.d.ts +1 -0
  134. package/dist/util/dense_set.js +90 -0
  135. package/dist/util/dense_set.js.map +1 -0
  136. package/dist/util/id_pool.d.ts +23 -0
  137. package/dist/util/id_pool.js +194 -0
  138. package/dist/util/id_pool.js.map +1 -0
  139. package/dist/world/index.d.ts +3 -0
  140. package/dist/world/index.js +3 -0
  141. package/dist/world/index.js.map +1 -0
  142. package/dist/world/world.base.d.ts +6 -0
  143. package/dist/world/world.base.js +21 -0
  144. package/dist/world/world.base.js.map +1 -0
  145. package/dist/world/world.components.d.ts +67 -0
  146. package/dist/world/world.components.js +93 -0
  147. package/dist/world/world.components.js.map +1 -0
  148. package/dist/world/world.d.ts +29 -0
  149. package/dist/world/world.deferred.d.ts +13 -0
  150. package/dist/world/world.deferred.js +93 -0
  151. package/dist/world/world.deferred.js.map +1 -0
  152. package/dist/world/world.entities.d.ts +18 -0
  153. package/dist/world/world.entities.js +97 -0
  154. package/dist/world/world.entities.js.map +1 -0
  155. package/dist/world/world.js +39 -0
  156. package/dist/world/world.js.map +1 -0
  157. package/dist/world/world.modules.d.ts +12 -0
  158. package/dist/world/world.modules.js +21 -0
  159. package/dist/world/world.modules.js.map +1 -0
  160. package/dist/world/world.pipeline.d.ts +21 -0
  161. package/dist/world/world.pipeline.js +105 -0
  162. package/dist/world/world.pipeline.js.map +1 -0
  163. package/dist/world/world.pools.d.ts +9 -0
  164. package/dist/world/world.pools.js +59 -0
  165. package/dist/world/world.pools.js.map +1 -0
  166. package/dist/world/world.queries.d.ts +18 -0
  167. package/dist/world/world.queries.js +101 -0
  168. package/dist/world/world.queries.js.map +1 -0
  169. package/dist/world/world.storage.d.ts +7 -0
  170. package/dist/world/world.storage.js +26 -0
  171. package/dist/world/world.storage.js.map +1 -0
  172. package/package.json +12 -1
  173. package/dist/entity.d.ts +0 -215
  174. package/dist/entity.js +0 -457
  175. package/dist/entity.js.map +0 -1
  176. package/dist/query.d.ts +0 -251
  177. package/dist/query.js +0 -353
  178. package/dist/query.js.map +0 -1
  179. package/dist/world.d.ts +0 -389
  180. package/dist/world.js +0 -631
  181. package/dist/world.js.map +0 -1
@@ -0,0 +1,53 @@
1
+ import { type ComponentType } from "../component.js";
2
+ import { type World } from "../world/index.js";
3
+ import { Group } from "./query.07.groups.js";
4
+ import { Groups } from "./query.07.groups.js";
5
+ /**
6
+ * A reactive, always-up-to-date set of entities matching a {@link QueryDSL}
7
+ * predicate.
8
+ *
9
+ * `Query` listens to entity / component mutations through the world's command
10
+ * queue and tracks which entities currently satisfy its predicate. It fires
11
+ * `enter`, `exit`, and `update` callbacks as the matched set changes. The
12
+ * tracked set is exposed via {@link count}, {@link has}, iteration, and
13
+ * {@link forEach}.
14
+ *
15
+ * Callbacks fire **synchronously** when the world routes a command — so
16
+ * mutations made inside one of these callbacks are themselves observed
17
+ * immediately by other queries / systems.
18
+ *
19
+ * {@link System} extends `Query` and queues callbacks into an inbox replayed
20
+ * during `_run` instead of firing them immediately. Use `Query` directly when
21
+ * you want a reactive entity set without pipeline integration.
22
+ *
23
+ * @typeParam R - Component classes guaranteed present on every matched entity
24
+ * (declared via {@link requires} or the `_guaranteed` hint of {@link query}).
25
+ * Components in `R` appear as non-nullable in {@link sort}, {@link forEach},
26
+ * and {@link update} callback tuples.
27
+ */
28
+ export declare class Query<R extends ComponentType[] = []> extends Groups<R> {
29
+ constructor(name: string, world: World, track?: boolean);
30
+ }
31
+ /**
32
+ * A {@link Query} that has been partitioned by {@link Query.groupBy}. Adds the
33
+ * typed group-accessor surface ({@link group}, {@link groups}, etc.) on top of
34
+ * the query's usual reactive membership.
35
+ *
36
+ * `GroupedQuery` lives in the query module alongside `Query`. Instances are
37
+ * created lazily by {@link Query.groupBy} via `Object.setPrototypeOf`.
38
+ *
39
+ * @typeParam K - The grouping key type produced by the key function (or the
40
+ * relationship target entity, for the relationship form).
41
+ * @typeParam R - Component classes guaranteed present on every matched entity.
42
+ */
43
+ export declare class GroupedQuery<K = unknown, R extends ComponentType[] = []> extends Query<R> {
44
+ private _grouping;
45
+ group(key: K): Group<K, R> | undefined;
46
+ groups(): IterableIterator<Group<K, R>>;
47
+ groupKeys(): IterableIterator<K>;
48
+ get groupCount(): number;
49
+ onGroupEnter(callback: (group: Group<K, R>) => void): this;
50
+ onGroupExit(callback: (key: K, group: Group<K, R>) => void): this;
51
+ private _composeGroupMembership;
52
+ destroy(): void;
53
+ }
@@ -0,0 +1,138 @@
1
+ import { _resolveRelationship } from "../dsl.js";
2
+ import { Entity } from "../entity/index.js";
3
+ import { directInjectEids, getInjected, injectArity, mapInject, } from "../inject.js";
4
+ import { _setGroupedQueryCtor } from "./query.00.base.js";
5
+ import { Grouping } from "./query.07.groups.js";
6
+ import { Groups } from "./query.07.groups.js";
7
+ /**
8
+ * A reactive, always-up-to-date set of entities matching a {@link QueryDSL}
9
+ * predicate.
10
+ *
11
+ * `Query` listens to entity / component mutations through the world's command
12
+ * queue and tracks which entities currently satisfy its predicate. It fires
13
+ * `enter`, `exit`, and `update` callbacks as the matched set changes. The
14
+ * tracked set is exposed via {@link count}, {@link has}, iteration, and
15
+ * {@link forEach}.
16
+ *
17
+ * Callbacks fire **synchronously** when the world routes a command — so
18
+ * mutations made inside one of these callbacks are themselves observed
19
+ * immediately by other queries / systems.
20
+ *
21
+ * {@link System} extends `Query` and queues callbacks into an inbox replayed
22
+ * during `_run` instead of firing them immediately. Use `Query` directly when
23
+ * you want a reactive entity set without pipeline integration.
24
+ *
25
+ * @typeParam R - Component classes guaranteed present on every matched entity
26
+ * (declared via {@link requires} or the `_guaranteed` hint of {@link query}).
27
+ * Components in `R` appear as non-nullable in {@link sort}, {@link forEach},
28
+ * and {@link update} callback tuples.
29
+ */
30
+ export class Query extends Groups {
31
+ constructor(name, world, track = true) {
32
+ super(name, world, Query, track);
33
+ }
34
+ }
35
+ const EMPTY_GROUPS = new Map();
36
+ /**
37
+ * A {@link Query} that has been partitioned by {@link Query.groupBy}. Adds the
38
+ * typed group-accessor surface ({@link group}, {@link groups}, etc.) on top of
39
+ * the query's usual reactive membership.
40
+ *
41
+ * `GroupedQuery` lives in the query module alongside `Query`. Instances are
42
+ * created lazily by {@link Query.groupBy} via `Object.setPrototypeOf`.
43
+ *
44
+ * @typeParam K - The grouping key type produced by the key function (or the
45
+ * relationship target entity, for the relationship form).
46
+ * @typeParam R - Component classes guaranteed present on every matched entity.
47
+ */
48
+ export class GroupedQuery extends Query {
49
+ /** @internal */
50
+ _initialize(arg0, arg1) {
51
+ if (this._grouping !== undefined) {
52
+ throw `query '${this.name}' is already grouped`;
53
+ }
54
+ let keyOf;
55
+ let watchEids;
56
+ if (typeof arg1 === "function") {
57
+ const components = arg0;
58
+ const inject = mapInject(this.world, components);
59
+ const arity = injectArity(inject);
60
+ const resolved = new Array(arity);
61
+ keyOf = (e) => {
62
+ getInjected(e, inject, false, resolved);
63
+ return arg1(e, resolved);
64
+ };
65
+ watchEids = directInjectEids(inject);
66
+ this._composeGroupMembership(components);
67
+ }
68
+ else {
69
+ const relEid = _resolveRelationship(arg0, this.world);
70
+ keyOf = (e) => e.parent(relEid);
71
+ watchEids = [relEid];
72
+ this._composeGroupMembership([arg0]);
73
+ }
74
+ for (const eid of watchEids) {
75
+ this._watchlistBitmask.add(eid);
76
+ }
77
+ this.track();
78
+ this._grouping = new Grouping(this.world, keyOf, watchEids);
79
+ return this;
80
+ }
81
+ /** @internal */
82
+ _enter(e) {
83
+ this._grouping.enter(e);
84
+ super._enter(e);
85
+ }
86
+ /** @internal */
87
+ _exit(e) {
88
+ super._exit(e);
89
+ this._grouping.exit(e);
90
+ }
91
+ /** @internal */
92
+ _notifyModified(e, meta, c) {
93
+ super._notifyModified(e, meta, c);
94
+ this._grouping.refresh(e, meta.eid);
95
+ }
96
+ /** @internal */
97
+ _watchesUpdates() {
98
+ return super._watchesUpdates() || true;
99
+ }
100
+ group(key) {
101
+ return this._grouping?.get(key);
102
+ }
103
+ groups() {
104
+ return (this._grouping?.groups.values() ?? EMPTY_GROUPS.values());
105
+ }
106
+ groupKeys() {
107
+ return (this._grouping?.keys() ?? EMPTY_GROUPS.keys());
108
+ }
109
+ get groupCount() {
110
+ return this._grouping?.groups.size ?? 0;
111
+ }
112
+ onGroupEnter(callback) {
113
+ this._assertConfigurable();
114
+ this._grouping?.setOnGroupEnter(callback);
115
+ return this;
116
+ }
117
+ onGroupExit(callback) {
118
+ this._assertConfigurable();
119
+ this._grouping?.setOnGroupExit(callback);
120
+ return this;
121
+ }
122
+ _composeGroupMembership(refs) {
123
+ const componentRefs = refs.filter((ref) => typeof ref === "number" || typeof ref === "function" || ref instanceof Entity);
124
+ if (componentRefs.length === 0) {
125
+ return;
126
+ }
127
+ const existing = this._dsl ?? true;
128
+ this._dsl = { all: [existing, ...componentRefs] };
129
+ this._hasExplicitQuery = true;
130
+ }
131
+ destroy() {
132
+ this._grouping?.clear();
133
+ this._grouping = undefined;
134
+ super.destroy();
135
+ }
136
+ }
137
+ _setGroupedQueryCtor(GroupedQuery);
138
+ //# sourceMappingURL=query.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"query.js","sourceRoot":"","sources":["../../src/query/query.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ import type { Entity } from "./entity/index.js";
2
+ /** Base class for relationship components that point at another entity. */
3
+ export declare abstract class Relationship {
4
+ target: Entity;
5
+ }
6
+ /** Built-in parent-child relationship. */
7
+ export declare class ChildOf extends Relationship {
8
+ }
9
+ /**
10
+ * Built-in relationship marking a feedback **silence domain** for a query
11
+ * or system.
12
+ *
13
+ * When a query carries a `SilenceSource` pointing at a query entity, it
14
+ * ignores `update` notifications whose originating entity (the system
15
+ * that wrote the component) is a member of that query. Configure it through
16
+ * {@link Query.ignoreSource}.
17
+ */
18
+ export declare class SilenceSource extends Relationship {
19
+ }
@@ -0,0 +1,18 @@
1
+ /** Base class for relationship components that point at another entity. */
2
+ export class Relationship {
3
+ }
4
+ /** Built-in parent-child relationship. */
5
+ export class ChildOf extends Relationship {
6
+ }
7
+ /**
8
+ * Built-in relationship marking a feedback **silence domain** for a query
9
+ * or system.
10
+ *
11
+ * When a query carries a `SilenceSource` pointing at a query entity, it
12
+ * ignores `update` notifications whose originating entity (the system
13
+ * that wrote the component) is a member of that query. Configure it through
14
+ * {@link Query.ignoreSource}.
15
+ */
16
+ export class SilenceSource extends Relationship {
17
+ }
18
+ //# sourceMappingURL=relationship.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"relationship.js","sourceRoot":"","sources":["../src/relationship.ts"],"names":[],"mappings":"AAEA,2EAA2E;AAC3E,MAAM,OAAgB,YAAY;CAEjC;AAED,0CAA0C;AAC1C,MAAM,OAAO,OAAQ,SAAQ,YAAY;CAAG;AAE5C;;;;;;;;GAQG;AACH,MAAM,OAAO,aAAc,SAAQ,YAAY;CAAG"}
package/dist/system.d.ts CHANGED
@@ -1,9 +1,10 @@
1
- import { type ComponentClass } from "./component.js";
2
- import { Query } from "./query.js";
3
- import { type QueryDSL, type MaybeRequired } from "./dsl.js";
4
- import type { Entity } from "./entity.js";
1
+ import { type ComponentType } from "./component.js";
2
+ import { Iter, type FanInjectTuple, type MaybeResolvedInjectTuple } from "./inject.js";
3
+ import { Query } from "./query/index.js";
4
+ import { type QueryDSL } from "./dsl.js";
5
+ import { Entity } from "./entity/index.js";
5
6
  import { type IPhase } from "./phase.js";
6
- import { type World } from "./world.js";
7
+ import { type World } from "./world/index.js";
7
8
  import { type ITickSource } from "./timer.js";
8
9
  export type { QueryDSL as SystemQuery, EntityTestFunc } from "./dsl.js";
9
10
  type RunCallback = (now: number, delta: number) => void;
@@ -34,8 +35,7 @@ type RunCallback = (now: number, delta: number) => void;
34
35
  *
35
36
  * `enter`, `exit`, `update`, `each`, and `sort` accept an array of component
36
37
  * classes resolved from the entity and passed as a typed tuple to the
37
- * callback. Use `{ parent: SomeComponent }` to resolve from the entity's
38
- * parent instead of the entity itself.
38
+ * callback.
39
39
  *
40
40
  * Components declared via {@link requires} (or the `_guaranteed` argument of
41
41
  * {@link query}) are tracked as the type parameter `R`. Inside `sort`,
@@ -44,7 +44,7 @@ type RunCallback = (now: number, delta: number) => void;
44
44
  *
45
45
  * @typeParam R - Component classes guaranteed present on every matched entity.
46
46
  */
47
- export declare class System<R extends ComponentClass[] = []> extends Query<R> implements ITickSource {
47
+ export declare class System<R extends ComponentType[] = []> extends Query<R> implements ITickSource {
48
48
  constructor(name: string, world: World);
49
49
  /** True when this system's cadence source fired during the current frame. */
50
50
  get didTick(): boolean;
@@ -151,11 +151,16 @@ export declare class System<R extends ComponentClass[] = []> extends Query<R> im
151
151
  *
152
152
  * `each` does **not** modify the system's query — define membership with
153
153
  * {@link requires} or {@link query} as usual. It does, however, implicitly
154
- * enable {@link track}, so matched entities are exposed via {@link entities}.
154
+ * enable {@link track}, so matched entities are exposed via {@link count},
155
+ * {@link has}, iteration, and {@link forEach}.
155
156
  *
156
157
  * Only one `each` callback may be registered per system; calling `each` a
157
158
  * second time throws.
158
159
  *
160
+ * The resolved tuple is a single array reused for every entity each tick;
161
+ * treat it as valid only for the duration of the callback. The component
162
+ * instances it holds are stable — do not retain the tuple array itself.
163
+ *
159
164
  * @param components - Component classes to resolve from each entity.
160
165
  * @param callback - Receives the entity and a tuple of resolved component
161
166
  * instances (`undefined` for any not covered by {@link requires}).
@@ -172,9 +177,20 @@ export declare class System<R extends ComponentClass[] = []> extends Query<R> im
172
177
  * });
173
178
  * ```
174
179
  */
175
- each<J extends ComponentClass[]>(components: readonly [...J], callback: (e: Entity, resolved: {
176
- [K in keyof J]: MaybeRequired<J[K], R>;
177
- }) => void): this;
180
+ each<J extends FanInjectTuple>(components: readonly [...J], callback: (e: Entity, resolved: MaybeResolvedInjectTuple<J, R>) => void): this;
181
+ /**
182
+ * As above, but pass `Entity` first to make the entity-first signature
183
+ * explicit. Identical behavior to the no-marker form.
184
+ */
185
+ each<J extends FanInjectTuple>(cursor: typeof Entity, components: readonly [...J], callback: (e: Entity, resolved: MaybeResolvedInjectTuple<J, R>) => void): this;
186
+ /**
187
+ * As above, but pass `Iter` first to receive a reused {@link Iter}
188
+ * cursor instead of the bare entity. The cursor exposes the visited entity
189
+ * (`it.entity`) and, in `it.src`, the source entity each resolved component
190
+ * was read from (the visited entity for direct components, the relationship
191
+ * target for `up`-injected ones).
192
+ */
193
+ each<J extends FanInjectTuple>(cursor: typeof Iter, components: readonly [...J], callback: (it: Iter, resolved: MaybeResolvedInjectTuple<J, R>) => void): this;
178
194
  /**
179
195
  * Set the entity-membership predicate using a {@link QueryDSL} expression.
180
196
  *
@@ -190,19 +206,23 @@ export declare class System<R extends ComponentClass[] = []> extends Query<R> im
190
206
  * entity (type hint only — not validated at runtime).
191
207
  * @returns This system, retyped with the guaranteed tuple as its `R`.
192
208
  */
193
- query<T extends ComponentClass[] = []>(q: QueryDSL, _guaranteed?: readonly [...T]): System<T>;
209
+ query<T extends ComponentType[] = []>(q: QueryDSL, _guaranteed?: readonly [...T]): System<T>;
194
210
  /**
195
211
  * Shorthand for `query([...components])` — tracks entities that have **all**
196
212
  * of the listed component types.
197
213
  *
198
- * Equivalent to `query({ HAS: components })`. The listed components are also
214
+ * Equivalent to `query(components)`. The listed components are also
199
215
  * recorded in the type parameter `R`, so {@link sort}, {@link each}, and
200
216
  * {@link update} callbacks treat them as non-nullable.
201
217
  *
202
218
  * @param components - Component classes to require.
203
219
  * @returns This system, retyped with the required tuple as its `R`.
204
220
  */
205
- requires<T extends ComponentClass[]>(...components: [...T]): System<T>;
221
+ requires<T extends ComponentType[]>(...components: [...T]): System<T>;
222
+ /**
223
+ * Systems cannot use groupBy. Use `world.query(...).groupBy(...)` instead.
224
+ */
225
+ groupBy(..._args: any[]): never;
206
226
  /**
207
227
  * Disable this system.
208
228
  *
@@ -245,12 +265,6 @@ export declare class System<R extends ComponentClass[] = []> extends Query<R> im
245
265
  * @returns This system, for chaining.
246
266
  */
247
267
  enable(): this;
248
- /**
249
- * Not supported on `System`. Throws unconditionally.
250
- *
251
- * Systems are owned by the world for the duration of the session; if you
252
- * need a temporary reactive set use a standalone {@link Query} via
253
- * {@link World.query}.
254
- */
255
- destroy(): never;
268
+ /** Permanently remove this system from the world. */
269
+ destroy(): void;
256
270
  }
package/dist/system.js CHANGED
@@ -1,4 +1,6 @@
1
- import { Query } from "./query.js";
1
+ import { isCursorMarker, makeInjectedInvoker, wantsIter, } from "./inject.js";
2
+ import { SOURCE_TRACKED_QUERY_ERROR, Query } from "./query/index.js";
3
+ import { containsDownTerm } from "./dsl.js";
2
4
  import { Phase } from "./phase.js";
3
5
  import { ALWAYS_TICK_SOURCE, IntervalTickSource, RateTickSource, } from "./timer.js";
4
6
  /**
@@ -28,8 +30,7 @@ import { ALWAYS_TICK_SOURCE, IntervalTickSource, RateTickSource, } from "./timer
28
30
  *
29
31
  * `enter`, `exit`, `update`, `each`, and `sort` accept an array of component
30
32
  * classes resolved from the entity and passed as a typed tuple to the
31
- * callback. Use `{ parent: SomeComponent }` to resolve from the entity's
32
- * parent instead of the entity itself.
33
+ * callback.
33
34
  *
34
35
  * Components declared via {@link requires} (or the `_guaranteed` argument of
35
36
  * {@link query}) are tracked as the type parameter `R`. Inside `sort`,
@@ -47,12 +48,28 @@ export class System extends Query {
47
48
  this._enabled = true;
48
49
  /** @internal Cadence source for this system. Defaults to every frame. */
49
50
  this._tickSource = ALWAYS_TICK_SOURCE;
51
+ this.entity.attach(System, this);
52
+ }
53
+ /** @internal Reject non-reactive source/children terms before registering this system. */
54
+ _build() {
55
+ if (this._dsl !== undefined && containsDownTerm(this._dsl)) {
56
+ this.destroy();
57
+ throw new Error(SOURCE_TRACKED_QUERY_ERROR);
58
+ }
59
+ return super._build();
60
+ }
61
+ /** @internal Systems may be run-only processors without entity membership. */
62
+ _isBuildable() {
63
+ return true;
50
64
  }
51
65
  /**
52
66
  * @internal Routing entry: register query membership for `e`, push an
53
67
  * inbox `enter` event when an `enter` callback is registered, and bridge
54
68
  * watched components through {@link _notifyModified} to surface them as
55
69
  * inbox `update` events on entry.
70
+ *
71
+ * Target relationship reactivity is handled by `TargetTerm`; systems only
72
+ * translate root-term membership events into inbox commands here.
56
73
  */
57
74
  _enter(e) {
58
75
  this._entities?.add(e);
@@ -63,10 +80,12 @@ export class System extends Query {
63
80
  if (this._enterCallback !== undefined) {
64
81
  this._inbox.push({ kind: 0 /* InboxCommand.Enter */, entity: e });
65
82
  }
66
- e.components.forEach((c, type) => {
67
- const meta = this.world.getComponentMeta(type);
83
+ e.components.forEach((c, eid) => {
84
+ const meta = this.world.entity(eid).ownMeta;
68
85
  if (this._watchlistBitmask.hasBit(meta.bitPtr)) {
69
- this._notifyModified(e, meta, c);
86
+ // Entry-time initialization bypasses the silence filter: an entity
87
+ // introduced by an ignored source must still initialize in this system.
88
+ this._pushUpdate(e, meta, c);
70
89
  }
71
90
  });
72
91
  }
@@ -86,10 +105,10 @@ export class System extends Query {
86
105
  let snapshot;
87
106
  if (this._exitSnapshotTypes && this._exitSnapshotTypes.length > 0) {
88
107
  snapshot = new Map();
89
- for (const type of this._exitSnapshotTypes) {
90
- const c = e._get(type);
108
+ for (const eid of this._exitSnapshotTypes) {
109
+ const c = e._get(eid);
91
110
  if (c) {
92
- snapshot.set(type, c);
111
+ snapshot.set(eid, c);
93
112
  }
94
113
  }
95
114
  }
@@ -98,12 +117,22 @@ export class System extends Query {
98
117
  }
99
118
  /**
100
119
  * @internal Routing entry: push an inbox `update` event when the modified
101
- * component matches the watchlist.
120
+ * component matches the watchlist and its source is not silenced.
102
121
  */
103
122
  _notifyModified(e, meta, c) {
104
- if (!this._enabled || !this._watchlistBitmask.hasBit(meta.bitPtr)) {
123
+ if (!this._watchlistBitmask.hasBit(meta.bitPtr)) {
124
+ return;
125
+ }
126
+ if (!this._enabled) {
127
+ return;
128
+ }
129
+ if (this._isSourceSilenced()) {
105
130
  return;
106
131
  }
132
+ this._pushUpdate(e, meta, c);
133
+ }
134
+ /** @internal Append an `update` event to the inbox, bypassing the silence filter. */
135
+ _pushUpdate(e, meta, c) {
107
136
  this._inbox.push({ kind: 2 /* InboxCommand.Update */, entity: e, meta, component: c });
108
137
  }
109
138
  /**
@@ -121,6 +150,20 @@ export class System extends Query {
121
150
  return;
122
151
  }
123
152
  const tickDelta = this._tickSource.lastFireDelta;
153
+ const prevSource = this.world._currentSource;
154
+ this.world._currentSource = this.entity;
155
+ try {
156
+ this._runDeferred(now, tickDelta);
157
+ }
158
+ finally {
159
+ this.world._currentSource = prevSource;
160
+ }
161
+ }
162
+ /**
163
+ * @internal Drain the inbox and fire callbacks inside a deferred scope, with
164
+ * this system credited as the source of any mutations made by callbacks.
165
+ */
166
+ _runDeferred(now, tickDelta) {
124
167
  this.world.defer(() => {
125
168
  for (let i = 0; i < this._inbox.length; i++) {
126
169
  const event = this._inbox[i];
@@ -132,7 +175,7 @@ export class System extends Query {
132
175
  this._exitCallback(event.entity, event.snapshot);
133
176
  break;
134
177
  case 2 /* InboxCommand.Update */:
135
- const callback = this._componentUpdateCallbacks.get(event.meta.type);
178
+ const callback = this._componentUpdateCallbacks.get(event.meta.eid);
136
179
  if (callback) {
137
180
  callback(event.entity, event.component);
138
181
  }
@@ -144,8 +187,7 @@ export class System extends Query {
144
187
  this._runCallback(now, tickDelta);
145
188
  }
146
189
  if (this._eachCallback) {
147
- const cb = this._eachCallback;
148
- this.forEach((e) => cb(e));
190
+ this.forEach(this._eachCallback);
149
191
  }
150
192
  });
151
193
  }
@@ -187,10 +229,12 @@ export class System extends Query {
187
229
  * ```
188
230
  */
189
231
  interval(seconds) {
232
+ this._assertConfigurable();
190
233
  this._setTickSource(new IntervalTickSource(seconds));
191
234
  return this;
192
235
  }
193
236
  rate(n, source) {
237
+ this._assertConfigurable();
194
238
  this._setTickSource(new RateTickSource(n, source ?? this._tickSource));
195
239
  return this;
196
240
  }
@@ -212,6 +256,7 @@ export class System extends Query {
212
256
  * ```
213
257
  */
214
258
  tickSource(source) {
259
+ this._assertConfigurable();
215
260
  this._setTickSource(source);
216
261
  return this;
217
262
  }
@@ -232,12 +277,13 @@ export class System extends Query {
232
277
  * different world.
233
278
  */
234
279
  phase(p) {
280
+ this._assertConfigurable();
235
281
  if (typeof p !== "string") {
236
282
  if (!(p instanceof Phase)) {
237
- throw "Invalid Phase object";
283
+ throw new Error("Invalid Phase object");
238
284
  }
239
285
  if (p.world !== this.world) {
240
- throw "Phase does not belong to this system's world";
286
+ throw new Error("Phase does not belong to this system's world");
241
287
  }
242
288
  }
243
289
  this._phase = p;
@@ -257,51 +303,20 @@ export class System extends Query {
257
303
  * @returns This system, for chaining.
258
304
  */
259
305
  run(callback) {
306
+ this._assertConfigurable();
260
307
  this._runCallback = callback;
261
308
  return this;
262
309
  }
263
- /**
264
- * Register a callback fired **every tick** for **every tracked entity**,
265
- * unconditionally, with the listed components resolved from each entity.
266
- *
267
- * Unlike {@link update} (which only fires when `entity.modified(C)` is
268
- * called), `each` fires every tick the system runs, once per tracked entity.
269
- * Components declared via {@link requires} are non-nullable in the resolved
270
- * tuple; any other component class may be `undefined` if the entity lacks it.
271
- *
272
- * `each` does **not** modify the system's query — define membership with
273
- * {@link requires} or {@link query} as usual. It does, however, implicitly
274
- * enable {@link track}, so matched entities are exposed via {@link entities}.
275
- *
276
- * Only one `each` callback may be registered per system; calling `each` a
277
- * second time throws.
278
- *
279
- * @param components - Component classes to resolve from each entity.
280
- * @param callback - Receives the entity and a tuple of resolved component
281
- * instances (`undefined` for any not covered by {@link requires}).
282
- * @returns This system, for chaining.
283
- * @throws When `each` has already been registered on this system.
284
- *
285
- * @example
286
- * ```ts
287
- * world.system("Move")
288
- * .requires(Position, Velocity)
289
- * .each([Position, Velocity], (e, [pos, vel]) => {
290
- * pos.x += vel.vx;
291
- * pos.y += vel.vy;
292
- * });
293
- * ```
294
- */
295
- each(components, callback) {
310
+ each(arg0, arg1, arg2) {
311
+ this._assertConfigurable();
296
312
  if (this._eachCallback) {
297
- throw `each already registered for system '${this.name}'`;
313
+ throw new Error(`each already registered for system '${this.name}'`);
298
314
  }
299
315
  this.track();
300
- const types = components.map((C) => this.world.getComponentType(C));
301
- this._eachCallback = (e) => {
302
- const resolved = types.map((t) => e.get(t));
303
- callback(e, resolved);
304
- };
316
+ const useIter = wantsIter(arg0);
317
+ const components = (isCursorMarker(arg0) ? arg1 : arg0);
318
+ const callback = (isCursorMarker(arg0) ? arg2 : arg1);
319
+ this._eachCallback = makeInjectedInvoker(this.world, components, useIter, callback);
305
320
  return this;
306
321
  }
307
322
  /**
@@ -327,7 +342,7 @@ export class System extends Query {
327
342
  * Shorthand for `query([...components])` — tracks entities that have **all**
328
343
  * of the listed component types.
329
344
  *
330
- * Equivalent to `query({ HAS: components })`. The listed components are also
345
+ * Equivalent to `query(components)`. The listed components are also
331
346
  * recorded in the type parameter `R`, so {@link sort}, {@link each}, and
332
347
  * {@link update} callbacks treat them as non-nullable.
333
348
  *
@@ -338,6 +353,12 @@ export class System extends Query {
338
353
  super.requires(...components);
339
354
  return this;
340
355
  }
356
+ /**
357
+ * Systems cannot use groupBy. Use `world.query(...).groupBy(...)` instead.
358
+ */
359
+ groupBy(..._args) {
360
+ throw new Error("System does not support groupBy; use world.query(...).groupBy(...)");
361
+ }
341
362
  /**
342
363
  * Disable this system.
343
364
  *
@@ -387,15 +408,10 @@ export class System extends Query {
387
408
  this._enabled = true;
388
409
  return this;
389
410
  }
390
- /**
391
- * Not supported on `System`. Throws unconditionally.
392
- *
393
- * Systems are owned by the world for the duration of the session; if you
394
- * need a temporary reactive set use a standalone {@link Query} via
395
- * {@link World.query}.
396
- */
411
+ /** Permanently remove this system from the world. */
397
412
  destroy() {
398
- throw `destroy() is not supported on System '${this.name}'`;
413
+ this.disable();
414
+ super.destroy();
399
415
  }
400
416
  }
401
417
  //# sourceMappingURL=system.js.map