iris-ecs 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +721 -0
- package/dist/actions.d.ts +43 -0
- package/dist/actions.d.ts.map +1 -0
- package/dist/actions.js +35 -0
- package/dist/actions.js.map +1 -0
- package/dist/archetype.d.ts +194 -0
- package/dist/archetype.d.ts.map +1 -0
- package/dist/archetype.js +412 -0
- package/dist/archetype.js.map +1 -0
- package/dist/component.d.ts +89 -0
- package/dist/component.d.ts.map +1 -0
- package/dist/component.js +237 -0
- package/dist/component.js.map +1 -0
- package/dist/encoding.d.ts +204 -0
- package/dist/encoding.d.ts.map +1 -0
- package/dist/encoding.js +215 -0
- package/dist/encoding.js.map +1 -0
- package/dist/entity.d.ts +129 -0
- package/dist/entity.d.ts.map +1 -0
- package/dist/entity.js +243 -0
- package/dist/entity.js.map +1 -0
- package/dist/event.d.ts +237 -0
- package/dist/event.d.ts.map +1 -0
- package/dist/event.js +293 -0
- package/dist/event.js.map +1 -0
- package/dist/filters.d.ts +121 -0
- package/dist/filters.d.ts.map +1 -0
- package/dist/filters.js +202 -0
- package/dist/filters.js.map +1 -0
- package/dist/index.d.ts +24 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +54 -0
- package/dist/index.js.map +1 -0
- package/dist/name.d.ts +70 -0
- package/dist/name.d.ts.map +1 -0
- package/dist/name.js +172 -0
- package/dist/name.js.map +1 -0
- package/dist/observer.d.ts +83 -0
- package/dist/observer.d.ts.map +1 -0
- package/dist/observer.js +62 -0
- package/dist/observer.js.map +1 -0
- package/dist/query.d.ts +198 -0
- package/dist/query.d.ts.map +1 -0
- package/dist/query.js +299 -0
- package/dist/query.js.map +1 -0
- package/dist/registry.d.ts +118 -0
- package/dist/registry.d.ts.map +1 -0
- package/dist/registry.js +112 -0
- package/dist/registry.js.map +1 -0
- package/dist/relation.d.ts +60 -0
- package/dist/relation.d.ts.map +1 -0
- package/dist/relation.js +171 -0
- package/dist/relation.js.map +1 -0
- package/dist/removal.d.ts +27 -0
- package/dist/removal.d.ts.map +1 -0
- package/dist/removal.js +66 -0
- package/dist/removal.js.map +1 -0
- package/dist/resource.d.ts +78 -0
- package/dist/resource.d.ts.map +1 -0
- package/dist/resource.js +86 -0
- package/dist/resource.js.map +1 -0
- package/dist/scheduler.d.ts +106 -0
- package/dist/scheduler.d.ts.map +1 -0
- package/dist/scheduler.js +204 -0
- package/dist/scheduler.js.map +1 -0
- package/dist/schema.d.ts +117 -0
- package/dist/schema.d.ts.map +1 -0
- package/dist/schema.js +113 -0
- package/dist/schema.js.map +1 -0
- package/dist/world.d.ts +172 -0
- package/dist/world.d.ts.map +1 -0
- package/dist/world.js +127 -0
- package/dist/world.js.map +1 -0
- package/package.json +52 -0
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import type { Component, Relation, Tag } from "./encoding.js";
|
|
2
|
+
import type { SchemaRecord } from "./schema.js";
|
|
3
|
+
/**
|
|
4
|
+
* Component metadata.
|
|
5
|
+
*
|
|
6
|
+
* Stores component name, optional schema, and relation traits.
|
|
7
|
+
*/
|
|
8
|
+
export type ComponentMeta = {
|
|
9
|
+
/**
|
|
10
|
+
* Component name (user-defined).
|
|
11
|
+
*/
|
|
12
|
+
name: string;
|
|
13
|
+
/**
|
|
14
|
+
* Field schemas for data components (undefined for tags).
|
|
15
|
+
*/
|
|
16
|
+
schema?: SchemaRecord;
|
|
17
|
+
/**
|
|
18
|
+
* If true, entity can only have one target at a time for this relation.
|
|
19
|
+
*/
|
|
20
|
+
exclusive?: boolean;
|
|
21
|
+
/**
|
|
22
|
+
* What happens when a pair target is destroyed. Default is "remove".
|
|
23
|
+
*/
|
|
24
|
+
onDeleteTarget?: "remove" | "delete";
|
|
25
|
+
};
|
|
26
|
+
/**
|
|
27
|
+
* Options for defining relations.
|
|
28
|
+
*
|
|
29
|
+
* Controls relation behavior including exclusivity and delete policies.
|
|
30
|
+
*/
|
|
31
|
+
export type RelationOptions<S extends SchemaRecord = Record<string, never>> = {
|
|
32
|
+
/**
|
|
33
|
+
* Field schemas for pair data (optional).
|
|
34
|
+
*/
|
|
35
|
+
schema?: S;
|
|
36
|
+
/**
|
|
37
|
+
* If true, entity can only have one target for this relation.
|
|
38
|
+
*/
|
|
39
|
+
exclusive?: boolean;
|
|
40
|
+
/**
|
|
41
|
+
* What happens when a pair target is destroyed. Default is "remove".
|
|
42
|
+
*/
|
|
43
|
+
onDeleteTarget?: "remove" | "delete";
|
|
44
|
+
};
|
|
45
|
+
/**
|
|
46
|
+
* Global singleton storing all component metadata across all worlds.
|
|
47
|
+
*/
|
|
48
|
+
export type ComponentRegistry = {
|
|
49
|
+
/**
|
|
50
|
+
* Component metadata lookup (component ID -> metadata).
|
|
51
|
+
*/
|
|
52
|
+
byId: Map<Tag | Component | Relation, ComponentMeta>;
|
|
53
|
+
/**
|
|
54
|
+
* Next raw ID to allocate for tags.
|
|
55
|
+
*/
|
|
56
|
+
nextTagId: number;
|
|
57
|
+
/**
|
|
58
|
+
* Next raw ID to allocate for data components.
|
|
59
|
+
*/
|
|
60
|
+
nextComponentId: number;
|
|
61
|
+
/**
|
|
62
|
+
* Next raw ID to allocate for relations.
|
|
63
|
+
*/
|
|
64
|
+
nextRelationId: number;
|
|
65
|
+
};
|
|
66
|
+
/**
|
|
67
|
+
* Global component registry singleton.
|
|
68
|
+
*/
|
|
69
|
+
export declare const COMPONENT_REGISTRY: ComponentRegistry;
|
|
70
|
+
/**
|
|
71
|
+
* Defines a tag component. Tags are lightweight markers without data.
|
|
72
|
+
* @param name - Human-readable tag name for debugging
|
|
73
|
+
* @returns Encoded tag ID
|
|
74
|
+
* @throws {RangeError} If tag limit (1,048,576) exceeded
|
|
75
|
+
* @example
|
|
76
|
+
* const Player = defineTag("Player");
|
|
77
|
+
* addTag(world, entity, Player);
|
|
78
|
+
*/
|
|
79
|
+
export declare function defineTag(name: string): Tag;
|
|
80
|
+
/**
|
|
81
|
+
* Defines a data component with a typed schema for storage.
|
|
82
|
+
* @param name - Human-readable component name for debugging
|
|
83
|
+
* @param schema - Field schema record defining data layout
|
|
84
|
+
* @returns Encoded component ID with schema type
|
|
85
|
+
* @throws {RangeError} If component limit (1,048,576) exceeded
|
|
86
|
+
* @example
|
|
87
|
+
* const Position = defineComponent("Position", { x: Type.f32, y: Type.f32 });
|
|
88
|
+
* set(world, entity, Position, { x: 10, y: 20 });
|
|
89
|
+
*/
|
|
90
|
+
export declare function defineComponent<S extends SchemaRecord>(name: string, schema: S): Component<S>;
|
|
91
|
+
/**
|
|
92
|
+
* Defines a relation for entity-to-entity relationships.
|
|
93
|
+
* @param name - Human-readable relation name for debugging
|
|
94
|
+
* @param options - Configuration: schema for data, exclusive trait, delete behavior
|
|
95
|
+
* @returns Encoded relation ID with schema type
|
|
96
|
+
* @throws {RangeError} If relation limit (256) exceeded
|
|
97
|
+
* @example
|
|
98
|
+
* const ChildOf = defineRelation("ChildOf", { exclusive: true, onDeleteTarget: "delete" });
|
|
99
|
+
* addPair(world, child, ChildOf, parent);
|
|
100
|
+
*/
|
|
101
|
+
export declare function defineRelation<S extends SchemaRecord = Record<string, never>>(name: string, options?: RelationOptions<S>): Relation<S>;
|
|
102
|
+
/**
|
|
103
|
+
* Wildcard relation for query patterns. Reserved as relation ID 0.
|
|
104
|
+
* - `pair(Wildcard, target)` matches all entities targeting target
|
|
105
|
+
* - `pair(relation, Wildcard)` matches entities with any target for relation
|
|
106
|
+
*/
|
|
107
|
+
export declare const Wildcard: Relation<Record<string, never>>;
|
|
108
|
+
/**
|
|
109
|
+
* Marks a relation as exclusive (one target per subject).
|
|
110
|
+
* Adding a pair with an exclusive relation auto-removes any existing pair with that relation.
|
|
111
|
+
*/
|
|
112
|
+
export declare const Exclusive: Tag;
|
|
113
|
+
/**
|
|
114
|
+
* Cascade delete subjects when target is destroyed.
|
|
115
|
+
* When an entity is destroyed, all entities with a pair targeting it are also destroyed.
|
|
116
|
+
*/
|
|
117
|
+
export declare const OnDeleteTarget: Tag;
|
|
118
|
+
//# sourceMappingURL=registry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,eAAe,CAAC;AAE9D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAMhD;;;;GAIG;AACH,MAAM,MAAM,aAAa,GAAG;IAC1B;;OAEG;IACH,IAAI,EAAE,MAAM,CAAC;IAEb;;OAEG;IACH,MAAM,CAAC,EAAE,YAAY,CAAC;IAEtB;;OAEG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IAEpB;;OAEG;IACH,cAAc,CAAC,EAAE,QAAQ,GAAG,QAAQ,CAAC;CACtC,CAAC;AAMF;;;;GAIG;AACH,MAAM,MAAM,eAAe,CAAC,CAAC,SAAS,YAAY,GAAG,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,IAAI;IAC5E;;OAEG;IACH,MAAM,CAAC,EAAE,CAAC,CAAC;IAEX;;OAEG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IAEpB;;OAEG;IACH,cAAc,CAAC,EAAE,QAAQ,GAAG,QAAQ,CAAC;CACtC,CAAC;AAMF;;GAEG;AACH,MAAM,MAAM,iBAAiB,GAAG;IAC9B;;OAEG;IACH,IAAI,EAAE,GAAG,CAAC,GAAG,GAAG,SAAS,GAAG,QAAQ,EAAE,aAAa,CAAC,CAAC;IACrD;;OAEG;IACH,SAAS,EAAE,MAAM,CAAC;IAClB;;OAEG;IACH,eAAe,EAAE,MAAM,CAAC;IACxB;;OAEG;IACH,cAAc,EAAE,MAAM,CAAC;CACxB,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,kBAAkB,EAAE,iBAKhC,CAAC;AAMF;;;;;;;;GAQG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,GAAG,CAiB3C;AAMD;;;;;;;;;GASG;AACH,wBAAgB,eAAe,CAAC,CAAC,SAAS,YAAY,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,GAAG,SAAS,CAAC,CAAC,CAAC,CAiB7F;AAMD;;;;;;;;;GASG;AACH,wBAAgB,cAAc,CAAC,CAAC,SAAS,YAAY,GAAG,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,EAC3E,IAAI,EAAE,MAAM,EACZ,OAAO,CAAC,EAAE,eAAe,CAAC,CAAC,CAAC,GAC3B,QAAQ,CAAC,CAAC,CAAC,CAmBb;AAMD;;;;GAIG;AACH,eAAO,MAAM,QAAQ,iCAA6B,CAAC;AAMnD;;;GAGG;AACH,eAAO,MAAM,SAAS,KAAyB,CAAC;AAEhD;;;GAGG;AACH,eAAO,MAAM,cAAc,KAA8B,CAAC"}
|
package/dist/registry.js
ADDED
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { encodeComponent, encodeRelation, encodeTag, ID_MASK_8, ID_MASK_20 } from "./encoding.js";
|
|
2
|
+
/**
|
|
3
|
+
* Global component registry singleton.
|
|
4
|
+
*/
|
|
5
|
+
export const COMPONENT_REGISTRY = {
|
|
6
|
+
byId: new Map(),
|
|
7
|
+
nextTagId: 0,
|
|
8
|
+
nextComponentId: 0,
|
|
9
|
+
nextRelationId: 0,
|
|
10
|
+
};
|
|
11
|
+
// ============================================================================
|
|
12
|
+
// Tag Definition
|
|
13
|
+
// ============================================================================
|
|
14
|
+
/**
|
|
15
|
+
* Defines a tag component. Tags are lightweight markers without data.
|
|
16
|
+
* @param name - Human-readable tag name for debugging
|
|
17
|
+
* @returns Encoded tag ID
|
|
18
|
+
* @throws {RangeError} If tag limit (1,048,576) exceeded
|
|
19
|
+
* @example
|
|
20
|
+
* const Player = defineTag("Player");
|
|
21
|
+
* addTag(world, entity, Player);
|
|
22
|
+
*/
|
|
23
|
+
export function defineTag(name) {
|
|
24
|
+
const rawId = COMPONENT_REGISTRY.nextTagId;
|
|
25
|
+
if (rawId > ID_MASK_20) {
|
|
26
|
+
throw new RangeError(`Tag limit exceeded (max ${ID_MASK_20})`);
|
|
27
|
+
}
|
|
28
|
+
const tagId = encodeTag(rawId);
|
|
29
|
+
COMPONENT_REGISTRY.byId.set(tagId, {
|
|
30
|
+
name,
|
|
31
|
+
schema: undefined,
|
|
32
|
+
});
|
|
33
|
+
COMPONENT_REGISTRY.nextTagId++;
|
|
34
|
+
return tagId;
|
|
35
|
+
}
|
|
36
|
+
// ============================================================================
|
|
37
|
+
// Component Definition
|
|
38
|
+
// ============================================================================
|
|
39
|
+
/**
|
|
40
|
+
* Defines a data component with a typed schema for storage.
|
|
41
|
+
* @param name - Human-readable component name for debugging
|
|
42
|
+
* @param schema - Field schema record defining data layout
|
|
43
|
+
* @returns Encoded component ID with schema type
|
|
44
|
+
* @throws {RangeError} If component limit (1,048,576) exceeded
|
|
45
|
+
* @example
|
|
46
|
+
* const Position = defineComponent("Position", { x: Type.f32, y: Type.f32 });
|
|
47
|
+
* set(world, entity, Position, { x: 10, y: 20 });
|
|
48
|
+
*/
|
|
49
|
+
export function defineComponent(name, schema) {
|
|
50
|
+
const rawId = COMPONENT_REGISTRY.nextComponentId;
|
|
51
|
+
if (rawId > ID_MASK_20) {
|
|
52
|
+
throw new RangeError(`Component limit exceeded (max ${ID_MASK_20})`);
|
|
53
|
+
}
|
|
54
|
+
const componentId = encodeComponent(rawId);
|
|
55
|
+
COMPONENT_REGISTRY.byId.set(componentId, {
|
|
56
|
+
name,
|
|
57
|
+
schema,
|
|
58
|
+
});
|
|
59
|
+
COMPONENT_REGISTRY.nextComponentId++;
|
|
60
|
+
return componentId;
|
|
61
|
+
}
|
|
62
|
+
// ============================================================================
|
|
63
|
+
// Relation Definition
|
|
64
|
+
// ============================================================================
|
|
65
|
+
/**
|
|
66
|
+
* Defines a relation for entity-to-entity relationships.
|
|
67
|
+
* @param name - Human-readable relation name for debugging
|
|
68
|
+
* @param options - Configuration: schema for data, exclusive trait, delete behavior
|
|
69
|
+
* @returns Encoded relation ID with schema type
|
|
70
|
+
* @throws {RangeError} If relation limit (256) exceeded
|
|
71
|
+
* @example
|
|
72
|
+
* const ChildOf = defineRelation("ChildOf", { exclusive: true, onDeleteTarget: "delete" });
|
|
73
|
+
* addPair(world, child, ChildOf, parent);
|
|
74
|
+
*/
|
|
75
|
+
export function defineRelation(name, options) {
|
|
76
|
+
const rawId = COMPONENT_REGISTRY.nextRelationId;
|
|
77
|
+
if (rawId > ID_MASK_8) {
|
|
78
|
+
throw new RangeError(`Relation limit exceeded (max ${ID_MASK_8})`);
|
|
79
|
+
}
|
|
80
|
+
const relationId = encodeRelation(rawId);
|
|
81
|
+
COMPONENT_REGISTRY.byId.set(relationId, {
|
|
82
|
+
name,
|
|
83
|
+
schema: options?.schema,
|
|
84
|
+
exclusive: options?.exclusive,
|
|
85
|
+
onDeleteTarget: options?.onDeleteTarget,
|
|
86
|
+
});
|
|
87
|
+
COMPONENT_REGISTRY.nextRelationId++;
|
|
88
|
+
return relationId;
|
|
89
|
+
}
|
|
90
|
+
// ============================================================================
|
|
91
|
+
// Built-in Relations
|
|
92
|
+
// ============================================================================
|
|
93
|
+
/**
|
|
94
|
+
* Wildcard relation for query patterns. Reserved as relation ID 0.
|
|
95
|
+
* - `pair(Wildcard, target)` matches all entities targeting target
|
|
96
|
+
* - `pair(relation, Wildcard)` matches entities with any target for relation
|
|
97
|
+
*/
|
|
98
|
+
export const Wildcard = defineRelation("Wildcard");
|
|
99
|
+
// ============================================================================
|
|
100
|
+
// Relation Trait Tags
|
|
101
|
+
// ============================================================================
|
|
102
|
+
/**
|
|
103
|
+
* Marks a relation as exclusive (one target per subject).
|
|
104
|
+
* Adding a pair with an exclusive relation auto-removes any existing pair with that relation.
|
|
105
|
+
*/
|
|
106
|
+
export const Exclusive = defineTag("Exclusive");
|
|
107
|
+
/**
|
|
108
|
+
* Cascade delete subjects when target is destroyed.
|
|
109
|
+
* When an entity is destroyed, all entities with a pair targeting it are also destroyed.
|
|
110
|
+
*/
|
|
111
|
+
export const OnDeleteTarget = defineTag("OnDeleteTarget");
|
|
112
|
+
//# sourceMappingURL=registry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.js","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,cAAc,EAAE,SAAS,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAsFlG;;GAEG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAsB;IACnD,IAAI,EAAE,IAAI,GAAG,EAAE;IACf,SAAS,EAAE,CAAC;IACZ,eAAe,EAAE,CAAC;IAClB,cAAc,EAAE,CAAC;CAClB,CAAC;AAEF,+EAA+E;AAC/E,iBAAiB;AACjB,+EAA+E;AAE/E;;;;;;;;GAQG;AACH,MAAM,UAAU,SAAS,CAAC,IAAY;IACpC,MAAM,KAAK,GAAG,kBAAkB,CAAC,SAAS,CAAC;IAE3C,IAAI,KAAK,GAAG,UAAU,EAAE,CAAC;QACvB,MAAM,IAAI,UAAU,CAAC,2BAA2B,UAAU,GAAG,CAAC,CAAC;IACjE,CAAC;IAED,MAAM,KAAK,GAAG,SAAS,CAAC,KAAK,CAAC,CAAC;IAE/B,kBAAkB,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE;QACjC,IAAI;QACJ,MAAM,EAAE,SAAS;KAClB,CAAC,CAAC;IAEH,kBAAkB,CAAC,SAAS,EAAE,CAAC;IAE/B,OAAO,KAAK,CAAC;AACf,CAAC;AAED,+EAA+E;AAC/E,uBAAuB;AACvB,+EAA+E;AAE/E;;;;;;;;;GASG;AACH,MAAM,UAAU,eAAe,CAAyB,IAAY,EAAE,MAAS;IAC7E,MAAM,KAAK,GAAG,kBAAkB,CAAC,eAAe,CAAC;IAEjD,IAAI,KAAK,GAAG,UAAU,EAAE,CAAC;QACvB,MAAM,IAAI,UAAU,CAAC,iCAAiC,UAAU,GAAG,CAAC,CAAC;IACvE,CAAC;IAED,MAAM,WAAW,GAAG,eAAe,CAAI,KAAK,CAAC,CAAC;IAE9C,kBAAkB,CAAC,IAAI,CAAC,GAAG,CAAC,WAAW,EAAE;QACvC,IAAI;QACJ,MAAM;KACP,CAAC,CAAC;IAEH,kBAAkB,CAAC,eAAe,EAAE,CAAC;IAErC,OAAO,WAAW,CAAC;AACrB,CAAC;AAED,+EAA+E;AAC/E,sBAAsB;AACtB,+EAA+E;AAE/E;;;;;;;;;GASG;AACH,MAAM,UAAU,cAAc,CAC5B,IAAY,EACZ,OAA4B;IAE5B,MAAM,KAAK,GAAG,kBAAkB,CAAC,cAAc,CAAC;IAEhD,IAAI,KAAK,GAAG,SAAS,EAAE,CAAC;QACtB,MAAM,IAAI,UAAU,CAAC,gCAAgC,SAAS,GAAG,CAAC,CAAC;IACrE,CAAC;IAED,MAAM,UAAU,GAAG,cAAc,CAAI,KAAK,CAAC,CAAC;IAE5C,kBAAkB,CAAC,IAAI,CAAC,GAAG,CAAC,UAAU,EAAE;QACtC,IAAI;QACJ,MAAM,EAAE,OAAO,EAAE,MAAM;QACvB,SAAS,EAAE,OAAO,EAAE,SAAS;QAC7B,cAAc,EAAE,OAAO,EAAE,cAAc;KACxC,CAAC,CAAC;IAEH,kBAAkB,CAAC,cAAc,EAAE,CAAC;IAEpC,OAAO,UAAU,CAAC;AACpB,CAAC;AAED,+EAA+E;AAC/E,qBAAqB;AACrB,+EAA+E;AAE/E;;;;GAIG;AACH,MAAM,CAAC,MAAM,QAAQ,GAAG,cAAc,CAAC,UAAU,CAAC,CAAC;AAEnD,+EAA+E;AAC/E,sBAAsB;AACtB,+EAA+E;AAE/E;;;GAGG;AACH,MAAM,CAAC,MAAM,SAAS,GAAG,SAAS,CAAC,WAAW,CAAC,CAAC;AAEhD;;;GAGG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG,SAAS,CAAC,gBAAgB,CAAC,CAAC"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import type { EntityId, Pair, Relation, RelationTargetId } from "./encoding.js";
|
|
2
|
+
import type { World } from "./world.js";
|
|
3
|
+
/**
|
|
4
|
+
* Create a pair from a relation and target.
|
|
5
|
+
*
|
|
6
|
+
* @param relation - Relation ID
|
|
7
|
+
* @param target - Target entity, tag, component, or relation
|
|
8
|
+
* @returns Encoded pair ID that can be used as a component
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* const childOf = pair(ChildOf, parent);
|
|
12
|
+
* addComponent(world, child, childOf);
|
|
13
|
+
*/
|
|
14
|
+
export declare function pair<R extends Relation>(relation: R, target: RelationTargetId): Pair<R>;
|
|
15
|
+
/**
|
|
16
|
+
* Extract the relation component from a pair.
|
|
17
|
+
*
|
|
18
|
+
* @param pairId - Encoded pair ID
|
|
19
|
+
* @returns The relation ID
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* const rel = getPairRelation(pair(ChildOf, parent)); // ChildOf
|
|
23
|
+
*/
|
|
24
|
+
export declare function getPairRelation<R extends Relation>(pairId: Pair<R>): R;
|
|
25
|
+
/**
|
|
26
|
+
* Extract the target from a pair.
|
|
27
|
+
*
|
|
28
|
+
* For entity targets, looks up current generation for weak reference semantics.
|
|
29
|
+
*
|
|
30
|
+
* @param world - World instance
|
|
31
|
+
* @param pairId - Encoded pair ID
|
|
32
|
+
* @returns Target entity, tag, component, or relation
|
|
33
|
+
*
|
|
34
|
+
* @example
|
|
35
|
+
* const target = getPairTarget(world, pair(ChildOf, parent)); // parent
|
|
36
|
+
*/
|
|
37
|
+
export declare function getPairTarget(world: World, pairId: Pair): RelationTargetId;
|
|
38
|
+
/**
|
|
39
|
+
* Get all targets for a relation on an entity.
|
|
40
|
+
*
|
|
41
|
+
* @param world - World instance
|
|
42
|
+
* @param entityId - Entity to query
|
|
43
|
+
* @param relation - Relation to find targets for
|
|
44
|
+
* @returns Array of target IDs
|
|
45
|
+
*
|
|
46
|
+
* @example
|
|
47
|
+
* const parents = getRelationTargets(world, child, ChildOf);
|
|
48
|
+
*/
|
|
49
|
+
export declare function getRelationTargets(world: World, entityId: EntityId, relation: Relation): RelationTargetId[];
|
|
50
|
+
/**
|
|
51
|
+
* Clean up all pairs targeting a specific entity when it is destroyed.
|
|
52
|
+
*
|
|
53
|
+
* Handles OnDeleteTarget cascade policy by collecting and destroying subjects
|
|
54
|
+
* that have pairs with the target entity.
|
|
55
|
+
*
|
|
56
|
+
* @param world - World instance
|
|
57
|
+
* @param targetEntity - Entity being destroyed that may be a target
|
|
58
|
+
*/
|
|
59
|
+
export declare function cleanupPairsTargetingEntity(world: World, targetEntity: EntityId): void;
|
|
60
|
+
//# sourceMappingURL=relation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"relation.d.ts","sourceRoot":"","sources":["../src/relation.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,IAAI,EAAE,QAAQ,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAmBhF,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAMxC;;;;;;;;;;GAUG;AACH,wBAAgB,IAAI,CAAC,CAAC,SAAS,QAAQ,EAAE,QAAQ,EAAE,CAAC,EAAE,MAAM,EAAE,gBAAgB,GAAG,IAAI,CAAC,CAAC,CAAC,CAEvF;AAED;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAAC,CAAC,SAAS,QAAQ,EAAE,MAAM,EAAE,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAItE;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,GAAG,gBAAgB,CA2B1E;AAMD;;;;;;;;;;GAUG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,GAAG,gBAAgB,EAAE,CA4B3G;AAMD;;;;;;;;GAQG;AACH,wBAAgB,2BAA2B,CAAC,KAAK,EAAE,KAAK,EAAE,YAAY,EAAE,QAAQ,GAAG,IAAI,CAkEtF"}
|
package/dist/relation.js
ADDED
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
import { hasComponent } from "./component.js";
|
|
2
|
+
import { COMPONENT_TYPE, ENTITY_TYPE, encodeComponent, encodeEntity, encodePair, encodeRelation, encodeTag, extractId, extractPairRelationId, extractPairTargetId, extractPairTargetType, isPair, RELATIONSHIP_TYPE, TAG_TYPE, } from "./encoding.js";
|
|
3
|
+
import { destroyEntity, ensureEntity, isEntityAlive } from "./entity.js";
|
|
4
|
+
import { OnDeleteTarget, Wildcard } from "./registry.js";
|
|
5
|
+
// ============================================================================
|
|
6
|
+
// Pair Creation and Extraction
|
|
7
|
+
// ============================================================================
|
|
8
|
+
/**
|
|
9
|
+
* Create a pair from a relation and target.
|
|
10
|
+
*
|
|
11
|
+
* @param relation - Relation ID
|
|
12
|
+
* @param target - Target entity, tag, component, or relation
|
|
13
|
+
* @returns Encoded pair ID that can be used as a component
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* const childOf = pair(ChildOf, parent);
|
|
17
|
+
* addComponent(world, child, childOf);
|
|
18
|
+
*/
|
|
19
|
+
export function pair(relation, target) {
|
|
20
|
+
return encodePair(relation, target);
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Extract the relation component from a pair.
|
|
24
|
+
*
|
|
25
|
+
* @param pairId - Encoded pair ID
|
|
26
|
+
* @returns The relation ID
|
|
27
|
+
*
|
|
28
|
+
* @example
|
|
29
|
+
* const rel = getPairRelation(pair(ChildOf, parent)); // ChildOf
|
|
30
|
+
*/
|
|
31
|
+
export function getPairRelation(pairId) {
|
|
32
|
+
const relationRawId = extractPairRelationId(pairId);
|
|
33
|
+
return encodeRelation(relationRawId);
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Extract the target from a pair.
|
|
37
|
+
*
|
|
38
|
+
* For entity targets, looks up current generation for weak reference semantics.
|
|
39
|
+
*
|
|
40
|
+
* @param world - World instance
|
|
41
|
+
* @param pairId - Encoded pair ID
|
|
42
|
+
* @returns Target entity, tag, component, or relation
|
|
43
|
+
*
|
|
44
|
+
* @example
|
|
45
|
+
* const target = getPairTarget(world, pair(ChildOf, parent)); // parent
|
|
46
|
+
*/
|
|
47
|
+
export function getPairTarget(world, pairId) {
|
|
48
|
+
const targetRawId = extractPairTargetId(pairId);
|
|
49
|
+
const targetType = extractPairTargetType(pairId);
|
|
50
|
+
switch (targetType) {
|
|
51
|
+
case ENTITY_TYPE: {
|
|
52
|
+
// Entity targets use weak reference semantics - look up current generation
|
|
53
|
+
const generation = world.entities.generations.get(targetRawId);
|
|
54
|
+
return encodeEntity(targetRawId, generation);
|
|
55
|
+
}
|
|
56
|
+
case TAG_TYPE: {
|
|
57
|
+
return encodeTag(targetRawId);
|
|
58
|
+
}
|
|
59
|
+
case COMPONENT_TYPE: {
|
|
60
|
+
return encodeComponent(targetRawId);
|
|
61
|
+
}
|
|
62
|
+
case RELATIONSHIP_TYPE: {
|
|
63
|
+
return encodeRelation(targetRawId);
|
|
64
|
+
}
|
|
65
|
+
default:
|
|
66
|
+
throw new Error(`Invalid target type in pair: ${targetType}`);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
// ============================================================================
|
|
70
|
+
// Relation Queries
|
|
71
|
+
// ============================================================================
|
|
72
|
+
/**
|
|
73
|
+
* Get all targets for a relation on an entity.
|
|
74
|
+
*
|
|
75
|
+
* @param world - World instance
|
|
76
|
+
* @param entityId - Entity to query
|
|
77
|
+
* @param relation - Relation to find targets for
|
|
78
|
+
* @returns Array of target IDs
|
|
79
|
+
*
|
|
80
|
+
* @example
|
|
81
|
+
* const parents = getRelationTargets(world, child, ChildOf);
|
|
82
|
+
*/
|
|
83
|
+
export function getRelationTargets(world, entityId, relation) {
|
|
84
|
+
const meta = ensureEntity(world, entityId);
|
|
85
|
+
const relationRawId = extractId(relation);
|
|
86
|
+
const relationWildcardPair = encodePair(relation, Wildcard);
|
|
87
|
+
const targets = [];
|
|
88
|
+
for (const typeId of meta.archetype.types) {
|
|
89
|
+
if (!isPair(typeId)) {
|
|
90
|
+
continue;
|
|
91
|
+
}
|
|
92
|
+
// Skip wildcard pair (pair(relation, Wildcard))
|
|
93
|
+
if (typeId === relationWildcardPair) {
|
|
94
|
+
continue;
|
|
95
|
+
}
|
|
96
|
+
const pairRelationRawId = extractPairRelationId(typeId);
|
|
97
|
+
if (pairRelationRawId !== relationRawId) {
|
|
98
|
+
continue;
|
|
99
|
+
}
|
|
100
|
+
targets.push(getPairTarget(world, typeId));
|
|
101
|
+
}
|
|
102
|
+
return targets;
|
|
103
|
+
}
|
|
104
|
+
// ============================================================================
|
|
105
|
+
// Cleanup
|
|
106
|
+
// ============================================================================
|
|
107
|
+
/**
|
|
108
|
+
* Clean up all pairs targeting a specific entity when it is destroyed.
|
|
109
|
+
*
|
|
110
|
+
* Handles OnDeleteTarget cascade policy by collecting and destroying subjects
|
|
111
|
+
* that have pairs with the target entity.
|
|
112
|
+
*
|
|
113
|
+
* @param world - World instance
|
|
114
|
+
* @param targetEntity - Entity being destroyed that may be a target
|
|
115
|
+
*/
|
|
116
|
+
export function cleanupPairsTargetingEntity(world, targetEntity) {
|
|
117
|
+
// Pairs themselves cannot be targets of other pairs
|
|
118
|
+
if (isPair(targetEntity)) {
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
// Use wildcard pair to find all archetypes containing pairs with this target
|
|
122
|
+
const wildcardTargetPair = encodePair(Wildcard, targetEntity);
|
|
123
|
+
if (!isEntityAlive(world, wildcardTargetPair)) {
|
|
124
|
+
// Entity was never used as a target, nothing to clean up
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
const wildcardMeta = ensureEntity(world, wildcardTargetPair);
|
|
128
|
+
// Separate pairs by their OnDeleteTarget policy:
|
|
129
|
+
// - pairsToRemove: Just destroy the pair entity (default behavior)
|
|
130
|
+
// - pairsToDelete: Cascade delete to subjects holding the pair
|
|
131
|
+
const pairsToRemove = new Set([wildcardTargetPair]);
|
|
132
|
+
const pairsToDelete = new Set();
|
|
133
|
+
for (const archetype of wildcardMeta.records) {
|
|
134
|
+
for (const typeId of archetype.types) {
|
|
135
|
+
if (typeId === wildcardTargetPair || !isPair(typeId) || getPairTarget(world, typeId) !== targetEntity) {
|
|
136
|
+
continue;
|
|
137
|
+
}
|
|
138
|
+
const relation = getPairRelation(typeId);
|
|
139
|
+
if (hasComponent(world, relation, OnDeleteTarget)) {
|
|
140
|
+
pairsToDelete.add(typeId);
|
|
141
|
+
}
|
|
142
|
+
else {
|
|
143
|
+
pairsToRemove.add(typeId);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
// Phase 1: Collect subjects for cascade delete before destroying pairs
|
|
148
|
+
// Using Set prevents duplicates when entity has multiple cascading pairs
|
|
149
|
+
const subjectsToDelete = new Set();
|
|
150
|
+
for (const pairId of pairsToDelete) {
|
|
151
|
+
const pairMeta = ensureEntity(world, pairId);
|
|
152
|
+
for (const archetype of pairMeta.records) {
|
|
153
|
+
for (const entityId of archetype.entities) {
|
|
154
|
+
subjectsToDelete.add(entityId);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
// Phase 2: Destroy non-cascading pair entities (removes pairs from subjects)
|
|
159
|
+
for (const pairId of pairsToRemove) {
|
|
160
|
+
destroyEntity(world, pairId);
|
|
161
|
+
}
|
|
162
|
+
// Phase 3: Destroy cascading pair entities
|
|
163
|
+
for (const pairId of pairsToDelete) {
|
|
164
|
+
destroyEntity(world, pairId);
|
|
165
|
+
}
|
|
166
|
+
// Phase 4: Delete subjects that had cascading pairs (may trigger recursive cascades)
|
|
167
|
+
for (const entityId of subjectsToDelete) {
|
|
168
|
+
destroyEntity(world, entityId);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
//# sourceMappingURL=relation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"relation.js","sourceRoot":"","sources":["../src/relation.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { EntityId } from "./encoding.js";
|
|
2
|
+
import type { Event } from "./event.js";
|
|
3
|
+
import type { World } from "./world.js";
|
|
4
|
+
/**
|
|
5
|
+
* Schema for removal events containing the entity that had a component removed.
|
|
6
|
+
*/
|
|
7
|
+
declare const RemovalEventSchema: {
|
|
8
|
+
entity: import("./schema.js").Schema<number>;
|
|
9
|
+
};
|
|
10
|
+
/**
|
|
11
|
+
* Gets the removal event for a component, creating it lazily if needed.
|
|
12
|
+
* @param componentId - Component to track removals for
|
|
13
|
+
* @returns Event that fires when the component is removed from any entity
|
|
14
|
+
* @example
|
|
15
|
+
* for (const { entity } of fetchEvents(world, removed(Health))) {
|
|
16
|
+
* playDeathEffect(entity);
|
|
17
|
+
* }
|
|
18
|
+
*/
|
|
19
|
+
export declare function removed(componentId: EntityId): Event<typeof RemovalEventSchema>;
|
|
20
|
+
/**
|
|
21
|
+
* Initializes removal tracking by registering observers for component removals.
|
|
22
|
+
* @param world - World instance to initialize
|
|
23
|
+
* @internal
|
|
24
|
+
*/
|
|
25
|
+
export declare function initRemovalSystem(world: World): void;
|
|
26
|
+
export {};
|
|
27
|
+
//# sourceMappingURL=removal.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"removal.d.ts","sourceRoot":"","sources":["../src/removal.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAIxC,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAMxC;;GAEG;AACH,QAAA,MAAM,kBAAkB;;CAEvB,CAAC;AAeF;;;;;;;;GAQG;AACH,wBAAgB,OAAO,CAAC,WAAW,EAAE,QAAQ,GAAG,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAS/E;AAMD;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI,CAmBpD"}
|
package/dist/removal.js
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { defineEvent, emitEvent } from "./event.js";
|
|
2
|
+
import { registerObserverCallback } from "./observer.js";
|
|
3
|
+
import { Type } from "./schema.js";
|
|
4
|
+
// ============================================================================
|
|
5
|
+
// Removal Event Schema
|
|
6
|
+
// ============================================================================
|
|
7
|
+
/**
|
|
8
|
+
* Schema for removal events containing the entity that had a component removed.
|
|
9
|
+
*/
|
|
10
|
+
const RemovalEventSchema = {
|
|
11
|
+
entity: Type.i32(),
|
|
12
|
+
};
|
|
13
|
+
// ============================================================================
|
|
14
|
+
// Global Removal Event Registry
|
|
15
|
+
// ============================================================================
|
|
16
|
+
/**
|
|
17
|
+
* Maps component IDs to their lazily-created removal events.
|
|
18
|
+
*/
|
|
19
|
+
const removalEvents = new Map();
|
|
20
|
+
// ============================================================================
|
|
21
|
+
// Public API
|
|
22
|
+
// ============================================================================
|
|
23
|
+
/**
|
|
24
|
+
* Gets the removal event for a component, creating it lazily if needed.
|
|
25
|
+
* @param componentId - Component to track removals for
|
|
26
|
+
* @returns Event that fires when the component is removed from any entity
|
|
27
|
+
* @example
|
|
28
|
+
* for (const { entity } of fetchEvents(world, removed(Health))) {
|
|
29
|
+
* playDeathEffect(entity);
|
|
30
|
+
* }
|
|
31
|
+
*/
|
|
32
|
+
export function removed(componentId) {
|
|
33
|
+
let event = removalEvents.get(componentId);
|
|
34
|
+
if (!event) {
|
|
35
|
+
event = defineEvent(`Removed<${componentId}>`, RemovalEventSchema);
|
|
36
|
+
removalEvents.set(componentId, event);
|
|
37
|
+
}
|
|
38
|
+
return event;
|
|
39
|
+
}
|
|
40
|
+
// ============================================================================
|
|
41
|
+
// Initialization
|
|
42
|
+
// ============================================================================
|
|
43
|
+
/**
|
|
44
|
+
* Initializes removal tracking by registering observers for component removals.
|
|
45
|
+
* @param world - World instance to initialize
|
|
46
|
+
* @internal
|
|
47
|
+
*/
|
|
48
|
+
export function initRemovalSystem(world) {
|
|
49
|
+
// Handle explicit component removal via removeComponent()
|
|
50
|
+
registerObserverCallback(world, "componentRemoved", (componentId, entityId) => {
|
|
51
|
+
emitEvent(world, removed(componentId), { entity: entityId });
|
|
52
|
+
});
|
|
53
|
+
// Handle entity destruction - destroyEntity() doesn't call removeComponent() for each
|
|
54
|
+
// component, so we emit removal events for all components on the entity here
|
|
55
|
+
registerObserverCallback(world, "entityDestroyed", (entityId) => {
|
|
56
|
+
// Observer fires before entity metadata is deleted, so meta is guaranteed to exist
|
|
57
|
+
const meta = world.entities.byId.get(entityId);
|
|
58
|
+
for (const componentId of meta.archetype.types) {
|
|
59
|
+
// Skip the entity's own ID (entities are components in ECS)
|
|
60
|
+
if (componentId !== entityId) {
|
|
61
|
+
emitEvent(world, removed(componentId), { entity: entityId });
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
//# sourceMappingURL=removal.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"removal.js","sourceRoot":"","sources":["../src/removal.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AACpD,OAAO,EAAE,wBAAwB,EAAE,MAAM,eAAe,CAAC;AACzD,OAAO,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AAGnC,+EAA+E;AAC/E,uBAAuB;AACvB,+EAA+E;AAE/E;;GAEG;AACH,MAAM,kBAAkB,GAAG;IACzB,MAAM,EAAE,IAAI,CAAC,GAAG,EAAE;CACnB,CAAC;AAEF,+EAA+E;AAC/E,gCAAgC;AAChC,+EAA+E;AAE/E;;GAEG;AACH,MAAM,aAAa,GAAG,IAAI,GAAG,EAA8C,CAAC;AAE5E,+EAA+E;AAC/E,aAAa;AACb,+EAA+E;AAE/E;;;;;;;;GAQG;AACH,MAAM,UAAU,OAAO,CAAC,WAAqB;IAC3C,IAAI,KAAK,GAAG,aAAa,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;IAE3C,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,KAAK,GAAG,WAAW,CAAC,WAAW,WAAW,GAAG,EAAE,kBAAkB,CAAC,CAAC;QACnE,aAAa,CAAC,GAAG,CAAC,WAAW,EAAE,KAAK,CAAC,CAAC;IACxC,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC;AAED,+EAA+E;AAC/E,iBAAiB;AACjB,+EAA+E;AAE/E;;;;GAIG;AACH,MAAM,UAAU,iBAAiB,CAAC,KAAY;IAC5C,0DAA0D;IAC1D,wBAAwB,CAAC,KAAK,EAAE,kBAAkB,EAAE,CAAC,WAAW,EAAE,QAAQ,EAAE,EAAE;QAC5E,SAAS,CAAC,KAAK,EAAE,OAAO,CAAC,WAAW,CAAC,EAAE,EAAE,MAAM,EAAE,QAAkB,EAAE,CAAC,CAAC;IACzE,CAAC,CAAC,CAAC;IAEH,sFAAsF;IACtF,6EAA6E;IAC7E,wBAAwB,CAAC,KAAK,EAAE,iBAAiB,EAAE,CAAC,QAAQ,EAAE,EAAE;QAC9D,mFAAmF;QACnF,MAAM,IAAI,GAAG,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAE,CAAC;QAEhD,KAAK,MAAM,WAAW,IAAI,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,CAAC;YAC/C,4DAA4D;YAC5D,IAAI,WAAW,KAAK,QAAQ,EAAE,CAAC;gBAC7B,SAAS,CAAC,KAAK,EAAE,OAAO,CAAC,WAAW,CAAC,EAAE,EAAE,MAAM,EAAE,QAAkB,EAAE,CAAC,CAAC;YACzE,CAAC;QACH,CAAC;IACH,CAAC,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import type { Component, EntityId } from "./encoding.js";
|
|
2
|
+
import type { InferSchema, InferSchemaRecord, SchemaRecord } from "./schema.js";
|
|
3
|
+
import type { World } from "./world.js";
|
|
4
|
+
/**
|
|
5
|
+
* Adds a global resource (singleton) to the world using the component-on-self pattern.
|
|
6
|
+
*
|
|
7
|
+
* Resources are stored by adding the component to itself as an entity. Idempotent if already present.
|
|
8
|
+
*
|
|
9
|
+
* @param world - World instance
|
|
10
|
+
* @param component - Component definition to use as resource
|
|
11
|
+
* @param data - Initial values for the resource
|
|
12
|
+
* @returns void
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* ```typescript
|
|
16
|
+
* const Time = defineComponent("Time", { delta: Type.f32() });
|
|
17
|
+
* addResource(world, Time, { delta: 0.016 });
|
|
18
|
+
* ```
|
|
19
|
+
*/
|
|
20
|
+
export declare function addResource<S extends SchemaRecord>(world: World, component: Component<S>, data: InferSchemaRecord<S>): void;
|
|
21
|
+
/**
|
|
22
|
+
* Removes a global resource from the world.
|
|
23
|
+
*
|
|
24
|
+
* @param world - World instance
|
|
25
|
+
* @param component - Component definition (acting as resource handle)
|
|
26
|
+
* @returns void
|
|
27
|
+
*
|
|
28
|
+
* @example
|
|
29
|
+
* ```typescript
|
|
30
|
+
* removeResource(world, Time);
|
|
31
|
+
* ```
|
|
32
|
+
*/
|
|
33
|
+
export declare function removeResource(world: World, component: EntityId): void;
|
|
34
|
+
/**
|
|
35
|
+
* Checks if a global resource exists in the world.
|
|
36
|
+
*
|
|
37
|
+
* @param world - World instance
|
|
38
|
+
* @param component - Component definition (acting as resource handle)
|
|
39
|
+
* @returns True if the resource exists, false otherwise
|
|
40
|
+
*
|
|
41
|
+
* @example
|
|
42
|
+
* ```typescript
|
|
43
|
+
* if (hasResource(world, Time)) {
|
|
44
|
+
* // Time resource is available
|
|
45
|
+
* }
|
|
46
|
+
* ```
|
|
47
|
+
*/
|
|
48
|
+
export declare function hasResource(world: World, component: EntityId): boolean;
|
|
49
|
+
/**
|
|
50
|
+
* Gets the value of a specific field on a global resource.
|
|
51
|
+
*
|
|
52
|
+
* @param world - World instance
|
|
53
|
+
* @param component - Component definition
|
|
54
|
+
* @param key - Field name to retrieve
|
|
55
|
+
* @returns The field value, or undefined if the resource is not present
|
|
56
|
+
*
|
|
57
|
+
* @example
|
|
58
|
+
* ```typescript
|
|
59
|
+
* const dt = getResourceValue(world, Time, "delta");
|
|
60
|
+
* ```
|
|
61
|
+
*/
|
|
62
|
+
export declare function getResourceValue<S extends SchemaRecord, K extends keyof S>(world: World, component: Component<S>, key: K): InferSchema<S[K]> | undefined;
|
|
63
|
+
/**
|
|
64
|
+
* Sets the value of a specific field on a global resource.
|
|
65
|
+
*
|
|
66
|
+
* @param world - World instance
|
|
67
|
+
* @param component - Component definition
|
|
68
|
+
* @param key - Field name to set
|
|
69
|
+
* @param value - New value for the field
|
|
70
|
+
* @returns void
|
|
71
|
+
*
|
|
72
|
+
* @example
|
|
73
|
+
* ```typescript
|
|
74
|
+
* setResourceValue(world, Time, "delta", 0.033);
|
|
75
|
+
* ```
|
|
76
|
+
*/
|
|
77
|
+
export declare function setResourceValue<S extends SchemaRecord, K extends keyof S>(world: World, component: Component<S>, key: K, value: InferSchema<S[K]>): void;
|
|
78
|
+
//# sourceMappingURL=resource.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resource.d.ts","sourceRoot":"","sources":["../src/resource.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzD,OAAO,KAAK,EAAE,WAAW,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAChF,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAExC;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,WAAW,CAAC,CAAC,SAAS,YAAY,EAChD,KAAK,EAAE,KAAK,EACZ,SAAS,EAAE,SAAS,CAAC,CAAC,CAAC,EACvB,IAAI,EAAE,iBAAiB,CAAC,CAAC,CAAC,GACzB,IAAI,CAEN;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,QAAQ,GAAG,IAAI,CAEtE;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,QAAQ,GAAG,OAAO,CAEtE;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,gBAAgB,CAAC,CAAC,SAAS,YAAY,EAAE,CAAC,SAAS,MAAM,CAAC,EACxE,KAAK,EAAE,KAAK,EACZ,SAAS,EAAE,SAAS,CAAC,CAAC,CAAC,EACvB,GAAG,EAAE,CAAC,GACL,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,SAAS,CAE/B;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,gBAAgB,CAAC,CAAC,SAAS,YAAY,EAAE,CAAC,SAAS,MAAM,CAAC,EACxE,KAAK,EAAE,KAAK,EACZ,SAAS,EAAE,SAAS,CAAC,CAAC,CAAC,EACvB,GAAG,EAAE,CAAC,EACN,KAAK,EAAE,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GACvB,IAAI,CAEN"}
|