@vworlds/vecs 1.0.45 → 1.0.47
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 +7 -1
- package/dist/component.d.ts +57 -60
- package/dist/component.js +24 -17
- package/dist/component.js.map +1 -1
- package/dist/component_meta.d.ts +67 -79
- package/dist/component_meta.js +331 -37
- package/dist/component_meta.js.map +1 -1
- package/dist/dsl.js +1 -1
- package/dist/dsl.js.map +1 -1
- package/dist/entity/entity.base.js +4 -0
- package/dist/entity/entity.base.js.map +1 -1
- package/dist/entity/entity.components.d.ts +39 -41
- package/dist/entity/entity.components.js +249 -82
- package/dist/entity/entity.components.js.map +1 -1
- package/dist/entity/entity.d.ts +1 -2
- package/dist/entity/entity.js +2 -3
- package/dist/entity/entity.js.map +1 -1
- package/dist/entity/entity.lifecycle.d.ts +7 -1
- package/dist/entity/entity.lifecycle.js +40 -50
- package/dist/entity/entity.lifecycle.js.map +1 -1
- package/dist/entity/entity.queries.js +30 -0
- package/dist/entity/entity.queries.js.map +1 -1
- package/dist/entity/entity.relationships.d.ts +4 -0
- package/dist/entity/entity.relationships.js +18 -10
- package/dist/entity/entity.relationships.js.map +1 -1
- package/dist/index.d.ts +7 -4
- package/dist/index.js +4 -2
- package/dist/index.js.map +1 -1
- package/dist/inject.d.ts +63 -14
- package/dist/inject.js +165 -89
- package/dist/inject.js.map +1 -1
- package/dist/modules/identity.js +2 -2
- package/dist/modules/identity.js.map +1 -1
- package/dist/modules/implements.js +2 -2
- package/dist/modules/implements.js.map +1 -1
- package/dist/modules/pipeline.js +5 -5
- package/dist/modules/pipeline.js.map +1 -1
- package/dist/modules/relationship_types.d.ts +70 -6
- package/dist/modules/relationship_types.js +70 -6
- package/dist/modules/relationship_types.js.map +1 -1
- package/dist/modules/relationships.d.ts +31 -9
- package/dist/modules/relationships.js +120 -44
- package/dist/modules/relationships.js.map +1 -1
- package/dist/modules/singleton.js +2 -2
- package/dist/modules/singleton.js.map +1 -1
- package/dist/modules/snapshot.d.ts +26 -0
- package/dist/modules/snapshot.js +45 -0
- package/dist/modules/snapshot.js.map +1 -0
- package/dist/modules/snapshot_types.d.ts +85 -0
- package/dist/modules/snapshot_types.js +130 -0
- package/dist/modules/snapshot_types.js.map +1 -0
- package/dist/package.json +2 -2
- package/dist/query/callbacks.d.ts +9 -7
- package/dist/query/callbacks.js +27 -41
- package/dist/query/callbacks.js.map +1 -1
- package/dist/query/grouped_query.js +7 -7
- package/dist/query/grouped_query.js.map +1 -1
- package/dist/query/grouping.d.ts +6 -2
- package/dist/query/grouping.js +84 -15
- package/dist/query/grouping.js.map +1 -1
- package/dist/query/query.d.ts +4 -4
- package/dist/query/query.js +37 -14
- package/dist/query/query.js.map +1 -1
- package/dist/snapshot/capture.d.ts +1 -0
- package/dist/snapshot/capture.js +212 -0
- package/dist/snapshot/capture.js.map +1 -0
- package/dist/snapshot/clone.d.ts +1 -0
- package/dist/snapshot/clone.js +107 -0
- package/dist/snapshot/clone.js.map +1 -0
- package/dist/snapshot/index.d.ts +5 -0
- package/dist/snapshot/index.js +21 -0
- package/dist/snapshot/index.js.map +1 -0
- package/dist/snapshot/preflight.d.ts +1 -0
- package/dist/snapshot/preflight.js +40 -0
- package/dist/snapshot/preflight.js.map +1 -0
- package/dist/snapshot/restore.d.ts +1 -0
- package/dist/snapshot/restore.js +111 -0
- package/dist/snapshot/restore.js.map +1 -0
- package/dist/snapshot/types.d.ts +135 -0
- package/dist/snapshot/types.js +26 -0
- package/dist/snapshot/types.js.map +1 -0
- package/dist/system.d.ts +3 -1
- package/dist/system.js +33 -23
- package/dist/system.js.map +1 -1
- package/dist/terms/all_term.js +19 -0
- package/dist/terms/all_term.js.map +1 -1
- package/dist/terms/any_term.js +19 -0
- package/dist/terms/any_term.js.map +1 -1
- package/dist/terms/not_term.js +4 -0
- package/dist/terms/not_term.js.map +1 -1
- package/dist/terms/target_term.d.ts +1 -2
- package/dist/terms/target_term.js +2 -4
- package/dist/terms/target_term.js.map +1 -1
- package/dist/terms/term.d.ts +2 -0
- package/dist/terms/term.js +59 -10
- package/dist/terms/term.js.map +1 -1
- package/dist/util/array_map.d.ts +43 -12
- package/dist/util/array_map.js +90 -41
- package/dist/util/array_map.js.map +1 -1
- package/dist/util/dense_set.js +26 -0
- package/dist/util/dense_set.js.map +1 -1
- package/dist/world/world.base.js +12 -0
- package/dist/world/world.base.js.map +1 -1
- package/dist/world/world.d.ts +7 -0
- package/dist/world/world.deferred.js +17 -0
- package/dist/world/world.deferred.js.map +1 -1
- package/dist/world/world.entities.d.ts +13 -2
- package/dist/world/world.entities.js +16 -2
- package/dist/world/world.entities.js.map +1 -1
- package/dist/world/world.js +15 -3
- package/dist/world/world.js.map +1 -1
- package/dist/world/world.pipeline.d.ts +2 -2
- package/dist/world/world.pipeline.js +4 -2
- package/dist/world/world.pipeline.js.map +1 -1
- package/dist/world/world.queries.d.ts +7 -0
- package/dist/world/world.queries.js +52 -0
- package/dist/world/world.queries.js.map +1 -1
- package/dist/world/world.transfers.d.ts +137 -0
- package/dist/world/world.transfers.js +188 -0
- package/dist/world/world.transfers.js.map +1 -0
- package/docs/README.md +18 -6
- package/docs/components.md +90 -53
- package/docs/concepts.md +21 -17
- package/docs/design-guide.md +125 -94
- package/docs/entities.md +62 -76
- package/docs/execution-model.md +26 -10
- package/docs/getting-started.md +6 -6
- package/docs/glossary.md +19 -10
- package/docs/modules.md +8 -8
- package/docs/queries-and-filters.md +15 -10
- package/docs/relationships.md +245 -124
- package/docs/snapshots.md +181 -0
- package/docs/systems.md +64 -21
- package/docs/utilities.md +10 -6
- package/package.json +2 -2
- package/skills/vecs/SKILL.md +5 -4
|
@@ -17,20 +17,84 @@ export class DependsOn extends Relationship {
|
|
|
17
17
|
export class SilenceSource extends Relationship {
|
|
18
18
|
}
|
|
19
19
|
/**
|
|
20
|
-
*
|
|
20
|
+
* Pair-form trait: attaching `(With, Y)` to a component `X` makes adding `X`
|
|
21
|
+
* to an entity automatically add `Y` as well.
|
|
22
|
+
*
|
|
23
|
+
* Plain form — `X` and `Y` are both non-relationship components:
|
|
24
|
+
*
|
|
25
|
+
* ```ts
|
|
26
|
+
* world.component(Armor);
|
|
27
|
+
* world.component(Helmet).add(With, world.component(Armor));
|
|
28
|
+
* const e = world.entity().add(Helmet); // e also has Armor
|
|
29
|
+
* ```
|
|
30
|
+
*
|
|
31
|
+
* Relationship form — `X` and `Y` are both relationships; the same target is
|
|
32
|
+
* propagated:
|
|
33
|
+
*
|
|
34
|
+
* ```ts
|
|
35
|
+
* world.component(OwnedBy);
|
|
36
|
+
* world.component(WornBy).add(With, world.component(OwnedBy));
|
|
37
|
+
* const wearer = world.entity();
|
|
38
|
+
* const e = world.entity().add(WornBy, wearer); // e also has (OwnedBy, wearer)
|
|
39
|
+
* ```
|
|
40
|
+
*
|
|
41
|
+
* `With` is irrevocable and rejects attach while `X` is already in use, so
|
|
42
|
+
* configure it during world setup before any entity carries `X`.
|
|
43
|
+
*/
|
|
44
|
+
export class With extends Relationship {
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Pair-form trait constraining the targets of a relationship to direct
|
|
48
|
+
* children (via {@link ChildOf}) of a specified parent entity.
|
|
49
|
+
*
|
|
50
|
+
* Self/enum form — the relationship's own entity is the parent. A faction
|
|
51
|
+
* diplomacy alignment enum is a natural fit: every `Alignment` target must be
|
|
52
|
+
* a declared alignment value.
|
|
53
|
+
*
|
|
54
|
+
* ```ts
|
|
55
|
+
* class Alignment extends Relationship {}
|
|
56
|
+
* const alignment = world.component(Alignment).add(OneOf, world.component(Alignment));
|
|
57
|
+
* const good = world.entity().childOf(alignment);
|
|
58
|
+
* const evil = world.entity().childOf(alignment);
|
|
59
|
+
* const weather = world.entity();
|
|
60
|
+
* world.entity().add(Alignment, good); // ok: good is a child of Alignment
|
|
61
|
+
* world.entity().add(Alignment, weather); // throws: weather is not a child of Alignment
|
|
62
|
+
* ```
|
|
63
|
+
*
|
|
64
|
+
* Other-parent form — a different entity is the parent:
|
|
65
|
+
*
|
|
66
|
+
* ```ts
|
|
67
|
+
* class ResidesIn extends Relationship {}
|
|
68
|
+
* class Region extends Relationship {}
|
|
69
|
+
* world.component(ResidesIn).add(OneOf, world.component(Region));
|
|
70
|
+
* const forest = world.entity().childOf(world.component(Region));
|
|
71
|
+
* const weather = world.entity();
|
|
72
|
+
* world.entity().add(ResidesIn, forest); // ok: forest is a child of Region
|
|
73
|
+
* world.entity().add(ResidesIn, weather); // throws: weather is not a child of Region
|
|
74
|
+
* ```
|
|
75
|
+
*
|
|
76
|
+
* `OneOf` is irrevocable and rejects attach while the relationship is already
|
|
77
|
+
* in use, so configure it during world setup before any entity carries an
|
|
78
|
+
* edge through the relationship.
|
|
79
|
+
*/
|
|
80
|
+
export class OneOf extends Relationship {
|
|
81
|
+
}
|
|
82
|
+
/** Marker trait restricting a relationship to one target. */
|
|
83
|
+
export class Exclusive {
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Marker component that makes every explicit target of a relationship a `ChildOf` child
|
|
21
87
|
* of the relationship source.
|
|
22
88
|
*
|
|
23
89
|
* Add during world setup, before creating relationship instances:
|
|
24
90
|
*
|
|
25
91
|
* ```ts
|
|
26
92
|
* world.component(Inventory).add(OwnedTarget);
|
|
27
|
-
* player.add(Inventory);
|
|
93
|
+
* player.add(Inventory, inventory);
|
|
28
94
|
* ```
|
|
29
95
|
*
|
|
30
|
-
*
|
|
31
|
-
* destroys
|
|
32
|
-
* current target. Configure owner lifecycle hooks before attaching this trait;
|
|
33
|
-
* the trait wraps them and runs ownership behavior first.
|
|
96
|
+
* The relationship must also carry {@link Exclusive}. Removing or replacing an
|
|
97
|
+
* edge destroys its target.
|
|
34
98
|
*/
|
|
35
99
|
export class OwnedTarget {
|
|
36
100
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"relationship_types.js","sourceRoot":"","sources":["../../src/modules/relationship_types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAGpD,0CAA0C;AAC1C,MAAM,OAAO,OAAQ,SAAQ,YAAY;CAAG;AAE5C,+CAA+C;AAC/C,MAAM,OAAO,SAAU,SAAQ,YAAY;CAAG;AAE9C;;;;;;;;GAQG;AACH,MAAM,OAAO,aAAc,SAAQ,YAAY;CAAG;AAElD
|
|
1
|
+
{"version":3,"file":"relationship_types.js","sourceRoot":"","sources":["../../src/modules/relationship_types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAGpD,0CAA0C;AAC1C,MAAM,OAAO,OAAQ,SAAQ,YAAY;CAAG;AAE5C,+CAA+C;AAC/C,MAAM,OAAO,SAAU,SAAQ,YAAY;CAAG;AAE9C;;;;;;;;GAQG;AACH,MAAM,OAAO,aAAc,SAAQ,YAAY;CAAG;AAElD;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,MAAM,OAAO,IAAK,SAAQ,YAAY;CAAG;AAEzC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,MAAM,OAAO,KAAM,SAAQ,YAAY;CAAG;AAE1C,6DAA6D;AAC7D,MAAM,OAAO,SAAS;CAAG;AAEzB;;;;;;;;;;;;;GAaG;AACH,MAAM,OAAO,WAAW;CAAG;AAE3B;;;;;;;;;;;;;GAaG;AACH,MAAM,OAAO,WAAW;IAAxB;QACE,+CAA+C;QAC/C,WAAM,GAAG,IAAI,GAAG,EAAkB,CAAC;IACrC,CAAC;CAAA"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Module } from "../module.js";
|
|
2
|
-
export { ChildOf, DependsOn, OwnedTarget, SilenceSource, Traversable, } from "./relationship_types.js";
|
|
2
|
+
export { ChildOf, DependsOn, Exclusive, OneOf, OwnedTarget, SilenceSource, Traversable, With, } from "./relationship_types.js";
|
|
3
3
|
/**
|
|
4
4
|
* Built-in world module that registers the `ChildOf` relationship and
|
|
5
5
|
* maintains ownership and depth tracking policies for relationship traits.
|
|
@@ -9,16 +9,26 @@ export { ChildOf, DependsOn, OwnedTarget, SilenceSource, Traversable, } from "./
|
|
|
9
9
|
* destroying a parent recursively destroys the children that target it through
|
|
10
10
|
* `ChildOf` (custom relationships default to `Remove`).
|
|
11
11
|
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
* or removed.
|
|
12
|
+
* `Traversable` requires `Exclusive`. The module wraps target-edge hooks on a
|
|
13
|
+
* traversable relationship so every entity's depth is updated when its edge is
|
|
14
|
+
* added, replaced, or removed.
|
|
16
15
|
*
|
|
17
16
|
* When a relationship component entity has `OwnedTarget` attached, the module
|
|
18
|
-
* wraps its hooks so
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
17
|
+
* wraps its target-edge hooks so every explicitly added target becomes a
|
|
18
|
+
* `ChildOf` child of its source and is destroyed when displaced or removed.
|
|
19
|
+
* `OwnedTarget` requires `Exclusive` and never creates a target implicitly.
|
|
20
|
+
*
|
|
21
|
+
* `OneOf` constrains the targets of a relationship to direct `ChildOf`
|
|
22
|
+
* children of a specified parent entity. Attach during setup as
|
|
23
|
+
* `relationship.add(OneOf, parent)`; the module installs a per-edge policy that
|
|
24
|
+
* rejects targets whose `ChildOf` parent is not the declared parent. `OneOf`
|
|
25
|
+
* is irrevocable once attached.
|
|
26
|
+
*
|
|
27
|
+
* `OwnedTarget` and `Traversable` are irrevocable once attached: both
|
|
28
|
+
* `entity.remove(Trait)` and `entity.attach(newInstance)` throw, and the world
|
|
29
|
+
* must be discarded after the throw. Teardown bypasses these guards —
|
|
30
|
+
* `Entity._destroy` does not fire `_onPolicyRemove` — so `clearAllEntities`
|
|
31
|
+
* can still tear down worlds with these traits configured.
|
|
22
32
|
*
|
|
23
33
|
* Depth is computed by walking `entity.target(relEid)` to the root. When an
|
|
24
34
|
* entity's depth changes, every descendant is recursively recomputed.
|
|
@@ -27,4 +37,16 @@ export declare class RelationshipsModule extends Module {
|
|
|
27
37
|
init(): void;
|
|
28
38
|
private _cascadeUpdate;
|
|
29
39
|
private _depthOf;
|
|
40
|
+
/**
|
|
41
|
+
* Make a pair-form trait irrevocable: removing an edge of `trait` throws
|
|
42
|
+
* once attached.
|
|
43
|
+
*
|
|
44
|
+
* Teardown fires `targetPolicyRemove` from two paths: `_detachRelationship`
|
|
45
|
+
* on the trait carrier (after `carrier._destroyed = true`) and the cleanup
|
|
46
|
+
* cascade when the pair target is destroyed (buffered via `_cleanupIncoming`
|
|
47
|
+
* → `_removeTarget`, where the carrier is still alive but the target is
|
|
48
|
+
* already gone). Skip the irrevocability guard in either case; see the
|
|
49
|
+
* teardown contract in the class JSDoc.
|
|
50
|
+
*/
|
|
51
|
+
private _forbidPairTraitRemoval;
|
|
30
52
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { CleanupPolicy } from "../component_meta.js";
|
|
2
2
|
import { Module } from "../module.js";
|
|
3
|
-
import { ChildOf, OwnedTarget, Traversable } from "./relationship_types.js";
|
|
4
|
-
export { ChildOf, DependsOn, OwnedTarget, SilenceSource, Traversable, } from "./relationship_types.js";
|
|
3
|
+
import { ChildOf, DependsOn, Exclusive, OneOf, OwnedTarget, SilenceSource, Traversable, With, } from "./relationship_types.js";
|
|
4
|
+
export { ChildOf, DependsOn, Exclusive, OneOf, OwnedTarget, SilenceSource, Traversable, With, } from "./relationship_types.js";
|
|
5
5
|
/**
|
|
6
6
|
* Built-in world module that registers the `ChildOf` relationship and
|
|
7
7
|
* maintains ownership and depth tracking policies for relationship traits.
|
|
@@ -11,16 +11,26 @@ export { ChildOf, DependsOn, OwnedTarget, SilenceSource, Traversable, } from "./
|
|
|
11
11
|
* destroying a parent recursively destroys the children that target it through
|
|
12
12
|
* `ChildOf` (custom relationships default to `Remove`).
|
|
13
13
|
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
* or removed.
|
|
14
|
+
* `Traversable` requires `Exclusive`. The module wraps target-edge hooks on a
|
|
15
|
+
* traversable relationship so every entity's depth is updated when its edge is
|
|
16
|
+
* added, replaced, or removed.
|
|
18
17
|
*
|
|
19
18
|
* When a relationship component entity has `OwnedTarget` attached, the module
|
|
20
|
-
* wraps its hooks so
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
19
|
+
* wraps its target-edge hooks so every explicitly added target becomes a
|
|
20
|
+
* `ChildOf` child of its source and is destroyed when displaced or removed.
|
|
21
|
+
* `OwnedTarget` requires `Exclusive` and never creates a target implicitly.
|
|
22
|
+
*
|
|
23
|
+
* `OneOf` constrains the targets of a relationship to direct `ChildOf`
|
|
24
|
+
* children of a specified parent entity. Attach during setup as
|
|
25
|
+
* `relationship.add(OneOf, parent)`; the module installs a per-edge policy that
|
|
26
|
+
* rejects targets whose `ChildOf` parent is not the declared parent. `OneOf`
|
|
27
|
+
* is irrevocable once attached.
|
|
28
|
+
*
|
|
29
|
+
* `OwnedTarget` and `Traversable` are irrevocable once attached: both
|
|
30
|
+
* `entity.remove(Trait)` and `entity.attach(newInstance)` throw, and the world
|
|
31
|
+
* must be discarded after the throw. Teardown bypasses these guards —
|
|
32
|
+
* `Entity._destroy` does not fire `_onPolicyRemove` — so `clearAllEntities`
|
|
33
|
+
* can still tear down worlds with these traits configured.
|
|
24
34
|
*
|
|
25
35
|
* Depth is computed by walking `entity.target(relEid)` to the root. When an
|
|
26
36
|
* entity's depth changes, every descendant is recursively recomputed.
|
|
@@ -29,50 +39,61 @@ export class RelationshipsModule extends Module {
|
|
|
29
39
|
init() {
|
|
30
40
|
const world = this.world;
|
|
31
41
|
const childOf = world.component(ChildOf);
|
|
42
|
+
const dependsOn = world.component(DependsOn);
|
|
43
|
+
const exclusive = world.component(Exclusive);
|
|
32
44
|
const ownedTarget = world.component(OwnedTarget);
|
|
33
|
-
const
|
|
45
|
+
const silenceSource = world.component(SilenceSource);
|
|
46
|
+
const traversableTrait = world.component(Traversable);
|
|
47
|
+
const withTrait = world.component(With);
|
|
48
|
+
const oneOfTrait = world.component(OneOf);
|
|
34
49
|
childOf.meta.onDeleteTarget = CleanupPolicy.Delete;
|
|
35
|
-
|
|
50
|
+
exclusive.meta.on("policyAdd", (relationship) => {
|
|
51
|
+
if (!relationship.meta.isRelationship) {
|
|
52
|
+
throw new Error("Exclusive can only be added to a Relationship component");
|
|
53
|
+
}
|
|
54
|
+
if (relationship.meta.usageCount > 0) {
|
|
55
|
+
throw new Error("Exclusive cannot be added or removed while the relationship is in use");
|
|
56
|
+
}
|
|
57
|
+
relationship.meta.relationshipExclusive = true;
|
|
58
|
+
});
|
|
59
|
+
exclusive.meta.on("policyRemove", (relationship) => {
|
|
60
|
+
if (relationship.has(OwnedTarget) || relationship.has(Traversable)) {
|
|
61
|
+
throw new Error("Exclusive cannot be removed while a dependent relationship trait exists");
|
|
62
|
+
}
|
|
63
|
+
if (relationship.meta.usageCount > 0) {
|
|
64
|
+
throw new Error("Exclusive cannot be added or removed while the relationship is in use");
|
|
65
|
+
}
|
|
66
|
+
relationship.meta.relationshipExclusive = false;
|
|
67
|
+
});
|
|
68
|
+
ownedTarget.meta.on("policyAdd", (rel) => {
|
|
36
69
|
if (!rel.meta.isRelationship) {
|
|
37
70
|
throw new Error("OwnedTarget can only be added to a Relationship component");
|
|
38
71
|
}
|
|
39
72
|
if (rel === childOf) {
|
|
40
73
|
throw new Error("OwnedTarget cannot be added to ChildOf");
|
|
41
74
|
}
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
rel
|
|
47
|
-
.onAdd((source, component) => {
|
|
48
|
-
const relationship = component;
|
|
49
|
-
relationship.target ?? (relationship.target = world.entity());
|
|
50
|
-
relationship.target.childOf(source);
|
|
51
|
-
onAdd?.(source, component);
|
|
52
|
-
})
|
|
53
|
-
.onSet((source, relationship) => {
|
|
54
|
-
relationship.target.childOf(source);
|
|
55
|
-
onSet?.(source, relationship);
|
|
56
|
-
})
|
|
57
|
-
.onRetarget((source, oldTarget, newTarget) => {
|
|
58
|
-
oldTarget.destroy();
|
|
59
|
-
onRetarget?.(source, oldTarget, newTarget);
|
|
60
|
-
})
|
|
61
|
-
.onRemove((source, relationship) => {
|
|
62
|
-
relationship.target.destroy();
|
|
63
|
-
onRemove?.(source, relationship);
|
|
64
|
-
});
|
|
75
|
+
if (!rel.has(Exclusive)) {
|
|
76
|
+
throw new Error("OwnedTarget requires Exclusive");
|
|
77
|
+
}
|
|
78
|
+
rel.meta.on("targetPolicyAdd", (source, _relationship, target) => target.add(ChildOf, source));
|
|
79
|
+
rel.meta.on("targetPolicyRemove", (_source, _relationship, target) => target.destroy());
|
|
65
80
|
});
|
|
66
|
-
|
|
81
|
+
ownedTarget.meta.on("policyRemove", () => {
|
|
82
|
+
throw new Error("OwnedTarget cannot be removed once added");
|
|
83
|
+
});
|
|
84
|
+
traversableTrait.meta.on("policyAdd", (rel, component) => {
|
|
85
|
+
if (!rel.meta.isRelationship) {
|
|
86
|
+
throw new Error("Traversable can only be added to a Relationship component");
|
|
87
|
+
}
|
|
88
|
+
if (!rel.has(Exclusive)) {
|
|
89
|
+
throw new Error("Traversable requires Exclusive");
|
|
90
|
+
}
|
|
91
|
+
const traversable = component;
|
|
67
92
|
const relEid = rel.eid;
|
|
68
|
-
rel
|
|
69
|
-
.onAdd((entity) => {
|
|
93
|
+
rel.meta.on("targetPolicyAdd", (entity) => {
|
|
70
94
|
this._cascadeUpdate(entity, relEid, traversable);
|
|
71
|
-
})
|
|
72
|
-
|
|
73
|
-
this._cascadeUpdate(entity, relEid, traversable);
|
|
74
|
-
})
|
|
75
|
-
.onRemove((entity) => {
|
|
95
|
+
});
|
|
96
|
+
rel.meta.on("targetPolicyRemove", (entity) => {
|
|
76
97
|
traversable.depths.delete(entity);
|
|
77
98
|
for (const child of entity._childrenByEid(relEid) ?? []) {
|
|
78
99
|
this._cascadeUpdate(child, relEid, traversable);
|
|
@@ -84,7 +105,43 @@ export class RelationshipsModule extends Module {
|
|
|
84
105
|
}
|
|
85
106
|
});
|
|
86
107
|
});
|
|
87
|
-
|
|
108
|
+
traversableTrait.meta.on("policyRemove", () => {
|
|
109
|
+
throw new Error("Traversable cannot be removed once added");
|
|
110
|
+
});
|
|
111
|
+
withTrait.meta.on("targetPolicyAdd", (xEntity, _withRelationship, yEntity) => {
|
|
112
|
+
const xMeta = xEntity.meta;
|
|
113
|
+
const yMeta = yEntity.meta;
|
|
114
|
+
if (xMeta.isRelationship !== yMeta.isRelationship) {
|
|
115
|
+
throw new Error("With: the component and its target must both be relationships or both be plain components");
|
|
116
|
+
}
|
|
117
|
+
if (xMeta.usageCount > 0) {
|
|
118
|
+
throw new Error("With cannot be added while the target component is in use");
|
|
119
|
+
}
|
|
120
|
+
if (xMeta.isRelationship) {
|
|
121
|
+
xMeta.on("targetPolicyAdd", (source, _rel, target) => source.add(yEntity, target));
|
|
122
|
+
}
|
|
123
|
+
else {
|
|
124
|
+
xMeta.on("policyAdd", (entity) => entity.add(yEntity));
|
|
125
|
+
}
|
|
126
|
+
});
|
|
127
|
+
this._forbidPairTraitRemoval(withTrait, "With");
|
|
128
|
+
oneOfTrait.meta.on("targetPolicyAdd", (rel, _oneOf, parent) => {
|
|
129
|
+
if (!rel.meta.isRelationship) {
|
|
130
|
+
throw new Error("OneOf can only be added to a Relationship component");
|
|
131
|
+
}
|
|
132
|
+
if (rel.meta.usageCount > 0) {
|
|
133
|
+
throw new Error("OneOf cannot be added while the relationship is in use");
|
|
134
|
+
}
|
|
135
|
+
rel.meta.on("targetPolicyAdd", (_source, _relationship, target) => {
|
|
136
|
+
if (target.parent !== parent) {
|
|
137
|
+
throw new Error(`OneOf: target ${target.eid} is not a child of entity ${parent.eid}`);
|
|
138
|
+
}
|
|
139
|
+
});
|
|
140
|
+
});
|
|
141
|
+
this._forbidPairTraitRemoval(oneOfTrait, "OneOf");
|
|
142
|
+
childOf.add(Exclusive).add(Traversable);
|
|
143
|
+
dependsOn.add(Exclusive).add(Traversable);
|
|
144
|
+
silenceSource.add(Exclusive);
|
|
88
145
|
}
|
|
89
146
|
_cascadeUpdate(entity, relEid, traversable, visited = new Set()) {
|
|
90
147
|
if (visited.has(entity)) {
|
|
@@ -116,5 +173,24 @@ export class RelationshipsModule extends Module {
|
|
|
116
173
|
}
|
|
117
174
|
return this._depthOf(parent, relEid, traversable, visited) + 1;
|
|
118
175
|
}
|
|
176
|
+
/**
|
|
177
|
+
* Make a pair-form trait irrevocable: removing an edge of `trait` throws
|
|
178
|
+
* once attached.
|
|
179
|
+
*
|
|
180
|
+
* Teardown fires `targetPolicyRemove` from two paths: `_detachRelationship`
|
|
181
|
+
* on the trait carrier (after `carrier._destroyed = true`) and the cleanup
|
|
182
|
+
* cascade when the pair target is destroyed (buffered via `_cleanupIncoming`
|
|
183
|
+
* → `_removeTarget`, where the carrier is still alive but the target is
|
|
184
|
+
* already gone). Skip the irrevocability guard in either case; see the
|
|
185
|
+
* teardown contract in the class JSDoc.
|
|
186
|
+
*/
|
|
187
|
+
_forbidPairTraitRemoval(trait, name) {
|
|
188
|
+
trait.meta.on("targetPolicyRemove", (carrier, _trait, target) => {
|
|
189
|
+
if (carrier.destroyed || target.destroyed) {
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
throw new Error(`${name} cannot be removed once added`);
|
|
193
|
+
});
|
|
194
|
+
}
|
|
119
195
|
}
|
|
120
196
|
//# sourceMappingURL=relationships.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"relationships.js","sourceRoot":"","sources":["../../src/modules/relationships.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,
|
|
1
|
+
{"version":3,"file":"relationships.js","sourceRoot":"","sources":["../../src/modules/relationships.ts"],"names":[],"mappings":"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"}
|
|
@@ -23,12 +23,12 @@ export class Singleton {
|
|
|
23
23
|
*/
|
|
24
24
|
export class SingletonModule extends Module {
|
|
25
25
|
init() {
|
|
26
|
-
this.world.component(Singleton).
|
|
26
|
+
this.world.component(Singleton).on("add", (target) => {
|
|
27
27
|
const targetMeta = target.meta;
|
|
28
28
|
if (targetMeta.usageCount !== 0) {
|
|
29
29
|
throw new Error(`Cannot make component ${targetMeta.Class.name} singleton; ${targetMeta.usageCount} instance(s) already exist`);
|
|
30
30
|
}
|
|
31
|
-
targetMeta.
|
|
31
|
+
targetMeta.on("add", (entity) => {
|
|
32
32
|
if (entity !== target || targetMeta.usageCount !== 1) {
|
|
33
33
|
throw new Error(`Cannot add singleton component ${targetMeta.Class.name} to entity ${entity.eid}; singleton instance is entity ${target.eid}`);
|
|
34
34
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"singleton.js","sourceRoot":"","sources":["../../src/modules/singleton.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAEtC;;;;;;;;;;;;GAYG;AACH,MAAM,OAAO,SAAS;CAAG;AAEzB;;;;;;GAMG;AACH,MAAM,OAAO,eAAgB,SAAQ,MAAM;IAClC,IAAI;QACT,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC,
|
|
1
|
+
{"version":3,"file":"singleton.js","sourceRoot":"","sources":["../../src/modules/singleton.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAEtC;;;;;;;;;;;;GAYG;AACH,MAAM,OAAO,SAAS;CAAG;AAEzB;;;;;;GAMG;AACH,MAAM,OAAO,eAAgB,SAAQ,MAAM;IAClC,IAAI;QACT,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC,MAAc,EAAQ,EAAE;YACjE,MAAM,UAAU,GAAG,MAAM,CAAC,IAAI,CAAC;YAC/B,IAAI,UAAU,CAAC,UAAU,KAAK,CAAC,EAAE,CAAC;gBAChC,MAAM,IAAI,KAAK,CACb,yBAAyB,UAAU,CAAC,KAAK,CAAC,IAAI,eAAe,UAAU,CAAC,UAAU,4BAA4B,CAC/G,CAAC;YACJ,CAAC;YAED,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC,MAAM,EAAE,EAAE;gBAC9B,IAAI,MAAM,KAAK,MAAM,IAAI,UAAU,CAAC,UAAU,KAAK,CAAC,EAAE,CAAC;oBACrD,MAAM,IAAI,KAAK,CACb,kCAAkC,UAAU,CAAC,KAAK,CAAC,IAAI,cAAc,MAAM,CAAC,GAAG,kCAAkC,MAAM,CAAC,GAAG,EAAE,CAC9H,CAAC;gBACJ,CAAC;YACH,CAAC,CAAC,CAAC;YACH,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QACrB,CAAC,CAAC,CAAC;IACL,CAAC;CACF"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { Module } from "../module.js";
|
|
2
|
+
export { type ResolvedSnapshotPolicy, type SnapshotCapture, type SnapshotMaterialize, type SnapshotPolicyType, ClonePublic, CustomSnapshot, DontSnapshot, OnSnapshot, _declareSnapshotPolicy, _resolveSnapshotPolicy, } from "./snapshot_types.js";
|
|
3
|
+
/**
|
|
4
|
+
* Built-in world module that registers the `OnSnapshot` trait and its policy
|
|
5
|
+
* values.
|
|
6
|
+
*
|
|
7
|
+
* Registered automatically by every {@link World}. `OnSnapshot` is an
|
|
8
|
+
* `Exclusive` pair-form trait restricted with {@link OneOf} to its own policy
|
|
9
|
+
* children, so a component entity always names exactly one policy:
|
|
10
|
+
* {@link ClonePublic} (the default), {@link DontSnapshot}, or
|
|
11
|
+
* {@link CustomSnapshot}.
|
|
12
|
+
*
|
|
13
|
+
* A policy may be declared, changed, or revoked at any time. It does not have to
|
|
14
|
+
* precede the component's first carrier, because a capture *binds* the
|
|
15
|
+
* materializer it resolved: {@link World.snapshotSubtree} stores that function
|
|
16
|
+
* in each record, so a snapshot always restores the way it was captured and a
|
|
17
|
+
* later policy declaration cannot retroactively change one.
|
|
18
|
+
*
|
|
19
|
+
* The module also marks vecs' own world-bound component types
|
|
20
|
+
* {@link DontSnapshot}: a
|
|
21
|
+
* live {@link Query} or {@link System} owns live membership, pending events, and
|
|
22
|
+
* pipeline slots, so it can never be reconstructed in another world.
|
|
23
|
+
*/
|
|
24
|
+
export declare class SnapshotModule extends Module {
|
|
25
|
+
init(): void;
|
|
26
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
// `SnapshotModule` installs the `OnSnapshot` trait's runtime invariants. The
|
|
2
|
+
// trait, its policy values, and the declaration helpers live in
|
|
3
|
+
// `snapshot_types.ts`, which is dependency-light on purpose: `component.ts`
|
|
4
|
+
// imports it, so it must not reach back through `module.ts`.
|
|
5
|
+
import { Module } from "../module.js";
|
|
6
|
+
import { Query } from "../query/index.js";
|
|
7
|
+
import { System } from "../system.js";
|
|
8
|
+
import { Exclusive, OneOf } from "./relationship_types.js";
|
|
9
|
+
import { ClonePublic, CustomSnapshot, DontSnapshot, OnSnapshot } from "./snapshot_types.js";
|
|
10
|
+
export { ClonePublic, CustomSnapshot, DontSnapshot, OnSnapshot, _declareSnapshotPolicy, _resolveSnapshotPolicy, } from "./snapshot_types.js";
|
|
11
|
+
/**
|
|
12
|
+
* Built-in world module that registers the `OnSnapshot` trait and its policy
|
|
13
|
+
* values.
|
|
14
|
+
*
|
|
15
|
+
* Registered automatically by every {@link World}. `OnSnapshot` is an
|
|
16
|
+
* `Exclusive` pair-form trait restricted with {@link OneOf} to its own policy
|
|
17
|
+
* children, so a component entity always names exactly one policy:
|
|
18
|
+
* {@link ClonePublic} (the default), {@link DontSnapshot}, or
|
|
19
|
+
* {@link CustomSnapshot}.
|
|
20
|
+
*
|
|
21
|
+
* A policy may be declared, changed, or revoked at any time. It does not have to
|
|
22
|
+
* precede the component's first carrier, because a capture *binds* the
|
|
23
|
+
* materializer it resolved: {@link World.snapshotSubtree} stores that function
|
|
24
|
+
* in each record, so a snapshot always restores the way it was captured and a
|
|
25
|
+
* later policy declaration cannot retroactively change one.
|
|
26
|
+
*
|
|
27
|
+
* The module also marks vecs' own world-bound component types
|
|
28
|
+
* {@link DontSnapshot}: a
|
|
29
|
+
* live {@link Query} or {@link System} owns live membership, pending events, and
|
|
30
|
+
* pipeline slots, so it can never be reconstructed in another world.
|
|
31
|
+
*/
|
|
32
|
+
export class SnapshotModule extends Module {
|
|
33
|
+
init() {
|
|
34
|
+
const world = this.world;
|
|
35
|
+
const onSnapshot = world.component(OnSnapshot);
|
|
36
|
+
world.component(ClonePublic).childOf(onSnapshot);
|
|
37
|
+
world.component(DontSnapshot).childOf(onSnapshot);
|
|
38
|
+
world.component(CustomSnapshot).childOf(onSnapshot);
|
|
39
|
+
onSnapshot.add(OneOf, onSnapshot);
|
|
40
|
+
onSnapshot.add(Exclusive);
|
|
41
|
+
world.component(Query).snapshotPolicy(DontSnapshot);
|
|
42
|
+
world.component(System).snapshotPolicy(DontSnapshot);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
//# sourceMappingURL=snapshot.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"snapshot.js","sourceRoot":"","sources":["../../src/modules/snapshot.ts"],"names":[],"mappings":"AAAA,6EAA6E;AAC7E,gEAAgE;AAChE,4EAA4E;AAC5E,6DAA6D;AAE7D,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AACtC,OAAO,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAC1C,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAEtC,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAE5F,OAAO,EAKL,WAAW,EACX,cAAc,EACd,YAAY,EACZ,UAAU,EACV,sBAAsB,EACtB,sBAAsB,GACvB,MAAM,qBAAqB,CAAC;AAE7B;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,OAAO,cAAe,SAAQ,MAAM;IACjC,IAAI;QACT,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC;QACzB,MAAM,UAAU,GAAG,KAAK,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC;QAE/C,KAAK,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;QACjD,KAAK,CAAC,SAAS,CAAC,YAAY,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;QAClD,KAAK,CAAC,SAAS,CAAC,cAAc,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;QAEpD,UAAU,CAAC,GAAG,CAAC,KAAK,EAAE,UAAU,CAAC,CAAC;QAClC,UAAU,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QAE1B,KAAK,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,cAAc,CAAC,YAAY,CAAC,CAAC;QACpD,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,cAAc,CAAC,YAAY,CAAC,CAAC;IACvD,CAAC;CACF"}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import type { ComponentInstance } from "../component_meta.js";
|
|
2
|
+
import { Relationship } from "../component_meta.js";
|
|
3
|
+
/**
|
|
4
|
+
* Captures one live component instance into detached, world-agnostic data.
|
|
5
|
+
*
|
|
6
|
+
* The returned value is stored in the snapshot and handed back to
|
|
7
|
+
* {@link SnapshotMaterialize} verbatim, so it must not reference the source
|
|
8
|
+
* world, its entities, or any mutable instance the source still holds.
|
|
9
|
+
*/
|
|
10
|
+
export type SnapshotCapture = (instance: ComponentInstance) => unknown;
|
|
11
|
+
/**
|
|
12
|
+
* Constructs one destination-owned component instance from previously captured
|
|
13
|
+
* data. The returned instance must be freshly constructed and belong to no
|
|
14
|
+
* other entity.
|
|
15
|
+
*/
|
|
16
|
+
export type SnapshotMaterialize = (data: unknown) => ComponentInstance;
|
|
17
|
+
/**
|
|
18
|
+
* Built-in pair-form trait declaring how {@link World.snapshotSubtree} captures
|
|
19
|
+
* one component type.
|
|
20
|
+
*
|
|
21
|
+
* The trait is attached to the **component entity**, not to ordinary entities,
|
|
22
|
+
* and its target selects the policy. It is exclusive, one-of
|
|
23
|
+
* {@link OneOf | restricted to its own children}. Configure it through the
|
|
24
|
+
* owning module; declarations affect future captures, while each existing
|
|
25
|
+
* snapshot retains the materializer bound at its capture time.
|
|
26
|
+
*
|
|
27
|
+
* ```ts
|
|
28
|
+
* // Declare "this type never crosses worlds" (resources, live queries, engines).
|
|
29
|
+
* world.component(PhysicsEngine).snapshotPolicy(DontSnapshot);
|
|
30
|
+
*
|
|
31
|
+
* // Declare a bespoke capture that drops runtime handles.
|
|
32
|
+
* world.component(Body).snapshotPolicy(CustomSnapshot, {
|
|
33
|
+
* capture: (body) => ({ ...body, _bodyId: undefined }),
|
|
34
|
+
* materialize: (data) => Object.assign(new Body(), data),
|
|
35
|
+
* });
|
|
36
|
+
* ```
|
|
37
|
+
*
|
|
38
|
+
* A type with no {@link OnSnapshot} edge uses {@link ClonePublic}, so ordinary
|
|
39
|
+
* plain-data components need no declaration at all.
|
|
40
|
+
*/
|
|
41
|
+
export declare class OnSnapshot extends Relationship {
|
|
42
|
+
/**
|
|
43
|
+
* Capture hook for the {@link CustomSnapshot} policy. `undefined` for every
|
|
44
|
+
* other policy.
|
|
45
|
+
*/
|
|
46
|
+
capture: SnapshotCapture | undefined;
|
|
47
|
+
/**
|
|
48
|
+
* Materialize hook for the {@link CustomSnapshot} policy. `undefined` for
|
|
49
|
+
* every other policy.
|
|
50
|
+
*/
|
|
51
|
+
materialize: SnapshotMaterialize | undefined;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Default snapshot policy: construct a fresh instance of the component class
|
|
55
|
+
* and clone the source instance's own enumerable fields onto it.
|
|
56
|
+
*
|
|
57
|
+
* Shallow, and therefore exactly as aliasing-sensitive as `set`: a component
|
|
58
|
+
* holding a nested object shares it with the source until something copies it.
|
|
59
|
+
* A type that must not carry runtime handles across worlds needs its own
|
|
60
|
+
* policy — see {@link CustomSnapshot}.
|
|
61
|
+
*/
|
|
62
|
+
export declare class ClonePublic {
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Snapshot policy declaring that a component type never crosses worlds.
|
|
66
|
+
*
|
|
67
|
+
* Use it for attached resources and other instances whose identity is bound to
|
|
68
|
+
* a single world: live queries and systems, engine handles, socket sessions.
|
|
69
|
+
* A snapshot silently omits an unselected `DontSnapshot` type, but *selecting*
|
|
70
|
+
* one explicitly is a preflight error, so a caller cannot silently lose state
|
|
71
|
+
* it asked for.
|
|
72
|
+
*/
|
|
73
|
+
export declare class DontSnapshot {
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Snapshot policy delegating capture and materialization to the owner.
|
|
77
|
+
*
|
|
78
|
+
* Register it with {@link Component.snapshotPolicy}, passing the `capture` and
|
|
79
|
+
* `materialize` callbacks; the callbacks are stored on that component entity's
|
|
80
|
+
* own {@link OnSnapshot} edge, so each component type keeps a separate policy.
|
|
81
|
+
*/
|
|
82
|
+
export declare class CustomSnapshot {
|
|
83
|
+
}
|
|
84
|
+
/** The policy values accepted by {@link Component.snapshotPolicy}. */
|
|
85
|
+
export type SnapshotPolicyType = typeof ClonePublic | typeof CustomSnapshot | typeof DontSnapshot;
|