@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
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { IECSSystem, IAbstractInputConstructor, IPlayerResourceConstructor } from '../types/index.js';
|
|
2
|
+
import type { ECSConfig } from '../ecs-config.js';
|
|
3
|
+
import type { AbstractInputProvider } from '../input/abstract-input-provider.js';
|
|
4
|
+
import type { PlayerResources } from '../mem/managers/player-resources-manager.js';
|
|
5
|
+
import type { DivergenceSignal } from './divergence.signal.js';
|
|
6
|
+
/**
|
|
7
|
+
* Abstract base class for ECS hash verification systems.
|
|
8
|
+
*
|
|
9
|
+
* Subclass this in your game simulation and provide the concrete
|
|
10
|
+
* `_reportHashRpc` and `_playerResourceClass` from your codegen.
|
|
11
|
+
*
|
|
12
|
+
* The subclass must use `@ECSSystem()` decorator and declare constructor
|
|
13
|
+
* params for DI injection matching the base constructor signature.
|
|
14
|
+
*/
|
|
15
|
+
export declare abstract class AbstractHashVerificationSystem implements IECSSystem {
|
|
16
|
+
protected readonly _ECSConfig: ECSConfig;
|
|
17
|
+
protected readonly _InputProvider: AbstractInputProvider;
|
|
18
|
+
protected readonly _PlayerResources: PlayerResources;
|
|
19
|
+
protected readonly _DivergenceSignal: DivergenceSignal;
|
|
20
|
+
constructor(_ECSConfig: ECSConfig, _InputProvider: AbstractInputProvider, _PlayerResources: PlayerResources, _DivergenceSignal: DivergenceSignal);
|
|
21
|
+
/**
|
|
22
|
+
* The codegen-generated ReportHash input constructor.
|
|
23
|
+
* Must have `{ readonly id: number }` and conform to `IAbstractInputConstructor`.
|
|
24
|
+
*/
|
|
25
|
+
protected abstract readonly _reportHashRpc: IAbstractInputConstructor;
|
|
26
|
+
/**
|
|
27
|
+
* The codegen-generated PlayerResource class constructor.
|
|
28
|
+
*/
|
|
29
|
+
protected abstract readonly _playerResourceClass: IPlayerResourceConstructor;
|
|
30
|
+
update(tick: number): void;
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=abstract-hash-verification.system.d.ts.map
|
|
@@ -0,0 +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;CAqClC"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Abstract base class for ECS hash verification systems.
|
|
3
|
+
*
|
|
4
|
+
* Subclass this in your game simulation and provide the concrete
|
|
5
|
+
* `_reportHashRpc` and `_playerResourceClass` from your codegen.
|
|
6
|
+
*
|
|
7
|
+
* The subclass must use `@ECSSystem()` decorator and declare constructor
|
|
8
|
+
* params for DI injection matching the base constructor signature.
|
|
9
|
+
*/ export class AbstractHashVerificationSystem {
|
|
10
|
+
update(tick) {
|
|
11
|
+
const rpcs = this._InputProvider.collectTickRPCs(tick, this._reportHashRpc);
|
|
12
|
+
for (const rpc of rpcs){
|
|
13
|
+
const playerResource = this._PlayerResources.get(this._playerResourceClass, rpc.meta.playerSlot);
|
|
14
|
+
const safe = playerResource.safe;
|
|
15
|
+
safe.lastReportedHash = rpc.data.hash;
|
|
16
|
+
safe.lastReportedHashTick = rpc.data.atTick;
|
|
17
|
+
}
|
|
18
|
+
const maxPlayers = this._ECSConfig.maxPlayers;
|
|
19
|
+
for(let a = 0; a < maxPlayers; a++){
|
|
20
|
+
const pa = this._PlayerResources.get(this._playerResourceClass, a);
|
|
21
|
+
const safeA = pa.safe;
|
|
22
|
+
if (safeA.connected === 0 || safeA.lastReportedHashTick === 0) continue;
|
|
23
|
+
for(let b = a + 1; b < maxPlayers; b++){
|
|
24
|
+
const pb = this._PlayerResources.get(this._playerResourceClass, b);
|
|
25
|
+
const safeB = pb.safe;
|
|
26
|
+
if (safeB.connected === 0 || safeB.lastReportedHashTick === 0) continue;
|
|
27
|
+
if (safeA.lastReportedHashTick === safeB.lastReportedHashTick && safeA.lastReportedHash !== safeB.lastReportedHash) {
|
|
28
|
+
safeA.hashMismatchCount++;
|
|
29
|
+
safeB.hashMismatchCount++;
|
|
30
|
+
this._DivergenceSignal.emit(tick, {
|
|
31
|
+
slotA: a,
|
|
32
|
+
slotB: b,
|
|
33
|
+
hashA: safeA.lastReportedHash,
|
|
34
|
+
hashB: safeB.lastReportedHash,
|
|
35
|
+
atTick: safeA.lastReportedHashTick
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
constructor(_ECSConfig, _InputProvider, _PlayerResources, _DivergenceSignal){
|
|
42
|
+
this._ECSConfig = _ECSConfig;
|
|
43
|
+
this._InputProvider = _InputProvider;
|
|
44
|
+
this._PlayerResources = _PlayerResources;
|
|
45
|
+
this._DivergenceSignal = _DivergenceSignal;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
//# sourceMappingURL=abstract-hash-verification.system.js.map
|
|
@@ -0,0 +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":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;","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,MAAMC,aAAa,IAAI,CAACC,UAAU,CAACD,UAAU;QAC7C,IAAK,IAAIE,IAAI,GAAGA,IAAIF,YAAYE,IAAK;YACnC,MAAMC,KAAK,IAAI,CAACd,gBAAgB,CAACC,GAAG,CAAC,IAAI,CAACC,oBAAoB,EAAEW;YAChE,MAAME,QAAQD,GAAGT,IAAI;YACrB,IAAIU,MAAMC,SAAS,KAAK,KAAKD,MAAMN,oBAAoB,KAAK,GAAG;YAE/D,IAAK,IAAIQ,IAAIJ,IAAI,GAAGI,IAAIN,YAAYM,IAAK;gBACvC,MAAMC,KAAK,IAAI,CAAClB,gBAAgB,CAACC,GAAG,CAAC,IAAI,CAACC,oBAAoB,EAAEe;gBAChE,MAAME,QAAQD,GAAGb,IAAI;gBACrB,IAAIc,MAAMH,SAAS,KAAK,KAAKG,MAAMV,oBAAoB,KAAK,GAAG;gBAE/D,IAAIM,MAAMN,oBAAoB,KAAKU,MAAMV,oBAAoB,IAC3DM,MAAMT,gBAAgB,KAAKa,MAAMb,gBAAgB,EAAE;oBACnDS,MAAMK,iBAAiB;oBACvBD,MAAMC,iBAAiB;oBAEvB,IAAI,CAACC,iBAAiB,CAACC,IAAI,CAAC7B,MAAM;wBAChC8B,OAAOV;wBACPW,OAAOP;wBACPQ,OAAOV,MAAMT,gBAAgB;wBAC7BoB,OAAOP,MAAMb,gBAAgB;wBAC7BI,QAAQK,MAAMN,oBAAoB;oBACpC;gBACF;YACF;QACF;IACF;IAtDAkB,YACE,AAAmBf,UAAqB,EACxC,AAAmBjB,cAAqC,EACxD,AAAmBK,gBAAiC,EACpD,AAAmBqB,iBAAmC,CACtD;aAJmBT,aAAAA;aACAjB,iBAAAA;aACAK,mBAAAA;aACAqB,oBAAAA;IAClB;AAkDL"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { ECSRunner } from '../ecs-runner.js';
|
|
2
|
+
import type { IAbstractInputConstructor, InputData } from '../types/index.js';
|
|
3
|
+
type AddRPCFn = <TInputCtor extends IAbstractInputConstructor>(InputCtor: TInputCtor, data: InputData<InstanceType<TInputCtor>>) => void;
|
|
4
|
+
export interface HashReporterConfig {
|
|
5
|
+
reportInterval: number;
|
|
6
|
+
reportHashRpc: IAbstractInputConstructor;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Creates a hash reporter function for use in `drainInputs`.
|
|
10
|
+
*
|
|
11
|
+
* The returned function should be called from your `drainInputs` callback.
|
|
12
|
+
* It periodically reports the simulation state hash via the ReportHash RPC.
|
|
13
|
+
*/
|
|
14
|
+
export declare function createHashReporter(runner: ECSRunner, config: HashReporterConfig): (addRPC: AddRPCFn) => void;
|
|
15
|
+
export {};
|
|
16
|
+
//# sourceMappingURL=create-hash-reporter.d.ts.map
|
|
@@ -0,0 +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,CAe5G"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Creates a hash reporter function for use in `drainInputs`.
|
|
3
|
+
*
|
|
4
|
+
* The returned function should be called from your `drainInputs` callback.
|
|
5
|
+
* It periodically reports the simulation state hash via the ReportHash RPC.
|
|
6
|
+
*/ export function createHashReporter(runner, config) {
|
|
7
|
+
let lastReportedTick = -1;
|
|
8
|
+
return (addRPC)=>{
|
|
9
|
+
const currentTick = runner.Simulation.tick;
|
|
10
|
+
if (currentTick > 0 && currentTick % config.reportInterval === 0 && currentTick !== lastReportedTick) {
|
|
11
|
+
lastReportedTick = currentTick;
|
|
12
|
+
const hash = runner.Simulation.mem.getHash();
|
|
13
|
+
addRPC(config.reportHashRpc, {
|
|
14
|
+
hash,
|
|
15
|
+
atTick: currentTick
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
//# sourceMappingURL=create-hash-reporter.js.map
|
|
@@ -0,0 +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 currentTick = runner.Simulation.tick;\n if (\n currentTick > 0 &&\n currentTick % config.reportInterval === 0 &&\n currentTick !== lastReportedTick\n ) {\n lastReportedTick = currentTick;\n const hash = runner.Simulation.mem.getHash();\n addRPC(config.reportHashRpc, { hash, atTick: currentTick });\n }\n };\n}\n"],"names":["createHashReporter","runner","config","lastReportedTick","addRPC","currentTick","Simulation","tick","reportInterval","hash","mem","getHash","reportHashRpc","atTick"],"rangeMappings":";;;;;;;;;;;;;;;;;;","mappings":"AAaA;;;;;CAKC,GACD,OAAO,SAASA,mBAAmBC,MAAiB,EAAEC,MAA0B;IAC9E,IAAIC,mBAAmB,CAAC;IAExB,OAAO,CAACC;QACN,MAAMC,cAAcJ,OAAOK,UAAU,CAACC,IAAI;QAC1C,IACEF,cAAc,KACdA,cAAcH,OAAOM,cAAc,KAAK,KACxCH,gBAAgBF,kBAChB;YACAA,mBAAmBE;YACnB,MAAMI,OAAOR,OAAOK,UAAU,CAACI,GAAG,CAACC,OAAO;YAC1CP,OAAOF,OAAOU,aAAa,EAAE;gBAAEH;gBAAMI,QAAQR;YAAY;QAC3D;IACF;AACF"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { Signal } from '../signals/signal.js';
|
|
2
|
+
export interface DivergenceData {
|
|
3
|
+
slotA: number;
|
|
4
|
+
slotB: number;
|
|
5
|
+
hashA: number;
|
|
6
|
+
hashB: number;
|
|
7
|
+
atTick: number;
|
|
8
|
+
}
|
|
9
|
+
export declare class DivergenceSignal extends Signal<DivergenceData> {
|
|
10
|
+
}
|
|
11
|
+
//# sourceMappingURL=divergence.signal.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"divergence.signal.d.ts","sourceRoot":"","sources":["../../../src/lib/hash-verification/divergence.signal.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAE9C,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,qBAAa,gBAAiB,SAAQ,MAAM,CAAC,cAAc,CAAC;CAAG"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/lib/hash-verification/divergence.signal.ts"],"sourcesContent":["import { Signal } from '../signals/signal.js';\n\nexport interface DivergenceData {\n slotA: number;\n slotB: number;\n hashA: number;\n hashB: number;\n atTick: number;\n}\n\nexport class DivergenceSignal extends Signal<DivergenceData> {}\n"],"names":["Signal","DivergenceSignal"],"rangeMappings":";;","mappings":"AAAA,SAASA,MAAM,QAAQ,uBAAuB;AAU9C,OAAO,MAAMC,yBAAyBD;AAAwB"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { DivergenceSignal, type DivergenceData } from './divergence.signal.js';
|
|
2
|
+
export { AbstractHashVerificationSystem } from './abstract-hash-verification.system.js';
|
|
3
|
+
export { createHashReporter, type HashReporterConfig } from './create-hash-reporter.js';
|
|
4
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/lib/hash-verification/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,KAAK,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAC/E,OAAO,EAAE,8BAA8B,EAAE,MAAM,wCAAwC,CAAC;AACxF,OAAO,EAAE,kBAAkB,EAAE,KAAK,kBAAkB,EAAE,MAAM,2BAA2B,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/lib/hash-verification/index.ts"],"sourcesContent":["export { DivergenceSignal, type DivergenceData } from './divergence.signal.js';\nexport { AbstractHashVerificationSystem } from './abstract-hash-verification.system.js';\nexport { createHashReporter, type HashReporterConfig } from './create-hash-reporter.js';\n"],"names":["DivergenceSignal","AbstractHashVerificationSystem","createHashReporter"],"rangeMappings":";;","mappings":"AAAA,SAASA,gBAAgB,QAA6B,yBAAyB;AAC/E,SAASC,8BAA8B,QAAQ,yCAAyC;AACxF,SAASC,kBAAkB,QAAiC,4BAA4B"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { ECSSimulation } from '../ecs-simulation.js';
|
|
2
|
+
import { IAbstractInputConstructor } from '../types/index.js';
|
|
3
|
+
import { ECSConfig } from '../ecs-config.js';
|
|
4
|
+
import { InputRegistry } from './input-registry.js';
|
|
5
|
+
import { RPCHistory } from './rpc-history.js';
|
|
6
|
+
import { RPC } from './rpc.js';
|
|
7
|
+
export declare abstract class AbstractInputProvider {
|
|
8
|
+
readonly ecsConfig: ECSConfig;
|
|
9
|
+
protected readonly _inputRegistry: InputRegistry;
|
|
10
|
+
private _nextSeq;
|
|
11
|
+
private _nextOrdinal;
|
|
12
|
+
private readonly _inputDrainers;
|
|
13
|
+
protected _frameRPCBuffer: Array<RPC>;
|
|
14
|
+
protected _frameLength: number;
|
|
15
|
+
protected _disposed: boolean;
|
|
16
|
+
protected _currentInputDelay: number;
|
|
17
|
+
protected _simulation: ECSSimulation;
|
|
18
|
+
protected readonly _rpcHistory: RPCHistory;
|
|
19
|
+
abstract playerSlot: number;
|
|
20
|
+
abstract getInvalidateRollbackTick(): void | number;
|
|
21
|
+
constructor(ecsConfig: ECSConfig, _inputRegistry: InputRegistry);
|
|
22
|
+
get currentInputDelay(): number;
|
|
23
|
+
get rpcHistory(): RPCHistory;
|
|
24
|
+
get inputRegistry(): InputRegistry;
|
|
25
|
+
/** @internal — used only by addLocalRpc for ordinal assignment */
|
|
26
|
+
private getNextOrdinal;
|
|
27
|
+
update(): void;
|
|
28
|
+
init(simulation: ECSSimulation): void;
|
|
29
|
+
dispose(): void;
|
|
30
|
+
protected resetSequences(): void;
|
|
31
|
+
private addLocalRpc;
|
|
32
|
+
/**
|
|
33
|
+
* Add an RPC received from a remote player via the network.
|
|
34
|
+
* Used by RelayInputProvider when receiving TickInputFanout.
|
|
35
|
+
*/
|
|
36
|
+
addRemoteRpc(rpc: RPC): void;
|
|
37
|
+
/**
|
|
38
|
+
* Add multiple remote RPCs at once (batch from fanout).
|
|
39
|
+
*/
|
|
40
|
+
addRemoteRpcBatch(rpcs: ReadonlyArray<RPC>): void;
|
|
41
|
+
/**
|
|
42
|
+
* Remove a specific RPC from history.
|
|
43
|
+
* Used when server sends CancelInput.
|
|
44
|
+
*/
|
|
45
|
+
removeRpcAt(playerSlot: number, tick: number, seq: number): void;
|
|
46
|
+
/**
|
|
47
|
+
* Dynamically change the input delay (in ticks).
|
|
48
|
+
* Used by InputDelayController based on network conditions.
|
|
49
|
+
*/
|
|
50
|
+
setInputDelay(ticks: number): void;
|
|
51
|
+
drainInputs(fn: InputDrainerFn): () => void;
|
|
52
|
+
collectTickRPCs<TInputCtor extends IAbstractInputConstructor>(tick: number, InputCtor: TInputCtor): ReadonlyArray<RPC<InstanceType<TInputCtor>>>;
|
|
53
|
+
/**
|
|
54
|
+
* Get the last buffered local RPCs from this frame.
|
|
55
|
+
* Used by RelayInputProvider to send local inputs to the server.
|
|
56
|
+
*/
|
|
57
|
+
getFrameRPCBuffer(): ReadonlyArray<RPC>;
|
|
58
|
+
}
|
|
59
|
+
type InputDrainerFn = (addRPC: AbstractInputProvider['addLocalRpc']) => void;
|
|
60
|
+
export {};
|
|
61
|
+
//# sourceMappingURL=abstract-input-provider.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"abstract-input-provider.d.ts","sourceRoot":"","sources":["../../../src/lib/input/abstract-input-provider.ts"],"names":[],"mappings":"AAAA,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;aAiBvB,SAAS,EAAE,SAAS;IACpC,SAAS,CAAC,QAAQ,CAAC,cAAc,EAAE,aAAa;IAjBlD,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;aAEnB,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;IAOd,IAAI,CAAC,UAAU,EAAE,aAAa,GAAG,IAAI;IAIrC,OAAO,IAAI,IAAI;IAItB,SAAS,CAAC,cAAc,IAAI,IAAI;IAQhC,OAAO,CAAC,WAAW,CAcjB;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"}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { RPCHistory } from './rpc-history.js';
|
|
2
|
+
import { RPC } from './rpc.js';
|
|
3
|
+
import { createLogger } from '@lagless/misc';
|
|
4
|
+
const log = createLogger('InputProvider');
|
|
5
|
+
export class AbstractInputProvider {
|
|
6
|
+
// ─── Public Getters ─────────────────────────────────────
|
|
7
|
+
get currentInputDelay() {
|
|
8
|
+
return this._currentInputDelay;
|
|
9
|
+
}
|
|
10
|
+
get rpcHistory() {
|
|
11
|
+
return this._rpcHistory;
|
|
12
|
+
}
|
|
13
|
+
get inputRegistry() {
|
|
14
|
+
return this._inputRegistry;
|
|
15
|
+
}
|
|
16
|
+
// ─── Lifecycle ──────────────────────────────────────────
|
|
17
|
+
/** @internal — used only by addLocalRpc for ordinal assignment */ getNextOrdinal() {
|
|
18
|
+
return this._nextOrdinal++;
|
|
19
|
+
}
|
|
20
|
+
update() {
|
|
21
|
+
this._frameRPCBuffer.length = 0;
|
|
22
|
+
this._inputDrainers.forEach((drainFn)=>drainFn(this.addLocalRpc));
|
|
23
|
+
if (this._frameRPCBuffer.length > 0) this._nextSeq++;
|
|
24
|
+
}
|
|
25
|
+
init(simulation) {
|
|
26
|
+
this._simulation = simulation;
|
|
27
|
+
}
|
|
28
|
+
dispose() {
|
|
29
|
+
this._disposed = true;
|
|
30
|
+
}
|
|
31
|
+
resetSequences() {
|
|
32
|
+
this._nextSeq = 1;
|
|
33
|
+
this._nextOrdinal = 1;
|
|
34
|
+
this._frameRPCBuffer.length = 0;
|
|
35
|
+
}
|
|
36
|
+
// ─── Remote Input (from network) ────────────────────────
|
|
37
|
+
/**
|
|
38
|
+
* Add an RPC received from a remote player via the network.
|
|
39
|
+
* Used by RelayInputProvider when receiving TickInputFanout.
|
|
40
|
+
*/ addRemoteRpc(rpc) {
|
|
41
|
+
this._rpcHistory.addRPC(rpc);
|
|
42
|
+
log.debug(`Remote RPC tick=${rpc.meta.tick} seq=${rpc.meta.seq} slot=${rpc.meta.playerSlot} inputId=${rpc.inputId}`);
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Add multiple remote RPCs at once (batch from fanout).
|
|
46
|
+
*/ addRemoteRpcBatch(rpcs) {
|
|
47
|
+
this._rpcHistory.addBatch(rpcs);
|
|
48
|
+
log.debug(`Remote RPC batch: ${rpcs.length} RPCs`);
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Remove a specific RPC from history.
|
|
52
|
+
* Used when server sends CancelInput.
|
|
53
|
+
*/ removeRpcAt(playerSlot, tick, seq) {
|
|
54
|
+
this._rpcHistory.removePlayerInputsAtTick(playerSlot, tick, seq);
|
|
55
|
+
log.debug(`Removed RPC slot=${playerSlot} tick=${tick} seq=${seq}`);
|
|
56
|
+
}
|
|
57
|
+
// ─── Input Delay ────────────────────────────────────────
|
|
58
|
+
/**
|
|
59
|
+
* Dynamically change the input delay (in ticks).
|
|
60
|
+
* Used by InputDelayController based on network conditions.
|
|
61
|
+
*/ setInputDelay(ticks) {
|
|
62
|
+
const clamped = Math.max(this.ecsConfig.minInputDelayTick, Math.min(ticks, this.ecsConfig.maxInputDelayTick));
|
|
63
|
+
if (clamped !== this._currentInputDelay) {
|
|
64
|
+
log.debug(`Input delay changed: ${this._currentInputDelay} → ${clamped}`);
|
|
65
|
+
this._currentInputDelay = clamped;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
// ─── Query ──────────────────────────────────────────────
|
|
69
|
+
drainInputs(fn) {
|
|
70
|
+
this._inputDrainers.add(fn);
|
|
71
|
+
return ()=>{
|
|
72
|
+
this._inputDrainers.delete(fn);
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
collectTickRPCs(tick, InputCtor) {
|
|
76
|
+
return this._rpcHistory.collectTickRPCs(tick, InputCtor);
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Get the last buffered local RPCs from this frame.
|
|
80
|
+
* Used by RelayInputProvider to send local inputs to the server.
|
|
81
|
+
*/ getFrameRPCBuffer() {
|
|
82
|
+
return this._frameRPCBuffer;
|
|
83
|
+
}
|
|
84
|
+
constructor(ecsConfig, _inputRegistry){
|
|
85
|
+
this.ecsConfig = ecsConfig;
|
|
86
|
+
this._inputRegistry = _inputRegistry;
|
|
87
|
+
this._nextSeq = 1;
|
|
88
|
+
this._nextOrdinal = 1;
|
|
89
|
+
this._inputDrainers = new Set();
|
|
90
|
+
this._frameRPCBuffer = [];
|
|
91
|
+
this._disposed = false;
|
|
92
|
+
this._rpcHistory = new RPCHistory();
|
|
93
|
+
this.addLocalRpc = (InputCtor, data)=>{
|
|
94
|
+
const newRPCMeta = {
|
|
95
|
+
tick: this._simulation.tick + this._currentInputDelay,
|
|
96
|
+
seq: this._nextSeq,
|
|
97
|
+
ordinal: this.getNextOrdinal(),
|
|
98
|
+
playerSlot: this.playerSlot
|
|
99
|
+
};
|
|
100
|
+
const rpc = new RPC(InputCtor.id, newRPCMeta, data);
|
|
101
|
+
this._frameRPCBuffer.push(rpc);
|
|
102
|
+
this._rpcHistory.addRPC(rpc);
|
|
103
|
+
log.debug(`Local RPC tick=${newRPCMeta.tick} delay=${this._currentInputDelay} seq=${newRPCMeta.seq} slot=${newRPCMeta.playerSlot} inputId=${InputCtor.id}`);
|
|
104
|
+
};
|
|
105
|
+
this._frameLength = this.ecsConfig.frameLength;
|
|
106
|
+
this._currentInputDelay = this.ecsConfig.initialInputDelayTick;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
//# sourceMappingURL=abstract-input-provider.js.map
|
|
@@ -0,0 +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.forEach((drainFn) => drainFn(this.addLocalRpc));\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 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":["RPCHistory","RPC","createLogger","log","AbstractInputProvider","currentInputDelay","_currentInputDelay","rpcHistory","_rpcHistory","inputRegistry","_inputRegistry","getNextOrdinal","_nextOrdinal","update","_frameRPCBuffer","length","_inputDrainers","forEach","drainFn","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","newRPCMeta","ordinal","id","push","_frameLength","frameLength","initialInputDelayTick"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;","mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export * from './rpc.js';
|
|
2
|
+
export * from './rpc-history.js';
|
|
3
|
+
export * from './input-registry.js';
|
|
4
|
+
export * from './local-input-provider.js';
|
|
5
|
+
export * from './abstract-input-provider.js';
|
|
6
|
+
export * from './input-provider-di-token.js';
|
|
7
|
+
export * from './replay-input-provider.js';
|
|
8
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/lib/input/index.ts"],"names":[],"mappings":"AAAA,cAAc,UAAU,CAAC;AACzB,cAAc,kBAAkB,CAAC;AACjC,cAAc,qBAAqB,CAAC;AACpC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,8BAA8B,CAAC;AAC7C,cAAc,8BAA8B,CAAC;AAC7C,cAAc,4BAA4B,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export * from './rpc.js';
|
|
2
|
+
export * from './rpc-history.js';
|
|
3
|
+
export * from './input-registry.js';
|
|
4
|
+
export * from './local-input-provider.js';
|
|
5
|
+
export * from './abstract-input-provider.js';
|
|
6
|
+
export * from './input-provider-di-token.js';
|
|
7
|
+
export * from './replay-input-provider.js';
|
|
8
|
+
|
|
9
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/lib/input/index.ts"],"sourcesContent":["export * from './rpc.js';\nexport * from './rpc-history.js';\nexport * from './input-registry.js';\nexport * from './local-input-provider.js';\nexport * from './abstract-input-provider.js';\nexport * from './input-provider-di-token.js';\nexport * from './replay-input-provider.js';\n"],"names":[],"rangeMappings":";;;;;;","mappings":"AAAA,cAAc,WAAW;AACzB,cAAc,mBAAmB;AACjC,cAAc,sBAAsB;AACpC,cAAc,4BAA4B;AAC1C,cAAc,+BAA+B;AAC7C,cAAc,+BAA+B;AAC7C,cAAc,6BAA6B"}
|
|
@@ -0,0 +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;IAEzB,yBAAyB;CAGjC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { AbstractInputProvider } from './abstract-input-provider.js';
|
|
2
|
+
export class InputProvider extends AbstractInputProvider {
|
|
3
|
+
getInvalidateRollbackTick() {
|
|
4
|
+
return undefined;
|
|
5
|
+
}
|
|
6
|
+
constructor(...args){
|
|
7
|
+
super(...args);
|
|
8
|
+
this.playerSlot = -1;
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
//# sourceMappingURL=input-provider-di-token.js.map
|
|
@@ -0,0 +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":";;;;;;;;;","mappings":"AAAA,SAASA,qBAAqB,QAAQ,+BAA+B;AAErE,OAAO,MAAMC,sBAAsBD;IAG1BE,4BAA4B;QACjC,OAAOC;IACT;;;aAJgBC,aAAa,CAAC;;AAKhC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { IAbstractInput, IAbstractInputConstructor } from '../types/index.js';
|
|
2
|
+
export declare class InputRegistry {
|
|
3
|
+
private readonly _inputs;
|
|
4
|
+
private readonly _idToInputMap;
|
|
5
|
+
constructor(_inputs: IAbstractInputConstructor[]);
|
|
6
|
+
get(inputId: number): IAbstractInput;
|
|
7
|
+
}
|
|
8
|
+
//# sourceMappingURL=input-registry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"input-registry.d.ts","sourceRoot":"","sources":["../../../src/lib/input/input-registry.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,yBAAyB,EAAE,MAAM,mBAAmB,CAAC;AAE9E,qBAAa,aAAa;IAOtB,OAAO,CAAC,QAAQ,CAAC,OAAO;IAH1B,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAqC;gBAGhD,OAAO,EAAE,yBAAyB,EAAE;IAYhD,GAAG,CAAC,OAAO,EAAE,MAAM,GAAG,cAAc;CAM5C"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export class InputRegistry {
|
|
2
|
+
get(inputId) {
|
|
3
|
+
const input = this._idToInputMap.get(inputId);
|
|
4
|
+
if (!input) throw new Error(`Input with id ${inputId} not found`);
|
|
5
|
+
return input;
|
|
6
|
+
}
|
|
7
|
+
constructor(_inputs){
|
|
8
|
+
this._inputs = _inputs;
|
|
9
|
+
this._idToInputMap = new Map();
|
|
10
|
+
for (const InputCtor of this._inputs){
|
|
11
|
+
const InputInstance = new InputCtor();
|
|
12
|
+
const id = InputInstance.id;
|
|
13
|
+
this._idToInputMap.set(id, InputInstance);
|
|
14
|
+
// this._inputToIdMap.set(InputInstance, id);
|
|
15
|
+
// this._inputCtorToIdMap.set(InputCtor, id);
|
|
16
|
+
// this._idToInputCtorMap.set(id, InputCtor);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
//# sourceMappingURL=input-registry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/lib/input/input-registry.ts"],"sourcesContent":["import { IAbstractInput, IAbstractInputConstructor } from '../types/index.js';\n\nexport class InputRegistry {\n // private readonly _inputCtorToIdMap = new Map<IAbstractInputConstructor, number>();\n // private readonly _idToInputCtorMap = new Map<number, IAbstractInputConstructor>();\n // private readonly _inputToIdMap = new Map<IAbstractInput, number>();\n private readonly _idToInputMap = new Map<number, IAbstractInput>();\n\n constructor(\n private readonly _inputs: IAbstractInputConstructor[],\n ) {\n for (const InputCtor of this._inputs) {\n const InputInstance = new InputCtor();\n const id = InputInstance.id;\n this._idToInputMap.set(id, InputInstance);\n // this._inputToIdMap.set(InputInstance, id);\n // this._inputCtorToIdMap.set(InputCtor, id);\n // this._idToInputCtorMap.set(id, InputCtor);\n }\n }\n\n public get(inputId: number): IAbstractInput {\n const input = this._idToInputMap.get(inputId);\n if (!input) throw new Error(`Input with id ${inputId} not found`);\n\n return input;\n }\n}\n"],"names":["InputRegistry","get","inputId","input","_idToInputMap","Error","constructor","_inputs","Map","InputCtor","InputInstance","id","set"],"rangeMappings":";;;;;;;;;;;;;;;;;;","mappings":"AAEA,OAAO,MAAMA;IAmBJC,IAAIC,OAAe,EAAkB;QAC1C,MAAMC,QAAQ,IAAI,CAACC,aAAa,CAACH,GAAG,CAACC;QACrC,IAAI,CAACC,OAAO,MAAM,IAAIE,MAAM,CAAC,cAAc,EAAEH,QAAQ,UAAU,CAAC;QAEhE,OAAOC;IACT;IAlBAG,YACE,AAAiBC,OAAoC,CACrD;aADiBA,UAAAA;aAHFH,gBAAgB,IAAII;QAKnC,KAAK,MAAMC,aAAa,IAAI,CAACF,OAAO,CAAE;YACpC,MAAMG,gBAAgB,IAAID;YAC1B,MAAME,KAAKD,cAAcC,EAAE;YAC3B,IAAI,CAACP,aAAa,CAACQ,GAAG,CAACD,IAAID;QAC3B,6CAA6C;QAC7C,6CAA6C;QAC7C,6CAA6C;QAC/C;IACF;AAQF"}
|
|
@@ -0,0 +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;IAEf,yBAAyB,IAAI,IAAI,GAAG,MAAM;CAG3D"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { AbstractInputProvider } from './abstract-input-provider.js';
|
|
2
|
+
export class LocalInputProvider extends AbstractInputProvider {
|
|
3
|
+
getInvalidateRollbackTick() {
|
|
4
|
+
return undefined;
|
|
5
|
+
}
|
|
6
|
+
constructor(...args){
|
|
7
|
+
super(...args);
|
|
8
|
+
this.playerSlot = 0;
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
//# sourceMappingURL=local-input-provider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/lib/input/local-input-provider.ts"],"sourcesContent":["import { AbstractInputProvider } from './abstract-input-provider.js';\n\nexport class LocalInputProvider extends AbstractInputProvider {\n public override playerSlot = 0;\n\n public override getInvalidateRollbackTick(): void | number {\n return undefined;\n }\n}\n"],"names":["AbstractInputProvider","LocalInputProvider","getInvalidateRollbackTick","undefined","playerSlot"],"rangeMappings":";;;;;;;;;","mappings":"AAAA,SAASA,qBAAqB,QAAQ,+BAA+B;AAErE,OAAO,MAAMC,2BAA2BD;IAGtBE,4BAA2C;QACzD,OAAOC;IACT;;;aAJgBC,aAAa;;AAK/B"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { AbstractInputProvider } from './abstract-input-provider.js';
|
|
2
|
+
import { ECSConfig } from '../ecs-config.js';
|
|
3
|
+
import { InputRegistry } from './input-registry.js';
|
|
4
|
+
export declare class ReplayInputProvider extends AbstractInputProvider {
|
|
5
|
+
playerSlot: number;
|
|
6
|
+
getInvalidateRollbackTick(): undefined;
|
|
7
|
+
constructor(replayData: ArrayBuffer, ecsConfig: ECSConfig, inputRegistry: InputRegistry);
|
|
8
|
+
update(): void;
|
|
9
|
+
static exportReplay(seed: Uint8Array, maxPlayers: number, fps: number, replayData: ArrayBuffer): ArrayBuffer;
|
|
10
|
+
static createFromReplay(replay: ArrayBuffer, inputRegistry: InputRegistry): ReplayInputProvider;
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=replay-input-provider.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"replay-input-provider.d.ts","sourceRoot":"","sources":["../../../src/lib/input/replay-input-provider.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,MAAM,8BAA8B,CAAC;AACrE,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC7C,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAQpD,qBAAa,mBAAoB,SAAQ,qBAAqB;IAC5C,UAAU,SAAK;IAEf,yBAAyB;gBAKvC,UAAU,EAAE,WAAW,EACvB,SAAS,EAAE,SAAS,EACpB,aAAa,EAAE,aAAa;IAMd,MAAM,IAAI,IAAI;WAIhB,YAAY,CAAC,IAAI,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,UAAU,EAAE,WAAW,GAAG,WAAW;WAWrG,gBAAgB,CAAC,MAAM,EAAE,WAAW,EAAE,aAAa,EAAE,aAAa,GAAG,mBAAmB;CAUvG"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { AbstractInputProvider } from './abstract-input-provider.js';
|
|
2
|
+
import { ECSConfig } from '../ecs-config.js';
|
|
3
|
+
const SEED_OFFSET = 0;
|
|
4
|
+
const SEED_LENGTH = 16;
|
|
5
|
+
const MAX_PLAYERS_OFFSET = SEED_OFFSET + SEED_LENGTH;
|
|
6
|
+
const FPS_OFFSET = MAX_PLAYERS_OFFSET + 1;
|
|
7
|
+
const REPLAY_DATA_OFFSET = FPS_OFFSET + 1;
|
|
8
|
+
export class ReplayInputProvider extends AbstractInputProvider {
|
|
9
|
+
getInvalidateRollbackTick() {
|
|
10
|
+
return undefined;
|
|
11
|
+
}
|
|
12
|
+
update() {
|
|
13
|
+
// do nothing, all inputs are pre-recorded
|
|
14
|
+
}
|
|
15
|
+
static exportReplay(seed, maxPlayers, fps, replayData) {
|
|
16
|
+
const replay = new ArrayBuffer(REPLAY_DATA_OFFSET + replayData.byteLength);
|
|
17
|
+
const replayUint8 = new Uint8Array(replay);
|
|
18
|
+
replayUint8.set(seed, SEED_OFFSET);
|
|
19
|
+
const replayView = new DataView(replay);
|
|
20
|
+
replayView.setUint8(MAX_PLAYERS_OFFSET, maxPlayers);
|
|
21
|
+
replayView.setUint8(FPS_OFFSET, fps);
|
|
22
|
+
replayUint8.set(new Uint8Array(replayData), REPLAY_DATA_OFFSET);
|
|
23
|
+
return replay;
|
|
24
|
+
}
|
|
25
|
+
static createFromReplay(replay, inputRegistry) {
|
|
26
|
+
const replayUint8 = new Uint8Array(replay);
|
|
27
|
+
const seed = replayUint8.slice(SEED_OFFSET, SEED_OFFSET + SEED_LENGTH);
|
|
28
|
+
const replayView = new DataView(replay);
|
|
29
|
+
const maxPlayers = replayView.getUint8(MAX_PLAYERS_OFFSET);
|
|
30
|
+
const fps = replayView.getUint8(FPS_OFFSET);
|
|
31
|
+
const rpcData = replay.slice(REPLAY_DATA_OFFSET);
|
|
32
|
+
const ecsConfig = new ECSConfig({
|
|
33
|
+
maxPlayers,
|
|
34
|
+
seed,
|
|
35
|
+
fps
|
|
36
|
+
});
|
|
37
|
+
return new ReplayInputProvider(rpcData, ecsConfig, inputRegistry);
|
|
38
|
+
}
|
|
39
|
+
constructor(replayData, ecsConfig, inputRegistry){
|
|
40
|
+
super(ecsConfig, inputRegistry);
|
|
41
|
+
this.playerSlot = 0;
|
|
42
|
+
this._rpcHistory.import(inputRegistry, replayData);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
//# sourceMappingURL=replay-input-provider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/lib/input/replay-input-provider.ts"],"sourcesContent":["import { AbstractInputProvider } from './abstract-input-provider.js';\nimport { ECSConfig } from '../ecs-config.js';\nimport { InputRegistry } from './input-registry.js';\n\nconst SEED_OFFSET = 0;\nconst SEED_LENGTH = 16;\nconst MAX_PLAYERS_OFFSET = SEED_OFFSET + SEED_LENGTH;\nconst FPS_OFFSET = MAX_PLAYERS_OFFSET + 1;\nconst REPLAY_DATA_OFFSET = FPS_OFFSET + 1;\n\nexport class ReplayInputProvider extends AbstractInputProvider {\n public override playerSlot = 0;\n\n public override getInvalidateRollbackTick() {\n return undefined;\n }\n\n constructor(\n replayData: ArrayBuffer,\n ecsConfig: ECSConfig,\n inputRegistry: InputRegistry,\n ) {\n super(ecsConfig, inputRegistry);\n this._rpcHistory.import(inputRegistry, replayData);\n }\n\n public override update(): void {\n // do nothing, all inputs are pre-recorded\n }\n\n public static exportReplay(seed: Uint8Array, maxPlayers: number, fps: number, replayData: ArrayBuffer): ArrayBuffer {\n const replay = new ArrayBuffer(REPLAY_DATA_OFFSET + replayData.byteLength);\n const replayUint8 = new Uint8Array(replay);\n replayUint8.set(seed, SEED_OFFSET);\n const replayView = new DataView(replay);\n replayView.setUint8(MAX_PLAYERS_OFFSET, maxPlayers);\n replayView.setUint8(FPS_OFFSET, fps);\n replayUint8.set(new Uint8Array(replayData), REPLAY_DATA_OFFSET);\n return replay;\n }\n\n public static createFromReplay(replay: ArrayBuffer, inputRegistry: InputRegistry): ReplayInputProvider {\n const replayUint8 = new Uint8Array(replay);\n const seed = replayUint8.slice(SEED_OFFSET, SEED_OFFSET + SEED_LENGTH);\n const replayView = new DataView(replay);\n const maxPlayers = replayView.getUint8(MAX_PLAYERS_OFFSET);\n const fps = replayView.getUint8(FPS_OFFSET);\n const rpcData = replay.slice(REPLAY_DATA_OFFSET);\n const ecsConfig = new ECSConfig({ maxPlayers, seed, fps });\n return new ReplayInputProvider(rpcData, ecsConfig, inputRegistry);\n }\n}\n"],"names":["AbstractInputProvider","ECSConfig","SEED_OFFSET","SEED_LENGTH","MAX_PLAYERS_OFFSET","FPS_OFFSET","REPLAY_DATA_OFFSET","ReplayInputProvider","getInvalidateRollbackTick","undefined","update","exportReplay","seed","maxPlayers","fps","replayData","replay","ArrayBuffer","byteLength","replayUint8","Uint8Array","set","replayView","DataView","setUint8","createFromReplay","inputRegistry","slice","getUint8","rpcData","ecsConfig","constructor","playerSlot","_rpcHistory","import"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;","mappings":"AAAA,SAASA,qBAAqB,QAAQ,+BAA+B;AACrE,SAASC,SAAS,QAAQ,mBAAmB;AAG7C,MAAMC,cAAc;AACpB,MAAMC,cAAc;AACpB,MAAMC,qBAAqBF,cAAcC;AACzC,MAAME,aAAaD,qBAAqB;AACxC,MAAME,qBAAqBD,aAAa;AAExC,OAAO,MAAME,4BAA4BP;IAGvBQ,4BAA4B;QAC1C,OAAOC;IACT;IAWgBC,SAAe;IAC7B,0CAA0C;IAC5C;IAEA,OAAcC,aAAaC,IAAgB,EAAEC,UAAkB,EAAEC,GAAW,EAAEC,UAAuB,EAAe;QAClH,MAAMC,SAAS,IAAIC,YAAYX,qBAAqBS,WAAWG,UAAU;QACzE,MAAMC,cAAc,IAAIC,WAAWJ;QACnCG,YAAYE,GAAG,CAACT,MAAMV;QACtB,MAAMoB,aAAa,IAAIC,SAASP;QAChCM,WAAWE,QAAQ,CAACpB,oBAAoBS;QACxCS,WAAWE,QAAQ,CAACnB,YAAYS;QAChCK,YAAYE,GAAG,CAAC,IAAID,WAAWL,aAAaT;QAC5C,OAAOU;IACT;IAEA,OAAcS,iBAAiBT,MAAmB,EAAEU,aAA4B,EAAuB;QACrG,MAAMP,cAAc,IAAIC,WAAWJ;QACnC,MAAMJ,OAAOO,YAAYQ,KAAK,CAACzB,aAAaA,cAAcC;QAC1D,MAAMmB,aAAa,IAAIC,SAASP;QAChC,MAAMH,aAAaS,WAAWM,QAAQ,CAACxB;QACvC,MAAMU,MAAMQ,WAAWM,QAAQ,CAACvB;QAChC,MAAMwB,UAAUb,OAAOW,KAAK,CAACrB;QAC7B,MAAMwB,YAAY,IAAI7B,UAAU;YAAEY;YAAYD;YAAME;QAAI;QACxD,OAAO,IAAIP,oBAAoBsB,SAASC,WAAWJ;IACrD;IAjCAK,YACEhB,UAAuB,EACvBe,SAAoB,EACpBJ,aAA4B,CAC5B;QACA,KAAK,CAACI,WAAWJ;aAXHM,aAAa;QAY3B,IAAI,CAACC,WAAW,CAACC,MAAM,CAACR,eAAeX;IACzC;AA2BF"}
|