mirror of
https://github.com/openfrontio/OpenFrontIO.git
synced 2026-07-05 19:25:08 +00:00
Clean up previous implementations
removed: - catchUpMode and its CATCH_UP_ENTER/EXIT thresholds in ClientGameRunner - tick metrics fields and overlay UI for inCatchUpMode and beatsPerFrame - leftover worker heartbeat plumbing (message type + WorkerClient.sendHeartbeat) that was no longer used after self-clocking changed: - backlog tracking: keep serverTurnHighWater / lastProcessedTick / backlogTurns, but simplify it to just compute backlog and a backlogGrowing flag instead of driving a dedicated catch-up mode - frame skip: adaptRenderFrequency now only increases renderEveryN when backlog > 0 and still growing; when backlog is stable/shrinking or zero, it decays renderEveryN back toward 1 - render loop: uses the backlog-aware renderEveryN unconditionally (no catch-up flag), and resets skipping completely when backlog reaches 0 - metrics/overlay: TickMetricsEvent now carries backlogTurns and renderEveryN; the performance overlay displays backlog and current “render every N frames” but no longer mentions catch-up or heartbeats Learnings during branch development leading to this Once the worker self-clocks, a separate “catch-up mode” and beats-per-frame knob don’t add real control; they just complicate the model. Backlog is still a valuable signal, but it’s more effective as a quantitative input (backlog size and whether it’s growing) than as a boolean mode toggle. Frame skipping should be driven by actual backlog pressure plus frame cost: throttle only while backlog is growing and frames are heavy, and automatically relax back to full-rate rendering once the simulation catches up.
This commit is contained in:
@@ -230,15 +230,12 @@ export class ClientGameRunner {
|
||||
private serverTurnHighWater: number = 0;
|
||||
private lastProcessedTick: number = 0;
|
||||
private backlogTurns: number = 0;
|
||||
|
||||
private catchUpMode: boolean = false;
|
||||
private readonly CATCH_UP_ENTER_BACKLOG = 120; // turns behind to enter catch-up
|
||||
private readonly CATCH_UP_EXIT_BACKLOG = 20; // turns behind to exit catch-up
|
||||
private backlogGrowing: boolean = false;
|
||||
|
||||
private pendingUpdates: GameUpdateViewData[] = [];
|
||||
private isProcessingUpdates = false;
|
||||
|
||||
// Adaptive rendering during catch-up: render at most once every N frames.
|
||||
// Adaptive rendering when frames are heavy: render at most once every N frames.
|
||||
private renderEveryN: number = 1;
|
||||
private renderSkipCounter: number = 0;
|
||||
private lastFrameTime: number = 0;
|
||||
@@ -329,7 +326,7 @@ export class ClientGameRunner {
|
||||
return;
|
||||
}
|
||||
this.pendingUpdates.push(gu);
|
||||
if (!this.catchUpMode) {
|
||||
if (this.renderEveryN === 1) {
|
||||
this.processPendingUpdates();
|
||||
}
|
||||
});
|
||||
@@ -344,13 +341,14 @@ export class ClientGameRunner {
|
||||
|
||||
// Decide whether to render (and thus process pending updates) this frame.
|
||||
let shouldRender = true;
|
||||
if (this.catchUpMode && this.renderEveryN > 1) {
|
||||
if (this.renderSkipCounter < this.renderEveryN - 1) {
|
||||
shouldRender = false;
|
||||
this.renderSkipCounter++;
|
||||
} else {
|
||||
this.renderSkipCounter = 0;
|
||||
}
|
||||
if (
|
||||
this.renderEveryN > 1 &&
|
||||
this.renderSkipCounter < this.renderEveryN - 1
|
||||
) {
|
||||
shouldRender = false;
|
||||
this.renderSkipCounter++;
|
||||
} else if (this.renderEveryN > 1) {
|
||||
this.renderSkipCounter = 0;
|
||||
}
|
||||
|
||||
if (shouldRender) {
|
||||
@@ -544,7 +542,6 @@ export class ClientGameRunner {
|
||||
lastTickDuration,
|
||||
this.currentTickDelay,
|
||||
this.backlogTurns,
|
||||
this.catchUpMode,
|
||||
this.renderEveryN,
|
||||
),
|
||||
);
|
||||
@@ -555,28 +552,26 @@ export class ClientGameRunner {
|
||||
}
|
||||
|
||||
private adaptRenderFrequency(frameDuration: number) {
|
||||
if (!this.catchUpMode) {
|
||||
// Back to normal rendering.
|
||||
// Frameskip only matters while we have a backlog; otherwise stay at 1.
|
||||
if (this.backlogTurns === 0) {
|
||||
this.renderEveryN = 1;
|
||||
this.renderSkipCounter = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
const HIGH_BACKLOG = 200;
|
||||
const LOW_BACKLOG = 50;
|
||||
const HIGH_FRAME_MS = 25;
|
||||
const LOW_FRAME_MS = 18;
|
||||
|
||||
if (this.backlogTurns > HIGH_BACKLOG && frameDuration > HIGH_FRAME_MS) {
|
||||
// We are far behind and frames are heavy → render less often.
|
||||
// Only throttle rendering if backlog is still growing; otherwise drift back toward 1.
|
||||
if (this.backlogGrowing && frameDuration > HIGH_FRAME_MS) {
|
||||
if (this.renderEveryN < this.MAX_RENDER_EVERY_N) {
|
||||
this.renderEveryN++;
|
||||
}
|
||||
} else if (
|
||||
this.backlogTurns < LOW_BACKLOG ||
|
||||
(frameDuration > 0 && frameDuration < LOW_FRAME_MS)
|
||||
!this.backlogGrowing &&
|
||||
frameDuration > 0 &&
|
||||
frameDuration < LOW_FRAME_MS
|
||||
) {
|
||||
// Either mostly caught up or frames are cheap again → move back toward normal.
|
||||
if (this.renderEveryN > 1) {
|
||||
this.renderEveryN--;
|
||||
}
|
||||
@@ -625,27 +620,12 @@ export class ClientGameRunner {
|
||||
|
||||
private updateBacklogMetrics(processedTick: number) {
|
||||
this.lastProcessedTick = processedTick;
|
||||
const previousBacklog = this.backlogTurns;
|
||||
this.backlogTurns = Math.max(
|
||||
0,
|
||||
this.serverTurnHighWater - this.lastProcessedTick,
|
||||
);
|
||||
|
||||
const wasCatchUp = this.catchUpMode;
|
||||
if (!this.catchUpMode && this.backlogTurns >= this.CATCH_UP_ENTER_BACKLOG) {
|
||||
this.catchUpMode = true;
|
||||
} else if (
|
||||
this.catchUpMode &&
|
||||
this.backlogTurns <= this.CATCH_UP_EXIT_BACKLOG
|
||||
) {
|
||||
this.catchUpMode = false;
|
||||
}
|
||||
if (wasCatchUp !== this.catchUpMode) {
|
||||
console.log(
|
||||
`Catch-up mode ${this.catchUpMode ? "enabled" : "disabled"} (backlog: ${
|
||||
this.backlogTurns
|
||||
} turns)`,
|
||||
);
|
||||
}
|
||||
this.backlogGrowing = this.backlogTurns > previousBacklog;
|
||||
}
|
||||
|
||||
private inputEvent(event: MouseUpEvent) {
|
||||
|
||||
Reference in New Issue
Block a user