@lagless/core 0.0.33
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 +970 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +12 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/di/di-container.d.ts +7 -0
- package/dist/lib/di/di-container.d.ts.map +1 -0
- package/dist/lib/di/di-container.js +25 -0
- package/dist/lib/di/di-container.js.map +1 -0
- package/dist/lib/di/di-decorators.d.ts +4 -0
- package/dist/lib/di/di-decorators.d.ts.map +1 -0
- package/dist/lib/di/di-decorators.js +96 -0
- package/dist/lib/di/di-decorators.js.map +1 -0
- package/dist/lib/di/index.d.ts +3 -0
- package/dist/lib/di/index.d.ts.map +1 -0
- package/dist/lib/di/index.js +4 -0
- package/dist/lib/di/index.js.map +1 -0
- package/dist/lib/ecs-config.d.ts +16 -0
- package/dist/lib/ecs-config.d.ts.map +1 -0
- package/dist/lib/ecs-config.js +28 -0
- package/dist/lib/ecs-config.js.map +1 -0
- package/dist/lib/ecs-runner.d.ts +20 -0
- package/dist/lib/ecs-runner.d.ts.map +1 -0
- package/dist/lib/ecs-runner.js +60 -0
- package/dist/lib/ecs-runner.js.map +1 -0
- package/dist/lib/ecs-simulation.d.ts +44 -0
- package/dist/lib/ecs-simulation.d.ts.map +1 -0
- package/dist/lib/ecs-simulation.js +138 -0
- package/dist/lib/ecs-simulation.js.map +1 -0
- package/dist/lib/hash-verification/abstract-hash-verification.system.d.ts +32 -0
- package/dist/lib/hash-verification/abstract-hash-verification.system.d.ts.map +1 -0
- package/dist/lib/hash-verification/abstract-hash-verification.system.js +49 -0
- package/dist/lib/hash-verification/abstract-hash-verification.system.js.map +1 -0
- package/dist/lib/hash-verification/create-hash-reporter.d.ts +16 -0
- package/dist/lib/hash-verification/create-hash-reporter.d.ts.map +1 -0
- package/dist/lib/hash-verification/create-hash-reporter.js +21 -0
- package/dist/lib/hash-verification/create-hash-reporter.js.map +1 -0
- package/dist/lib/hash-verification/divergence.signal.d.ts +11 -0
- package/dist/lib/hash-verification/divergence.signal.d.ts.map +1 -0
- package/dist/lib/hash-verification/divergence.signal.js +5 -0
- package/dist/lib/hash-verification/divergence.signal.js.map +1 -0
- package/dist/lib/hash-verification/index.d.ts +4 -0
- package/dist/lib/hash-verification/index.d.ts.map +1 -0
- package/dist/lib/hash-verification/index.js +5 -0
- package/dist/lib/hash-verification/index.js.map +1 -0
- package/dist/lib/input/abstract-input-provider.d.ts +61 -0
- package/dist/lib/input/abstract-input-provider.d.ts.map +1 -0
- package/dist/lib/input/abstract-input-provider.js +110 -0
- package/dist/lib/input/abstract-input-provider.js.map +1 -0
- package/dist/lib/input/index.d.ts +8 -0
- package/dist/lib/input/index.d.ts.map +1 -0
- package/dist/lib/input/index.js +9 -0
- package/dist/lib/input/index.js.map +1 -0
- package/dist/lib/input/input-provider-di-token.d.ts +6 -0
- package/dist/lib/input/input-provider-di-token.d.ts.map +1 -0
- package/dist/lib/input/input-provider-di-token.js +12 -0
- package/dist/lib/input/input-provider-di-token.js.map +1 -0
- package/dist/lib/input/input-registry.d.ts +8 -0
- package/dist/lib/input/input-registry.d.ts.map +1 -0
- package/dist/lib/input/input-registry.js +21 -0
- package/dist/lib/input/input-registry.js.map +1 -0
- package/dist/lib/input/local-input-provider.d.ts +6 -0
- package/dist/lib/input/local-input-provider.d.ts.map +1 -0
- package/dist/lib/input/local-input-provider.js +12 -0
- package/dist/lib/input/local-input-provider.js.map +1 -0
- package/dist/lib/input/replay-input-provider.d.ts +12 -0
- package/dist/lib/input/replay-input-provider.d.ts.map +1 -0
- package/dist/lib/input/replay-input-provider.js +46 -0
- package/dist/lib/input/replay-input-provider.js.map +1 -0
- package/dist/lib/input/rpc-history.d.ts +40 -0
- package/dist/lib/input/rpc-history.d.ts.map +1 -0
- package/dist/lib/input/rpc-history.js +308 -0
- package/dist/lib/input/rpc-history.js.map +1 -0
- package/dist/lib/input/rpc.d.ts +8 -0
- package/dist/lib/input/rpc.d.ts.map +1 -0
- package/dist/lib/input/rpc.js +9 -0
- package/dist/lib/input/rpc.js.map +1 -0
- package/dist/lib/mem/abstract-memory.interface.d.ts +6 -0
- package/dist/lib/mem/abstract-memory.interface.d.ts.map +1 -0
- package/dist/lib/mem/abstract-memory.interface.js +3 -0
- package/dist/lib/mem/abstract-memory.interface.js.map +1 -0
- package/dist/lib/mem/index.d.ts +5 -0
- package/dist/lib/mem/index.d.ts.map +1 -0
- package/dist/lib/mem/index.js +6 -0
- package/dist/lib/mem/index.js.map +1 -0
- package/dist/lib/mem/managers/components-manager.d.ts +15 -0
- package/dist/lib/mem/managers/components-manager.d.ts.map +1 -0
- package/dist/lib/mem/managers/components-manager.js +30 -0
- package/dist/lib/mem/managers/components-manager.js.map +1 -0
- package/dist/lib/mem/managers/entities-manager.d.ts +31 -0
- package/dist/lib/mem/managers/entities-manager.d.ts.map +1 -0
- package/dist/lib/mem/managers/entities-manager.js +106 -0
- package/dist/lib/mem/managers/entities-manager.js.map +1 -0
- package/dist/lib/mem/managers/filters-manager.d.ts +17 -0
- package/dist/lib/mem/managers/filters-manager.d.ts.map +1 -0
- package/dist/lib/mem/managers/filters-manager.js +46 -0
- package/dist/lib/mem/managers/filters-manager.js.map +1 -0
- package/dist/lib/mem/managers/player-resources-manager.d.ts +21 -0
- package/dist/lib/mem/managers/player-resources-manager.d.ts.map +1 -0
- package/dist/lib/mem/managers/player-resources-manager.js +52 -0
- package/dist/lib/mem/managers/player-resources-manager.js.map +1 -0
- package/dist/lib/mem/managers/prng-manager.d.ts +36 -0
- package/dist/lib/mem/managers/prng-manager.d.ts.map +1 -0
- package/dist/lib/mem/managers/prng-manager.js +126 -0
- package/dist/lib/mem/managers/prng-manager.js.map +1 -0
- package/dist/lib/mem/managers/singletons-manager.d.ts +13 -0
- package/dist/lib/mem/managers/singletons-manager.d.ts.map +1 -0
- package/dist/lib/mem/managers/singletons-manager.js +29 -0
- package/dist/lib/mem/managers/singletons-manager.js.map +1 -0
- package/dist/lib/mem/managers/tick-manager.d.ts +10 -0
- package/dist/lib/mem/managers/tick-manager.d.ts.map +1 -0
- package/dist/lib/mem/managers/tick-manager.js +18 -0
- package/dist/lib/mem/managers/tick-manager.js.map +1 -0
- package/dist/lib/mem/mem.d.ts +28 -0
- package/dist/lib/mem/mem.d.ts.map +1 -0
- package/dist/lib/mem/mem.js +63 -0
- package/dist/lib/mem/mem.js.map +1 -0
- package/dist/lib/prefab.d.ts +16 -0
- package/dist/lib/prefab.d.ts.map +1 -0
- package/dist/lib/prefab.js +17 -0
- package/dist/lib/prefab.js.map +1 -0
- package/dist/lib/signals/event-emitter.d.ts +9 -0
- package/dist/lib/signals/event-emitter.d.ts.map +1 -0
- package/dist/lib/signals/event-emitter.js +22 -0
- package/dist/lib/signals/event-emitter.js.map +1 -0
- package/dist/lib/signals/signal.d.ts +40 -0
- package/dist/lib/signals/signal.d.ts.map +1 -0
- package/dist/lib/signals/signal.js +133 -0
- package/dist/lib/signals/signal.js.map +1 -0
- package/dist/lib/signals/signals.registry.d.ts +9 -0
- package/dist/lib/signals/signals.registry.d.ts.map +1 -0
- package/dist/lib/signals/signals.registry.js +31 -0
- package/dist/lib/signals/signals.registry.js.map +1 -0
- package/dist/lib/types/abstract-filter.d.ts +16 -0
- package/dist/lib/types/abstract-filter.d.ts.map +1 -0
- package/dist/lib/types/abstract-filter.js +53 -0
- package/dist/lib/types/abstract-filter.js.map +1 -0
- package/dist/lib/types/ecs-types.d.ts +109 -0
- package/dist/lib/types/ecs-types.d.ts.map +1 -0
- package/dist/lib/types/ecs-types.js +3 -0
- package/dist/lib/types/ecs-types.js.map +1 -0
- package/dist/lib/types/index.d.ts +3 -0
- package/dist/lib/types/index.d.ts.map +1 -0
- package/dist/lib/types/index.js +4 -0
- package/dist/lib/types/index.js.map +1 -0
- package/dist/tsconfig.lib.tsbuildinfo +1 -0
- package/package.json +57 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export * from './lib/prefab.js';
|
|
2
|
+
export * from './lib/di/index.js';
|
|
3
|
+
export * from './lib/mem/index.js';
|
|
4
|
+
export * from './lib/ecs-config.js';
|
|
5
|
+
export * from './lib/ecs-runner.js';
|
|
6
|
+
export * from './lib/types/index.js';
|
|
7
|
+
export * from './lib/input/index.js';
|
|
8
|
+
export * from './lib/ecs-simulation.js';
|
|
9
|
+
export * from './lib/signals/signal.js';
|
|
10
|
+
export * from './lib/hash-verification/index.js';
|
|
11
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,iBAAiB,CAAC;AAChC,cAAc,mBAAmB,CAAC;AAClC,cAAc,oBAAoB,CAAC;AACnC,cAAc,qBAAqB,CAAC;AACpC,cAAc,qBAAqB,CAAC;AACpC,cAAc,sBAAsB,CAAC;AACrC,cAAc,sBAAsB,CAAC;AACrC,cAAc,yBAAyB,CAAC;AACxC,cAAc,yBAAyB,CAAC;AACxC,cAAc,kCAAkC,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export * from './lib/prefab.js';
|
|
2
|
+
export * from './lib/di/index.js';
|
|
3
|
+
export * from './lib/mem/index.js';
|
|
4
|
+
export * from './lib/ecs-config.js';
|
|
5
|
+
export * from './lib/ecs-runner.js';
|
|
6
|
+
export * from './lib/types/index.js';
|
|
7
|
+
export * from './lib/input/index.js';
|
|
8
|
+
export * from './lib/ecs-simulation.js';
|
|
9
|
+
export * from './lib/signals/signal.js';
|
|
10
|
+
export * from './lib/hash-verification/index.js';
|
|
11
|
+
|
|
12
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["export * from './lib/prefab.js';\nexport * from './lib/di/index.js';\nexport * from './lib/mem/index.js';\nexport * from './lib/ecs-config.js';\nexport * from './lib/ecs-runner.js';\nexport * from './lib/types/index.js';\nexport * from './lib/input/index.js';\nexport * from './lib/ecs-simulation.js';\nexport * from './lib/signals/signal.js';\nexport * from './lib/hash-verification/index.js';\n"],"names":[],"rangeMappings":";;;;;;;;;","mappings":"AAAA,cAAc,kBAAkB;AAChC,cAAc,oBAAoB;AAClC,cAAc,qBAAqB;AACnC,cAAc,sBAAsB;AACpC,cAAc,sBAAsB;AACpC,cAAc,uBAAuB;AACrC,cAAc,uBAAuB;AACrC,cAAc,0BAA0B;AACxC,cAAc,0BAA0B;AACxC,cAAc,mCAAmC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"di-container.d.ts","sourceRoot":"","sources":["../../../src/lib/di/di-container.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,KAAK,CAAC,CAAC,GAAG,GAAG,IAAI,KAAK,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,CAAC,CAAC;AAEvD,qBAAa,SAAS;IACpB,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAyB;IAE9C,OAAO,CAAC,CAAC,EAAE,GAAG,EAAE,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC;IAgB5B,QAAQ,CAAC,CAAC,EAAE,GAAG,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,GAAG,IAAI;CAGrD"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export class Container {
|
|
2
|
+
resolve(cls) {
|
|
3
|
+
if (this._singletons.has(cls)) return this._singletons.get(cls);
|
|
4
|
+
const deps = cls.deps;
|
|
5
|
+
if (!deps) throw new Error(`Non injectable class ${cls.name}`);
|
|
6
|
+
const args = deps.map((t)=>{
|
|
7
|
+
try {
|
|
8
|
+
return this.resolve(t);
|
|
9
|
+
} catch (e) {
|
|
10
|
+
throw new Error(`Failed to resolve ${cls.name} dependency ${t.name}`);
|
|
11
|
+
}
|
|
12
|
+
});
|
|
13
|
+
const obj = new cls(...args);
|
|
14
|
+
this._singletons.set(cls, obj);
|
|
15
|
+
return obj;
|
|
16
|
+
}
|
|
17
|
+
register(cls, instance) {
|
|
18
|
+
this._singletons.set(cls, instance);
|
|
19
|
+
}
|
|
20
|
+
constructor(){
|
|
21
|
+
this._singletons = new Map();
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
//# sourceMappingURL=di-container.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/lib/di/di-container.ts"],"sourcesContent":["export type Token<T = any> = new (...args: any[]) => T;\n\nexport class Container {\n private readonly _singletons = new Map<Token, any>();\n\n public resolve<T>(cls: Token<T>): T {\n if (this._singletons.has(cls)) return this._singletons.get(cls);\n const deps: Token[] = (cls as any).deps;\n if (!deps) throw new Error(`Non injectable class ${cls.name}`);\n const args = deps.map((t) => {\n try {\n return this.resolve(t);\n } catch {\n throw new Error(`Failed to resolve ${cls.name} dependency ${t.name}`);\n }\n });\n const obj = new cls(...args);\n this._singletons.set(cls, obj);\n return obj;\n }\n\n public register<T>(cls: Token<T>, instance: T): void {\n this._singletons.set(cls, instance);\n }\n}\n"],"names":["Container","resolve","cls","_singletons","has","get","deps","Error","name","args","map","t","obj","set","register","instance","Map"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;","mappings":"AAEA,OAAO,MAAMA;IAGJC,QAAWC,GAAa,EAAK;QAClC,IAAI,IAAI,CAACC,WAAW,CAACC,GAAG,CAACF,MAAM,OAAO,IAAI,CAACC,WAAW,CAACE,GAAG,CAACH;QAC3D,MAAMI,OAAgB,AAACJ,IAAYI,IAAI;QACvC,IAAI,CAACA,MAAM,MAAM,IAAIC,MAAM,CAAC,qBAAqB,EAAEL,IAAIM,IAAI,CAAC,CAAC;QAC7D,MAAMC,OAAOH,KAAKI,GAAG,CAAC,CAACC;YACrB,IAAI;gBACF,OAAO,IAAI,CAACV,OAAO,CAACU;YACtB,EAAE,UAAM;gBACN,MAAM,IAAIJ,MAAM,CAAC,kBAAkB,EAAEL,IAAIM,IAAI,CAAC,YAAY,EAAEG,EAAEH,IAAI,CAAC,CAAC;YACtE;QACF;QACA,MAAMI,MAAM,IAAIV,OAAOO;QACvB,IAAI,CAACN,WAAW,CAACU,GAAG,CAACX,KAAKU;QAC1B,OAAOA;IACT;IAEOE,SAAYZ,GAAa,EAAEa,QAAW,EAAQ;QACnD,IAAI,CAACZ,WAAW,CAACU,GAAG,CAACX,KAAKa;IAC5B;;aApBiBZ,cAAc,IAAIa;;AAqBrC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"di-decorators.d.ts","sourceRoot":"","sources":["../../../src/lib/di/di-decorators.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAO/C,wBAAgB,SAAS,CAAC,GAAG,YAAY,EAAE,KAAK,EAAE,GAAG,cAAc,CAiElE;AAED,wBAAgB,SAAS,CAAC,GAAG,YAAY,EAAE,KAAK,EAAE,GAAG,cAAc,CAoElE"}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
const DESIGN_PARAM_TYPES = 'design:paramtypes';
|
|
2
|
+
export function ECSSignal(...overrideDeps) {
|
|
3
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
|
|
4
|
+
return (target)=>{
|
|
5
|
+
let deps = overrideDeps.length ? overrideDeps : undefined;
|
|
6
|
+
if (!deps) {
|
|
7
|
+
const getMeta = Reflect['getMetadata'];
|
|
8
|
+
if (typeof getMeta !== 'function') {
|
|
9
|
+
if (target.length > 0) {
|
|
10
|
+
throw new Error(`[ECSSignal] Unable to infer deps for ${target.name}: Reflect.getMetadata is not available. ` + `Import 'reflect-metadata' BEFORE any decorated classes (e.g., via test/setup file).`);
|
|
11
|
+
}
|
|
12
|
+
deps = [];
|
|
13
|
+
} else {
|
|
14
|
+
deps = getMeta(DESIGN_PARAM_TYPES, target);
|
|
15
|
+
if ((!deps || deps.length === 0) && target.length > 0) {
|
|
16
|
+
// Metadata not emitted (transpiler/config issue)
|
|
17
|
+
throw new Error(`[ECSSignal] No metadata for ${target.name}. ` + `Ensure your TS transpile enables decorator metadata (SWC: transform.decoratorMetadata=true, legacyDecorator=true) ` + `and that 'reflect-metadata' is imported early.`);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
// 3) Sanity checks and helpful diagnostics
|
|
22
|
+
deps = deps != null ? deps : [];
|
|
23
|
+
if (deps.length > 0) {
|
|
24
|
+
// Function.length is the number of declared constructor parameters (excludes rest/default nuance)
|
|
25
|
+
const ctorParams = target.length;
|
|
26
|
+
if (ctorParams > 0 && deps.length !== ctorParams) {
|
|
27
|
+
// Not fatal in runtime, but it usually indicates miscompiled metadata
|
|
28
|
+
// Throw to fail fast with a clear message.
|
|
29
|
+
throw new Error(`[ECSSignal] Mismatch for ${target.name}: constructor has ${ctorParams} param(s), ` + `but inferred deps array has ${deps.length}. Check your build/transpile settings.`);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
// Warn about interfaces/primitives where metadata becomes Object
|
|
33
|
+
if (deps.some((d)=>d === Object)) {
|
|
34
|
+
console.warn(`[ECSSignal] ${target.name} has constructor params typed as interfaces/primitives. ` + `Runtime tokens will be 'Object'. Use class types or pass tokens explicitly: @ECSSystem(A, B).`);
|
|
35
|
+
}
|
|
36
|
+
// Validate tokens are constructable (best-effort)
|
|
37
|
+
for (const d of deps){
|
|
38
|
+
if (typeof d !== 'function') {
|
|
39
|
+
throw new Error(`[ECSSignal] ${target.name} received a non-constructable token in deps. ` + `Each token must be a class (newable).`);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
// 4) Expose deps for your Container (must be on the static 'deps' field to stay compatible)
|
|
43
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
|
|
44
|
+
target.deps = deps;
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
export function ECSSystem(...overrideDeps) {
|
|
48
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
|
|
49
|
+
return (target)=>{
|
|
50
|
+
// 1) Prefer explicit override tokens if provided
|
|
51
|
+
let deps = overrideDeps.length ? overrideDeps : undefined;
|
|
52
|
+
// 2) Otherwise try to read from reflect metadata
|
|
53
|
+
if (!deps) {
|
|
54
|
+
const getMeta = Reflect['getMetadata'];
|
|
55
|
+
if (typeof getMeta !== 'function') {
|
|
56
|
+
// No reflect-metadata loaded
|
|
57
|
+
if (target.length > 0) {
|
|
58
|
+
throw new Error(`[ECSSystem] Unable to infer deps for ${target.name}: Reflect.getMetadata is not available. ` + `Import 'reflect-metadata' BEFORE any decorated classes (e.g., via test/setup file).`);
|
|
59
|
+
}
|
|
60
|
+
deps = [];
|
|
61
|
+
} else {
|
|
62
|
+
deps = getMeta(DESIGN_PARAM_TYPES, target);
|
|
63
|
+
if ((!deps || deps.length === 0) && target.length > 0) {
|
|
64
|
+
// Metadata not emitted (transpiler/config issue)
|
|
65
|
+
throw new Error(`[ECSSystem] No metadata for ${target.name}. ` + `Ensure your TS transpile enables decorator metadata (SWC: transform.decoratorMetadata=true, legacyDecorator=true) ` + `and that 'reflect-metadata' is imported early.`);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
// 3) Sanity checks and helpful diagnostics
|
|
70
|
+
deps = deps != null ? deps : [];
|
|
71
|
+
if (deps.length > 0) {
|
|
72
|
+
// Function.length is the number of declared constructor parameters (excludes rest/default nuance)
|
|
73
|
+
const ctorParams = target.length;
|
|
74
|
+
if (ctorParams > 0 && deps.length !== ctorParams) {
|
|
75
|
+
// Not fatal in runtime, but it usually indicates miscompiled metadata
|
|
76
|
+
// Throw to fail fast with a clear message.
|
|
77
|
+
throw new Error(`[ECSSystem] Mismatch for ${target.name}: constructor has ${ctorParams} param(s), ` + `but inferred deps array has ${deps.length}. Check your build/transpile settings.`);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
// Warn about interfaces/primitives where metadata becomes Object
|
|
81
|
+
if (deps.some((d)=>d === Object)) {
|
|
82
|
+
console.warn(`[ECSSystem] ${target.name} has constructor params typed as interfaces/primitives. ` + `Runtime tokens will be 'Object'. Use class types or pass tokens explicitly: @ECSSystem(A, B).`);
|
|
83
|
+
}
|
|
84
|
+
// Validate tokens are constructable (best-effort)
|
|
85
|
+
for (const d of deps){
|
|
86
|
+
if (typeof d !== 'function') {
|
|
87
|
+
throw new Error(`[ECSSystem] ${target.name} received a non-constructable token in deps. ` + `Each token must be a class (newable).`);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
// 4) Expose deps for your Container (must be on the static 'deps' field to stay compatible)
|
|
91
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
|
|
92
|
+
target.deps = deps;
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
//# sourceMappingURL=di-decorators.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/lib/di/di-decorators.ts"],"sourcesContent":["import type { Token } from './di-container.js';\n\nconst DESIGN_PARAM_TYPES = 'design:paramtypes';\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ndeclare const Reflect: any;\n\nexport function ECSSignal(...overrideDeps: Token[]): ClassDecorator {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type\n return (target: Function) => {\n let deps: Token[] | undefined = overrideDeps.length ? overrideDeps : undefined;\n\n if (!deps) {\n const getMeta = Reflect['getMetadata'];\n if (typeof getMeta !== 'function') {\n if (target.length > 0) {\n throw new Error(\n `[ECSSignal] Unable to infer deps for ${target.name}: Reflect.getMetadata is not available. ` +\n `Import 'reflect-metadata' BEFORE any decorated classes (e.g., via test/setup file).`\n );\n }\n deps = [];\n } else {\n deps = getMeta(DESIGN_PARAM_TYPES, target) as Token[] | undefined;\n if ((!deps || deps.length === 0) && target.length > 0) {\n // Metadata not emitted (transpiler/config issue)\n throw new Error(\n `[ECSSignal] No metadata for ${target.name}. ` +\n `Ensure your TS transpile enables decorator metadata (SWC: transform.decoratorMetadata=true, legacyDecorator=true) ` +\n `and that 'reflect-metadata' is imported early.`\n );\n }\n }\n }\n\n // 3) Sanity checks and helpful diagnostics\n deps = deps ?? [];\n if (deps.length > 0) {\n // Function.length is the number of declared constructor parameters (excludes rest/default nuance)\n const ctorParams = target.length;\n if (ctorParams > 0 && deps.length !== ctorParams) {\n // Not fatal in runtime, but it usually indicates miscompiled metadata\n // Throw to fail fast with a clear message.\n throw new Error(\n `[ECSSignal] Mismatch for ${target.name}: constructor has ${ctorParams} param(s), ` +\n `but inferred deps array has ${deps.length}. Check your build/transpile settings.`\n );\n }\n }\n\n // Warn about interfaces/primitives where metadata becomes Object\n if (deps.some((d) => d === Object)) {\n console.warn(\n `[ECSSignal] ${target.name} has constructor params typed as interfaces/primitives. ` +\n `Runtime tokens will be 'Object'. Use class types or pass tokens explicitly: @ECSSystem(A, B).`\n );\n }\n\n // Validate tokens are constructable (best-effort)\n for (const d of deps) {\n if (typeof d !== 'function') {\n throw new Error(\n `[ECSSignal] ${target.name} received a non-constructable token in deps. ` +\n `Each token must be a class (newable).`\n );\n }\n }\n\n // 4) Expose deps for your Container (must be on the static 'deps' field to stay compatible)\n // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type\n (target as unknown as { deps: Array<Function> }).deps = deps;\n };\n}\n\nexport function ECSSystem(...overrideDeps: Token[]): ClassDecorator {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type\n return (target: Function) => {\n // 1) Prefer explicit override tokens if provided\n let deps: Token[] | undefined = overrideDeps.length ? overrideDeps : undefined;\n\n // 2) Otherwise try to read from reflect metadata\n if (!deps) {\n const getMeta = Reflect['getMetadata'];\n if (typeof getMeta !== 'function') {\n // No reflect-metadata loaded\n if (target.length > 0) {\n throw new Error(\n `[ECSSystem] Unable to infer deps for ${target.name}: Reflect.getMetadata is not available. ` +\n `Import 'reflect-metadata' BEFORE any decorated classes (e.g., via test/setup file).`\n );\n }\n deps = [];\n } else {\n deps = getMeta(DESIGN_PARAM_TYPES, target) as Token[] | undefined;\n if ((!deps || deps.length === 0) && target.length > 0) {\n // Metadata not emitted (transpiler/config issue)\n throw new Error(\n `[ECSSystem] No metadata for ${target.name}. ` +\n `Ensure your TS transpile enables decorator metadata (SWC: transform.decoratorMetadata=true, legacyDecorator=true) ` +\n `and that 'reflect-metadata' is imported early.`\n );\n }\n }\n }\n\n // 3) Sanity checks and helpful diagnostics\n deps = deps ?? [];\n if (deps.length > 0) {\n // Function.length is the number of declared constructor parameters (excludes rest/default nuance)\n const ctorParams = target.length;\n if (ctorParams > 0 && deps.length !== ctorParams) {\n // Not fatal in runtime, but it usually indicates miscompiled metadata\n // Throw to fail fast with a clear message.\n throw new Error(\n `[ECSSystem] Mismatch for ${target.name}: constructor has ${ctorParams} param(s), ` +\n `but inferred deps array has ${deps.length}. Check your build/transpile settings.`\n );\n }\n }\n\n // Warn about interfaces/primitives where metadata becomes Object\n if (deps.some((d) => d === Object)) {\n console.warn(\n `[ECSSystem] ${target.name} has constructor params typed as interfaces/primitives. ` +\n `Runtime tokens will be 'Object'. Use class types or pass tokens explicitly: @ECSSystem(A, B).`\n );\n }\n\n // Validate tokens are constructable (best-effort)\n for (const d of deps) {\n if (typeof d !== 'function') {\n throw new Error(\n `[ECSSystem] ${target.name} received a non-constructable token in deps. ` +\n `Each token must be a class (newable).`\n );\n }\n }\n\n // 4) Expose deps for your Container (must be on the static 'deps' field to stay compatible)\n // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type\n (target as unknown as { deps: Array<Function> }).deps = deps;\n };\n}\n"],"names":["DESIGN_PARAM_TYPES","ECSSignal","overrideDeps","target","deps","length","undefined","getMeta","Reflect","Error","name","ctorParams","some","d","Object","console","warn","ECSSystem"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;","mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/lib/di/index.ts"],"names":[],"mappings":"AAAA,cAAc,mBAAmB,CAAC;AAClC,cAAc,oBAAoB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/lib/di/index.ts"],"sourcesContent":["export * from './di-container.js';\nexport * from './di-decorators.js';\n"],"names":[],"rangeMappings":";","mappings":"AAAA,cAAc,oBAAoB;AAClC,cAAc,qBAAqB"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export type RawSeed = Uint8Array;
|
|
2
|
+
export declare class ECSConfig {
|
|
3
|
+
readonly seed: RawSeed;
|
|
4
|
+
readonly maxEntities: number;
|
|
5
|
+
readonly maxPlayers: number;
|
|
6
|
+
readonly initialInputDelayTick: number;
|
|
7
|
+
readonly minInputDelayTick: number;
|
|
8
|
+
readonly maxInputDelayTick: number;
|
|
9
|
+
readonly fps: number;
|
|
10
|
+
readonly frameLength: number;
|
|
11
|
+
readonly snapshotRate: number;
|
|
12
|
+
readonly snapshotHistorySize: number;
|
|
13
|
+
readonly maxNudgePerFrame: number;
|
|
14
|
+
constructor(options?: Partial<ECSConfig>);
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=ecs-config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ecs-config.d.ts","sourceRoot":"","sources":["../../src/lib/ecs-config.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,OAAO,GAAG,UAAU,CAAC;AAIjC,qBAAa,SAAS;IACpB,SAAgB,IAAI,EAAE,OAAO,CAAC;IAC9B,SAAgB,WAAW,EAAE,MAAM,CAAC;IACpC,SAAgB,UAAU,EAAE,MAAM,CAAC;IACnC,SAAgB,qBAAqB,EAAE,MAAM,CAAC;IAC9C,SAAgB,iBAAiB,EAAE,MAAM,CAAC;IAC1C,SAAgB,iBAAiB,EAAE,MAAM,CAAC;IAC1C,SAAgB,GAAG,EAAE,MAAM,CAAC;IAC5B,SAAgB,WAAW,EAAE,MAAM,CAAC;IACpC,SAAgB,YAAY,EAAE,MAAM,CAAC;IACrC,SAAgB,mBAAmB,EAAE,MAAM,CAAC;IAC5C,SAAgB,gBAAgB,EAAE,MAAM,CAAC;gBAE7B,OAAO,CAAC,EAAE,OAAO,CAAC,SAAS,CAAC;CAazC"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
const ZERO_SEED = new Uint8Array(16);
|
|
2
|
+
export class ECSConfig {
|
|
3
|
+
constructor(options){
|
|
4
|
+
var _options_seed;
|
|
5
|
+
this.seed = (_options_seed = options == null ? void 0 : options.seed) != null ? _options_seed : ZERO_SEED;
|
|
6
|
+
var _options_maxEntities;
|
|
7
|
+
this.maxEntities = (_options_maxEntities = options == null ? void 0 : options.maxEntities) != null ? _options_maxEntities : 1000;
|
|
8
|
+
var _options_maxPlayers;
|
|
9
|
+
this.maxPlayers = (_options_maxPlayers = options == null ? void 0 : options.maxPlayers) != null ? _options_maxPlayers : 6;
|
|
10
|
+
var _options_initialInputDelayTick;
|
|
11
|
+
this.initialInputDelayTick = (_options_initialInputDelayTick = options == null ? void 0 : options.initialInputDelayTick) != null ? _options_initialInputDelayTick : 2;
|
|
12
|
+
var _options_minInputDelayTick;
|
|
13
|
+
this.minInputDelayTick = (_options_minInputDelayTick = options == null ? void 0 : options.minInputDelayTick) != null ? _options_minInputDelayTick : 1;
|
|
14
|
+
var _options_maxInputDelayTick;
|
|
15
|
+
this.maxInputDelayTick = (_options_maxInputDelayTick = options == null ? void 0 : options.maxInputDelayTick) != null ? _options_maxInputDelayTick : 12;
|
|
16
|
+
var _options_fps;
|
|
17
|
+
this.fps = (_options_fps = options == null ? void 0 : options.fps) != null ? _options_fps : 60;
|
|
18
|
+
this.frameLength = 1000 / this.fps;
|
|
19
|
+
var _options_snapshotRate;
|
|
20
|
+
this.snapshotRate = (_options_snapshotRate = options == null ? void 0 : options.snapshotRate) != null ? _options_snapshotRate : 1;
|
|
21
|
+
var _options_snapshotHistorySize;
|
|
22
|
+
this.snapshotHistorySize = (_options_snapshotHistorySize = options == null ? void 0 : options.snapshotHistorySize) != null ? _options_snapshotHistorySize : 100;
|
|
23
|
+
var _options_maxNudgePerFrame;
|
|
24
|
+
this.maxNudgePerFrame = (_options_maxNudgePerFrame = options == null ? void 0 : options.maxNudgePerFrame) != null ? _options_maxNudgePerFrame : this.frameLength / 4;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
//# sourceMappingURL=ecs-config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/lib/ecs-config.ts"],"sourcesContent":["export type RawSeed = Uint8Array; // 128-bit (16-byte) seed for PRNG\n\nconst ZERO_SEED: RawSeed = new Uint8Array(16);\n\nexport class ECSConfig {\n public readonly seed: RawSeed;\n public readonly maxEntities: number;\n public readonly maxPlayers: number;\n public readonly initialInputDelayTick: number;\n public readonly minInputDelayTick: number;\n public readonly maxInputDelayTick: number;\n public readonly fps: number;\n public readonly frameLength: number;\n public readonly snapshotRate: number;\n public readonly snapshotHistorySize: number;\n public readonly maxNudgePerFrame: number;\n\n constructor(options?: Partial<ECSConfig>) {\n this.seed = options?.seed ?? ZERO_SEED;\n this.maxEntities = options?.maxEntities ?? 1000;\n this.maxPlayers = options?.maxPlayers ?? 6;\n this.initialInputDelayTick = options?.initialInputDelayTick ?? 2;\n this.minInputDelayTick = options?.minInputDelayTick ?? 1;\n this.maxInputDelayTick = options?.maxInputDelayTick ?? 12;\n this.fps = options?.fps ?? 60;\n this.frameLength = 1000 / this.fps;\n this.snapshotRate = options?.snapshotRate ?? 1;\n this.snapshotHistorySize = options?.snapshotHistorySize ?? 100;\n this.maxNudgePerFrame = options?.maxNudgePerFrame ?? this.frameLength / 4;\n }\n}\n"],"names":["ZERO_SEED","Uint8Array","ECSConfig","constructor","options","seed","maxEntities","maxPlayers","initialInputDelayTick","minInputDelayTick","maxInputDelayTick","fps","frameLength","snapshotRate","snapshotHistorySize","maxNudgePerFrame"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;;;","mappings":"AAEA,MAAMA,YAAqB,IAAIC,WAAW;AAE1C,OAAO,MAAMC;IAaXC,YAAYC,OAA4B,CAAE;YAC5BA;QAAZ,IAAI,CAACC,IAAI,GAAGD,CAAAA,gBAAAA,2BAAAA,QAASC,IAAI,YAAbD,gBAAiBJ;YACVI;QAAnB,IAAI,CAACE,WAAW,GAAGF,CAAAA,uBAAAA,2BAAAA,QAASE,WAAW,YAApBF,uBAAwB;YACzBA;QAAlB,IAAI,CAACG,UAAU,GAAGH,CAAAA,sBAAAA,2BAAAA,QAASG,UAAU,YAAnBH,sBAAuB;YACZA;QAA7B,IAAI,CAACI,qBAAqB,GAAGJ,CAAAA,iCAAAA,2BAAAA,QAASI,qBAAqB,YAA9BJ,iCAAkC;YACtCA;QAAzB,IAAI,CAACK,iBAAiB,GAAGL,CAAAA,6BAAAA,2BAAAA,QAASK,iBAAiB,YAA1BL,6BAA8B;YAC9BA;QAAzB,IAAI,CAACM,iBAAiB,GAAGN,CAAAA,6BAAAA,2BAAAA,QAASM,iBAAiB,YAA1BN,6BAA8B;YAC5CA;QAAX,IAAI,CAACO,GAAG,GAAGP,CAAAA,eAAAA,2BAAAA,QAASO,GAAG,YAAZP,eAAgB;QAC3B,IAAI,CAACQ,WAAW,GAAG,OAAO,IAAI,CAACD,GAAG;YACdP;QAApB,IAAI,CAACS,YAAY,GAAGT,CAAAA,wBAAAA,2BAAAA,QAASS,YAAY,YAArBT,wBAAyB;YAClBA;QAA3B,IAAI,CAACU,mBAAmB,GAAGV,CAAAA,+BAAAA,2BAAAA,QAASU,mBAAmB,YAA5BV,+BAAgC;YACnCA;QAAxB,IAAI,CAACW,gBAAgB,GAAGX,CAAAA,4BAAAA,2BAAAA,QAASW,gBAAgB,YAAzBX,4BAA6B,IAAI,CAACQ,WAAW,GAAG;IAC1E;AACF"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { Container } from './di/index.js';
|
|
2
|
+
import { ECSConfig } from './ecs-config.js';
|
|
3
|
+
import { ECSSimulation } from './ecs-simulation.js';
|
|
4
|
+
import { AbstractInputProvider } from './input/index.js';
|
|
5
|
+
import { ECSDeps, IECSSystemConstructor } from './types/index.js';
|
|
6
|
+
import { ISignalConstructor } from './signals/signal.js';
|
|
7
|
+
export declare abstract class ECSRunner {
|
|
8
|
+
readonly Config: ECSConfig;
|
|
9
|
+
readonly InputProviderInstance: AbstractInputProvider;
|
|
10
|
+
readonly Systems: Array<IECSSystemConstructor>;
|
|
11
|
+
readonly Signals: Array<ISignalConstructor>;
|
|
12
|
+
readonly Deps: ECSDeps;
|
|
13
|
+
readonly DIContainer: Container;
|
|
14
|
+
readonly Simulation: ECSSimulation;
|
|
15
|
+
protected constructor(Config: ECSConfig, InputProviderInstance: AbstractInputProvider, Systems: Array<IECSSystemConstructor>, Signals: Array<ISignalConstructor> | undefined, Deps: ECSDeps);
|
|
16
|
+
start(): void;
|
|
17
|
+
update(dt: number): void;
|
|
18
|
+
dispose(): void;
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=ecs-runner.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ecs-runner.d.ts","sourceRoot":"","sources":["../../src/lib/ecs-runner.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAC1C,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,qBAAqB,EAAE,MAAM,kBAAkB,CAAC;AACzD,OAAO,EAAE,OAAO,EAAE,qBAAqB,EAAE,MAAM,kBAAkB,CAAC;AAGlE,OAAO,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAEzD,8BAAsB,SAAS;aAKX,MAAM,EAAE,SAAS;aACjB,qBAAqB,EAAE,qBAAqB;aAC5C,OAAO,EAAE,KAAK,CAAC,qBAAqB,CAAC;aACrC,OAAO,EAAE,KAAK,CAAC,kBAAkB,CAAC;aAClC,IAAI,EAAE,OAAO;IAR/B,SAAgB,WAAW,EAAE,SAAS,CAAC;IACvC,SAAgB,UAAU,EAAE,aAAa,CAAC;IAE1C,SAAS,aACS,MAAM,EAAE,SAAS,EACjB,qBAAqB,EAAE,qBAAqB,EAC5C,OAAO,EAAE,KAAK,CAAC,qBAAqB,CAAC,EACrC,OAAO,EAAE,KAAK,CAAC,kBAAkB,CAAC,YAAK,EACvC,IAAI,EAAE,OAAO;IA2CxB,KAAK,IAAI,IAAI;IAIb,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI;IAIxB,OAAO,IAAI,IAAI;CAMvB"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { Container } from './di/index.js';
|
|
2
|
+
import { ECSConfig } from './ecs-config.js';
|
|
3
|
+
import { ECSSimulation } from './ecs-simulation.js';
|
|
4
|
+
import { InputProvider } from './input/index.js';
|
|
5
|
+
import { EntitiesManager, PlayerResources, PRNG } from './mem/index.js';
|
|
6
|
+
export class ECSRunner {
|
|
7
|
+
start() {
|
|
8
|
+
this.Simulation.start();
|
|
9
|
+
}
|
|
10
|
+
update(dt) {
|
|
11
|
+
this.Simulation.update(dt);
|
|
12
|
+
}
|
|
13
|
+
dispose() {
|
|
14
|
+
// ECSRunner disposed
|
|
15
|
+
this.InputProviderInstance.dispose();
|
|
16
|
+
this.Simulation.disposeSignals();
|
|
17
|
+
}
|
|
18
|
+
constructor(Config, InputProviderInstance, Systems, Signals = [], Deps){
|
|
19
|
+
this.Config = Config;
|
|
20
|
+
this.InputProviderInstance = InputProviderInstance;
|
|
21
|
+
this.Systems = Systems;
|
|
22
|
+
this.Signals = Signals;
|
|
23
|
+
this.Deps = Deps;
|
|
24
|
+
this.DIContainer = new Container();
|
|
25
|
+
this.Simulation = new ECSSimulation(this.Config, this.Deps, this.InputProviderInstance);
|
|
26
|
+
this.InputProviderInstance.init(this.Simulation);
|
|
27
|
+
const mem = this.Simulation.mem;
|
|
28
|
+
this.DIContainer.register(ECSConfig, this.Config);
|
|
29
|
+
this.DIContainer.register(InputProvider, this.InputProviderInstance);
|
|
30
|
+
this.DIContainer.register(ECSSimulation, this.Simulation);
|
|
31
|
+
this.DIContainer.register(EntitiesManager, mem.entitiesManager);
|
|
32
|
+
this.DIContainer.register(PRNG, mem.prngManager.prng);
|
|
33
|
+
// components
|
|
34
|
+
for (const [ComponentConstructor, ComponentInstance] of mem.componentsManager){
|
|
35
|
+
this.DIContainer.register(ComponentConstructor, ComponentInstance);
|
|
36
|
+
}
|
|
37
|
+
// singletons
|
|
38
|
+
for (const [SingletonConstructor, SingletonInstance] of mem.singletonsManager){
|
|
39
|
+
this.DIContainer.register(SingletonConstructor, SingletonInstance);
|
|
40
|
+
}
|
|
41
|
+
// filters
|
|
42
|
+
for (const [FilterConstructor, FilterInstance] of mem.filtersManager){
|
|
43
|
+
this.DIContainer.register(FilterConstructor, FilterInstance);
|
|
44
|
+
}
|
|
45
|
+
// player resources
|
|
46
|
+
this.DIContainer.register(PlayerResources, mem.playerResourcesManager.PlayerResources);
|
|
47
|
+
// signals
|
|
48
|
+
const signalInstances = this.Signals.map((SignalConstructor)=>{
|
|
49
|
+
return this.DIContainer.resolve(SignalConstructor);
|
|
50
|
+
});
|
|
51
|
+
this.Simulation.initSignals(signalInstances);
|
|
52
|
+
// systems
|
|
53
|
+
const systemInstances = this.Systems.map((SystemConstructor)=>{
|
|
54
|
+
return this.DIContainer.resolve(SystemConstructor);
|
|
55
|
+
});
|
|
56
|
+
this.Simulation.registerSystems(systemInstances);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
//# sourceMappingURL=ecs-runner.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/lib/ecs-runner.ts"],"sourcesContent":["import { Container } from './di/index.js';\nimport { ECSConfig } from './ecs-config.js';\nimport { ECSSimulation } from './ecs-simulation.js';\nimport { AbstractInputProvider } from './input/index.js';\nimport { ECSDeps, IECSSystemConstructor } from './types/index.js';\nimport { InputProvider } from './input/index.js';\nimport { EntitiesManager, PlayerResources, PRNG } from './mem/index.js';\nimport { ISignalConstructor } from './signals/signal.js';\n\nexport abstract class ECSRunner {\n public readonly DIContainer: Container;\n public readonly Simulation: ECSSimulation;\n\n protected constructor(\n public readonly Config: ECSConfig,\n public readonly InputProviderInstance: AbstractInputProvider,\n public readonly Systems: Array<IECSSystemConstructor>,\n public readonly Signals: Array<ISignalConstructor> = [],\n public readonly Deps: ECSDeps,\n ) {\n this.DIContainer = new Container();\n this.Simulation = new ECSSimulation(this.Config, this.Deps, this.InputProviderInstance);\n this.InputProviderInstance.init(this.Simulation);\n\n const mem = this.Simulation.mem;\n\n this.DIContainer.register(ECSConfig, this.Config);\n this.DIContainer.register(InputProvider, this.InputProviderInstance);\n this.DIContainer.register(ECSSimulation, this.Simulation);\n this.DIContainer.register(EntitiesManager, mem.entitiesManager);\n this.DIContainer.register(PRNG, mem.prngManager.prng);\n\n // components\n for (const [ ComponentConstructor, ComponentInstance ] of mem.componentsManager) {\n this.DIContainer.register(ComponentConstructor, ComponentInstance);\n }\n // singletons\n for (const [ SingletonConstructor, SingletonInstance ] of mem.singletonsManager) {\n this.DIContainer.register(SingletonConstructor, SingletonInstance);\n }\n // filters\n for (const [ FilterConstructor, FilterInstance ] of mem.filtersManager) {\n this.DIContainer.register(FilterConstructor, FilterInstance);\n }\n // player resources\n this.DIContainer.register(PlayerResources, mem.playerResourcesManager.PlayerResources);\n\n // signals\n const signalInstances = this.Signals.map((SignalConstructor) => {\n return this.DIContainer.resolve(SignalConstructor);\n });\n this.Simulation.initSignals(signalInstances);\n\n // systems\n const systemInstances = this.Systems.map((SystemConstructor) => {\n return this.DIContainer.resolve(SystemConstructor);\n });\n\n this.Simulation.registerSystems(systemInstances);\n }\n\n public start(): void {\n this.Simulation.start();\n }\n\n public update(dt: number): void {\n this.Simulation.update(dt);\n }\n\n public dispose(): void {\n // ECSRunner disposed\n this.InputProviderInstance.dispose();\n this.Simulation.disposeSignals();\n\n }\n}\n"],"names":["Container","ECSConfig","ECSSimulation","InputProvider","EntitiesManager","PlayerResources","PRNG","ECSRunner","start","Simulation","update","dt","dispose","InputProviderInstance","disposeSignals","Config","Systems","Signals","Deps","DIContainer","init","mem","register","entitiesManager","prngManager","prng","ComponentConstructor","ComponentInstance","componentsManager","SingletonConstructor","SingletonInstance","singletonsManager","FilterConstructor","FilterInstance","filtersManager","playerResourcesManager","signalInstances","map","SignalConstructor","resolve","initSignals","systemInstances","SystemConstructor","registerSystems"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;","mappings":"AAAA,SAASA,SAAS,QAAQ,gBAAgB;AAC1C,SAASC,SAAS,QAAQ,kBAAkB;AAC5C,SAASC,aAAa,QAAQ,sBAAsB;AAGpD,SAASC,aAAa,QAAQ,mBAAmB;AACjD,SAASC,eAAe,EAAEC,eAAe,EAAEC,IAAI,QAAQ,iBAAiB;AAGxE,OAAO,MAAeC;IAoDbC,QAAc;QACnB,IAAI,CAACC,UAAU,CAACD,KAAK;IACvB;IAEOE,OAAOC,EAAU,EAAQ;QAC9B,IAAI,CAACF,UAAU,CAACC,MAAM,CAACC;IACzB;IAEOC,UAAgB;QACrB,qBAAqB;QACrB,IAAI,CAACC,qBAAqB,CAACD,OAAO;QAClC,IAAI,CAACH,UAAU,CAACK,cAAc;IAEhC;IA7DA,YACE,AAAgBC,MAAiB,EACjC,AAAgBF,qBAA4C,EAC5D,AAAgBG,OAAqC,EACrD,AAAgBC,UAAqC,EAAE,EACvD,AAAgBC,IAAa,CAC7B;aALgBH,SAAAA;aACAF,wBAAAA;aACAG,UAAAA;aACAC,UAAAA;aACAC,OAAAA;QAEhB,IAAI,CAACC,WAAW,GAAG,IAAInB;QACvB,IAAI,CAACS,UAAU,GAAG,IAAIP,cAAc,IAAI,CAACa,MAAM,EAAE,IAAI,CAACG,IAAI,EAAE,IAAI,CAACL,qBAAqB;QACtF,IAAI,CAACA,qBAAqB,CAACO,IAAI,CAAC,IAAI,CAACX,UAAU;QAE/C,MAAMY,MAAM,IAAI,CAACZ,UAAU,CAACY,GAAG;QAE/B,IAAI,CAACF,WAAW,CAACG,QAAQ,CAACrB,WAAW,IAAI,CAACc,MAAM;QAChD,IAAI,CAACI,WAAW,CAACG,QAAQ,CAACnB,eAAe,IAAI,CAACU,qBAAqB;QACnE,IAAI,CAACM,WAAW,CAACG,QAAQ,CAACpB,eAAe,IAAI,CAACO,UAAU;QACxD,IAAI,CAACU,WAAW,CAACG,QAAQ,CAAClB,iBAAiBiB,IAAIE,eAAe;QAC9D,IAAI,CAACJ,WAAW,CAACG,QAAQ,CAAChB,MAAMe,IAAIG,WAAW,CAACC,IAAI;QAEpD,aAAa;QACb,KAAK,MAAM,CAAEC,sBAAsBC,kBAAmB,IAAIN,IAAIO,iBAAiB,CAAE;YAC/E,IAAI,CAACT,WAAW,CAACG,QAAQ,CAACI,sBAAsBC;QAClD;QACA,aAAa;QACb,KAAK,MAAM,CAAEE,sBAAsBC,kBAAmB,IAAIT,IAAIU,iBAAiB,CAAE;YAC/E,IAAI,CAACZ,WAAW,CAACG,QAAQ,CAACO,sBAAsBC;QAClD;QACA,UAAU;QACV,KAAK,MAAM,CAAEE,mBAAmBC,eAAgB,IAAIZ,IAAIa,cAAc,CAAE;YACtE,IAAI,CAACf,WAAW,CAACG,QAAQ,CAACU,mBAAmBC;QAC/C;QACA,mBAAmB;QACnB,IAAI,CAACd,WAAW,CAACG,QAAQ,CAACjB,iBAAiBgB,IAAIc,sBAAsB,CAAC9B,eAAe;QAErF,UAAU;QACV,MAAM+B,kBAAkB,IAAI,CAACnB,OAAO,CAACoB,GAAG,CAAC,CAACC;YACxC,OAAO,IAAI,CAACnB,WAAW,CAACoB,OAAO,CAACD;QAClC;QACA,IAAI,CAAC7B,UAAU,CAAC+B,WAAW,CAACJ;QAE5B,UAAU;QACV,MAAMK,kBAAkB,IAAI,CAACzB,OAAO,CAACqB,GAAG,CAAC,CAACK;YACxC,OAAO,IAAI,CAACvB,WAAW,CAACoB,OAAO,CAACG;QAClC;QAEA,IAAI,CAACjC,UAAU,CAACkC,eAAe,CAACF;IAClC;AAgBF"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { Mem } from './mem/index.js';
|
|
2
|
+
import { ECSConfig } from './ecs-config.js';
|
|
3
|
+
import { SimulationClock } from '@lagless/misc';
|
|
4
|
+
import { ECSDeps, IECSSystem } from './types/index.js';
|
|
5
|
+
import { AbstractInputProvider } from './input/index.js';
|
|
6
|
+
export declare class ECSSimulation {
|
|
7
|
+
private readonly _ECSConfig;
|
|
8
|
+
private readonly _ECSDeps;
|
|
9
|
+
private readonly _inputProvider;
|
|
10
|
+
readonly mem: Mem;
|
|
11
|
+
readonly clock: SimulationClock;
|
|
12
|
+
private readonly _signalsRegistry;
|
|
13
|
+
private readonly _frameLength;
|
|
14
|
+
private readonly _snapshotRate;
|
|
15
|
+
private readonly _initialSnapshot;
|
|
16
|
+
private readonly _systems;
|
|
17
|
+
private readonly _onTickHandlers;
|
|
18
|
+
private _interpolationFactor;
|
|
19
|
+
private _snapshotHistory;
|
|
20
|
+
get tick(): number;
|
|
21
|
+
get interpolationFactor(): number;
|
|
22
|
+
constructor(_ECSConfig: ECSConfig, _ECSDeps: ECSDeps, _inputProvider: AbstractInputProvider);
|
|
23
|
+
addTickHandler(handler: (tick: number) => void): () => void;
|
|
24
|
+
removeTickHandler(handler: (tick: number) => void): void;
|
|
25
|
+
registerSystems(systems: IECSSystem[]): void;
|
|
26
|
+
initSignals(signals: import('./signals/signal.js').Signal[]): void;
|
|
27
|
+
disposeSignals(): void;
|
|
28
|
+
throwIfSystemsNotRegistered(): void;
|
|
29
|
+
get frameLength(): number;
|
|
30
|
+
start(): void;
|
|
31
|
+
/**
|
|
32
|
+
* Apply external state received from another client (late-join / reconnect).
|
|
33
|
+
* Replaces the entire simulation state, sets the tick, and resets history.
|
|
34
|
+
*/
|
|
35
|
+
applyExternalState(state: ArrayBuffer, tick: number): void;
|
|
36
|
+
update(dt: number): void;
|
|
37
|
+
private checkAndRollback;
|
|
38
|
+
private simulationTicks;
|
|
39
|
+
protected rollback(tick: number): void;
|
|
40
|
+
protected simulate(tick: number): void;
|
|
41
|
+
private storeSnapshotIfNeeded;
|
|
42
|
+
protected saveSnapshot(tick: number): void;
|
|
43
|
+
}
|
|
44
|
+
//# sourceMappingURL=ecs-simulation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ecs-simulation.d.ts","sourceRoot":"","sources":["../../src/lib/ecs-simulation.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,GAAG,EAAE,MAAM,gBAAgB,CAAC;AACrC,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,EAAE,eAAe,EAAiC,MAAM,eAAe,CAAC;AAC/E,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AACvD,OAAO,EAAE,qBAAqB,EAAE,MAAM,kBAAkB,CAAC;AAKzD,qBAAa,aAAa;IAsBtB,OAAO,CAAC,QAAQ,CAAC,UAAU;IAC3B,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,QAAQ,CAAC,cAAc;IAvBjC,SAAgB,GAAG,EAAE,GAAG,CAAC;IACzB,SAAgB,KAAK,EAAE,eAAe,CAAC;IACvC,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAkB;IACnD,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAS;IACtC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAS;IACvC,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAe;IAChD,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAA2B;IACpD,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAqC;IAErE,OAAO,CAAC,oBAAoB,CAAK;IACjC,OAAO,CAAC,gBAAgB,CAA+B;IAEvD,IAAW,IAAI,IAAI,MAAM,CAExB;IAED,IAAW,mBAAmB,IAAI,MAAM,CAEvC;gBAGkB,UAAU,EAAE,SAAS,EACrB,QAAQ,EAAE,OAAO,EACjB,cAAc,EAAE,qBAAqB;IAWjD,cAAc,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,GAAG,MAAM,IAAI;IAO3D,iBAAiB,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,GAAG,IAAI;IAIxD,eAAe,CAAC,OAAO,EAAE,UAAU,EAAE,GAAG,IAAI;IAQ5C,WAAW,CAAC,OAAO,EAAE,OAAO,qBAAqB,EAAE,MAAM,EAAE,GAAG,IAAI;IAIlE,cAAc,IAAI,IAAI;IAItB,2BAA2B,IAAI,IAAI;IAM1C,IAAW,WAAW,IAAI,MAAM,CAE/B;IAEM,KAAK,IAAI,IAAI;IAIpB;;;OAGG;IACI,kBAAkB,CAAC,KAAK,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI;IAsB1D,MAAM,CAAC,EAAE,EAAE,MAAM;IAiBxB,OAAO,CAAC,gBAAgB;IAQxB,OAAO,CAAC,eAAe;IAcvB,SAAS,CAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAgBtC,SAAS,CAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAMtC,OAAO,CAAC,qBAAqB;IAY7B,SAAS,CAAC,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;CAG3C"}
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import { MathOps } from '@lagless/math';
|
|
2
|
+
import { Mem } from './mem/index.js';
|
|
3
|
+
import { SimulationClock, SnapshotHistory, createLogger } from '@lagless/misc';
|
|
4
|
+
import { SignalsRegistry } from './signals/signals.registry.js';
|
|
5
|
+
const log = createLogger('ECSSimulation');
|
|
6
|
+
export class ECSSimulation {
|
|
7
|
+
get tick() {
|
|
8
|
+
return this.mem.tickManager.tick;
|
|
9
|
+
}
|
|
10
|
+
get interpolationFactor() {
|
|
11
|
+
return this._interpolationFactor;
|
|
12
|
+
}
|
|
13
|
+
addTickHandler(handler) {
|
|
14
|
+
this._onTickHandlers.add(handler);
|
|
15
|
+
return ()=>{
|
|
16
|
+
this._onTickHandlers.delete(handler);
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
removeTickHandler(handler) {
|
|
20
|
+
this._onTickHandlers.delete(handler);
|
|
21
|
+
}
|
|
22
|
+
registerSystems(systems) {
|
|
23
|
+
if (this._systems.length !== 0) throw new Error('Systems already registered');
|
|
24
|
+
for (const system of systems){
|
|
25
|
+
this._systems.push(system);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
initSignals(signals) {
|
|
29
|
+
this._signalsRegistry.init(signals);
|
|
30
|
+
}
|
|
31
|
+
disposeSignals() {
|
|
32
|
+
this._signalsRegistry.dispose();
|
|
33
|
+
}
|
|
34
|
+
throwIfSystemsNotRegistered() {
|
|
35
|
+
if (this._systems.length === 0) {
|
|
36
|
+
throw new Error('No systems registered.');
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
get frameLength() {
|
|
40
|
+
return this._frameLength;
|
|
41
|
+
}
|
|
42
|
+
start() {
|
|
43
|
+
this.clock.start();
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Apply external state received from another client (late-join / reconnect).
|
|
47
|
+
* Replaces the entire simulation state, sets the tick, and resets history.
|
|
48
|
+
*/ applyExternalState(state, tick) {
|
|
49
|
+
log.info(`Applying external state at tick ${tick} (${state.byteLength} bytes)`);
|
|
50
|
+
// Apply the snapshot to memory
|
|
51
|
+
this.mem.applySnapshot(state);
|
|
52
|
+
// Set tick (snapshot may have been taken at a different tick than requested)
|
|
53
|
+
this.mem.tickManager.setTick(tick);
|
|
54
|
+
// Reset snapshot history — old snapshots are from a different timeline
|
|
55
|
+
this._snapshotHistory = new SnapshotHistory(this._ECSConfig.snapshotHistorySize);
|
|
56
|
+
// Save the received state as the new baseline snapshot
|
|
57
|
+
this.saveSnapshot(tick);
|
|
58
|
+
// Adjust clock to match the new tick
|
|
59
|
+
this.clock.setAccumulatedTime(tick * this._frameLength);
|
|
60
|
+
// Reset signals — old predictions are invalid
|
|
61
|
+
this._signalsRegistry.dispose();
|
|
62
|
+
}
|
|
63
|
+
update(dt) {
|
|
64
|
+
this.clock.update(dt);
|
|
65
|
+
const targetTick = Math.floor(this.clock.accumulatedTime / this._frameLength);
|
|
66
|
+
this.checkAndRollback(this.mem.tickManager.tick);
|
|
67
|
+
this.simulationTicks(this.mem.tickManager.tick, targetTick);
|
|
68
|
+
this._inputProvider.update();
|
|
69
|
+
const simTick = this.mem.tickManager.tick;
|
|
70
|
+
const tickTime = simTick * this._frameLength;
|
|
71
|
+
const leftover = this.clock.accumulatedTime - tickTime;
|
|
72
|
+
this._interpolationFactor = MathOps.clamp01(leftover / this._frameLength);
|
|
73
|
+
}
|
|
74
|
+
checkAndRollback(currentTick) {
|
|
75
|
+
const rollbackTick = this._inputProvider.getInvalidateRollbackTick();
|
|
76
|
+
if (rollbackTick === undefined || rollbackTick > currentTick) return;
|
|
77
|
+
this.rollback(rollbackTick);
|
|
78
|
+
}
|
|
79
|
+
simulationTicks(currentTick, toTick) {
|
|
80
|
+
if (toTick - currentTick > 1) {
|
|
81
|
+
log.warn(`Simulation ticks: ${currentTick} -> ${toTick} (simulate ${toTick - currentTick})`);
|
|
82
|
+
}
|
|
83
|
+
while(currentTick < toTick){
|
|
84
|
+
this.mem.tickManager.setTick(++currentTick);
|
|
85
|
+
this.simulate(currentTick);
|
|
86
|
+
this._signalsRegistry.onTick(currentTick);
|
|
87
|
+
this.storeSnapshotIfNeeded(currentTick);
|
|
88
|
+
for (const handler of this._onTickHandlers)handler(currentTick);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
rollback(tick) {
|
|
92
|
+
this._signalsRegistry.onBeforeRollback(tick);
|
|
93
|
+
let snapshot;
|
|
94
|
+
try {
|
|
95
|
+
snapshot = this._snapshotHistory.getNearest(tick);
|
|
96
|
+
log.warn(`Rollback to tick ${tick} succeeded`);
|
|
97
|
+
} catch (e) {
|
|
98
|
+
snapshot = this._initialSnapshot;
|
|
99
|
+
log.warn(`Rollback to tick ${tick} failed, using initial snapshot`);
|
|
100
|
+
}
|
|
101
|
+
this.mem.applySnapshot(snapshot);
|
|
102
|
+
this._snapshotHistory.rollback(this.mem.tickManager.tick);
|
|
103
|
+
}
|
|
104
|
+
simulate(tick) {
|
|
105
|
+
for(let i = 0; i < this._systems.length; i++){
|
|
106
|
+
this._systems[i].update(tick);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
storeSnapshotIfNeeded(tick) {
|
|
110
|
+
if (this._snapshotRate === 0) return;
|
|
111
|
+
if (tick % this._snapshotRate === 0) {
|
|
112
|
+
this.saveSnapshot(tick);
|
|
113
|
+
}
|
|
114
|
+
if (tick % 200 === 0) {
|
|
115
|
+
log.debug(`Mem Hash at tick ${tick}: ${this.mem.getHash()}`);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
saveSnapshot(tick) {
|
|
119
|
+
this._snapshotHistory.set(tick, this.mem.exportSnapshot());
|
|
120
|
+
}
|
|
121
|
+
constructor(_ECSConfig, _ECSDeps, _inputProvider){
|
|
122
|
+
this._ECSConfig = _ECSConfig;
|
|
123
|
+
this._ECSDeps = _ECSDeps;
|
|
124
|
+
this._inputProvider = _inputProvider;
|
|
125
|
+
this._systems = new Array();
|
|
126
|
+
this._onTickHandlers = new Set();
|
|
127
|
+
this._interpolationFactor = 0;
|
|
128
|
+
this.mem = new Mem(this._ECSConfig, this._ECSDeps);
|
|
129
|
+
this._frameLength = this._ECSConfig.frameLength;
|
|
130
|
+
this._snapshotRate = this._ECSConfig.snapshotRate;
|
|
131
|
+
this._snapshotHistory = new SnapshotHistory(this._ECSConfig.snapshotHistorySize);
|
|
132
|
+
this._initialSnapshot = this.mem.exportSnapshot();
|
|
133
|
+
this.clock = new SimulationClock(_ECSConfig.frameLength, _ECSConfig.maxNudgePerFrame);
|
|
134
|
+
this._signalsRegistry = new SignalsRegistry();
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
//# sourceMappingURL=ecs-simulation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/lib/ecs-simulation.ts"],"sourcesContent":["import { MathOps } from '@lagless/math';\nimport { Mem } from './mem/index.js';\nimport { ECSConfig } from './ecs-config.js';\nimport { SimulationClock, SnapshotHistory, createLogger } from '@lagless/misc';\nimport { ECSDeps, IECSSystem } from './types/index.js';\nimport { AbstractInputProvider } from './input/index.js';\nimport { SignalsRegistry } from './signals/signals.registry.js';\n\nconst log = createLogger('ECSSimulation');\n\nexport class ECSSimulation {\n public readonly mem: Mem;\n public readonly clock: SimulationClock;\n private readonly _signalsRegistry: SignalsRegistry;\n private readonly _frameLength: number;\n private readonly _snapshotRate: number;\n private readonly _initialSnapshot!: ArrayBuffer;\n private readonly _systems = new Array<IECSSystem>();\n private readonly _onTickHandlers = new Set<(tick: number) => void>();\n\n private _interpolationFactor = 0;\n private _snapshotHistory: SnapshotHistory<ArrayBuffer>;\n\n public get tick(): number {\n return this.mem.tickManager.tick;\n }\n\n public get interpolationFactor(): number {\n return this._interpolationFactor;\n }\n\n constructor(\n private readonly _ECSConfig: ECSConfig,\n private readonly _ECSDeps: ECSDeps,\n private readonly _inputProvider: AbstractInputProvider,\n ) {\n this.mem = new Mem(this._ECSConfig, this._ECSDeps);\n this._frameLength = this._ECSConfig.frameLength;\n this._snapshotRate = this._ECSConfig.snapshotRate;\n this._snapshotHistory = new SnapshotHistory<ArrayBuffer>(this._ECSConfig.snapshotHistorySize);\n this._initialSnapshot = this.mem.exportSnapshot();\n this.clock = new SimulationClock(_ECSConfig.frameLength, _ECSConfig.maxNudgePerFrame);\n this._signalsRegistry = new SignalsRegistry();\n }\n\n public addTickHandler(handler: (tick: number) => void): () => void {\n this._onTickHandlers.add(handler);\n return () => {\n this._onTickHandlers.delete(handler);\n };\n }\n\n public removeTickHandler(handler: (tick: number) => void): void {\n this._onTickHandlers.delete(handler);\n }\n\n public registerSystems(systems: IECSSystem[]): void {\n if (this._systems.length !== 0) throw new Error('Systems already registered');\n\n for (const system of systems) {\n this._systems.push(system);\n }\n }\n\n public initSignals(signals: import('./signals/signal.js').Signal[]): void {\n this._signalsRegistry.init(signals);\n }\n\n public disposeSignals(): void {\n this._signalsRegistry.dispose();\n }\n\n public throwIfSystemsNotRegistered(): void {\n if (this._systems.length === 0) {\n throw new Error('No systems registered.');\n }\n }\n\n public get frameLength(): number {\n return this._frameLength;\n }\n\n public start(): void {\n this.clock.start();\n }\n\n /**\n * Apply external state received from another client (late-join / reconnect).\n * Replaces the entire simulation state, sets the tick, and resets history.\n */\n public applyExternalState(state: ArrayBuffer, tick: number): void {\n log.info(`Applying external state at tick ${tick} (${state.byteLength} bytes)`);\n\n // Apply the snapshot to memory\n this.mem.applySnapshot(state);\n\n // Set tick (snapshot may have been taken at a different tick than requested)\n this.mem.tickManager.setTick(tick);\n\n // Reset snapshot history — old snapshots are from a different timeline\n this._snapshotHistory = new SnapshotHistory<ArrayBuffer>(this._ECSConfig.snapshotHistorySize);\n\n // Save the received state as the new baseline snapshot\n this.saveSnapshot(tick);\n\n // Adjust clock to match the new tick\n this.clock.setAccumulatedTime(tick * this._frameLength);\n\n // Reset signals — old predictions are invalid\n this._signalsRegistry.dispose();\n }\n\n public update(dt: number) {\n this.clock.update(dt);\n\n const targetTick = Math.floor(this.clock.accumulatedTime / this._frameLength);\n\n this.checkAndRollback(this.mem.tickManager.tick);\n this.simulationTicks(this.mem.tickManager.tick, targetTick);\n\n this._inputProvider.update();\n\n const simTick = this.mem.tickManager.tick;\n const tickTime = simTick * this._frameLength;\n const leftover = this.clock.accumulatedTime - tickTime;\n\n this._interpolationFactor = MathOps.clamp01(leftover / this._frameLength);\n }\n\n private checkAndRollback(currentTick: number) {\n const rollbackTick = this._inputProvider.getInvalidateRollbackTick();\n\n if (rollbackTick === undefined || rollbackTick > currentTick) return;\n\n this.rollback(rollbackTick);\n }\n\n private simulationTicks(currentTick: number, toTick: number): void {\n if (toTick - currentTick > 1) {\n log.warn(`Simulation ticks: ${currentTick} -> ${toTick} (simulate ${toTick - currentTick})`);\n }\n\n while (currentTick < toTick) {\n this.mem.tickManager.setTick(++currentTick);\n this.simulate(currentTick);\n this._signalsRegistry.onTick(currentTick);\n this.storeSnapshotIfNeeded(currentTick);\n for (const handler of this._onTickHandlers) handler(currentTick);\n }\n }\n\n protected rollback(tick: number): void {\n this._signalsRegistry.onBeforeRollback(tick);\n let snapshot: ArrayBuffer;\n\n try {\n snapshot = this._snapshotHistory.getNearest(tick);\n log.warn(`Rollback to tick ${tick} succeeded`);\n } catch {\n snapshot = this._initialSnapshot;\n log.warn(`Rollback to tick ${tick} failed, using initial snapshot`);\n }\n\n this.mem.applySnapshot(snapshot);\n this._snapshotHistory.rollback(this.mem.tickManager.tick);\n }\n\n protected simulate(tick: number): void {\n for (let i = 0; i < this._systems.length; i++) {\n this._systems[i].update(tick);\n }\n }\n\n private storeSnapshotIfNeeded(tick: number): void {\n if (this._snapshotRate === 0) return;\n\n if (tick % this._snapshotRate === 0) {\n this.saveSnapshot(tick);\n }\n\n if (tick % 200 === 0) {\n log.debug(`Mem Hash at tick ${tick}: ${this.mem.getHash()}`);\n }\n }\n\n protected saveSnapshot(tick: number): void {\n this._snapshotHistory.set(tick, this.mem.exportSnapshot());\n }\n}\n"],"names":["MathOps","Mem","SimulationClock","SnapshotHistory","createLogger","SignalsRegistry","log","ECSSimulation","tick","mem","tickManager","interpolationFactor","_interpolationFactor","addTickHandler","handler","_onTickHandlers","add","delete","removeTickHandler","registerSystems","systems","_systems","length","Error","system","push","initSignals","signals","_signalsRegistry","init","disposeSignals","dispose","throwIfSystemsNotRegistered","frameLength","_frameLength","start","clock","applyExternalState","state","info","byteLength","applySnapshot","setTick","_snapshotHistory","_ECSConfig","snapshotHistorySize","saveSnapshot","setAccumulatedTime","update","dt","targetTick","Math","floor","accumulatedTime","checkAndRollback","simulationTicks","_inputProvider","simTick","tickTime","leftover","clamp01","currentTick","rollbackTick","getInvalidateRollbackTick","undefined","rollback","toTick","warn","simulate","onTick","storeSnapshotIfNeeded","onBeforeRollback","snapshot","getNearest","_initialSnapshot","i","_snapshotRate","debug","getHash","set","exportSnapshot","constructor","_ECSDeps","Array","Set","snapshotRate","maxNudgePerFrame"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;","mappings":"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"}
|