@vworlds/vecs 1.0.53 → 1.0.55
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -0
- package/dist/entity/entity.components.js +4 -2
- package/dist/entity/entity.components.js.map +1 -1
- package/dist/entity/entity.lifecycle.d.ts +2 -0
- package/dist/entity/entity.lifecycle.js +9 -4
- package/dist/entity/entity.lifecycle.js.map +1 -1
- package/dist/geometry.d.ts +5 -0
- package/dist/geometry.js +2 -0
- package/dist/geometry.js.map +1 -0
- package/dist/index.d.ts +3 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/package.json +1 -1
- package/dist/system.d.ts +10 -0
- package/dist/system.js +19 -2
- package/dist/system.js.map +1 -1
- package/dist/timer.d.ts +15 -1
- package/dist/timer.js +24 -4
- package/dist/timer.js.map +1 -1
- package/dist/world/destroy-order.d.ts +8 -0
- package/dist/world/destroy-order.js +60 -0
- package/dist/world/destroy-order.js.map +1 -0
- package/dist/world/stats.d.ts +51 -0
- package/dist/world/stats.js +88 -0
- package/dist/world/stats.js.map +1 -0
- package/dist/world/world.base.js +2 -0
- package/dist/world/world.base.js.map +1 -1
- package/dist/world/world.components.d.ts +2 -0
- package/dist/world/world.components.js +4 -0
- package/dist/world/world.components.js.map +1 -1
- package/dist/world/world.disposal.d.ts +34 -36
- package/dist/world/world.disposal.js +89 -94
- package/dist/world/world.disposal.js.map +1 -1
- package/dist/world/world.entities.d.ts +21 -1
- package/dist/world/world.entities.js +54 -7
- package/dist/world/world.entities.js.map +1 -1
- package/dist/world/world.js +17 -11
- package/dist/world/world.js.map +1 -1
- package/dist/world/world.modules.d.ts +8 -0
- package/dist/world/world.modules.js +22 -1
- package/dist/world/world.modules.js.map +1 -1
- package/dist/world/world.pipeline.d.ts +15 -1
- package/dist/world/world.pipeline.js +40 -4
- package/dist/world/world.pipeline.js.map +1 -1
- package/docs/README.md +21 -19
- package/docs/components.md +9 -0
- package/docs/concepts.md +4 -0
- package/docs/design-guide.md +7 -3
- package/docs/entities.md +36 -25
- package/docs/glossary.md +3 -3
- package/docs/modules.md +62 -0
- package/docs/systems.md +108 -2
- package/package.json +1 -1
- package/tsconfig.types.json +6 -1
|
@@ -1,7 +1,14 @@
|
|
|
1
1
|
import { Entity, Identity } from "../entity/index.js";
|
|
2
2
|
import { Deferred } from "./world.deferred.js";
|
|
3
|
+
import { carriersFirst } from "./destroy-order.js";
|
|
4
|
+
import { ChildOf } from "../modules/relationship_types.js";
|
|
3
5
|
const RESERVED_EID = 0;
|
|
4
6
|
export class Entities extends Deferred {
|
|
7
|
+
constructor() {
|
|
8
|
+
super(...arguments);
|
|
9
|
+
/** @internal Parent applied only to entities created in the current scope. */
|
|
10
|
+
this._scope = undefined;
|
|
11
|
+
}
|
|
5
12
|
/**
|
|
6
13
|
* Return the entity with id `eid`, creating it if it does not yet exist.
|
|
7
14
|
*
|
|
@@ -30,6 +37,10 @@ export class Entities extends Deferred {
|
|
|
30
37
|
}
|
|
31
38
|
else {
|
|
32
39
|
this._entities.set(eid, e);
|
|
40
|
+
const parent = this._scope;
|
|
41
|
+
if (parent !== undefined) {
|
|
42
|
+
e.childOf(parent);
|
|
43
|
+
}
|
|
33
44
|
this._notifyEntityCreated(e);
|
|
34
45
|
onCreateCallback?.(e);
|
|
35
46
|
}
|
|
@@ -92,26 +103,58 @@ export class Entities extends Deferred {
|
|
|
92
103
|
}
|
|
93
104
|
throw new Error(`No entity with eid ${ref.eid}`);
|
|
94
105
|
}
|
|
95
|
-
/**
|
|
106
|
+
/**
|
|
107
|
+
* Destroy every tracked entity, ordering both carriers and ChildOf children
|
|
108
|
+
* before their keys/parents. Retains ordinary cleanup policies; throws when
|
|
109
|
+
* dependency cycles prevent safe destruction (unlike dispose's final pass).
|
|
110
|
+
*/
|
|
96
111
|
clearAllEntities() {
|
|
97
112
|
const pending = new Set(this._entities.values());
|
|
98
113
|
while (pending.size > 0) {
|
|
99
114
|
let destroyed = 0;
|
|
100
|
-
for (const entity of [...pending]) {
|
|
101
|
-
const instanceCount = entity.instanceCount();
|
|
102
|
-
if (instanceCount > (entity._get(entity.eid) ? 1 : 0)) {
|
|
103
|
-
continue;
|
|
104
|
-
}
|
|
115
|
+
for (const entity of carriersFirst([...pending], this._classRegistry.get(ChildOf)?.eid)) {
|
|
105
116
|
entity.destroy();
|
|
106
117
|
pending.delete(entity);
|
|
107
118
|
destroyed++;
|
|
108
119
|
}
|
|
109
120
|
if (destroyed === 0) {
|
|
110
|
-
throw new Error("Cannot clear entities because component
|
|
121
|
+
throw new Error("Cannot clear entities because component or ChildOf dependencies cannot be ordered");
|
|
111
122
|
}
|
|
112
123
|
}
|
|
113
124
|
this.flush();
|
|
114
125
|
}
|
|
126
|
+
/**
|
|
127
|
+
* Parent entities created synchronously in `fn`'s body to `parent` through ChildOf.
|
|
128
|
+
* Includes components, modules, queries, systems and ordinary entities. Existing
|
|
129
|
+
* lookups are not reparented; an explicit childOf call replaces the scope parent.
|
|
130
|
+
* Nested scopes restore their caller in finally, even when fn throws.
|
|
131
|
+
* Entities created by deferred callbacks inside the body are not parented:
|
|
132
|
+
* query.forEach, enter backfill during query build, or an explicit world.defer.
|
|
133
|
+
* These are run-time data; the same callback outside the scope would not parent
|
|
134
|
+
* them either. For example, health bars created per existing ship by an enter
|
|
135
|
+
* or forEach callback remain roots, unlike definitions created directly in init.
|
|
136
|
+
* Throws while deferred: call outside progress() and defer, not during a command
|
|
137
|
+
* drain. Schedule lazy module loading after progress() returns.
|
|
138
|
+
* The parent must be a live entity of this world. This is a synchronous scope,
|
|
139
|
+
* not an async context; it does not change deferral or catch callback errors.
|
|
140
|
+
*/
|
|
141
|
+
scope(parent, fn) {
|
|
142
|
+
if (this.deferred) {
|
|
143
|
+
throw new Error("Call world.scope() outside progress() and defer");
|
|
144
|
+
}
|
|
145
|
+
this.entity(parent);
|
|
146
|
+
if (parent.destroyed) {
|
|
147
|
+
throw new Error("scope parent must be alive");
|
|
148
|
+
}
|
|
149
|
+
const previous = this._scope;
|
|
150
|
+
this._scope = parent;
|
|
151
|
+
try {
|
|
152
|
+
fn();
|
|
153
|
+
}
|
|
154
|
+
finally {
|
|
155
|
+
this._scope = previous;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
115
158
|
/** @internal Create an entity with an id from the entity pool. */
|
|
116
159
|
_entity(Constructor) {
|
|
117
160
|
const eid = this._entityPool.alloc();
|
|
@@ -122,6 +165,10 @@ export class Entities extends Deferred {
|
|
|
122
165
|
}
|
|
123
166
|
else {
|
|
124
167
|
this._entities.set(eid, e);
|
|
168
|
+
const parent = this._scope;
|
|
169
|
+
if (parent !== undefined) {
|
|
170
|
+
e.childOf(parent);
|
|
171
|
+
}
|
|
125
172
|
this._notifyEntityCreated(e);
|
|
126
173
|
}
|
|
127
174
|
return e;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"world.entities.js","sourceRoot":"","sources":["../../src/world/world.entities.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,MAAM,EAAE,QAAQ,EAA8B,MAAM,oBAAoB,CAAC;AAClF,OAAO,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"world.entities.js","sourceRoot":"","sources":["../../src/world/world.entities.ts"],"names":[],"mappings":"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"}
|
package/dist/world/world.js
CHANGED
|
@@ -44,17 +44,23 @@ export class World extends Pipeline {
|
|
|
44
44
|
this.component(SilenceSource).on("remove", (entity) => entity.get(Query)?._clearSilence());
|
|
45
45
|
this.component(Query).on("remove", (_entity, query) => query.destroy());
|
|
46
46
|
this.component(System).on("remove", (_entity, system) => system.destroy());
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
47
|
+
this._initializingModules = true;
|
|
48
|
+
try {
|
|
49
|
+
[
|
|
50
|
+
IdentityModule,
|
|
51
|
+
ImplementsModule,
|
|
52
|
+
SingletonModule,
|
|
53
|
+
RelationshipsModule,
|
|
54
|
+
// Registration order is not load-bearing: a capture binds the materializer
|
|
55
|
+
// its policy resolved to, so `SnapshotModule` may install or change a
|
|
56
|
+
// policy after entities already carry the component.
|
|
57
|
+
SnapshotModule,
|
|
58
|
+
PipelineModule,
|
|
59
|
+
].forEach((mod) => this.module(mod));
|
|
60
|
+
}
|
|
61
|
+
finally {
|
|
62
|
+
this._initializingModules = false;
|
|
63
|
+
}
|
|
58
64
|
}
|
|
59
65
|
}
|
|
60
66
|
//# sourceMappingURL=world.js.map
|
package/dist/world/world.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"world.js","sourceRoot":"","sources":["../../src/world/world.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAC5D,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AACxD,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAC5D,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AACxD,OAAO,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AAClE,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAC1D,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AACxD,OAAO,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAC1C,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AACtC,OAAO,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAG/C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,MAAM,OAAO,KAAM,SAAQ,QAAQ;IACjC,YAAmB,UAAwB,EAAE;QAC3C,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,SAAS,CAAC,aAAa,CAAC,CAAC,EAAE,CAAC,QAAQ,EAAE,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,aAAa,EAAE,CAAC,CAAC;QAC3F,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,QAAQ,EAAE,CAAC,OAAO,EAAE,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;QACxE,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,QAAQ,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC;QAC3E;
|
|
1
|
+
{"version":3,"file":"world.js","sourceRoot":"","sources":["../../src/world/world.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAC5D,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AACxD,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAC5D,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AACxD,OAAO,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AAClE,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAC1D,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AACxD,OAAO,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAC1C,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AACtC,OAAO,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAG/C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,MAAM,OAAO,KAAM,SAAQ,QAAQ;IACjC,YAAmB,UAAwB,EAAE;QAC3C,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,SAAS,CAAC,aAAa,CAAC,CAAC,EAAE,CAAC,QAAQ,EAAE,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,aAAa,EAAE,CAAC,CAAC;QAC3F,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,QAAQ,EAAE,CAAC,OAAO,EAAE,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;QACxE,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,QAAQ,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC;QAC3E,IAAI,CAAC,oBAAoB,GAAG,IAAI,CAAC;QACjC,IAAI,CAAC;YACH;gBACE,cAAc;gBACd,gBAAgB;gBAChB,eAAe;gBACf,mBAAmB;gBACnB,2EAA2E;gBAC3E,sEAAsE;gBACtE,qDAAqD;gBACrD,cAAc;gBACd,cAAc;aACf,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;QACvC,CAAC;gBAAS,CAAC;YACT,IAAI,CAAC,oBAAoB,GAAG,KAAK,CAAC;QACpC,CAAC;IACH,CAAC;CACF"}
|
|
@@ -4,6 +4,14 @@ import { Components } from "./world.components.js";
|
|
|
4
4
|
import type { World } from "./world.js";
|
|
5
5
|
type ModuleArgs<T extends Module<any>> = undefined extends ModuleConfig<T> ? [eid?: EID] | [config: Exclude<ModuleConfig<T>, undefined>, eid?: EID] : [config: ModuleConfig<T>, eid?: EID];
|
|
6
6
|
export declare class Modules extends Components {
|
|
7
|
+
/**
|
|
8
|
+
* Install a module once and run its synchronous init inside its entity scope.
|
|
9
|
+
* Constructor-installed core modules are unscoped; later modules parent all
|
|
10
|
+
* newly created entities, including nested modules. Existing entities stay put.
|
|
11
|
+
* Subsequent calls return the existing instance; passing config again throws.
|
|
12
|
+
* New installations throw while deferred; call outside progress() and defer.
|
|
13
|
+
* Existing-instance lookups remain available while deferred.
|
|
14
|
+
*/
|
|
7
15
|
module<T extends Module<any>>(this: World, ModuleClass: EntityClass<T>, ...args: ModuleArgs<T>): T;
|
|
8
16
|
}
|
|
9
17
|
export {};
|
|
@@ -1,15 +1,36 @@
|
|
|
1
1
|
import { Components } from "./world.components.js";
|
|
2
2
|
export class Modules extends Components {
|
|
3
|
+
constructor() {
|
|
4
|
+
super(...arguments);
|
|
5
|
+
/** @internal Constructor-installed core modules predate scoped ChildOf support. */
|
|
6
|
+
this._initializingModules = false;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Install a module once and run its synchronous init inside its entity scope.
|
|
10
|
+
* Constructor-installed core modules are unscoped; later modules parent all
|
|
11
|
+
* newly created entities, including nested modules. Existing entities stay put.
|
|
12
|
+
* Subsequent calls return the existing instance; passing config again throws.
|
|
13
|
+
* New installations throw while deferred; call outside progress() and defer.
|
|
14
|
+
* Existing-instance lookups remain available while deferred.
|
|
15
|
+
*/
|
|
3
16
|
module(ModuleClass, ...args) {
|
|
4
17
|
const { config, eid } = resolveModuleArgs(args);
|
|
5
18
|
const ComponentClass = ModuleClass;
|
|
6
19
|
const isNew = !this._classRegistry.has(ComponentClass);
|
|
20
|
+
if (isNew && this.deferred) {
|
|
21
|
+
throw new Error("Call world.module() outside progress() and defer to install a new module");
|
|
22
|
+
}
|
|
7
23
|
const mod = this._component(ModuleClass, ComponentClass, eid, this._modulePool);
|
|
8
24
|
if (!isNew && config !== undefined) {
|
|
9
25
|
throw new Error(`Module ${ModuleClass.name} is already registered; configuration is only accepted on first registration`);
|
|
10
26
|
}
|
|
11
27
|
if (isNew) {
|
|
12
|
-
|
|
28
|
+
if (this._initializingModules) {
|
|
29
|
+
mod.init(config);
|
|
30
|
+
}
|
|
31
|
+
else {
|
|
32
|
+
this.scope(mod, () => mod.init(config));
|
|
33
|
+
}
|
|
13
34
|
}
|
|
14
35
|
return mod;
|
|
15
36
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"world.modules.js","sourceRoot":"","sources":["../../src/world/world.modules.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAQnD,MAAM,OAAO,OAAQ,SAAQ,UAAU;
|
|
1
|
+
{"version":3,"file":"world.modules.js","sourceRoot":"","sources":["../../src/world/world.modules.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAQnD,MAAM,OAAO,OAAQ,SAAQ,UAAU;IAAvC;;QACE,mFAAmF;QACzE,yBAAoB,GAAG,KAAK,CAAC;IAoCzC,CAAC;IAlCC;;;;;;;OAOG;IACI,MAAM,CAEX,WAA2B,EAC3B,GAAG,IAAmB;QAEtB,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,GAAG,iBAAiB,CAAC,IAAiD,CAAC,CAAC;QAC7F,MAAM,cAAc,GAAG,WAAwC,CAAC;QAChE,MAAM,KAAK,GAAG,CAAC,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;QACvD,IAAI,KAAK,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;YAC3B,MAAM,IAAI,KAAK,CAAC,0EAA0E,CAAC,CAAC;QAC9F,CAAC;QACD,MAAM,GAAG,GAAG,IAAI,CAAC,UAAU,CAAI,WAAW,EAAE,cAAc,EAAE,GAAG,EAAE,IAAI,CAAC,WAAW,CAAC,CAAC;QACnF,IAAI,CAAC,KAAK,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;YACnC,MAAM,IAAI,KAAK,CACb,UAAU,WAAW,CAAC,IAAI,8EAA8E,CACzG,CAAC;QACJ,CAAC;QACD,IAAI,KAAK,EAAE,CAAC;YACV,IAAI,IAAI,CAAC,oBAAoB,EAAE,CAAC;gBAC9B,GAAG,CAAC,IAAI,CAAC,MAAyB,CAAC,CAAC;YACtC,CAAC;iBAAM,CAAC;gBACN,IAAI,CAAC,KAAK,CAAC,GAAG,EAAE,GAAG,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,MAAyB,CAAC,CAAC,CAAC;YAC7D,CAAC;QACH,CAAC;QACD,OAAO,GAAG,CAAC;IACb,CAAC;CACF;AAED,SAAS,iBAAiB,CAAC,IAA+C;IAIxE,MAAM,KAAK,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;IACtB,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC9B,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,GAAG,EAAE,KAAK,EAAE,CAAC;IAC3C,CAAC;IACD,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,EAAE,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;AACzC,CAAC"}
|
|
@@ -3,16 +3,30 @@ import { Query } from "../query/index.js";
|
|
|
3
3
|
import { System } from "../system.js";
|
|
4
4
|
import type { WorldOptions } from "./world.base.js";
|
|
5
5
|
import { Disposal } from "./world.disposal.js";
|
|
6
|
+
import { WorldStats } from "./stats.js";
|
|
6
7
|
export declare class Pipeline extends Disposal {
|
|
8
|
+
/** Opt-in per-system timing, including each admitted system's subsequent flush. */
|
|
9
|
+
readonly stats: WorldStats;
|
|
7
10
|
constructor(options?: WorldOptions);
|
|
11
|
+
/**
|
|
12
|
+
* Systems in pipeline execution order, including disabled systems.
|
|
13
|
+
* Between frames, builds pending queries (finishing builder configuration)
|
|
14
|
+
* and refreshes the existing flat pipeline only when its query changed.
|
|
15
|
+
* During a frame, returns that frame's pipeline. Does not drain deferred
|
|
16
|
+
* commands or run systems.
|
|
17
|
+
* The array is read-only at the type level; do not mutate it. Re-read this
|
|
18
|
+
* getter after configuration changes rather than retaining an old array.
|
|
19
|
+
*/
|
|
20
|
+
get pipeline(): readonly System[];
|
|
8
21
|
/** Open a new frame and evaluate every registered tick source once. */
|
|
9
22
|
beginFrame(delta: number): void;
|
|
10
23
|
/** Close the current frame. */
|
|
11
24
|
endFrame(): void;
|
|
12
|
-
/** Run every system in
|
|
25
|
+
/** Run every system in pipeline order; opt-in stats include each system's flush. */
|
|
13
26
|
progress(now: number, delta: number): void;
|
|
14
27
|
/** Define the query whose ordered results become this world's system pipeline. */
|
|
15
28
|
setPipeline<const S extends QuerySpec>(spec: S): Query<[typeof System]>;
|
|
16
29
|
/** Create and return a new {@link System}, ready for fluent configuration. */
|
|
17
30
|
system(name: string): System;
|
|
31
|
+
private _progressInstrumented;
|
|
18
32
|
}
|
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import { System } from "../system.js";
|
|
2
2
|
import { ALWAYS_TICK_SOURCE } from "../timer.js";
|
|
3
3
|
import { Disposal } from "./world.disposal.js";
|
|
4
|
+
import { WorldStats } from "./stats.js";
|
|
4
5
|
export class Pipeline extends Disposal {
|
|
5
6
|
constructor(options = {}) {
|
|
6
7
|
super(options);
|
|
8
|
+
/** Opt-in per-system timing, including each admitted system's subsequent flush. */
|
|
9
|
+
this.stats = new WorldStats(() => this._pipeline);
|
|
7
10
|
/** @internal Flat system execution pipeline, rebuilt from `_pipelineQuery`. */
|
|
8
11
|
this._pipeline = [];
|
|
9
12
|
/** @internal Query whose ordered result defines the system pipeline. */
|
|
@@ -14,6 +17,22 @@ export class Pipeline extends Disposal {
|
|
|
14
17
|
this._frameCounter = 0;
|
|
15
18
|
this._tickSources.add(ALWAYS_TICK_SOURCE);
|
|
16
19
|
}
|
|
20
|
+
/**
|
|
21
|
+
* Systems in pipeline execution order, including disabled systems.
|
|
22
|
+
* Between frames, builds pending queries (finishing builder configuration)
|
|
23
|
+
* and refreshes the existing flat pipeline only when its query changed.
|
|
24
|
+
* During a frame, returns that frame's pipeline. Does not drain deferred
|
|
25
|
+
* commands or run systems.
|
|
26
|
+
* The array is read-only at the type level; do not mutate it. Re-read this
|
|
27
|
+
* getter after configuration changes rather than retaining an old array.
|
|
28
|
+
*/
|
|
29
|
+
get pipeline() {
|
|
30
|
+
if (!this._frameInProgress) {
|
|
31
|
+
this._buildPendingQueries();
|
|
32
|
+
this._refreshPipelineIfChanged();
|
|
33
|
+
}
|
|
34
|
+
return this._pipeline;
|
|
35
|
+
}
|
|
17
36
|
/** Open a new frame and evaluate every registered tick source once. */
|
|
18
37
|
beginFrame(delta) {
|
|
19
38
|
if (this._frameInProgress) {
|
|
@@ -33,13 +52,18 @@ export class Pipeline extends Disposal {
|
|
|
33
52
|
}
|
|
34
53
|
this._frameInProgress = false;
|
|
35
54
|
}
|
|
36
|
-
/** Run every system in
|
|
55
|
+
/** Run every system in pipeline order; opt-in stats include each system's flush. */
|
|
37
56
|
progress(now, delta) {
|
|
38
57
|
this.beginFrame(delta);
|
|
39
58
|
try {
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
59
|
+
if (this.stats.systemsEnabled) {
|
|
60
|
+
this._progressInstrumented(now, delta);
|
|
61
|
+
}
|
|
62
|
+
else {
|
|
63
|
+
for (const system of this._pipeline) {
|
|
64
|
+
system._run(now, delta);
|
|
65
|
+
this.flush();
|
|
66
|
+
}
|
|
43
67
|
}
|
|
44
68
|
}
|
|
45
69
|
finally {
|
|
@@ -75,5 +99,17 @@ export class Pipeline extends Disposal {
|
|
|
75
99
|
});
|
|
76
100
|
this._pipeline = systems;
|
|
77
101
|
}
|
|
102
|
+
_progressInstrumented(now, delta) {
|
|
103
|
+
for (const system of this._pipeline) {
|
|
104
|
+
const slot = this.stats._systemSlot(system);
|
|
105
|
+
const start = performance.now();
|
|
106
|
+
const ran = system._run(now, delta);
|
|
107
|
+
this.flush();
|
|
108
|
+
const elapsed = performance.now() - start;
|
|
109
|
+
if (ran) {
|
|
110
|
+
this.stats._record(slot, elapsed);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
78
114
|
}
|
|
79
115
|
//# sourceMappingURL=world.pipeline.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"world.pipeline.js","sourceRoot":"","sources":["../../src/world/world.pipeline.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AACtC,OAAO,EAAE,kBAAkB,EAAoB,MAAM,aAAa,CAAC;AAEnE,OAAO,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"world.pipeline.js","sourceRoot":"","sources":["../../src/world/world.pipeline.ts"],"names":[],"mappings":"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"}
|
package/docs/README.md
CHANGED
|
@@ -15,16 +15,18 @@ Read in this order the first time through:
|
|
|
15
15
|
routing. Read this before designing anything non-trivial.
|
|
16
16
|
4. Subsystem guides, in any order:
|
|
17
17
|
- [Components](./components.md) — registration, hooks, traits, exclusivity, cleanup policies,
|
|
18
|
-
interfaces, singletons.
|
|
18
|
+
interfaces, singletons, and [registration provenance](./components.md#registration-provenance).
|
|
19
19
|
- [Entities](./entities.md) — creation, lookup, the component API, relationship targets, lifecycle,
|
|
20
|
-
disposing
|
|
20
|
+
[synchronous world disposal and allowed call sites](./entities.md#disposing-a-world).
|
|
21
21
|
- [Systems](./systems.md) — membership, reactive callbacks, callback options, `each`/`run`, cadence,
|
|
22
|
-
component, relationship, and [clock injection](./systems.md#clock-injection)
|
|
22
|
+
component, relationship, and [clock injection](./systems.md#clock-injection), plus
|
|
23
|
+
[execution-order and cadence introspection](./systems.md#introspection) and
|
|
24
|
+
[opt-in timing and run counts](./systems.md#measuring-systems).
|
|
23
25
|
- [Queries and filters](./queries-and-filters.md) — the query DSL, live queries, one-shot
|
|
24
26
|
filters, grouped queries, `Bitset`.
|
|
25
27
|
- [Relationships](./relationships.md) — links, target creation and projection, ownership, hierarchy,
|
|
26
28
|
cleanup cascades.
|
|
27
|
-
- [Modules](./modules.md) — packaging features, composition,
|
|
29
|
+
- [Modules](./modules.md) — packaging features, composition, scopes and module provenance, built-in modules.
|
|
28
30
|
- [Subtree snapshots](./snapshots.md) — capturing, restoring, and moving an entity forest
|
|
29
31
|
between two worlds.
|
|
30
32
|
5. [Design guide](./design-guide.md) — opinionated patterns and anti-patterns distilled from real
|
|
@@ -38,21 +40,21 @@ Keep the [Glossary](./glossary.md) at hand for terminology.
|
|
|
38
40
|
|
|
39
41
|
For Node clients that need replicated Phaser poses, see [Headless clients](../../vecs-phaser-client/README.md#headless-clients).
|
|
40
42
|
|
|
41
|
-
| Guide | Covers
|
|
42
|
-
| -------------------------------------------------- |
|
|
43
|
-
| [getting-started.md](./getting-started.md) | A runnable tutorial from `npm install` to a ticking world.
|
|
44
|
-
| [concepts.md](./concepts.md) | The core vocabulary and how the pieces relate.
|
|
45
|
-
| [execution-model.md](./execution-model.md) | `world.progress`, the 8 built-in phases, deferred commands, flush boundaries, event routing.
|
|
46
|
-
| [components.md](./components.md) | Component registration, hooks, traits, exclusivity, cleanup, aliases, and singletons.
|
|
47
|
-
| [entities.md](./entities.md) | Entity creation, mutation, relationship targets, lifecycle, disposal, deferred reads.
|
|
48
|
-
| [systems.md](./systems.md) | `world.system`, callbacks,
|
|
49
|
-
| [queries-and-filters.md](./queries-and-filters.md) | `QueryDSL`, `Query`, `Filter`, `groupBy`, `ignoreSource`.
|
|
50
|
-
| [relationships.md](./relationships.md) | Relationships, target creation, projection and ownership, hierarchy, traversal, and cleanup.
|
|
51
|
-
| [modules.md](./modules.md) | `Module<Config>`, `world.module`,
|
|
52
|
-
| [snapshots.md](./snapshots.md) | `snapshotSubtree`, `restoreSubtree`, `moveSubtree`, and `OnSnapshot` capture policies.
|
|
53
|
-
| [design-guide.md](./design-guide.md) | Patterns, anti-patterns, and a Phaser render-layer case study.
|
|
54
|
-
| [utilities.md](./utilities.md) | Public helper classes: `Events`, `ArrayMap`, `IterableArrayMap`, plus `Bitset` cross-ref.
|
|
55
|
-
| [glossary.md](./glossary.md) | ECS and vecs terminology.
|
|
43
|
+
| Guide | Covers |
|
|
44
|
+
| -------------------------------------------------- | -------------------------------------------------------------------------------------------------------- |
|
|
45
|
+
| [getting-started.md](./getting-started.md) | A runnable tutorial from `npm install` to a ticking world. |
|
|
46
|
+
| [concepts.md](./concepts.md) | The core vocabulary and how the pieces relate, including the shared `Vec2` type. |
|
|
47
|
+
| [execution-model.md](./execution-model.md) | `world.progress`, the 8 built-in phases, deferred commands, flush boundaries, event routing. |
|
|
48
|
+
| [components.md](./components.md) | Component registration/provenance, hooks, traits, exclusivity, cleanup, aliases, and singletons. |
|
|
49
|
+
| [entities.md](./entities.md) | Entity creation, mutation, relationship targets, lifecycle, disposal, deferred reads. |
|
|
50
|
+
| [systems.md](./systems.md) | `world.system`, callbacks, injection, ordering, cadence, tick sources, introspection, and opt-in timing. |
|
|
51
|
+
| [queries-and-filters.md](./queries-and-filters.md) | `QueryDSL`, `Query`, `Filter`, `groupBy`, `ignoreSource`. |
|
|
52
|
+
| [relationships.md](./relationships.md) | Relationships, target creation, projection and ownership, hierarchy, traversal, and cleanup. |
|
|
53
|
+
| [modules.md](./modules.md) | `Module<Config>`, `world.module`, `world.scope`, hierarchy provenance, built-in modules. |
|
|
54
|
+
| [snapshots.md](./snapshots.md) | `snapshotSubtree`, `restoreSubtree`, `moveSubtree`, and `OnSnapshot` capture policies. |
|
|
55
|
+
| [design-guide.md](./design-guide.md) | Patterns, anti-patterns, and a Phaser render-layer case study. |
|
|
56
|
+
| [utilities.md](./utilities.md) | Public helper classes: `Events`, `ArrayMap`, `IterableArrayMap`, plus `Bitset` cross-ref. |
|
|
57
|
+
| [glossary.md](./glossary.md) | ECS and vecs terminology. |
|
|
56
58
|
|
|
57
59
|
Networking (wire encoding with `@wireType`, protocol component ordering, replication, RPCs, server
|
|
58
60
|
sessions, and the client world) lives in the `@vworlds/vecs-wire`, `@vworlds/vecs-protocol`,
|
package/docs/components.md
CHANGED
|
@@ -55,6 +55,15 @@ same class return the same entity. The same class can be registered independentl
|
|
|
55
55
|
worlds — metadata is world-specific. Passing an explicit id for an already-registered class (with
|
|
56
56
|
a different id) throws, as does passing a name with no matching component entity.
|
|
57
57
|
|
|
58
|
+
### Registration provenance
|
|
59
|
+
|
|
60
|
+
Components created during a module's `init` become its `ChildOf` children, through
|
|
61
|
+
[`world.scope`](./modules.md#scopes-and-module-provenance). Read `world.component(C).parent`,
|
|
62
|
+
or walk parents to the nearest `Module` when an explicit hierarchy intervenes (for example
|
|
63
|
+
`OneOf` values). Existing registrations are never reparented by a second module. There is no
|
|
64
|
+
registrar list or per-trait audit; trait additions do not create separate entities. Vecs' own
|
|
65
|
+
constructor-installed built-in modules remain unscoped.
|
|
66
|
+
|
|
58
67
|
### Id pools
|
|
59
68
|
|
|
60
69
|
Entity ids are drawn from configurable pools. The defaults
|
package/docs/concepts.md
CHANGED
|
@@ -12,6 +12,10 @@ every idiom in the [Design guide](./design-guide.md) is a consequence of taking
|
|
|
12
12
|
|
|
13
13
|
## The pieces
|
|
14
14
|
|
|
15
|
+
For packages and applications that exchange 2D points or vectors, import the shared type with
|
|
16
|
+
`import type { Vec2 } from "@vworlds/vecs"`. It is structural (`{ x: number; y: number }`) and has
|
|
17
|
+
no runtime or wire representation.
|
|
18
|
+
|
|
15
19
|
| Concept | What it is |
|
|
16
20
|
| -------------------------- | ------------------------------------------------------------------------------------------------------------ |
|
|
17
21
|
| **World** | Central container. Owns every entity, registered component, query, system, and the flat system pipeline. |
|
package/docs/design-guide.md
CHANGED
|
@@ -135,7 +135,8 @@ world.component(Phaser.GameObjects.Arc).on("remove", (_entity, obj) => obj.destr
|
|
|
135
135
|
|
|
136
136
|
`onRemove` (below) releases the resource whenever it leaves — whether removed explicitly,
|
|
137
137
|
because the entity was destroyed, or because the world was disposed (`world.dispose()` destroys
|
|
138
|
-
|
|
138
|
+
application entities and then infrastructure and singleton data; see
|
|
139
|
+
[Disposing a world](./entities.md#disposing-a-world)).
|
|
139
140
|
When several resource types should share one cleanup hook or be queried together, give them a
|
|
140
141
|
common **interface** with `Implements` (see §7 and the §10 case study). A plain wrapper component
|
|
141
142
|
(`class Handle { obj }`) is still fine when you need extra fields beside the resource.
|
|
@@ -881,9 +882,12 @@ system after whatever produces the entity/companion.
|
|
|
881
882
|
That guard is legitimate; elsewhere a `destroyed` check usually signals a missing edge (see §8 and
|
|
882
883
|
[Hooks](./components.md#hooks-component-and-relationship-edges)).
|
|
883
884
|
- **Release resources in `remove` hooks, not in a system's `exit` callback.** `world.dispose()`
|
|
884
|
-
runs
|
|
885
|
-
|
|
885
|
+
runs hooks during teardown, but a system's `exit` callback only queues its event and may not
|
|
886
|
+
run before infrastructure is destroyed (see
|
|
886
887
|
[Disposing a world](./entities.md#disposing-a-world)).
|
|
888
|
+
- **Request shutdown in a system; dispose after the tick.** For allowed call sites and refusal
|
|
889
|
+
behavior, see [Disposing a world](./entities.md#disposing-a-world). No core tick or mutation
|
|
890
|
+
boundary performs disposal for you.
|
|
887
891
|
- **Within a phase, order = registration order;** across phases, the spine guarantees order. Don't
|
|
888
892
|
use registration order for cross-module correctness — use phases.
|
|
889
893
|
- **Networked component order = wire protocol.** Reordering breaks the protocol.
|
package/docs/entities.md
CHANGED
|
@@ -186,8 +186,8 @@ runtime-created component types work without declaring a class.
|
|
|
186
186
|
## Disposing a world
|
|
187
187
|
|
|
188
188
|
When you are finished with a world — a scene or route change, a hot reload — call
|
|
189
|
-
`world.dispose()` and drop the reference. It destroys
|
|
190
|
-
|
|
189
|
+
`world.dispose()` and drop the reference. It destroys application entities, then the world's
|
|
190
|
+
infrastructure, so the `remove` hook of each component they carry runs and releases what the component
|
|
191
191
|
owns: a render object, a handle, a timer.
|
|
192
192
|
|
|
193
193
|
```ts
|
|
@@ -206,13 +206,13 @@ world.dispose();
|
|
|
206
206
|
handle.released; // true
|
|
207
207
|
```
|
|
208
208
|
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
209
|
+
Disposal uses two passes through the existing entity destroy path. Every `remove` hook fires once;
|
|
210
|
+
entities already destroyed by a hook or cascade are skipped. In **pass 1**, every application entity
|
|
211
|
+
uses ordinary [cleanup policies and cascades](./relationships.md#cleanup-when-a-target-dies).
|
|
212
|
+
This includes plain entities created inside module scopes, even though their parent is infrastructure.
|
|
213
|
+
Application hook-generated commands settle before pass 2 starts.
|
|
213
214
|
|
|
214
|
-
|
|
215
|
-
coherent. It recognizes it as follows (`lib/vecs/src/world/world.disposal.ts`):
|
|
215
|
+
**Pass 2** destroys remaining infrastructure (`lib/vecs/src/world/world.disposal.ts`):
|
|
216
216
|
|
|
217
217
|
| Infrastructure | Recognized by |
|
|
218
218
|
| ----------------------------- | ------------------------------------------------------------- |
|
|
@@ -220,26 +220,37 @@ coherent. It recognizes it as follows (`lib/vecs/src/world/world.disposal.ts`):
|
|
|
220
220
|
| Query and system entities | They carry the `Query` component. |
|
|
221
221
|
| Phase entities | They carry the `Phase` component. |
|
|
222
222
|
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
223
|
+
Data stored on component entities (including singletons set with `world.set`) is removed once,
|
|
224
|
+
after queued application cleanup. Bind module-owned resources to that data with `remove` hooks;
|
|
225
|
+
you do not need a separate disposal callback.
|
|
226
|
+
|
|
227
|
+
During pass 2 only, cleanup policies are suspended. `ChildOf`/`OwnedTarget` do not cascade;
|
|
228
|
+
children are destroyed explicitly in the pass. A component still carried by another entity is removed
|
|
229
|
+
from each carrier through the ordinary remove path, firing its public `remove` hooks, instead of
|
|
230
|
+
throwing or deleting the carriers. Irrevocable relationship-trait guards are bypassed, extending the
|
|
231
|
+
existing destroy-time exemption. This suspension also covers the pass's hook-generated commands and
|
|
232
|
+
is reset in `finally`. Successful disposal leaves nothing, including component-carrier cycles.
|
|
227
233
|
|
|
228
234
|
- **Order.** Among unrelated entities the order is unspecified, so do not make a hook depend on it.
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
235
|
+
Pass 2 processes systems and queries first, then modules in reverse registration order, then the
|
|
236
|
+
rest. Beyond those priorities the order is unspecified; it is not a resource dependency contract.
|
|
237
|
+
There is no infrastructure carriers-first sort or dependency-survivor error. If an internal bug
|
|
238
|
+
prevents a full teardown pass from destroying anything, an invariant error names the remaining
|
|
239
|
+
registered entities instead of looping forever. `clearAllEntities()` retains its
|
|
240
|
+
ordinary cleanup policies and throwing behavior; it orders both carriers before component keys
|
|
241
|
+
and children before parents, and throws if those dependencies cannot be ordered. The suspension
|
|
242
|
+
belongs only to `dispose()`.
|
|
243
|
+
- **Call site.** Call at top level: not inside `progress()`, `defer`, a command drain or an
|
|
244
|
+
entity's destroy. A forbidden call throws before disposal changes anything, leaving the world
|
|
245
|
+
usable; finish the enclosing operation and dispose afterwards. Ordinary synchronous top-level
|
|
246
|
+
`add`, `set` and `remove` hooks may call it. Teardown is synchronous: application hook-generated
|
|
247
|
+
commands settle before infrastructure teardown, and `dispose()` returns with the entities gone.
|
|
248
|
+
The final pass drains its own hook-generated commands and repeats while it can destroy more entities.
|
|
238
249
|
- **After disposal.** A disposed world must not be used again. Nothing enforces it — no other method
|
|
239
|
-
checks
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
250
|
+
mutation checks are added. Calling `dispose()` again at top level does nothing; the call-site
|
|
251
|
+
rule still applies during teardown. Do not keep spawning from teardown hooks: that prevents
|
|
252
|
+
the repeated final pass from settling. A system's queued `exit` callback will not run after
|
|
253
|
+
teardown; release resources in `remove` hooks, as
|
|
243
254
|
[Resources as components](./design-guide.md#resources-as-components-hold-non-ecs-objects)
|
|
244
255
|
recommends.
|
|
245
256
|
|
package/docs/glossary.md
CHANGED
|
@@ -38,9 +38,9 @@ behavior. [Components](./components.md).
|
|
|
38
38
|
queued as commands; `flush` drains the queue at the scope boundary (after each system in the
|
|
39
39
|
pipeline). [Execution model](./execution-model.md#deferred-mutation-and-flush-boundaries).
|
|
40
40
|
|
|
41
|
-
**Dispose** — `world.dispose()`: end a world's life by destroying
|
|
42
|
-
|
|
43
|
-
|
|
41
|
+
**Dispose** — `world.dispose()`: end a world's life by destroying application entities, then
|
|
42
|
+
infrastructure and singleton data, through their `remove` hooks. See
|
|
43
|
+
[Entities](./entities.md#disposing-a-world) for timing, ordering and still-carried keys.
|
|
44
44
|
|
|
45
45
|
**Entity** — a unique numeric id (`eid`) owned by a world, with a set of components attached.
|
|
46
46
|
[Entities](./entities.md).
|