@lagless/core 0.0.36 → 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/index.d.ts +11 -0
- package/dist/index.d.ts.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-decorators.d.ts +4 -0
- package/dist/lib/di/di-decorators.d.ts.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/ecs-config.d.ts +16 -0
- package/dist/lib/ecs-config.d.ts.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 +8 -2
- package/dist/lib/ecs-runner.js.map +1 -1
- package/dist/lib/ecs-simulation.d.ts +64 -0
- package/dist/lib/ecs-simulation.d.ts.map +1 -0
- 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 +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 +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 +16 -0
- package/dist/lib/hash-verification/create-hash-reporter.d.ts.map +1 -0
- 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/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/index.d.ts +4 -0
- package/dist/lib/hash-verification/index.d.ts.map +1 -0
- package/dist/lib/input/abstract-input-provider.d.ts +62 -0
- package/dist/lib/input/abstract-input-provider.d.ts.map +1 -0
- 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/index.d.ts +8 -0
- package/dist/lib/input/index.d.ts.map +1 -0
- package/dist/lib/input/input-provider-di-token.d.ts +7 -0
- package/dist/lib/input/input-provider-di-token.d.ts.map +1 -0
- 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/input-registry.d.ts +8 -0
- package/dist/lib/input/input-registry.d.ts.map +1 -0
- package/dist/lib/input/local-input-provider.d.ts +7 -0
- package/dist/lib/input/local-input-provider.d.ts.map +1 -0
- 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 +13 -0
- package/dist/lib/input/replay-input-provider.d.ts.map +1 -0
- package/dist/lib/input/replay-input-provider.js +5 -0
- package/dist/lib/input/replay-input-provider.js.map +1 -1
- 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.d.ts +8 -0
- package/dist/lib/input/rpc.d.ts.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/index.d.ts +5 -0
- package/dist/lib/mem/index.d.ts.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/entities-manager.d.ts +32 -0
- package/dist/lib/mem/managers/entities-manager.d.ts.map +1 -0
- 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 +17 -0
- package/dist/lib/mem/managers/filters-manager.d.ts.map +1 -0
- 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/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/prng-manager.d.ts +36 -0
- package/dist/lib/mem/managers/prng-manager.d.ts.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/tick-manager.d.ts +10 -0
- package/dist/lib/mem/managers/tick-manager.d.ts.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 +4 -2
- package/dist/lib/mem/mem.js.map +1 -1
- package/dist/lib/prefab.d.ts +16 -0
- package/dist/lib/prefab.d.ts.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/signal.d.ts +41 -0
- package/dist/lib/signals/signal.d.ts.map +1 -0
- 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 +9 -0
- package/dist/lib/signals/signals.registry.d.ts.map +1 -0
- 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 +17 -0
- package/dist/lib/types/abstract-filter.d.ts.map +1 -0
- 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 +111 -0
- package/dist/lib/types/ecs-types.d.ts.map +1 -0
- package/dist/lib/types/ecs-types.js.map +1 -1
- package/dist/lib/types/index.d.ts +3 -0
- package/dist/lib/types/index.d.ts.map +1 -0
- package/package.json +4 -5
|
@@ -0,0 +1,62 @@
|
|
|
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 get verifiedTick(): number;
|
|
21
|
+
abstract getInvalidateRollbackTick(): void | number;
|
|
22
|
+
constructor(ecsConfig: ECSConfig, _inputRegistry: InputRegistry);
|
|
23
|
+
get currentInputDelay(): number;
|
|
24
|
+
get rpcHistory(): RPCHistory;
|
|
25
|
+
get inputRegistry(): InputRegistry;
|
|
26
|
+
/** @internal — used only by addLocalRpc for ordinal assignment */
|
|
27
|
+
private getNextOrdinal;
|
|
28
|
+
update(): void;
|
|
29
|
+
init(simulation: ECSSimulation): void;
|
|
30
|
+
dispose(): void;
|
|
31
|
+
protected resetSequences(): void;
|
|
32
|
+
private addLocalRpc;
|
|
33
|
+
/**
|
|
34
|
+
* Add an RPC received from a remote player via the network.
|
|
35
|
+
* Used by RelayInputProvider when receiving TickInputFanout.
|
|
36
|
+
*/
|
|
37
|
+
addRemoteRpc(rpc: RPC): void;
|
|
38
|
+
/**
|
|
39
|
+
* Add multiple remote RPCs at once (batch from fanout).
|
|
40
|
+
*/
|
|
41
|
+
addRemoteRpcBatch(rpcs: ReadonlyArray<RPC>): void;
|
|
42
|
+
/**
|
|
43
|
+
* Remove a specific RPC from history.
|
|
44
|
+
* Used when server sends CancelInput.
|
|
45
|
+
*/
|
|
46
|
+
removeRpcAt(playerSlot: number, tick: number, seq: number): void;
|
|
47
|
+
/**
|
|
48
|
+
* Dynamically change the input delay (in ticks).
|
|
49
|
+
* Used by InputDelayController based on network conditions.
|
|
50
|
+
*/
|
|
51
|
+
setInputDelay(ticks: number): void;
|
|
52
|
+
drainInputs(fn: InputDrainerFn): () => void;
|
|
53
|
+
collectTickRPCs<TInputCtor extends IAbstractInputConstructor>(tick: number, InputCtor: TInputCtor): ReadonlyArray<RPC<InstanceType<TInputCtor>>>;
|
|
54
|
+
/**
|
|
55
|
+
* Get the last buffered local RPCs from this frame.
|
|
56
|
+
* Used by RelayInputProvider to send local inputs to the server.
|
|
57
|
+
*/
|
|
58
|
+
getFrameRPCBuffer(): ReadonlyArray<RPC>;
|
|
59
|
+
}
|
|
60
|
+
type InputDrainerFn = (addRPC: AbstractInputProvider['addLocalRpc']) => void;
|
|
61
|
+
export {};
|
|
62
|
+
//# 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":"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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"}
|
|
@@ -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,7 @@
|
|
|
1
|
+
import { AbstractInputProvider } from './abstract-input-provider.js';
|
|
2
|
+
export declare class InputProvider extends AbstractInputProvider {
|
|
3
|
+
playerSlot: number;
|
|
4
|
+
get verifiedTick(): number;
|
|
5
|
+
getInvalidateRollbackTick(): undefined;
|
|
6
|
+
}
|
|
7
|
+
//# sourceMappingURL=input-provider-di-token.d.ts.map
|
|
@@ -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;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"}
|
|
@@ -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,7 @@
|
|
|
1
|
+
import { AbstractInputProvider } from './abstract-input-provider.js';
|
|
2
|
+
export declare class LocalInputProvider extends AbstractInputProvider {
|
|
3
|
+
playerSlot: number;
|
|
4
|
+
get verifiedTick(): number;
|
|
5
|
+
getInvalidateRollbackTick(): void | number;
|
|
6
|
+
}
|
|
7
|
+
//# sourceMappingURL=local-input-provider.d.ts.map
|
|
@@ -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;IAE/B,IAAoB,YAAY,IAAI,MAAM,CAEzC;IAEe,yBAAyB,IAAI,IAAI,GAAG,MAAM;CAG3D"}
|
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
import { AbstractInputProvider } from './abstract-input-provider.js';
|
|
2
2
|
export class LocalInputProvider extends AbstractInputProvider {
|
|
3
|
+
get verifiedTick() {
|
|
4
|
+
var _this__simulation;
|
|
5
|
+
var _this__simulation_tick;
|
|
6
|
+
return (_this__simulation_tick = (_this__simulation = this._simulation) == null ? void 0 : _this__simulation.tick) != null ? _this__simulation_tick : -1;
|
|
7
|
+
}
|
|
3
8
|
getInvalidateRollbackTick() {
|
|
4
9
|
return undefined;
|
|
5
10
|
}
|
|
@@ -1 +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":"
|
|
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 get verifiedTick(): number {\n return this._simulation?.tick ?? -1;\n }\n\n public override getInvalidateRollbackTick(): void | number {\n return undefined;\n }\n}\n"],"names":["AbstractInputProvider","LocalInputProvider","verifiedTick","_simulation","tick","getInvalidateRollbackTick","undefined","playerSlot"],"rangeMappings":";;;;;;;;;;;;;;","mappings":"AAAA,SAASA,qBAAqB,QAAQ,+BAA+B;AAErE,OAAO,MAAMC,2BAA2BD;IAGtC,IAAoBE,eAAuB;YAClC;YAAA;QAAP,OAAO,CAAA,0BAAA,oBAAA,IAAI,CAACC,WAAW,qBAAhB,kBAAkBC,IAAI,YAAtB,yBAA0B,CAAC;IACpC;IAEgBC,4BAA2C;QACzD,OAAOC;IACT;;;aARgBC,aAAa;;AAS/B"}
|
|
@@ -0,0 +1,13 @@
|
|
|
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
|
+
get verifiedTick(): number;
|
|
7
|
+
getInvalidateRollbackTick(): undefined;
|
|
8
|
+
constructor(replayData: ArrayBuffer, ecsConfig: ECSConfig, inputRegistry: InputRegistry);
|
|
9
|
+
update(): void;
|
|
10
|
+
static exportReplay(seed: Uint8Array, maxPlayers: number, fps: number, replayData: ArrayBuffer): ArrayBuffer;
|
|
11
|
+
static createFromReplay(replay: ArrayBuffer, inputRegistry: InputRegistry): ReplayInputProvider;
|
|
12
|
+
}
|
|
13
|
+
//# 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;IAE/B,IAAoB,YAAY,IAAI,MAAM,CAEzC;IAEe,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"}
|
|
@@ -6,6 +6,11 @@ const MAX_PLAYERS_OFFSET = SEED_OFFSET + SEED_LENGTH;
|
|
|
6
6
|
const FPS_OFFSET = MAX_PLAYERS_OFFSET + 1;
|
|
7
7
|
const REPLAY_DATA_OFFSET = FPS_OFFSET + 1;
|
|
8
8
|
export class ReplayInputProvider extends AbstractInputProvider {
|
|
9
|
+
get verifiedTick() {
|
|
10
|
+
var _this__simulation;
|
|
11
|
+
var _this__simulation_tick;
|
|
12
|
+
return (_this__simulation_tick = (_this__simulation = this._simulation) == null ? void 0 : _this__simulation.tick) != null ? _this__simulation_tick : -1;
|
|
13
|
+
}
|
|
9
14
|
getInvalidateRollbackTick() {
|
|
10
15
|
return undefined;
|
|
11
16
|
}
|
|
@@ -1 +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":"
|
|
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 get verifiedTick(): number {\n return this._simulation?.tick ?? -1;\n }\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","verifiedTick","_simulation","tick","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;IAGvC,IAAoBQ,eAAuB;YAClC;YAAA;QAAP,OAAO,CAAA,0BAAA,oBAAA,IAAI,CAACC,WAAW,qBAAhB,kBAAkBC,IAAI,YAAtB,yBAA0B,CAAC;IACpC;IAEgBC,4BAA4B;QAC1C,OAAOC;IACT;IAWgBC,SAAe;IAC7B,0CAA0C;IAC5C;IAEA,OAAcC,aAAaC,IAAgB,EAAEC,UAAkB,EAAEC,GAAW,EAAEC,UAAuB,EAAe;QAClH,MAAMC,SAAS,IAAIC,YAAYd,qBAAqBY,WAAWG,UAAU;QACzE,MAAMC,cAAc,IAAIC,WAAWJ;QACnCG,YAAYE,GAAG,CAACT,MAAMb;QACtB,MAAMuB,aAAa,IAAIC,SAASP;QAChCM,WAAWE,QAAQ,CAACvB,oBAAoBY;QACxCS,WAAWE,QAAQ,CAACtB,YAAYY;QAChCK,YAAYE,GAAG,CAAC,IAAID,WAAWL,aAAaZ;QAC5C,OAAOa;IACT;IAEA,OAAcS,iBAAiBT,MAAmB,EAAEU,aAA4B,EAAuB;QACrG,MAAMP,cAAc,IAAIC,WAAWJ;QACnC,MAAMJ,OAAOO,YAAYQ,KAAK,CAAC5B,aAAaA,cAAcC;QAC1D,MAAMsB,aAAa,IAAIC,SAASP;QAChC,MAAMH,aAAaS,WAAWM,QAAQ,CAAC3B;QACvC,MAAMa,MAAMQ,WAAWM,QAAQ,CAAC1B;QAChC,MAAM2B,UAAUb,OAAOW,KAAK,CAACxB;QAC7B,MAAM2B,YAAY,IAAIhC,UAAU;YAAEe;YAAYD;YAAME;QAAI;QACxD,OAAO,IAAIV,oBAAoByB,SAASC,WAAWJ;IACrD;IAjCAK,YACEhB,UAAuB,EACvBe,SAAoB,EACpBJ,aAA4B,CAC5B;QACA,KAAK,CAACI,WAAWJ;aAfHM,aAAa;QAgB3B,IAAI,CAACC,WAAW,CAACC,MAAM,CAACR,eAAeX;IACzC;AA2BF"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { RPC } from './rpc.js';
|
|
2
|
+
import { IAbstractInputConstructor } from '../types/index.js';
|
|
3
|
+
import { InputRegistry } from './input-registry.js';
|
|
4
|
+
export declare class RPCHistory {
|
|
5
|
+
private readonly _history;
|
|
6
|
+
static excludeLocalRPCs(rpcs: ReadonlyArray<RPC>, localPlayerSlot: number): RPC[];
|
|
7
|
+
addRPC(rpc: RPC): void;
|
|
8
|
+
addBatch(rpcs: ReadonlyArray<RPC>): void;
|
|
9
|
+
/**
|
|
10
|
+
* Returns a new array of RPCs matching the given input type at the specified tick.
|
|
11
|
+
* Each call allocates a fresh array — safe to store and use across multiple calls.
|
|
12
|
+
*/
|
|
13
|
+
collectTickRPCs<TInputCtor extends IAbstractInputConstructor>(tick: number, InputCtor: TInputCtor): ReadonlyArray<RPC<InstanceType<TInputCtor>>>;
|
|
14
|
+
removePlayerInputsAtTick(playerSlot: number, tick: number, seq: number): void;
|
|
15
|
+
clear(): void;
|
|
16
|
+
get size(): number;
|
|
17
|
+
get totalRPCCount(): number;
|
|
18
|
+
debugExportAsJSON(): string;
|
|
19
|
+
/**
|
|
20
|
+
* Exports entire history to a compact binary format.
|
|
21
|
+
* @param registry - InputRegistry for serializing input data
|
|
22
|
+
* @returns ArrayBuffer containing serialized history
|
|
23
|
+
*/
|
|
24
|
+
export(registry: InputRegistry): ArrayBuffer;
|
|
25
|
+
/**
|
|
26
|
+
* Imports history from binary format, replacing current content.
|
|
27
|
+
* @param registry - InputRegistry for deserializing input data
|
|
28
|
+
* @param buffer - ArrayBuffer containing serialized history
|
|
29
|
+
*/
|
|
30
|
+
import(registry: InputRegistry, buffer: ArrayBuffer): void;
|
|
31
|
+
private prepareExportData;
|
|
32
|
+
private calculateExportSize;
|
|
33
|
+
private writeHeader;
|
|
34
|
+
private writeTickEntries;
|
|
35
|
+
private readHeader;
|
|
36
|
+
private readTickEntry;
|
|
37
|
+
/** Insert rpc into arr maintaining sorted order by (playerSlot, ordinal). */
|
|
38
|
+
private insertSorted;
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=rpc-history.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rpc-history.d.ts","sourceRoot":"","sources":["../../../src/lib/input/rpc-history.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;AAC/B,OAAO,EAAE,yBAAyB,EAAE,MAAM,mBAAmB,CAAC;AAC9D,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAiDpD,qBAAa,UAAU;IACrB,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAiC;WAM5C,gBAAgB,CAAC,IAAI,EAAE,aAAa,CAAC,GAAG,CAAC,EAAE,eAAe,EAAE,MAAM,GAAG,GAAG,EAAE;IAQjF,MAAM,CAAC,GAAG,EAAE,GAAG,GAAG,IAAI;IAStB,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAC,GAAG,CAAC,GAAG,IAAI;IA6B/C;;;OAGG;IACI,eAAe,CAAC,UAAU,SAAS,yBAAyB,EACjE,IAAI,EAAE,MAAM,EACZ,SAAS,EAAE,UAAU,GACpB,aAAa,CAAC,GAAG,CAAC,YAAY,CAAC,UAAU,CAAC,CAAC,CAAC;IAaxC,wBAAwB,CAAC,UAAU,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI;IAmB7E,KAAK,IAAI,IAAI;IAIpB,IAAW,IAAI,IAAI,MAAM,CAExB;IAED,IAAW,aAAa,IAAI,MAAM,CAMjC;IAMM,iBAAiB,IAAI,MAAM;IAsBlC;;;;OAIG;IACI,MAAM,CAAC,QAAQ,EAAE,aAAa,GAAG,WAAW;IAgBnD;;;;OAIG;IACI,MAAM,CAAC,QAAQ,EAAE,aAAa,EAAE,MAAM,EAAE,WAAW,GAAG,IAAI;IAgCjE,OAAO,CAAC,iBAAiB;IA6BzB,OAAO,CAAC,mBAAmB;IAa3B,OAAO,CAAC,WAAW;IAYnB,OAAO,CAAC,gBAAgB;IAwCxB,OAAO,CAAC,UAAU;IAMlB,OAAO,CAAC,aAAa;IAmDrB,6EAA6E;IAC7E,OAAO,CAAC,YAAY;CAOrB"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { IAbstractInput, InputData, InputMeta } from '../types/index.js';
|
|
2
|
+
export declare class RPC<TInput extends IAbstractInput = IAbstractInput> {
|
|
3
|
+
readonly inputId: IAbstractInput['id'];
|
|
4
|
+
readonly meta: InputMeta;
|
|
5
|
+
readonly data: InputData<TInput>;
|
|
6
|
+
constructor(inputId: IAbstractInput['id'], meta: InputMeta, data: InputData<TInput>);
|
|
7
|
+
}
|
|
8
|
+
//# sourceMappingURL=rpc.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rpc.d.ts","sourceRoot":"","sources":["../../../src/lib/input/rpc.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAEzE,qBAAa,GAAG,CAAC,MAAM,SAAS,cAAc,GAAG,cAAc;aAE3C,OAAO,EAAE,cAAc,CAAC,IAAI,CAAC;aAC7B,IAAI,EAAE,SAAS;aACf,IAAI,EAAE,SAAS,CAAC,MAAM,CAAC;gBAFvB,OAAO,EAAE,cAAc,CAAC,IAAI,CAAC,EAC7B,IAAI,EAAE,SAAS,EACf,IAAI,EAAE,SAAS,CAAC,MAAM,CAAC;CAG1C"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"abstract-memory.interface.d.ts","sourceRoot":"","sources":["../../../src/lib/mem/abstract-memory.interface.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAEhD,MAAM,WAAW,eAAe;IAC9B,IAAI,CAAC,WAAW,EAAE,WAAW,EAAE,OAAO,EAAE,aAAa,GAAG,IAAI,CAAC;IAC7D,aAAa,CAAC,OAAO,EAAE,aAAa,GAAG,IAAI,CAAC;CAC7C"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/lib/mem/index.ts"],"names":[],"mappings":"AAAA,cAAc,UAAU,CAAC;AACzB,cAAc,4BAA4B,CAAC;AAC3C,cAAc,gCAAgC,CAAC;AAC/C,cAAc,wCAAwC,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { IAbstractMemory } from '../abstract-memory.interface.js';
|
|
2
|
+
import { ECSConfig } from '../../ecs-config.js';
|
|
3
|
+
import { ECSDeps, IComponentConstructor, IComponentInstance } from '../../types/index.js';
|
|
4
|
+
import { MemoryTracker } from '@lagless/binary';
|
|
5
|
+
export declare class ComponentsManager implements IAbstractMemory {
|
|
6
|
+
private readonly _ECSConfig;
|
|
7
|
+
private readonly _ECSDeps;
|
|
8
|
+
private readonly _componentsInstances;
|
|
9
|
+
constructor(_ECSConfig: ECSConfig, _ECSDeps: ECSDeps);
|
|
10
|
+
init(arrayBuffer: ArrayBuffer, tracker: MemoryTracker): void;
|
|
11
|
+
calculateSize(tracker: MemoryTracker): void;
|
|
12
|
+
get<Ctor extends IComponentConstructor>(ComponentConstructor: Ctor): InstanceType<Ctor>;
|
|
13
|
+
[Symbol.iterator](): MapIterator<[IComponentConstructor, IComponentInstance]>;
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=components-manager.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"components-manager.d.ts","sourceRoot":"","sources":["../../../../src/lib/mem/managers/components-manager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,iCAAiC,CAAC;AAClE,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAChD,OAAO,EAAE,OAAO,EAAE,qBAAqB,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAC1F,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAEhD,qBAAa,iBAAkB,YAAW,eAAe;IAG3C,OAAO,CAAC,QAAQ,CAAC,UAAU;IAAa,OAAO,CAAC,QAAQ,CAAC,QAAQ;IAF7E,OAAO,CAAC,QAAQ,CAAC,oBAAoB,CAAwD;gBAEhE,UAAU,EAAE,SAAS,EAAmB,QAAQ,EAAE,OAAO;IAE/E,IAAI,CAAC,WAAW,EAAE,WAAW,EAAE,OAAO,EAAE,aAAa,GAAG,IAAI;IAO5D,aAAa,CAAC,OAAO,EAAE,aAAa,GAAG,IAAI;IAM3C,GAAG,CAAC,IAAI,SAAS,qBAAqB,EAAE,oBAAoB,EAAE,IAAI,GAAG,YAAY,CAAC,IAAI,CAAC;IAQvF,CAAC,MAAM,CAAC,QAAQ,CAAC;CAGzB"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { FiltersManager } from './filters-manager.js';
|
|
2
|
+
import { ComponentsManager } from './components-manager.js';
|
|
3
|
+
import { IAbstractMemory } from '../abstract-memory.interface.js';
|
|
4
|
+
import { ECSConfig } from '../../ecs-config.js';
|
|
5
|
+
import { Prefab } from '../../prefab.js';
|
|
6
|
+
import { IComponentConstructor } from '../../types/index.js';
|
|
7
|
+
import { MemoryTracker } from '@lagless/binary';
|
|
8
|
+
/** Sentinel value indicating an entity slot is unused / removed. All mask words are set to 0xFFFFFFFF. */
|
|
9
|
+
export declare const ENTITY_REMOVED_MASK = 4294967295;
|
|
10
|
+
export declare class EntitiesManager implements IAbstractMemory {
|
|
11
|
+
private readonly _ECSConfig;
|
|
12
|
+
private readonly _ComponentsMemory;
|
|
13
|
+
private readonly _FiltersMemory;
|
|
14
|
+
private readonly _maskWords;
|
|
15
|
+
private _nextEntityId;
|
|
16
|
+
private _removedEntitiesLength;
|
|
17
|
+
private _removedEntities;
|
|
18
|
+
private _entitiesComponentsMasks;
|
|
19
|
+
constructor(_ECSConfig: ECSConfig, _ComponentsMemory: ComponentsManager, _FiltersMemory: FiltersManager, _maskWords?: 1 | 2);
|
|
20
|
+
createEntity(prefab?: Prefab): number;
|
|
21
|
+
removeEntity(entity: number): void;
|
|
22
|
+
isEntityAlive(entity: number): boolean;
|
|
23
|
+
addComponent(entity: number, ComponentConstructor: IComponentConstructor): void;
|
|
24
|
+
removeComponent(entity: number, ComponentConstructor: IComponentConstructor): void;
|
|
25
|
+
hasComponent(entity: number, ComponentConstructor: IComponentConstructor): boolean;
|
|
26
|
+
hasPrefab(entity: number, prefab: Prefab): boolean;
|
|
27
|
+
private updateFilters;
|
|
28
|
+
private popRemovedEntities;
|
|
29
|
+
init(arrayBuffer: ArrayBuffer, tracker: MemoryTracker): void;
|
|
30
|
+
calculateSize(tracker: MemoryTracker): void;
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=entities-manager.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"entities-manager.d.ts","sourceRoot":"","sources":["../../../../src/lib/mem/managers/entities-manager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,EAAE,eAAe,EAAE,MAAM,iCAAiC,CAAC;AAClE,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAChD,OAAO,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AACzC,OAAO,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAC7D,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAEhD,0GAA0G;AAC1G,eAAO,MAAM,mBAAmB,aAAa,CAAC;AAE9C,qBAAa,eAAgB,YAAW,eAAe;IAOnD,OAAO,CAAC,QAAQ,CAAC,UAAU;IAC3B,OAAO,CAAC,QAAQ,CAAC,iBAAiB;IAClC,OAAO,CAAC,QAAQ,CAAC,cAAc;IAC/B,OAAO,CAAC,QAAQ,CAAC,UAAU;IAT7B,OAAO,CAAC,aAAa,CAAe;IACpC,OAAO,CAAC,sBAAsB,CAAe;IAC7C,OAAO,CAAC,gBAAgB,CAAe;IACvC,OAAO,CAAC,wBAAwB,CAAe;gBAG5B,UAAU,EAAE,SAAS,EACrB,iBAAiB,EAAE,iBAAiB,EACpC,cAAc,EAAE,cAAc,EAC9B,UAAU,GAAE,CAAC,GAAG,CAAK;IAGjC,YAAY,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM;IAoCrC,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IA6BlC,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO;IAStC,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,oBAAoB,EAAE,qBAAqB,GAAG,IAAI;IAQ/E,eAAe,CAAC,MAAM,EAAE,MAAM,EAAE,oBAAoB,EAAE,qBAAqB,GAAG,IAAI;IAQlF,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,oBAAoB,EAAE,qBAAqB,GAAG,OAAO;IAUlF,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO;IAazD,OAAO,CAAC,aAAa;IAmBrB,OAAO,CAAC,kBAAkB;IAWnB,IAAI,CAAC,WAAW,EAAE,WAAW,EAAE,OAAO,EAAE,aAAa,GAAG,IAAI;IAe5D,aAAa,CAAC,OAAO,EAAE,aAAa,GAAG,IAAI;CAMnD"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/** Sentinel value indicating an entity slot is unused / removed. */ export const ENTITY_REMOVED_MASK = 0xFFFFFFFF;
|
|
1
|
+
/** Sentinel value indicating an entity slot is unused / removed. All mask words are set to 0xFFFFFFFF. */ export const ENTITY_REMOVED_MASK = 0xFFFFFFFF;
|
|
2
2
|
export class EntitiesManager {
|
|
3
3
|
createEntity(prefab) {
|
|
4
4
|
let entity = this.popRemovedEntities();
|
|
@@ -9,66 +9,107 @@ export class EntitiesManager {
|
|
|
9
9
|
if (entity >= this._ECSConfig.maxEntities) {
|
|
10
10
|
throw new Error(`Maximum number of entities (${this._ECSConfig.maxEntities}) exceeded`);
|
|
11
11
|
}
|
|
12
|
-
|
|
12
|
+
// Clear all mask words for the entity
|
|
13
|
+
const base = entity * this._maskWords;
|
|
14
|
+
for(let w = 0; w < this._maskWords; w++){
|
|
15
|
+
this._entitiesComponentsMasks[base + w] = 0;
|
|
16
|
+
}
|
|
13
17
|
if (prefab) {
|
|
14
18
|
for (const [ComponentConstructor, Values] of prefab){
|
|
15
|
-
const
|
|
16
|
-
|
|
19
|
+
const bitIndex = ComponentConstructor.ID;
|
|
20
|
+
const wordOffset = bitIndex >>> 5;
|
|
21
|
+
const bit = 1 << (bitIndex & 31);
|
|
22
|
+
this._entitiesComponentsMasks[base + wordOffset] |= bit;
|
|
17
23
|
if (!Values) continue;
|
|
24
|
+
const componentInstance = this._ComponentsMemory.get(ComponentConstructor);
|
|
18
25
|
for (const [fieldName, value] of Object.entries(Values)){
|
|
19
26
|
if (value === undefined) continue;
|
|
20
27
|
componentInstance.unsafe[fieldName][entity] = value;
|
|
21
28
|
}
|
|
22
29
|
}
|
|
23
30
|
}
|
|
24
|
-
this.updateFilters(entity
|
|
31
|
+
this.updateFilters(entity);
|
|
25
32
|
return entity;
|
|
26
33
|
}
|
|
27
34
|
removeEntity(entity) {
|
|
28
35
|
if (entity < 0 || entity >= this._ECSConfig.maxEntities) {
|
|
29
36
|
throw new Error(`Entity ID ${entity} is out of bounds`);
|
|
30
37
|
}
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
38
|
+
const base = entity * this._maskWords;
|
|
39
|
+
// Guard against double removal (all mask words must be sentinel)
|
|
40
|
+
let isRemoved = true;
|
|
41
|
+
for(let w = 0; w < this._maskWords; w++){
|
|
42
|
+
if (this._entitiesComponentsMasks[base + w] !== ENTITY_REMOVED_MASK) {
|
|
43
|
+
isRemoved = false;
|
|
44
|
+
break;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
if (isRemoved) return;
|
|
48
|
+
// Set all mask words to sentinel
|
|
49
|
+
for(let w = 0; w < this._maskWords; w++){
|
|
50
|
+
this._entitiesComponentsMasks[base + w] = ENTITY_REMOVED_MASK;
|
|
34
51
|
}
|
|
35
|
-
this._entitiesComponentsMasks[entity] = ENTITY_REMOVED_MASK;
|
|
36
52
|
// Add the entity to the removed entities stack
|
|
37
53
|
this._removedEntities[this._removedEntitiesLength[0]] = entity;
|
|
38
54
|
this._removedEntitiesLength[0]++;
|
|
39
|
-
this.
|
|
55
|
+
this._FiltersMemory.removeEntityFromAllFilters(entity);
|
|
40
56
|
}
|
|
41
57
|
isEntityAlive(entity) {
|
|
42
58
|
if (entity < 0 || entity >= this._ECSConfig.maxEntities) return false;
|
|
43
|
-
|
|
59
|
+
const base = entity * this._maskWords;
|
|
60
|
+
for(let w = 0; w < this._maskWords; w++){
|
|
61
|
+
if (this._entitiesComponentsMasks[base + w] !== ENTITY_REMOVED_MASK) return true;
|
|
62
|
+
}
|
|
63
|
+
return false;
|
|
44
64
|
}
|
|
45
65
|
addComponent(entity, ComponentConstructor) {
|
|
46
|
-
|
|
47
|
-
|
|
66
|
+
const bitIndex = ComponentConstructor.ID;
|
|
67
|
+
const base = entity * this._maskWords;
|
|
68
|
+
const wordOffset = bitIndex >>> 5;
|
|
69
|
+
this._entitiesComponentsMasks[base + wordOffset] |= 1 << (bitIndex & 31);
|
|
70
|
+
this.updateFilters(entity);
|
|
48
71
|
}
|
|
49
72
|
removeComponent(entity, ComponentConstructor) {
|
|
50
|
-
|
|
51
|
-
|
|
73
|
+
const bitIndex = ComponentConstructor.ID;
|
|
74
|
+
const base = entity * this._maskWords;
|
|
75
|
+
const wordOffset = bitIndex >>> 5;
|
|
76
|
+
this._entitiesComponentsMasks[base + wordOffset] &= ~(1 << (bitIndex & 31));
|
|
77
|
+
this.updateFilters(entity);
|
|
52
78
|
}
|
|
53
79
|
hasComponent(entity, ComponentConstructor) {
|
|
54
80
|
if (entity < 0 || entity >= this._ECSConfig.maxEntities) {
|
|
55
81
|
throw new Error(`Entity ID ${entity} is out of bounds`);
|
|
56
82
|
}
|
|
57
|
-
|
|
83
|
+
const bitIndex = ComponentConstructor.ID;
|
|
84
|
+
const base = entity * this._maskWords;
|
|
85
|
+
const wordOffset = bitIndex >>> 5;
|
|
86
|
+
return (this._entitiesComponentsMasks[base + wordOffset] & 1 << (bitIndex & 31)) !== 0;
|
|
58
87
|
}
|
|
59
88
|
hasPrefab(entity, prefab) {
|
|
89
|
+
const base = entity * this._maskWords;
|
|
60
90
|
for (const [ComponentConstructor] of prefab){
|
|
61
|
-
|
|
91
|
+
const bitIndex = ComponentConstructor.ID;
|
|
92
|
+
const wordOffset = bitIndex >>> 5;
|
|
93
|
+
if ((this._entitiesComponentsMasks[base + wordOffset] & 1 << (bitIndex & 31)) === 0) {
|
|
62
94
|
return false;
|
|
63
95
|
}
|
|
64
96
|
}
|
|
65
97
|
return true;
|
|
66
98
|
}
|
|
67
|
-
updateFilters(entity
|
|
68
|
-
|
|
99
|
+
updateFilters(entity) {
|
|
100
|
+
const base = entity * this._maskWords;
|
|
101
|
+
// Check if entity has any components set (all words zero means empty)
|
|
102
|
+
let isEmpty = true;
|
|
103
|
+
for(let w = 0; w < this._maskWords; w++){
|
|
104
|
+
if (this._entitiesComponentsMasks[base + w] !== 0) {
|
|
105
|
+
isEmpty = false;
|
|
106
|
+
break;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
if (isEmpty) {
|
|
69
110
|
this._FiltersMemory.removeEntityFromAllFilters(entity);
|
|
70
111
|
} else {
|
|
71
|
-
this._FiltersMemory.updateEntityInAllFilters(entity,
|
|
112
|
+
this._FiltersMemory.updateEntityInAllFilters(entity, this._entitiesComponentsMasks, base, this._maskWords);
|
|
72
113
|
}
|
|
73
114
|
}
|
|
74
115
|
popRemovedEntities() {
|
|
@@ -86,7 +127,7 @@ export class EntitiesManager {
|
|
|
86
127
|
tracker.add(this._removedEntitiesLength.byteLength);
|
|
87
128
|
this._removedEntities = new Uint32Array(arrayBuffer, tracker.ptr, this._ECSConfig.maxEntities);
|
|
88
129
|
tracker.add(this._removedEntities.byteLength);
|
|
89
|
-
this._entitiesComponentsMasks = new Uint32Array(arrayBuffer, tracker.ptr, this._ECSConfig.maxEntities);
|
|
130
|
+
this._entitiesComponentsMasks = new Uint32Array(arrayBuffer, tracker.ptr, this._ECSConfig.maxEntities * this._maskWords);
|
|
90
131
|
this._entitiesComponentsMasks.fill(ENTITY_REMOVED_MASK);
|
|
91
132
|
tracker.add(this._entitiesComponentsMasks.byteLength);
|
|
92
133
|
}
|
|
@@ -94,12 +135,13 @@ export class EntitiesManager {
|
|
|
94
135
|
tracker.add(Uint32Array.BYTES_PER_ELEMENT); // nextEntityId
|
|
95
136
|
tracker.add(Uint32Array.BYTES_PER_ELEMENT); // removedEntitiesLength
|
|
96
137
|
tracker.add(this._ECSConfig.maxEntities * Uint32Array.BYTES_PER_ELEMENT); // removedEntities
|
|
97
|
-
tracker.add(this._ECSConfig.maxEntities * Uint32Array.BYTES_PER_ELEMENT); // entitiesComponentsMasks
|
|
138
|
+
tracker.add(this._ECSConfig.maxEntities * this._maskWords * Uint32Array.BYTES_PER_ELEMENT); // entitiesComponentsMasks
|
|
98
139
|
}
|
|
99
|
-
constructor(_ECSConfig, _ComponentsMemory, _FiltersMemory){
|
|
140
|
+
constructor(_ECSConfig, _ComponentsMemory, _FiltersMemory, _maskWords = 1){
|
|
100
141
|
this._ECSConfig = _ECSConfig;
|
|
101
142
|
this._ComponentsMemory = _ComponentsMemory;
|
|
102
143
|
this._FiltersMemory = _FiltersMemory;
|
|
144
|
+
this._maskWords = _maskWords;
|
|
103
145
|
}
|
|
104
146
|
}
|
|
105
147
|
|