tolerate internet latency for initial inputs
All checks were successful
build / image (push) Successful in 1m49s

This commit is contained in:
Syncer Deploy
2026-08-28 11:01:08 -03:00
parent b29b7697a6
commit 0bf2b95755
3 changed files with 34 additions and 2 deletions

View File

@@ -91,7 +91,7 @@ export class NetworkedAuthoritativeEngine<
) {
this.game = game;
this.historyTicks = options.historyTicks ?? game.tickRateHz * 2;
this.maxPastTicks = options.maxPastTicks ?? 2;
this.maxPastTicks = options.maxPastTicks ?? game.tickRateHz;
this.maxFutureTicks = options.maxFutureTicks ?? game.tickRateHz;
this.snapshotEveryTicks = game.tickRateHz / game.snapshotRateHz;
this.state = game.server.createInitialState();

View File

@@ -11,6 +11,10 @@ import type {
export interface ServerEngineOptions {
historyTicks?: number;
/**
* Maximum transport delay accepted for an input. Late inputs are applied on
* the next simulation step; they never rewrite authoritative history.
*/
maxPastTicks?: number;
maxFutureTicks?: number;
}
@@ -63,7 +67,7 @@ export class AuthoritativeEngine<State, Input> {
) {
this.game = game;
this.historyTicks = options.historyTicks ?? game.tickRateHz * 2;
this.maxPastTicks = options.maxPastTicks ?? 2;
this.maxPastTicks = options.maxPastTicks ?? game.tickRateHz;
this.maxFutureTicks = options.maxFutureTicks ?? game.tickRateHz;
this.snapshotEveryTicks = game.tickRateHz / game.snapshotRateHz;
this.state = game.createInitialState();

View File

@@ -151,6 +151,34 @@ test("the developer-facing API compiles named sections into a networked game", (
);
server.step();
assert.equal(server.currentState.value, 3);
// Internet clients can be several ticks behind the server when their first
// input arrives. Accept it within the default one-second transport window
// and apply it on the next authoritative step.
for (let index = 0; index < 6; index++) server.step();
assert.deepEqual(
server.submitInput(1, {
sequence: 2,
targetTick: 2,
observedTick: 2,
input: { amount: 2 },
}),
{ accepted: true },
);
server.step();
assert.equal(server.currentState.value, 5);
for (let index = 0; index < 7; index++) server.step();
assert.deepEqual(
server.submitInput(1, {
sequence: 3,
targetTick: 2,
observedTick: 2,
input: { amount: 2 },
}),
{ accepted: false, reason: "past" },
);
assert.deepEqual(codec.decode(codec.encode({ unicode: "flux ⚡" })), {
unicode: "flux ⚡",
});