archetype-ecs 1.2.0 → 2.0.0

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.
@@ -0,0 +1,12 @@
1
+ export interface ProfilerEntry {
2
+ avg: number;
3
+ }
4
+ export interface Profiler {
5
+ readonly enabled: boolean;
6
+ setEnabled(value: boolean): void;
7
+ begin(): number;
8
+ end(name: string, t0: number): void;
9
+ record(name: string, ms: number): void;
10
+ getData(): Map<string, ProfilerEntry>;
11
+ }
12
+ export declare const profiler: Profiler;
@@ -0,0 +1,38 @@
1
+ const EMA_ALPHA = 0.1;
2
+ const data = new Map();
3
+ let enabled = false;
4
+ export const profiler = {
5
+ get enabled() { return enabled; },
6
+ setEnabled(value) {
7
+ enabled = value;
8
+ if (!value)
9
+ data.clear();
10
+ },
11
+ begin() {
12
+ return enabled ? performance.now() : 0;
13
+ },
14
+ end(name, t0) {
15
+ if (!enabled)
16
+ return;
17
+ const ms = performance.now() - t0;
18
+ const entry = data.get(name);
19
+ if (entry) {
20
+ entry.avg += (ms - entry.avg) * EMA_ALPHA;
21
+ }
22
+ else {
23
+ data.set(name, { avg: ms });
24
+ }
25
+ },
26
+ record(name, ms) {
27
+ if (!enabled)
28
+ return;
29
+ const entry = data.get(name);
30
+ if (entry) {
31
+ entry.avg += (ms - entry.avg) * EMA_ALPHA;
32
+ }
33
+ else {
34
+ data.set(name, { avg: ms });
35
+ }
36
+ },
37
+ getData() { return data; }
38
+ };
@@ -0,0 +1,37 @@
1
+ import type { ComponentDef } from './ComponentRegistry.js';
2
+ import type { EntityId, EntityManager, ArchetypeView } from './EntityManager.js';
3
+ export declare function OnAdded(...types: ComponentDef[]): (_method: Function, context: ClassMethodDecoratorContext) => void;
4
+ export declare function OnRemoved(...types: ComponentDef[]): (_method: Function, context: ClassMethodDecoratorContext) => void;
5
+ interface Hook {
6
+ buffer: Set<EntityId>;
7
+ handler: (id: EntityId) => void;
8
+ }
9
+ export declare class System {
10
+ em: EntityManager;
11
+ _unsubs: (() => void)[];
12
+ _hooks: Hook[];
13
+ constructor(em: EntityManager);
14
+ _registerHook(kind: 'add' | 'remove', types: ComponentDef[], handler: (id: EntityId) => void): void;
15
+ forEach(types: ComponentDef[], callback: (view: ArchetypeView) => void, exclude?: ComponentDef[]): void;
16
+ tick?(): void;
17
+ run(): void;
18
+ dispose(): void;
19
+ }
20
+ type HookCallback = (entityId: EntityId) => void;
21
+ export interface SystemContext {
22
+ onAdded(...args: [...ComponentDef[], HookCallback]): void;
23
+ onRemoved(...args: [...ComponentDef[], HookCallback]): void;
24
+ forEach(types: ComponentDef[], callback: (view: ArchetypeView) => void, exclude?: ComponentDef[]): void;
25
+ }
26
+ export type FunctionalSystemConstructor = (sys: SystemContext) => (() => void) | void;
27
+ export interface FunctionalSystem {
28
+ (): void;
29
+ dispose(): void;
30
+ }
31
+ export declare function createSystem(em: EntityManager, constructor: FunctionalSystemConstructor): FunctionalSystem;
32
+ export interface Pipeline {
33
+ (): void;
34
+ dispose(): void;
35
+ }
36
+ export declare function createSystems(em: EntityManager, entries: (FunctionalSystemConstructor | (new (em: EntityManager) => System))[]): Pipeline;
37
+ export {};
@@ -0,0 +1,139 @@
1
+ // ── Decorators (TC39 Stage 3) ────────────────────────────
2
+ export function OnAdded(...types) {
3
+ return function (_method, context) {
4
+ context.addInitializer(function () {
5
+ const self = this;
6
+ self._registerHook('add', types, self[context.name].bind(self));
7
+ });
8
+ };
9
+ }
10
+ export function OnRemoved(...types) {
11
+ return function (_method, context) {
12
+ context.addInitializer(function () {
13
+ const self = this;
14
+ self._registerHook('remove', types, self[context.name].bind(self));
15
+ });
16
+ };
17
+ }
18
+ export class System {
19
+ em;
20
+ _unsubs = [];
21
+ _hooks = [];
22
+ constructor(em) {
23
+ this.em = em;
24
+ }
25
+ _registerHook(kind, types, handler) {
26
+ const buffer = new Set();
27
+ if (kind === 'add') {
28
+ for (const comp of types) {
29
+ const unsub = this.em.onAdd(comp, (id) => {
30
+ for (let i = 0; i < types.length; i++) {
31
+ if (!this.em.hasComponent(id, types[i]))
32
+ return;
33
+ }
34
+ buffer.add(id);
35
+ });
36
+ this._unsubs.push(unsub);
37
+ }
38
+ }
39
+ else {
40
+ for (const comp of types) {
41
+ const unsub = this.em.onRemove(comp, (id) => buffer.add(id));
42
+ this._unsubs.push(unsub);
43
+ }
44
+ }
45
+ this._hooks.push({ buffer, handler });
46
+ }
47
+ forEach(types, callback, exclude) {
48
+ this.em.forEach(types, callback, exclude);
49
+ }
50
+ run() {
51
+ for (const hook of this._hooks) {
52
+ for (const id of hook.buffer)
53
+ hook.handler(id);
54
+ hook.buffer.clear();
55
+ }
56
+ if (this.tick)
57
+ this.tick();
58
+ }
59
+ dispose() {
60
+ for (const unsub of this._unsubs)
61
+ unsub();
62
+ this._unsubs.length = 0;
63
+ this._hooks.length = 0;
64
+ }
65
+ }
66
+ export function createSystem(em, constructor) {
67
+ const hooks = [];
68
+ const sys = {
69
+ onAdded(...args) {
70
+ const callback = args[args.length - 1];
71
+ const types = args.slice(0, -1);
72
+ const buffer = new Set();
73
+ const unsubs = [];
74
+ for (const comp of types) {
75
+ const unsub = em.onAdd(comp, (id) => {
76
+ for (let i = 0; i < types.length; i++) {
77
+ if (!em.hasComponent(id, types[i]))
78
+ return;
79
+ }
80
+ buffer.add(id);
81
+ });
82
+ unsubs.push(unsub);
83
+ }
84
+ hooks.push({ unsubs, buffer, callback });
85
+ },
86
+ onRemoved(...args) {
87
+ const callback = args[args.length - 1];
88
+ const types = args.slice(0, -1);
89
+ const buffer = new Set();
90
+ const unsubs = [];
91
+ for (const comp of types) {
92
+ const unsub = em.onRemove(comp, (id) => {
93
+ buffer.add(id);
94
+ });
95
+ unsubs.push(unsub);
96
+ }
97
+ hooks.push({ unsubs, buffer, callback });
98
+ },
99
+ forEach(types, callback, exclude) {
100
+ em.forEach(types, callback, exclude);
101
+ },
102
+ };
103
+ const tick = constructor(sys);
104
+ function system() {
105
+ for (const hook of hooks) {
106
+ for (const id of hook.buffer)
107
+ hook.callback(id);
108
+ hook.buffer.clear();
109
+ }
110
+ if (tick)
111
+ tick();
112
+ }
113
+ system.dispose = function () {
114
+ for (const hook of hooks) {
115
+ for (const unsub of hook.unsubs)
116
+ unsub();
117
+ }
118
+ hooks.length = 0;
119
+ };
120
+ return system;
121
+ }
122
+ export function createSystems(em, entries) {
123
+ const systems = entries.map(Entry => {
124
+ if (Entry.prototype instanceof System) {
125
+ return new Entry(em);
126
+ }
127
+ const sys = createSystem(em, Entry);
128
+ return { run: sys, dispose: sys.dispose };
129
+ });
130
+ function pipeline() {
131
+ for (let i = 0; i < systems.length; i++)
132
+ systems[i].run();
133
+ }
134
+ pipeline.dispose = function () {
135
+ for (let i = 0; i < systems.length; i++)
136
+ systems[i].dispose();
137
+ };
138
+ return pipeline;
139
+ }
@@ -0,0 +1,10 @@
1
+ export { createEntityManager } from './EntityManager.js';
2
+ export type { EntityId, FieldRef, ArchetypeView, EntityManager, SerializedData } from './EntityManager.js';
3
+ export { createSystem, createSystems, System, OnAdded, OnRemoved } from './System.js';
4
+ export type { SystemContext, FunctionalSystemConstructor, FunctionalSystem, Pipeline } from './System.js';
5
+ export { profiler } from './Profiler.js';
6
+ export type { Profiler, ProfilerEntry } from './Profiler.js';
7
+ export { TYPED, componentSchemas, parseTypeSpec } from './ComponentRegistry.js';
8
+ export type { ComponentDef, TypeSpec } from './ComponentRegistry.js';
9
+ import { type ComponentDef } from './ComponentRegistry.js';
10
+ export declare function component(name: string, typeOrSchema?: string | Record<string, string>, fields?: string[]): ComponentDef;
@@ -0,0 +1,29 @@
1
+ export { createEntityManager } from './EntityManager.js';
2
+ export { createSystem, createSystems, System, OnAdded, OnRemoved } from './System.js';
3
+ export { profiler } from './Profiler.js';
4
+ export { TYPED, componentSchemas, parseTypeSpec } from './ComponentRegistry.js';
5
+ import { parseTypeSpec, componentSchemas } from './ComponentRegistry.js';
6
+ export function component(name, typeOrSchema, fields) {
7
+ const sym = Symbol(name);
8
+ const comp = { _sym: sym, _name: name };
9
+ let schema;
10
+ if (typeof typeOrSchema === 'string' && Array.isArray(fields)) {
11
+ const spec = parseTypeSpec(typeOrSchema);
12
+ schema = {};
13
+ for (const f of fields) {
14
+ schema[f] = spec;
15
+ comp[f] = { _sym: sym, _field: f };
16
+ }
17
+ }
18
+ else if (typeOrSchema && typeof typeOrSchema === 'object') {
19
+ schema = {};
20
+ for (const [field, type] of Object.entries(typeOrSchema)) {
21
+ schema[field] = parseTypeSpec(type);
22
+ comp[field] = { _sym: sym, _field: field };
23
+ }
24
+ }
25
+ if (schema) {
26
+ componentSchemas.set(sym, schema);
27
+ }
28
+ return comp;
29
+ }
@@ -0,0 +1 @@
1
+ export {};