@lagless/core 0.0.35 → 0.0.38
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/dist/lib/ecs-runner.d.ts +1 -1
- package/dist/lib/ecs-runner.d.ts.map +1 -1
- package/dist/lib/ecs-runner.js +8 -2
- package/dist/lib/ecs-runner.js.map +1 -1
- package/dist/lib/ecs-simulation.d.ts +24 -4
- package/dist/lib/ecs-simulation.d.ts.map +1 -1
- package/dist/lib/ecs-simulation.js +57 -1
- package/dist/lib/ecs-simulation.js.map +1 -1
- package/dist/lib/hash-verification/abstract-hash-verification.system.d.ts.map +1 -1
- package/dist/lib/hash-verification/abstract-hash-verification.system.js +5 -0
- package/dist/lib/hash-verification/abstract-hash-verification.system.js.map +1 -1
- package/dist/lib/hash-verification/create-hash-reporter.d.ts.map +1 -1
- package/dist/lib/hash-verification/create-hash-reporter.js +11 -8
- package/dist/lib/hash-verification/create-hash-reporter.js.map +1 -1
- package/dist/lib/input/abstract-input-provider.d.ts +1 -0
- package/dist/lib/input/abstract-input-provider.d.ts.map +1 -1
- package/dist/lib/input/abstract-input-provider.js +8 -1
- package/dist/lib/input/abstract-input-provider.js.map +1 -1
- package/dist/lib/input/input-provider-di-token.d.ts +1 -0
- package/dist/lib/input/input-provider-di-token.d.ts.map +1 -1
- package/dist/lib/input/input-provider-di-token.js +3 -0
- package/dist/lib/input/input-provider-di-token.js.map +1 -1
- package/dist/lib/input/local-input-provider.d.ts +1 -0
- package/dist/lib/input/local-input-provider.d.ts.map +1 -1
- package/dist/lib/input/local-input-provider.js +5 -0
- package/dist/lib/input/local-input-provider.js.map +1 -1
- package/dist/lib/input/replay-input-provider.d.ts +1 -0
- package/dist/lib/input/replay-input-provider.d.ts.map +1 -1
- package/dist/lib/input/replay-input-provider.js +5 -0
- package/dist/lib/input/replay-input-provider.js.map +1 -1
- package/dist/lib/mem/managers/entities-manager.d.ts +3 -2
- package/dist/lib/mem/managers/entities-manager.d.ts.map +1 -1
- package/dist/lib/mem/managers/entities-manager.js +65 -23
- package/dist/lib/mem/managers/entities-manager.js.map +1 -1
- package/dist/lib/mem/managers/filters-manager.d.ts +2 -2
- package/dist/lib/mem/managers/filters-manager.d.ts.map +1 -1
- package/dist/lib/mem/managers/filters-manager.js +19 -4
- package/dist/lib/mem/managers/filters-manager.js.map +1 -1
- package/dist/lib/mem/mem.d.ts.map +1 -1
- package/dist/lib/mem/mem.js +4 -2
- package/dist/lib/mem/mem.js.map +1 -1
- package/dist/lib/signals/signal.d.ts +4 -3
- package/dist/lib/signals/signal.d.ts.map +1 -1
- package/dist/lib/signals/signal.js +34 -34
- package/dist/lib/signals/signal.js.map +1 -1
- package/dist/lib/signals/signals.registry.d.ts +1 -1
- package/dist/lib/signals/signals.registry.d.ts.map +1 -1
- package/dist/lib/signals/signals.registry.js +2 -2
- package/dist/lib/signals/signals.registry.js.map +1 -1
- package/dist/lib/types/abstract-filter.d.ts +3 -2
- package/dist/lib/types/abstract-filter.d.ts.map +1 -1
- package/dist/lib/types/abstract-filter.js +22 -21
- package/dist/lib/types/abstract-filter.js.map +1 -1
- package/dist/lib/types/ecs-types.d.ts +5 -3
- package/dist/lib/types/ecs-types.d.ts.map +1 -1
- package/dist/lib/types/ecs-types.js.map +1 -1
- package/package.json +4 -5
package/dist/lib/ecs-runner.d.ts
CHANGED
|
@@ -12,7 +12,7 @@ export declare abstract class ECSRunner {
|
|
|
12
12
|
readonly Deps: ECSDeps;
|
|
13
13
|
readonly DIContainer: Container;
|
|
14
14
|
readonly Simulation: ECSSimulation;
|
|
15
|
-
protected constructor(Config: ECSConfig, InputProviderInstance: AbstractInputProvider, Systems: Array<IECSSystemConstructor>, Signals: Array<ISignalConstructor> | undefined, Deps: ECSDeps);
|
|
15
|
+
protected constructor(Config: ECSConfig, InputProviderInstance: AbstractInputProvider, Systems: Array<IECSSystemConstructor>, Signals: Array<ISignalConstructor> | undefined, Deps: ECSDeps, simulation?: ECSSimulation, extraRegistrations?: Array<[unknown, unknown]>);
|
|
16
16
|
start(): void;
|
|
17
17
|
update(dt: number): void;
|
|
18
18
|
dispose(): void;
|
|
@@ -1 +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;
|
|
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,EAC7B,UAAU,CAAC,EAAE,aAAa,EAC1B,kBAAkB,CAAC,EAAE,KAAK,CAAC,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;IAkDzC,KAAK,IAAI,IAAI;IAIb,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI;IAIxB,OAAO,IAAI,IAAI;CAMvB"}
|
package/dist/lib/ecs-runner.js
CHANGED
|
@@ -15,14 +15,14 @@ export class ECSRunner {
|
|
|
15
15
|
this.InputProviderInstance.dispose();
|
|
16
16
|
this.Simulation.disposeSignals();
|
|
17
17
|
}
|
|
18
|
-
constructor(Config, InputProviderInstance, Systems, Signals = [], Deps){
|
|
18
|
+
constructor(Config, InputProviderInstance, Systems, Signals = [], Deps, simulation, extraRegistrations){
|
|
19
19
|
this.Config = Config;
|
|
20
20
|
this.InputProviderInstance = InputProviderInstance;
|
|
21
21
|
this.Systems = Systems;
|
|
22
22
|
this.Signals = Signals;
|
|
23
23
|
this.Deps = Deps;
|
|
24
24
|
this.DIContainer = new Container();
|
|
25
|
-
this.Simulation = new ECSSimulation(this.Config, this.Deps, this.InputProviderInstance);
|
|
25
|
+
this.Simulation = simulation != null ? simulation : new ECSSimulation(this.Config, this.Deps, this.InputProviderInstance);
|
|
26
26
|
this.InputProviderInstance.init(this.Simulation);
|
|
27
27
|
const mem = this.Simulation.mem;
|
|
28
28
|
this.DIContainer.register(ECSConfig, this.Config);
|
|
@@ -44,6 +44,12 @@ export class ECSRunner {
|
|
|
44
44
|
}
|
|
45
45
|
// player resources
|
|
46
46
|
this.DIContainer.register(PlayerResources, mem.playerResourcesManager.PlayerResources);
|
|
47
|
+
// extra registrations (from subclasses like PhysicsRunner3d)
|
|
48
|
+
if (extraRegistrations) {
|
|
49
|
+
for (const [token, instance] of extraRegistrations){
|
|
50
|
+
this.DIContainer.register(token, instance);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
47
53
|
// signals
|
|
48
54
|
const signalInstances = this.Signals.map((SignalConstructor)=>{
|
|
49
55
|
return this.DIContainer.resolve(SignalConstructor);
|
|
@@ -1 +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":"
|
|
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 simulation?: ECSSimulation,\n extraRegistrations?: Array<[unknown, unknown]>,\n ) {\n this.DIContainer = new Container();\n this.Simulation = 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 // extra registrations (from subclasses like PhysicsRunner3d)\n if (extraRegistrations) {\n for (const [token, instance] of extraRegistrations) {\n this.DIContainer.register(token as new (...args: unknown[]) => unknown, instance);\n }\n }\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","simulation","extraRegistrations","DIContainer","init","mem","register","entitiesManager","prngManager","prng","ComponentConstructor","ComponentInstance","componentsManager","SingletonConstructor","SingletonInstance","singletonsManager","FilterConstructor","FilterInstance","filtersManager","playerResourcesManager","token","instance","signalInstances","map","SignalConstructor","resolve","initSignals","systemInstances","SystemConstructor","registerSystems"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;","mappings":"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"}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { Mem } from './mem/index.js';
|
|
2
2
|
import { ECSConfig } from './ecs-config.js';
|
|
3
|
-
import { SimulationClock } from '@lagless/misc';
|
|
3
|
+
import { SimulationClock, SnapshotHistory } from '@lagless/misc';
|
|
4
4
|
import { ECSDeps, IECSSystem } from './types/index.js';
|
|
5
5
|
import { AbstractInputProvider } from './input/index.js';
|
|
6
6
|
export declare class ECSSimulation {
|
|
7
|
-
|
|
7
|
+
protected readonly _ECSConfig: ECSConfig;
|
|
8
8
|
private readonly _ECSDeps;
|
|
9
9
|
private readonly _inputProvider;
|
|
10
10
|
readonly mem: Mem;
|
|
@@ -12,27 +12,47 @@ export declare class ECSSimulation {
|
|
|
12
12
|
private readonly _signalsRegistry;
|
|
13
13
|
private readonly _frameLength;
|
|
14
14
|
private readonly _snapshotRate;
|
|
15
|
-
|
|
15
|
+
protected readonly _initialSnapshot: ArrayBuffer;
|
|
16
16
|
private readonly _systems;
|
|
17
17
|
private readonly _onTickHandlers;
|
|
18
|
+
private readonly _onRollbackHandlers;
|
|
19
|
+
private readonly _onStateTransferHandlers;
|
|
18
20
|
private _interpolationFactor;
|
|
19
|
-
|
|
21
|
+
protected _snapshotHistory: SnapshotHistory<ArrayBuffer>;
|
|
22
|
+
private _hashTrackingInterval;
|
|
23
|
+
private _hashHistory;
|
|
20
24
|
get tick(): number;
|
|
21
25
|
get interpolationFactor(): number;
|
|
22
26
|
constructor(_ECSConfig: ECSConfig, _ECSDeps: ECSDeps, _inputProvider: AbstractInputProvider);
|
|
23
27
|
addTickHandler(handler: (tick: number) => void): () => void;
|
|
24
28
|
removeTickHandler(handler: (tick: number) => void): void;
|
|
29
|
+
addRollbackHandler(handler: (tick: number) => void): () => void;
|
|
30
|
+
addStateTransferHandler(handler: (tick: number) => void): () => void;
|
|
25
31
|
registerSystems(systems: IECSSystem[]): void;
|
|
26
32
|
initSignals(signals: import('./signals/signal.js').Signal[]): void;
|
|
27
33
|
disposeSignals(): void;
|
|
28
34
|
throwIfSystemsNotRegistered(): void;
|
|
29
35
|
get frameLength(): number;
|
|
36
|
+
get inputProvider(): AbstractInputProvider;
|
|
37
|
+
enableHashTracking(interval: number): void;
|
|
38
|
+
getHashAtTick(tick: number): number | undefined;
|
|
30
39
|
start(): void;
|
|
31
40
|
/**
|
|
32
41
|
* Apply external state received from another client (late-join / reconnect).
|
|
33
42
|
* Replaces the entire simulation state, sets the tick, and resets history.
|
|
34
43
|
*/
|
|
35
44
|
applyExternalState(state: ArrayBuffer, tick: number): void;
|
|
45
|
+
/**
|
|
46
|
+
* Export simulation state for network state transfer (late-join / reconnect).
|
|
47
|
+
* Override in subclasses to include additional state (e.g. physics world).
|
|
48
|
+
*/
|
|
49
|
+
exportStateForTransfer(): ArrayBuffer;
|
|
50
|
+
/**
|
|
51
|
+
* Apply state received from network state transfer (late-join / reconnect).
|
|
52
|
+
* Override in subclasses to restore additional state (e.g. physics world).
|
|
53
|
+
*/
|
|
54
|
+
applyStateFromTransfer(blob: ArrayBuffer, tick: number): void;
|
|
55
|
+
protected notifyStateTransferHandlers(tick: number): void;
|
|
36
56
|
update(dt: number): void;
|
|
37
57
|
private checkAndRollback;
|
|
38
58
|
private simulationTicks;
|
|
@@ -1 +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,
|
|
1
|
+
{"version":3,"file":"ecs-simulation.d.ts","sourceRoot":"","sources":["../../src/lib/ecs-simulation.ts"],"names":[],"mappings":"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"}
|
|
@@ -19,6 +19,18 @@ export class ECSSimulation {
|
|
|
19
19
|
removeTickHandler(handler) {
|
|
20
20
|
this._onTickHandlers.delete(handler);
|
|
21
21
|
}
|
|
22
|
+
addRollbackHandler(handler) {
|
|
23
|
+
this._onRollbackHandlers.add(handler);
|
|
24
|
+
return ()=>{
|
|
25
|
+
this._onRollbackHandlers.delete(handler);
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
addStateTransferHandler(handler) {
|
|
29
|
+
this._onStateTransferHandlers.add(handler);
|
|
30
|
+
return ()=>{
|
|
31
|
+
this._onStateTransferHandlers.delete(handler);
|
|
32
|
+
};
|
|
33
|
+
}
|
|
22
34
|
registerSystems(systems) {
|
|
23
35
|
if (this._systems.length !== 0) throw new Error('Systems already registered');
|
|
24
36
|
for (const system of systems){
|
|
@@ -39,6 +51,15 @@ export class ECSSimulation {
|
|
|
39
51
|
get frameLength() {
|
|
40
52
|
return this._frameLength;
|
|
41
53
|
}
|
|
54
|
+
get inputProvider() {
|
|
55
|
+
return this._inputProvider;
|
|
56
|
+
}
|
|
57
|
+
enableHashTracking(interval) {
|
|
58
|
+
this._hashTrackingInterval = interval;
|
|
59
|
+
}
|
|
60
|
+
getHashAtTick(tick) {
|
|
61
|
+
return this._hashHistory.get(tick);
|
|
62
|
+
}
|
|
42
63
|
start() {
|
|
43
64
|
this.clock.start();
|
|
44
65
|
}
|
|
@@ -59,6 +80,24 @@ export class ECSSimulation {
|
|
|
59
80
|
this.clock.setAccumulatedTime(tick * this._frameLength);
|
|
60
81
|
// Reset signals — old predictions are invalid
|
|
61
82
|
this._signalsRegistry.dispose();
|
|
83
|
+
// Clear hash history — old hashes are from a different timeline
|
|
84
|
+
this._hashHistory.clear();
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Export simulation state for network state transfer (late-join / reconnect).
|
|
88
|
+
* Override in subclasses to include additional state (e.g. physics world).
|
|
89
|
+
*/ exportStateForTransfer() {
|
|
90
|
+
return this.mem.exportSnapshot();
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Apply state received from network state transfer (late-join / reconnect).
|
|
94
|
+
* Override in subclasses to restore additional state (e.g. physics world).
|
|
95
|
+
*/ applyStateFromTransfer(blob, tick) {
|
|
96
|
+
this.applyExternalState(blob, tick);
|
|
97
|
+
this.notifyStateTransferHandlers(tick);
|
|
98
|
+
}
|
|
99
|
+
notifyStateTransferHandlers(tick) {
|
|
100
|
+
for (const handler of this._onStateTransferHandlers)handler(tick);
|
|
62
101
|
}
|
|
63
102
|
update(dt) {
|
|
64
103
|
this.clock.update(dt);
|
|
@@ -75,6 +114,7 @@ export class ECSSimulation {
|
|
|
75
114
|
const rollbackTick = this._inputProvider.getInvalidateRollbackTick();
|
|
76
115
|
if (rollbackTick === undefined || rollbackTick > currentTick) return;
|
|
77
116
|
this.rollback(rollbackTick);
|
|
117
|
+
for (const handler of this._onRollbackHandlers)handler(this.tick);
|
|
78
118
|
}
|
|
79
119
|
simulationTicks(currentTick, toTick) {
|
|
80
120
|
if (toTick - currentTick > 1) {
|
|
@@ -83,10 +123,22 @@ export class ECSSimulation {
|
|
|
83
123
|
while(currentTick < toTick){
|
|
84
124
|
this.mem.tickManager.setTick(++currentTick);
|
|
85
125
|
this.simulate(currentTick);
|
|
86
|
-
this.
|
|
126
|
+
if (this._hashTrackingInterval > 0 && currentTick % this._hashTrackingInterval === 0) {
|
|
127
|
+
this._hashHistory.set(currentTick, this.mem.getHash());
|
|
128
|
+
}
|
|
129
|
+
this._signalsRegistry.onTick(this._inputProvider.verifiedTick);
|
|
87
130
|
this.storeSnapshotIfNeeded(currentTick);
|
|
88
131
|
for (const handler of this._onTickHandlers)handler(currentTick);
|
|
89
132
|
}
|
|
133
|
+
// Prune old hash entries
|
|
134
|
+
if (this._hashHistory.size > 0) {
|
|
135
|
+
const pruneBelow = this._inputProvider.verifiedTick - 600;
|
|
136
|
+
if (pruneBelow > 0) {
|
|
137
|
+
for (const tick of this._hashHistory.keys()){
|
|
138
|
+
if (tick < pruneBelow) this._hashHistory.delete(tick);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
90
142
|
}
|
|
91
143
|
rollback(tick) {
|
|
92
144
|
this._signalsRegistry.onBeforeRollback(tick);
|
|
@@ -124,7 +176,11 @@ export class ECSSimulation {
|
|
|
124
176
|
this._inputProvider = _inputProvider;
|
|
125
177
|
this._systems = new Array();
|
|
126
178
|
this._onTickHandlers = new Set();
|
|
179
|
+
this._onRollbackHandlers = new Set();
|
|
180
|
+
this._onStateTransferHandlers = new Set();
|
|
127
181
|
this._interpolationFactor = 0;
|
|
182
|
+
this._hashTrackingInterval = 0;
|
|
183
|
+
this._hashHistory = new Map();
|
|
128
184
|
this.mem = new Mem(this._ECSConfig, this._ECSDeps);
|
|
129
185
|
this._frameLength = this._ECSConfig.frameLength;
|
|
130
186
|
this._snapshotRate = this._ECSConfig.snapshotRate;
|
|
@@ -1 +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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"}
|
|
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 protected readonly _initialSnapshot!: ArrayBuffer;\n private readonly _systems = new Array<IECSSystem>();\n private readonly _onTickHandlers = new Set<(tick: number) => void>();\n private readonly _onRollbackHandlers = new Set<(tick: number) => void>();\n private readonly _onStateTransferHandlers = new Set<(tick: number) => void>();\n\n private _interpolationFactor = 0;\n protected _snapshotHistory: SnapshotHistory<ArrayBuffer>;\n private _hashTrackingInterval = 0;\n private _hashHistory = new Map<number, number>();\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 protected 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 addRollbackHandler(handler: (tick: number) => void): () => void {\n this._onRollbackHandlers.add(handler);\n return () => { this._onRollbackHandlers.delete(handler); };\n }\n\n public addStateTransferHandler(handler: (tick: number) => void): () => void {\n this._onStateTransferHandlers.add(handler);\n return () => { this._onStateTransferHandlers.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 get inputProvider(): AbstractInputProvider {\n return this._inputProvider;\n }\n\n public enableHashTracking(interval: number): void {\n this._hashTrackingInterval = interval;\n }\n\n public getHashAtTick(tick: number): number | undefined {\n return this._hashHistory.get(tick);\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 // Clear hash history — old hashes are from a different timeline\n this._hashHistory.clear();\n }\n\n /**\n * Export simulation state for network state transfer (late-join / reconnect).\n * Override in subclasses to include additional state (e.g. physics world).\n */\n public exportStateForTransfer(): ArrayBuffer {\n return this.mem.exportSnapshot();\n }\n\n /**\n * Apply state received from network state transfer (late-join / reconnect).\n * Override in subclasses to restore additional state (e.g. physics world).\n */\n public applyStateFromTransfer(blob: ArrayBuffer, tick: number): void {\n this.applyExternalState(blob, tick);\n this.notifyStateTransferHandlers(tick);\n }\n\n protected notifyStateTransferHandlers(tick: number): void {\n for (const handler of this._onStateTransferHandlers) handler(tick);\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 for (const handler of this._onRollbackHandlers) handler(this.tick);\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\n if (this._hashTrackingInterval > 0 && currentTick % this._hashTrackingInterval === 0) {\n this._hashHistory.set(currentTick, this.mem.getHash());\n }\n\n this._signalsRegistry.onTick(this._inputProvider.verifiedTick);\n this.storeSnapshotIfNeeded(currentTick);\n for (const handler of this._onTickHandlers) handler(currentTick);\n }\n\n // Prune old hash entries\n if (this._hashHistory.size > 0) {\n const pruneBelow = this._inputProvider.verifiedTick - 600;\n if (pruneBelow > 0) {\n for (const tick of this._hashHistory.keys()) {\n if (tick < pruneBelow) this._hashHistory.delete(tick);\n }\n }\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","addRollbackHandler","_onRollbackHandlers","addStateTransferHandler","_onStateTransferHandlers","registerSystems","systems","_systems","length","Error","system","push","initSignals","signals","_signalsRegistry","init","disposeSignals","dispose","throwIfSystemsNotRegistered","frameLength","_frameLength","inputProvider","_inputProvider","enableHashTracking","interval","_hashTrackingInterval","getHashAtTick","_hashHistory","get","start","clock","applyExternalState","state","info","byteLength","applySnapshot","setTick","_snapshotHistory","_ECSConfig","snapshotHistorySize","saveSnapshot","setAccumulatedTime","clear","exportStateForTransfer","exportSnapshot","applyStateFromTransfer","blob","notifyStateTransferHandlers","update","dt","targetTick","Math","floor","accumulatedTime","checkAndRollback","simulationTicks","simTick","tickTime","leftover","clamp01","currentTick","rollbackTick","getInvalidateRollbackTick","undefined","rollback","toTick","warn","simulate","set","getHash","onTick","verifiedTick","storeSnapshotIfNeeded","size","pruneBelow","keys","onBeforeRollback","snapshot","getNearest","_initialSnapshot","i","_snapshotRate","debug","constructor","_ECSDeps","Array","Set","Map","snapshotRate","maxNudgePerFrame"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;","mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"abstract-hash-verification.system.d.ts","sourceRoot":"","sources":["../../../src/lib/hash-verification/abstract-hash-verification.system.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,yBAAyB,EAAE,0BAA0B,EAAE,MAAM,mBAAmB,CAAC;AAC3G,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,qCAAqC,CAAC;AACjF,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,6CAA6C,CAAC;AACnF,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAY/D;;;;;;;;GAQG;AACH,8BAAsB,8BAA+B,YAAW,UAAU;IAEtE,SAAS,CAAC,QAAQ,CAAC,UAAU,EAAE,SAAS;IACxC,SAAS,CAAC,QAAQ,CAAC,cAAc,EAAE,qBAAqB;IACxD,SAAS,CAAC,QAAQ,CAAC,gBAAgB,EAAE,eAAe;IACpD,SAAS,CAAC,QAAQ,CAAC,iBAAiB,EAAE,gBAAgB;gBAHnC,UAAU,EAAE,SAAS,EACrB,cAAc,EAAE,qBAAqB,EACrC,gBAAgB,EAAE,eAAe,EACjC,iBAAiB,EAAE,gBAAgB;IAGxD;;;OAGG;IACH,SAAS,CAAC,QAAQ,CAAC,QAAQ,CAAC,cAAc,EAAE,yBAAyB,CAAC;IAEtE;;OAEG;IACH,SAAS,CAAC,QAAQ,CAAC,QAAQ,CAAC,oBAAoB,EAAE,0BAA0B,CAAC;IAEtE,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;
|
|
1
|
+
{"version":3,"file":"abstract-hash-verification.system.d.ts","sourceRoot":"","sources":["../../../src/lib/hash-verification/abstract-hash-verification.system.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,yBAAyB,EAAE,0BAA0B,EAAE,MAAM,mBAAmB,CAAC;AAC3G,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,qCAAqC,CAAC;AACjF,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,6CAA6C,CAAC;AACnF,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAY/D;;;;;;;;GAQG;AACH,8BAAsB,8BAA+B,YAAW,UAAU;IAEtE,SAAS,CAAC,QAAQ,CAAC,UAAU,EAAE,SAAS;IACxC,SAAS,CAAC,QAAQ,CAAC,cAAc,EAAE,qBAAqB;IACxD,SAAS,CAAC,QAAQ,CAAC,gBAAgB,EAAE,eAAe;IACpD,SAAS,CAAC,QAAQ,CAAC,iBAAiB,EAAE,gBAAgB;gBAHnC,UAAU,EAAE,SAAS,EACrB,cAAc,EAAE,qBAAqB,EACrC,gBAAgB,EAAE,eAAe,EACjC,iBAAiB,EAAE,gBAAgB;IAGxD;;;OAGG;IACH,SAAS,CAAC,QAAQ,CAAC,QAAQ,CAAC,cAAc,EAAE,yBAAyB,CAAC;IAEtE;;OAEG;IACH,SAAS,CAAC,QAAQ,CAAC,QAAQ,CAAC,oBAAoB,EAAE,0BAA0B,CAAC;IAEtE,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;CA2ClC"}
|
|
@@ -15,15 +15,20 @@
|
|
|
15
15
|
safe.lastReportedHash = rpc.data.hash;
|
|
16
16
|
safe.lastReportedHashTick = rpc.data.atTick;
|
|
17
17
|
}
|
|
18
|
+
// Only compare hashes for ticks that are verified (server-confirmed, no
|
|
19
|
+
// future rollback possible). This replaces the old heuristic delay.
|
|
20
|
+
const verifiedTick = this._InputProvider.verifiedTick;
|
|
18
21
|
const maxPlayers = this._ECSConfig.maxPlayers;
|
|
19
22
|
for(let a = 0; a < maxPlayers; a++){
|
|
20
23
|
const pa = this._PlayerResources.get(this._playerResourceClass, a);
|
|
21
24
|
const safeA = pa.safe;
|
|
22
25
|
if (safeA.connected === 0 || safeA.lastReportedHashTick === 0) continue;
|
|
26
|
+
if (safeA.lastReportedHashTick > verifiedTick) continue;
|
|
23
27
|
for(let b = a + 1; b < maxPlayers; b++){
|
|
24
28
|
const pb = this._PlayerResources.get(this._playerResourceClass, b);
|
|
25
29
|
const safeB = pb.safe;
|
|
26
30
|
if (safeB.connected === 0 || safeB.lastReportedHashTick === 0) continue;
|
|
31
|
+
if (safeB.lastReportedHashTick > verifiedTick) continue;
|
|
27
32
|
if (safeA.lastReportedHashTick === safeB.lastReportedHashTick && safeA.lastReportedHash !== safeB.lastReportedHash) {
|
|
28
33
|
safeA.hashMismatchCount++;
|
|
29
34
|
safeB.hashMismatchCount++;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/lib/hash-verification/abstract-hash-verification.system.ts"],"sourcesContent":["import type { IECSSystem, IAbstractInputConstructor, IPlayerResourceConstructor } from '../types/index.js';\nimport type { ECSConfig } from '../ecs-config.js';\nimport type { AbstractInputProvider } from '../input/abstract-input-provider.js';\nimport type { PlayerResources } from '../mem/managers/player-resources-manager.js';\nimport type { DivergenceSignal } from './divergence.signal.js';\n\n/**\n * Minimum fields that a PlayerResource must expose for hash verification.\n */\ninterface HashPlayerResourceProxy {\n connected: number;\n lastReportedHash: number;\n lastReportedHashTick: number;\n hashMismatchCount: number;\n}\n\n/**\n * Abstract base class for ECS hash verification systems.\n *\n * Subclass this in your game simulation and provide the concrete\n * `_reportHashRpc` and `_playerResourceClass` from your codegen.\n *\n * The subclass must use `@ECSSystem()` decorator and declare constructor\n * params for DI injection matching the base constructor signature.\n */\nexport abstract class AbstractHashVerificationSystem implements IECSSystem {\n constructor(\n protected readonly _ECSConfig: ECSConfig,\n protected readonly _InputProvider: AbstractInputProvider,\n protected readonly _PlayerResources: PlayerResources,\n protected readonly _DivergenceSignal: DivergenceSignal,\n ) {}\n\n /**\n * The codegen-generated ReportHash input constructor.\n * Must have `{ readonly id: number }` and conform to `IAbstractInputConstructor`.\n */\n protected abstract readonly _reportHashRpc: IAbstractInputConstructor;\n\n /**\n * The codegen-generated PlayerResource class constructor.\n */\n protected abstract readonly _playerResourceClass: IPlayerResourceConstructor;\n\n public update(tick: number): void {\n const rpcs = this._InputProvider.collectTickRPCs(tick, this._reportHashRpc) as unknown as Array<{ meta: { playerSlot: number }, data: { hash: number, atTick: number } }>;\n\n for (const rpc of rpcs) {\n const playerResource = this._PlayerResources.get(this._playerResourceClass, rpc.meta.playerSlot) as unknown as { safe: HashPlayerResourceProxy };\n const safe = playerResource.safe as HashPlayerResourceProxy;\n safe.lastReportedHash = rpc.data.hash;\n safe.lastReportedHashTick = rpc.data.atTick;\n }\n\n const maxPlayers = this._ECSConfig.maxPlayers;\n for (let a = 0; a < maxPlayers; a++) {\n const pa = this._PlayerResources.get(this._playerResourceClass, a) as unknown as { safe: HashPlayerResourceProxy };\n const safeA = pa.safe as HashPlayerResourceProxy;\n if (safeA.connected === 0 || safeA.lastReportedHashTick === 0) continue;\n\n for (let b = a + 1; b < maxPlayers; b++) {\n const pb = this._PlayerResources.get(this._playerResourceClass, b) as unknown as { safe: HashPlayerResourceProxy };\n const safeB = pb.safe as HashPlayerResourceProxy;\n if (safeB.connected === 0 || safeB.lastReportedHashTick === 0) continue;\n\n if (safeA.lastReportedHashTick === safeB.lastReportedHashTick &&\n safeA.lastReportedHash !== safeB.lastReportedHash) {\n safeA.hashMismatchCount++;\n safeB.hashMismatchCount++;\n\n this._DivergenceSignal.emit(tick, {\n slotA: a,\n slotB: b,\n hashA: safeA.lastReportedHash,\n hashB: safeB.lastReportedHash,\n atTick: safeA.lastReportedHashTick,\n });\n }\n }\n }\n }\n}\n"],"names":["AbstractHashVerificationSystem","update","tick","rpcs","_InputProvider","collectTickRPCs","_reportHashRpc","rpc","playerResource","_PlayerResources","get","_playerResourceClass","meta","playerSlot","safe","lastReportedHash","data","hash","lastReportedHashTick","atTick","maxPlayers","_ECSConfig","a","pa","safeA","connected","b","pb","safeB","hashMismatchCount","_DivergenceSignal","emit","slotA","slotB","hashA","hashB","constructor"],"rangeMappings":"
|
|
1
|
+
{"version":3,"sources":["../../../src/lib/hash-verification/abstract-hash-verification.system.ts"],"sourcesContent":["import type { IECSSystem, IAbstractInputConstructor, IPlayerResourceConstructor } from '../types/index.js';\nimport type { ECSConfig } from '../ecs-config.js';\nimport type { AbstractInputProvider } from '../input/abstract-input-provider.js';\nimport type { PlayerResources } from '../mem/managers/player-resources-manager.js';\nimport type { DivergenceSignal } from './divergence.signal.js';\n\n/**\n * Minimum fields that a PlayerResource must expose for hash verification.\n */\ninterface HashPlayerResourceProxy {\n connected: number;\n lastReportedHash: number;\n lastReportedHashTick: number;\n hashMismatchCount: number;\n}\n\n/**\n * Abstract base class for ECS hash verification systems.\n *\n * Subclass this in your game simulation and provide the concrete\n * `_reportHashRpc` and `_playerResourceClass` from your codegen.\n *\n * The subclass must use `@ECSSystem()` decorator and declare constructor\n * params for DI injection matching the base constructor signature.\n */\nexport abstract class AbstractHashVerificationSystem implements IECSSystem {\n constructor(\n protected readonly _ECSConfig: ECSConfig,\n protected readonly _InputProvider: AbstractInputProvider,\n protected readonly _PlayerResources: PlayerResources,\n protected readonly _DivergenceSignal: DivergenceSignal,\n ) {}\n\n /**\n * The codegen-generated ReportHash input constructor.\n * Must have `{ readonly id: number }` and conform to `IAbstractInputConstructor`.\n */\n protected abstract readonly _reportHashRpc: IAbstractInputConstructor;\n\n /**\n * The codegen-generated PlayerResource class constructor.\n */\n protected abstract readonly _playerResourceClass: IPlayerResourceConstructor;\n\n public update(tick: number): void {\n const rpcs = this._InputProvider.collectTickRPCs(tick, this._reportHashRpc) as unknown as Array<{ meta: { playerSlot: number }, data: { hash: number, atTick: number } }>;\n\n for (const rpc of rpcs) {\n const playerResource = this._PlayerResources.get(this._playerResourceClass, rpc.meta.playerSlot) as unknown as { safe: HashPlayerResourceProxy };\n const safe = playerResource.safe as HashPlayerResourceProxy;\n safe.lastReportedHash = rpc.data.hash;\n safe.lastReportedHashTick = rpc.data.atTick;\n }\n\n // Only compare hashes for ticks that are verified (server-confirmed, no\n // future rollback possible). This replaces the old heuristic delay.\n const verifiedTick = this._InputProvider.verifiedTick;\n\n const maxPlayers = this._ECSConfig.maxPlayers;\n for (let a = 0; a < maxPlayers; a++) {\n const pa = this._PlayerResources.get(this._playerResourceClass, a) as unknown as { safe: HashPlayerResourceProxy };\n const safeA = pa.safe as HashPlayerResourceProxy;\n if (safeA.connected === 0 || safeA.lastReportedHashTick === 0) continue;\n if (safeA.lastReportedHashTick > verifiedTick) continue;\n\n for (let b = a + 1; b < maxPlayers; b++) {\n const pb = this._PlayerResources.get(this._playerResourceClass, b) as unknown as { safe: HashPlayerResourceProxy };\n const safeB = pb.safe as HashPlayerResourceProxy;\n if (safeB.connected === 0 || safeB.lastReportedHashTick === 0) continue;\n if (safeB.lastReportedHashTick > verifiedTick) continue;\n\n if (safeA.lastReportedHashTick === safeB.lastReportedHashTick &&\n safeA.lastReportedHash !== safeB.lastReportedHash) {\n safeA.hashMismatchCount++;\n safeB.hashMismatchCount++;\n\n this._DivergenceSignal.emit(tick, {\n slotA: a,\n slotB: b,\n hashA: safeA.lastReportedHash,\n hashB: safeB.lastReportedHash,\n atTick: safeA.lastReportedHashTick,\n });\n }\n }\n }\n }\n}\n"],"names":["AbstractHashVerificationSystem","update","tick","rpcs","_InputProvider","collectTickRPCs","_reportHashRpc","rpc","playerResource","_PlayerResources","get","_playerResourceClass","meta","playerSlot","safe","lastReportedHash","data","hash","lastReportedHashTick","atTick","verifiedTick","maxPlayers","_ECSConfig","a","pa","safeA","connected","b","pb","safeB","hashMismatchCount","_DivergenceSignal","emit","slotA","slotB","hashA","hashB","constructor"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;","mappings":"AAgBA;;;;;;;;CAQC,GACD,OAAO,MAAeA;IAmBbC,OAAOC,IAAY,EAAQ;QAChC,MAAMC,OAAO,IAAI,CAACC,cAAc,CAACC,eAAe,CAACH,MAAM,IAAI,CAACI,cAAc;QAE1E,KAAK,MAAMC,OAAOJ,KAAM;YACtB,MAAMK,iBAAiB,IAAI,CAACC,gBAAgB,CAACC,GAAG,CAAC,IAAI,CAACC,oBAAoB,EAAEJ,IAAIK,IAAI,CAACC,UAAU;YAC/F,MAAMC,OAAON,eAAeM,IAAI;YAChCA,KAAKC,gBAAgB,GAAGR,IAAIS,IAAI,CAACC,IAAI;YACrCH,KAAKI,oBAAoB,GAAGX,IAAIS,IAAI,CAACG,MAAM;QAC7C;QAEA,wEAAwE;QACxE,oEAAoE;QACpE,MAAMC,eAAe,IAAI,CAAChB,cAAc,CAACgB,YAAY;QAErD,MAAMC,aAAa,IAAI,CAACC,UAAU,CAACD,UAAU;QAC7C,IAAK,IAAIE,IAAI,GAAGA,IAAIF,YAAYE,IAAK;YACnC,MAAMC,KAAK,IAAI,CAACf,gBAAgB,CAACC,GAAG,CAAC,IAAI,CAACC,oBAAoB,EAAEY;YAChE,MAAME,QAAQD,GAAGV,IAAI;YACrB,IAAIW,MAAMC,SAAS,KAAK,KAAKD,MAAMP,oBAAoB,KAAK,GAAG;YAC/D,IAAIO,MAAMP,oBAAoB,GAAGE,cAAc;YAE/C,IAAK,IAAIO,IAAIJ,IAAI,GAAGI,IAAIN,YAAYM,IAAK;gBACvC,MAAMC,KAAK,IAAI,CAACnB,gBAAgB,CAACC,GAAG,CAAC,IAAI,CAACC,oBAAoB,EAAEgB;gBAChE,MAAME,QAAQD,GAAGd,IAAI;gBACrB,IAAIe,MAAMH,SAAS,KAAK,KAAKG,MAAMX,oBAAoB,KAAK,GAAG;gBAC/D,IAAIW,MAAMX,oBAAoB,GAAGE,cAAc;gBAE/C,IAAIK,MAAMP,oBAAoB,KAAKW,MAAMX,oBAAoB,IAC3DO,MAAMV,gBAAgB,KAAKc,MAAMd,gBAAgB,EAAE;oBACnDU,MAAMK,iBAAiB;oBACvBD,MAAMC,iBAAiB;oBAEvB,IAAI,CAACC,iBAAiB,CAACC,IAAI,CAAC9B,MAAM;wBAChC+B,OAAOV;wBACPW,OAAOP;wBACPQ,OAAOV,MAAMV,gBAAgB;wBAC7BqB,OAAOP,MAAMd,gBAAgB;wBAC7BI,QAAQM,MAAMP,oBAAoB;oBACpC;gBACF;YACF;QACF;IACF;IA5DAmB,YACE,AAAmBf,UAAqB,EACxC,AAAmBlB,cAAqC,EACxD,AAAmBK,gBAAiC,EACpD,AAAmBsB,iBAAmC,CACtD;aAJmBT,aAAAA;aACAlB,iBAAAA;aACAK,mBAAAA;aACAsB,oBAAAA;IAClB;AAwDL"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"create-hash-reporter.d.ts","sourceRoot":"","sources":["../../../src/lib/hash-verification/create-hash-reporter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,KAAK,EAAE,yBAAyB,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAE9E,KAAK,QAAQ,GAAG,CAAC,UAAU,SAAS,yBAAyB,EAC3D,SAAS,EAAE,UAAU,EACrB,IAAI,EAAE,SAAS,CAAC,YAAY,CAAC,UAAU,CAAC,CAAC,KACtC,IAAI,CAAC;AAEV,MAAM,WAAW,kBAAkB;IACjC,cAAc,EAAE,MAAM,CAAC;IACvB,aAAa,EAAE,yBAAyB,CAAC;CAC1C;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,kBAAkB,GAAG,CAAC,MAAM,EAAE,QAAQ,KAAK,IAAI,
|
|
1
|
+
{"version":3,"file":"create-hash-reporter.d.ts","sourceRoot":"","sources":["../../../src/lib/hash-verification/create-hash-reporter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,KAAK,EAAE,yBAAyB,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAE9E,KAAK,QAAQ,GAAG,CAAC,UAAU,SAAS,yBAAyB,EAC3D,SAAS,EAAE,UAAU,EACrB,IAAI,EAAE,SAAS,CAAC,YAAY,CAAC,UAAU,CAAC,CAAC,KACtC,IAAI,CAAC;AAEV,MAAM,WAAW,kBAAkB;IACjC,cAAc,EAAE,MAAM,CAAC;IACvB,aAAa,EAAE,yBAAyB,CAAC;CAC1C;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,kBAAkB,GAAG,CAAC,MAAM,EAAE,QAAQ,KAAK,IAAI,CAc5G"}
|
|
@@ -6,14 +6,17 @@
|
|
|
6
6
|
*/ export function createHashReporter(runner, config) {
|
|
7
7
|
let lastReportedTick = -1;
|
|
8
8
|
return (addRPC)=>{
|
|
9
|
-
const
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
const hash = runner.Simulation.
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
9
|
+
const verifiedTick = runner.Simulation.inputProvider.verifiedTick;
|
|
10
|
+
const latestReportTick = Math.floor(verifiedTick / config.reportInterval) * config.reportInterval;
|
|
11
|
+
if (latestReportTick > lastReportedTick && latestReportTick > 0) {
|
|
12
|
+
const hash = runner.Simulation.getHashAtTick(latestReportTick);
|
|
13
|
+
if (hash !== undefined) {
|
|
14
|
+
lastReportedTick = latestReportTick;
|
|
15
|
+
addRPC(config.reportHashRpc, {
|
|
16
|
+
hash,
|
|
17
|
+
atTick: latestReportTick
|
|
18
|
+
});
|
|
19
|
+
}
|
|
17
20
|
}
|
|
18
21
|
};
|
|
19
22
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/lib/hash-verification/create-hash-reporter.ts"],"sourcesContent":["import type { ECSRunner } from '../ecs-runner.js';\nimport type { IAbstractInputConstructor, InputData } from '../types/index.js';\n\ntype AddRPCFn = <TInputCtor extends IAbstractInputConstructor>(\n InputCtor: TInputCtor,\n data: InputData<InstanceType<TInputCtor>>,\n) => void;\n\nexport interface HashReporterConfig {\n reportInterval: number;\n reportHashRpc: IAbstractInputConstructor;\n}\n\n/**\n * Creates a hash reporter function for use in `drainInputs`.\n *\n * The returned function should be called from your `drainInputs` callback.\n * It periodically reports the simulation state hash via the ReportHash RPC.\n */\nexport function createHashReporter(runner: ECSRunner, config: HashReporterConfig): (addRPC: AddRPCFn) => void {\n let lastReportedTick = -1;\n\n return (addRPC: AddRPCFn) => {\n const
|
|
1
|
+
{"version":3,"sources":["../../../src/lib/hash-verification/create-hash-reporter.ts"],"sourcesContent":["import type { ECSRunner } from '../ecs-runner.js';\nimport type { IAbstractInputConstructor, InputData } from '../types/index.js';\n\ntype AddRPCFn = <TInputCtor extends IAbstractInputConstructor>(\n InputCtor: TInputCtor,\n data: InputData<InstanceType<TInputCtor>>,\n) => void;\n\nexport interface HashReporterConfig {\n reportInterval: number;\n reportHashRpc: IAbstractInputConstructor;\n}\n\n/**\n * Creates a hash reporter function for use in `drainInputs`.\n *\n * The returned function should be called from your `drainInputs` callback.\n * It periodically reports the simulation state hash via the ReportHash RPC.\n */\nexport function createHashReporter(runner: ECSRunner, config: HashReporterConfig): (addRPC: AddRPCFn) => void {\n let lastReportedTick = -1;\n\n return (addRPC: AddRPCFn) => {\n const verifiedTick = runner.Simulation.inputProvider.verifiedTick;\n const latestReportTick = Math.floor(verifiedTick / config.reportInterval) * config.reportInterval;\n if (latestReportTick > lastReportedTick && latestReportTick > 0) {\n const hash = runner.Simulation.getHashAtTick(latestReportTick);\n if (hash !== undefined) {\n lastReportedTick = latestReportTick;\n addRPC(config.reportHashRpc, { hash, atTick: latestReportTick });\n }\n }\n };\n}\n"],"names":["createHashReporter","runner","config","lastReportedTick","addRPC","verifiedTick","Simulation","inputProvider","latestReportTick","Math","floor","reportInterval","hash","getHashAtTick","undefined","reportHashRpc","atTick"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;","mappings":"AAaA;;;;;CAKC,GACD,OAAO,SAASA,mBAAmBC,MAAiB,EAAEC,MAA0B;IAC9E,IAAIC,mBAAmB,CAAC;IAExB,OAAO,CAACC;QACN,MAAMC,eAAeJ,OAAOK,UAAU,CAACC,aAAa,CAACF,YAAY;QACjE,MAAMG,mBAAmBC,KAAKC,KAAK,CAACL,eAAeH,OAAOS,cAAc,IAAIT,OAAOS,cAAc;QACjG,IAAIH,mBAAmBL,oBAAoBK,mBAAmB,GAAG;YAC/D,MAAMI,OAAOX,OAAOK,UAAU,CAACO,aAAa,CAACL;YAC7C,IAAII,SAASE,WAAW;gBACtBX,mBAAmBK;gBACnBJ,OAAOF,OAAOa,aAAa,EAAE;oBAAEH;oBAAMI,QAAQR;gBAAiB;YAChE;QACF;IACF;AACF"}
|
|
@@ -17,6 +17,7 @@ export declare abstract class AbstractInputProvider {
|
|
|
17
17
|
protected _simulation: ECSSimulation;
|
|
18
18
|
protected readonly _rpcHistory: RPCHistory;
|
|
19
19
|
abstract playerSlot: number;
|
|
20
|
+
abstract get verifiedTick(): number;
|
|
20
21
|
abstract getInvalidateRollbackTick(): void | number;
|
|
21
22
|
constructor(ecsConfig: ECSConfig, _inputRegistry: InputRegistry);
|
|
22
23
|
get currentInputDelay(): number;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"abstract-input-provider.d.ts","sourceRoot":"","sources":["../../../src/lib/input/abstract-input-provider.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"abstract-input-provider.d.ts","sourceRoot":"","sources":["../../../src/lib/input/abstract-input-provider.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,yBAAyB,EAAwB,MAAM,mBAAmB,CAAC;AACpF,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC7C,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;AAK/B,8BAAsB,qBAAqB;aAmBvB,SAAS,EAAE,SAAS;IACpC,SAAS,CAAC,QAAQ,CAAC,cAAc,EAAE,aAAa;IAnBlD,OAAO,CAAC,QAAQ,CAAK;IACrB,OAAO,CAAC,YAAY,CAAK;IACzB,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAkC;IACjE,SAAS,CAAC,eAAe,EAAE,KAAK,CAAC,GAAG,CAAC,CAAM;IAC3C,SAAS,CAAC,YAAY,EAAE,MAAM,CAAC;IAE/B,SAAS,CAAC,SAAS,UAAS;IAC5B,SAAS,CAAC,kBAAkB,EAAE,MAAM,CAAC;IACrC,SAAS,CAAC,WAAW,EAAG,aAAa,CAAC;IACtC,SAAS,CAAC,QAAQ,CAAC,WAAW,aAAoB;IAElD,SAAgB,UAAU,EAAE,MAAM,CAAC;IAEnC,aAAoB,YAAY,IAAI,MAAM,CAAC;aAE3B,yBAAyB,IAAI,IAAI,GAAG,MAAM;gBAGxC,SAAS,EAAE,SAAS,EACjB,cAAc,EAAE,aAAa;IAQlD,IAAW,iBAAiB,IAAI,MAAM,CAErC;IAED,IAAW,UAAU,IAAI,UAAU,CAElC;IAED,IAAW,aAAa,IAAI,aAAa,CAExC;IAID,kEAAkE;IAClE,OAAO,CAAC,cAAc;IAIf,MAAM,IAAI,IAAI;IASd,IAAI,CAAC,UAAU,EAAE,aAAa,GAAG,IAAI;IAIrC,OAAO,IAAI,IAAI;IAItB,SAAS,CAAC,cAAc,IAAI,IAAI;IAQhC,OAAO,CAAC,WAAW,CAmBjB;IAIF;;;OAGG;IACI,YAAY,CAAC,GAAG,EAAE,GAAG,GAAG,IAAI;IAKnC;;OAEG;IACI,iBAAiB,CAAC,IAAI,EAAE,aAAa,CAAC,GAAG,CAAC,GAAG,IAAI;IAKxD;;;OAGG;IACI,WAAW,CAAC,UAAU,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI;IAOvE;;;OAGG;IACI,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAalC,WAAW,CAAC,EAAE,EAAE,cAAc,GAAG,MAAM,IAAI;IAQ3C,eAAe,CAAC,UAAU,SAAS,yBAAyB,EACjE,IAAI,EAAE,MAAM,EACZ,SAAS,EAAE,UAAU,GACpB,aAAa,CAAC,GAAG,CAAC,YAAY,CAAC,UAAU,CAAC,CAAC,CAAC;IAI/C;;;OAGG;IACI,iBAAiB,IAAI,aAAa,CAAC,GAAG,CAAC;CAG/C;AAED,KAAK,cAAc,GAAG,CAAC,MAAM,EAAE,qBAAqB,CAAC,aAAa,CAAC,KAAK,IAAI,CAAC"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { sanitizeInputData } from '@lagless/binary';
|
|
1
2
|
import { RPCHistory } from './rpc-history.js';
|
|
2
3
|
import { RPC } from './rpc.js';
|
|
3
4
|
import { createLogger } from '@lagless/misc';
|
|
@@ -19,7 +20,9 @@ export class AbstractInputProvider {
|
|
|
19
20
|
}
|
|
20
21
|
update() {
|
|
21
22
|
this._frameRPCBuffer.length = 0;
|
|
22
|
-
|
|
23
|
+
for (const drainFn of this._inputDrainers){
|
|
24
|
+
drainFn(this.addLocalRpc);
|
|
25
|
+
}
|
|
23
26
|
if (this._frameRPCBuffer.length > 0) this._nextSeq++;
|
|
24
27
|
}
|
|
25
28
|
init(simulation) {
|
|
@@ -91,6 +94,10 @@ export class AbstractInputProvider {
|
|
|
91
94
|
this._disposed = false;
|
|
92
95
|
this._rpcHistory = new RPCHistory();
|
|
93
96
|
this.addLocalRpc = (InputCtor, data)=>{
|
|
97
|
+
// Truncate numeric fields to their declared binary precision to prevent
|
|
98
|
+
// desync between local (float64) and remote (float32-via-network) values.
|
|
99
|
+
const inputInstance = this._inputRegistry.get(InputCtor.id);
|
|
100
|
+
sanitizeInputData(inputInstance.fields, data);
|
|
94
101
|
const newRPCMeta = {
|
|
95
102
|
tick: this._simulation.tick + this._currentInputDelay,
|
|
96
103
|
seq: this._nextSeq,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/lib/input/abstract-input-provider.ts"],"sourcesContent":["import { ECSSimulation } from '../ecs-simulation.js';\nimport { IAbstractInputConstructor, InputData, InputMeta } from '../types/index.js';\nimport { ECSConfig } from '../ecs-config.js';\nimport { InputRegistry } from './input-registry.js';\nimport { RPCHistory } from './rpc-history.js';\nimport { RPC } from './rpc.js';\nimport { createLogger } from '@lagless/misc';\n\nconst log = createLogger('InputProvider');\n\nexport abstract class AbstractInputProvider {\n private _nextSeq = 1;\n private _nextOrdinal = 1;\n private readonly _inputDrainers: Set<InputDrainerFn> = new Set();\n protected _frameRPCBuffer: Array<RPC> = [];\n protected _frameLength: number;\n\n protected _disposed = false;\n protected _currentInputDelay: number;\n protected _simulation!: ECSSimulation;\n protected readonly _rpcHistory = new RPCHistory();\n\n public abstract playerSlot: number;\n\n public abstract getInvalidateRollbackTick(): void | number;\n\n constructor(\n public readonly ecsConfig: ECSConfig,\n protected readonly _inputRegistry: InputRegistry,\n ) {\n this._frameLength = this.ecsConfig.frameLength;\n this._currentInputDelay = this.ecsConfig.initialInputDelayTick;\n }\n\n // ─── Public Getters ─────────────────────────────────────\n\n public get currentInputDelay(): number {\n return this._currentInputDelay;\n }\n\n public get rpcHistory(): RPCHistory {\n return this._rpcHistory;\n }\n\n public get inputRegistry(): InputRegistry {\n return this._inputRegistry;\n }\n\n // ─── Lifecycle ──────────────────────────────────────────\n\n /** @internal — used only by addLocalRpc for ordinal assignment */\n private getNextOrdinal(): number {\n return this._nextOrdinal++;\n }\n\n public update(): void {\n this._frameRPCBuffer.length = 0;\n this._inputDrainers
|
|
1
|
+
{"version":3,"sources":["../../../src/lib/input/abstract-input-provider.ts"],"sourcesContent":["import { sanitizeInputData } from '@lagless/binary';\nimport { ECSSimulation } from '../ecs-simulation.js';\nimport { IAbstractInputConstructor, InputData, InputMeta } from '../types/index.js';\nimport { ECSConfig } from '../ecs-config.js';\nimport { InputRegistry } from './input-registry.js';\nimport { RPCHistory } from './rpc-history.js';\nimport { RPC } from './rpc.js';\nimport { createLogger } from '@lagless/misc';\n\nconst log = createLogger('InputProvider');\n\nexport abstract class AbstractInputProvider {\n private _nextSeq = 1;\n private _nextOrdinal = 1;\n private readonly _inputDrainers: Set<InputDrainerFn> = new Set();\n protected _frameRPCBuffer: Array<RPC> = [];\n protected _frameLength: number;\n\n protected _disposed = false;\n protected _currentInputDelay: number;\n protected _simulation!: ECSSimulation;\n protected readonly _rpcHistory = new RPCHistory();\n\n public abstract playerSlot: number;\n\n public abstract get verifiedTick(): number;\n\n public abstract getInvalidateRollbackTick(): void | number;\n\n constructor(\n public readonly ecsConfig: ECSConfig,\n protected readonly _inputRegistry: InputRegistry,\n ) {\n this._frameLength = this.ecsConfig.frameLength;\n this._currentInputDelay = this.ecsConfig.initialInputDelayTick;\n }\n\n // ─── Public Getters ─────────────────────────────────────\n\n public get currentInputDelay(): number {\n return this._currentInputDelay;\n }\n\n public get rpcHistory(): RPCHistory {\n return this._rpcHistory;\n }\n\n public get inputRegistry(): InputRegistry {\n return this._inputRegistry;\n }\n\n // ─── Lifecycle ──────────────────────────────────────────\n\n /** @internal — used only by addLocalRpc for ordinal assignment */\n private getNextOrdinal(): number {\n return this._nextOrdinal++;\n }\n\n public update(): void {\n this._frameRPCBuffer.length = 0;\n for (const drainFn of this._inputDrainers) {\n drainFn(this.addLocalRpc);\n }\n\n if (this._frameRPCBuffer.length > 0) this._nextSeq++;\n }\n\n public init(simulation: ECSSimulation): void {\n this._simulation = simulation;\n }\n\n public dispose(): void {\n this._disposed = true;\n }\n\n protected resetSequences(): void {\n this._nextSeq = 1;\n this._nextOrdinal = 1;\n this._frameRPCBuffer.length = 0;\n }\n\n // ─── Local Input (from drainers) ────────────────────────\n\n private addLocalRpc = <TInputCtor extends IAbstractInputConstructor>(\n InputCtor: TInputCtor,\n data: InputData<InstanceType<TInputCtor>>,\n ): void => {\n // Truncate numeric fields to their declared binary precision to prevent\n // desync between local (float64) and remote (float32-via-network) values.\n const inputInstance = this._inputRegistry.get(InputCtor.id);\n sanitizeInputData(inputInstance.fields, data as Record<string, number | ArrayLike<number>>);\n\n const newRPCMeta: InputMeta = {\n tick: this._simulation.tick + this._currentInputDelay,\n seq: this._nextSeq,\n ordinal: this.getNextOrdinal(),\n playerSlot: this.playerSlot,\n };\n const rpc = new RPC(InputCtor.id, newRPCMeta, data);\n this._frameRPCBuffer.push(rpc);\n this._rpcHistory.addRPC(rpc);\n log.debug(`Local RPC tick=${newRPCMeta.tick} delay=${this._currentInputDelay} seq=${newRPCMeta.seq} slot=${newRPCMeta.playerSlot} inputId=${InputCtor.id}`);\n };\n\n // ─── Remote Input (from network) ────────────────────────\n\n /**\n * Add an RPC received from a remote player via the network.\n * Used by RelayInputProvider when receiving TickInputFanout.\n */\n public addRemoteRpc(rpc: RPC): void {\n this._rpcHistory.addRPC(rpc);\n log.debug(`Remote RPC tick=${rpc.meta.tick} seq=${rpc.meta.seq} slot=${rpc.meta.playerSlot} inputId=${rpc.inputId}`);\n }\n\n /**\n * Add multiple remote RPCs at once (batch from fanout).\n */\n public addRemoteRpcBatch(rpcs: ReadonlyArray<RPC>): void {\n this._rpcHistory.addBatch(rpcs);\n log.debug(`Remote RPC batch: ${rpcs.length} RPCs`);\n }\n\n /**\n * Remove a specific RPC from history.\n * Used when server sends CancelInput.\n */\n public removeRpcAt(playerSlot: number, tick: number, seq: number): void {\n this._rpcHistory.removePlayerInputsAtTick(playerSlot, tick, seq);\n log.debug(`Removed RPC slot=${playerSlot} tick=${tick} seq=${seq}`);\n }\n\n // ─── Input Delay ────────────────────────────────────────\n\n /**\n * Dynamically change the input delay (in ticks).\n * Used by InputDelayController based on network conditions.\n */\n public setInputDelay(ticks: number): void {\n const clamped = Math.max(\n this.ecsConfig.minInputDelayTick,\n Math.min(ticks, this.ecsConfig.maxInputDelayTick),\n );\n if (clamped !== this._currentInputDelay) {\n log.debug(`Input delay changed: ${this._currentInputDelay} → ${clamped}`);\n this._currentInputDelay = clamped;\n }\n }\n\n // ─── Query ──────────────────────────────────────────────\n\n public drainInputs(fn: InputDrainerFn): () => void {\n this._inputDrainers.add(fn);\n\n return () => {\n this._inputDrainers.delete(fn);\n };\n }\n\n public collectTickRPCs<TInputCtor extends IAbstractInputConstructor>(\n tick: number,\n InputCtor: TInputCtor\n ): ReadonlyArray<RPC<InstanceType<TInputCtor>>> {\n return this._rpcHistory.collectTickRPCs(tick, InputCtor);\n }\n\n /**\n * Get the last buffered local RPCs from this frame.\n * Used by RelayInputProvider to send local inputs to the server.\n */\n public getFrameRPCBuffer(): ReadonlyArray<RPC> {\n return this._frameRPCBuffer;\n }\n}\n\ntype InputDrainerFn = (addRPC: AbstractInputProvider['addLocalRpc']) => void;\n"],"names":["sanitizeInputData","RPCHistory","RPC","createLogger","log","AbstractInputProvider","currentInputDelay","_currentInputDelay","rpcHistory","_rpcHistory","inputRegistry","_inputRegistry","getNextOrdinal","_nextOrdinal","update","_frameRPCBuffer","length","drainFn","_inputDrainers","addLocalRpc","_nextSeq","init","simulation","_simulation","dispose","_disposed","resetSequences","addRemoteRpc","rpc","addRPC","debug","meta","tick","seq","playerSlot","inputId","addRemoteRpcBatch","rpcs","addBatch","removeRpcAt","removePlayerInputsAtTick","setInputDelay","ticks","clamped","Math","max","ecsConfig","minInputDelayTick","min","maxInputDelayTick","drainInputs","fn","add","delete","collectTickRPCs","InputCtor","getFrameRPCBuffer","constructor","Set","data","inputInstance","get","id","fields","newRPCMeta","ordinal","push","_frameLength","frameLength","initialInputDelayTick"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;","mappings":"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"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { AbstractInputProvider } from './abstract-input-provider.js';
|
|
2
2
|
export declare class InputProvider extends AbstractInputProvider {
|
|
3
3
|
playerSlot: number;
|
|
4
|
+
get verifiedTick(): number;
|
|
4
5
|
getInvalidateRollbackTick(): undefined;
|
|
5
6
|
}
|
|
6
7
|
//# sourceMappingURL=input-provider-di-token.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"input-provider-di-token.d.ts","sourceRoot":"","sources":["../../../src/lib/input/input-provider-di-token.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,MAAM,8BAA8B,CAAC;AAErE,qBAAa,aAAc,SAAQ,qBAAqB;IACtC,UAAU,SAAM;
|
|
1
|
+
{"version":3,"file":"input-provider-di-token.d.ts","sourceRoot":"","sources":["../../../src/lib/input/input-provider-di-token.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,MAAM,8BAA8B,CAAC;AAErE,qBAAa,aAAc,SAAQ,qBAAqB;IACtC,UAAU,SAAM;IAEhC,IAAW,YAAY,IAAI,MAAM,CAEhC;IAEM,yBAAyB;CAGjC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/lib/input/input-provider-di-token.ts"],"sourcesContent":["import { AbstractInputProvider } from './abstract-input-provider.js';\n\nexport class InputProvider extends AbstractInputProvider {\n public override playerSlot = -1;\n\n public getInvalidateRollbackTick() {\n return undefined;\n }\n}\n"],"names":["AbstractInputProvider","InputProvider","getInvalidateRollbackTick","undefined","playerSlot"],"rangeMappings":"
|
|
1
|
+
{"version":3,"sources":["../../../src/lib/input/input-provider-di-token.ts"],"sourcesContent":["import { AbstractInputProvider } from './abstract-input-provider.js';\n\nexport class InputProvider extends AbstractInputProvider {\n public override playerSlot = -1;\n\n public get verifiedTick(): number {\n return -1;\n }\n\n public getInvalidateRollbackTick() {\n return undefined;\n }\n}\n"],"names":["AbstractInputProvider","InputProvider","verifiedTick","getInvalidateRollbackTick","undefined","playerSlot"],"rangeMappings":";;;;;;;;;;;;","mappings":"AAAA,SAASA,qBAAqB,QAAQ,+BAA+B;AAErE,OAAO,MAAMC,sBAAsBD;IAGjC,IAAWE,eAAuB;QAChC,OAAO,CAAC;IACV;IAEOC,4BAA4B;QACjC,OAAOC;IACT;;;aARgBC,aAAa,CAAC;;AAShC"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { AbstractInputProvider } from './abstract-input-provider.js';
|
|
2
2
|
export declare class LocalInputProvider extends AbstractInputProvider {
|
|
3
3
|
playerSlot: number;
|
|
4
|
+
get verifiedTick(): number;
|
|
4
5
|
getInvalidateRollbackTick(): void | number;
|
|
5
6
|
}
|
|
6
7
|
//# sourceMappingURL=local-input-provider.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"local-input-provider.d.ts","sourceRoot":"","sources":["../../../src/lib/input/local-input-provider.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,MAAM,8BAA8B,CAAC;AAErE,qBAAa,kBAAmB,SAAQ,qBAAqB;IAC3C,UAAU,SAAK;
|
|
1
|
+
{"version":3,"file":"local-input-provider.d.ts","sourceRoot":"","sources":["../../../src/lib/input/local-input-provider.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,MAAM,8BAA8B,CAAC;AAErE,qBAAa,kBAAmB,SAAQ,qBAAqB;IAC3C,UAAU,SAAK;IAE/B,IAAoB,YAAY,IAAI,MAAM,CAEzC;IAEe,yBAAyB,IAAI,IAAI,GAAG,MAAM;CAG3D"}
|