mirror of
https://github.com/openfrontio/OpenFrontIO.git
synced 2026-06-21 19:01:00 +00:00
Refactor rendering and throttle based on backlog
- Refactor rendering and metrics emission in ClientGameRunner to ensure updates occur only after all processing is complete - Throttle renderGame() based on the current backlog
This commit is contained in:
@@ -28,6 +28,7 @@ import { UserSettings } from "../core/game/UserSettings";
|
||||
import { WorkerClient } from "../core/worker/WorkerClient";
|
||||
import {
|
||||
AutoUpgradeEvent,
|
||||
BacklogStatusEvent,
|
||||
DoBoatAttackEvent,
|
||||
DoGroundAttackEvent,
|
||||
InputHandler,
|
||||
@@ -511,33 +512,35 @@ export class ClientGameRunner {
|
||||
this.pendingStart = 0;
|
||||
}
|
||||
|
||||
if (batch.length > 0 && lastTick !== undefined) {
|
||||
// Only update view and render when ALL processing is complete
|
||||
if (
|
||||
this.pendingStart >= this.pendingUpdates.length &&
|
||||
batch.length > 0 &&
|
||||
lastTick !== undefined
|
||||
) {
|
||||
const combinedGu = this.mergeGameUpdates(batch);
|
||||
if (combinedGu) {
|
||||
this.gameView.update(combinedGu);
|
||||
}
|
||||
|
||||
// Only emit metrics when ALL processing is complete
|
||||
if (this.pendingStart >= this.pendingUpdates.length) {
|
||||
const ticksPerRender =
|
||||
this.lastRenderedTick === 0
|
||||
? lastTick
|
||||
: lastTick - this.lastRenderedTick;
|
||||
this.lastRenderedTick = lastTick;
|
||||
const ticksPerRender =
|
||||
this.lastRenderedTick === 0
|
||||
? lastTick
|
||||
: lastTick - this.lastRenderedTick;
|
||||
this.lastRenderedTick = lastTick;
|
||||
|
||||
this.renderer.tick();
|
||||
this.eventBus.emit(
|
||||
new TickMetricsEvent(
|
||||
lastTickDuration,
|
||||
this.currentTickDelay,
|
||||
this.backlogTurns,
|
||||
ticksPerRender,
|
||||
),
|
||||
);
|
||||
this.renderer.tick();
|
||||
this.eventBus.emit(
|
||||
new TickMetricsEvent(
|
||||
lastTickDuration,
|
||||
this.currentTickDelay,
|
||||
this.backlogTurns,
|
||||
ticksPerRender,
|
||||
),
|
||||
);
|
||||
|
||||
// Reset tick delay for next measurement
|
||||
this.currentTickDelay = undefined;
|
||||
}
|
||||
// Reset tick delay for next measurement
|
||||
this.currentTickDelay = undefined;
|
||||
}
|
||||
|
||||
if (this.pendingStart < this.pendingUpdates.length) {
|
||||
@@ -598,6 +601,9 @@ export class ClientGameRunner {
|
||||
this.serverTurnHighWater - this.lastProcessedTick,
|
||||
);
|
||||
this.backlogGrowing = this.backlogTurns > previousBacklog;
|
||||
this.eventBus.emit(
|
||||
new BacklogStatusEvent(this.backlogTurns, this.backlogGrowing),
|
||||
);
|
||||
}
|
||||
|
||||
private inputEvent(event: MouseUpEvent) {
|
||||
|
||||
@@ -136,6 +136,13 @@ export class TickMetricsEvent implements GameEvent {
|
||||
) {}
|
||||
}
|
||||
|
||||
export class BacklogStatusEvent implements GameEvent {
|
||||
constructor(
|
||||
public readonly backlogTurns: number,
|
||||
public readonly backlogGrowing: boolean,
|
||||
) {}
|
||||
}
|
||||
|
||||
export class InputHandler {
|
||||
private lastPointerX: number = 0;
|
||||
private lastPointerY: number = 0;
|
||||
|
||||
@@ -2,7 +2,10 @@ import { EventBus } from "../../core/EventBus";
|
||||
import { GameView } from "../../core/game/GameView";
|
||||
import { UserSettings } from "../../core/game/UserSettings";
|
||||
import { GameStartingModal } from "../GameStartingModal";
|
||||
import { RefreshGraphicsEvent as RedrawGraphicsEvent } from "../InputHandler";
|
||||
import {
|
||||
BacklogStatusEvent,
|
||||
RefreshGraphicsEvent as RedrawGraphicsEvent,
|
||||
} from "../InputHandler";
|
||||
import { FrameProfiler } from "./FrameProfiler";
|
||||
import { TransformHandler } from "./TransformHandler";
|
||||
import { UIState } from "./UIState";
|
||||
@@ -292,6 +295,9 @@ export function createRenderer(
|
||||
|
||||
export class GameRenderer {
|
||||
private context: CanvasRenderingContext2D;
|
||||
private backlogTurns: number = 0;
|
||||
private backlogGrowing: boolean = false;
|
||||
private lastRenderTime: number = 0;
|
||||
|
||||
constructor(
|
||||
private game: GameView,
|
||||
@@ -309,6 +315,10 @@ export class GameRenderer {
|
||||
|
||||
initialize() {
|
||||
this.eventBus.on(RedrawGraphicsEvent, () => this.redraw());
|
||||
this.eventBus.on(BacklogStatusEvent, (event: BacklogStatusEvent) => {
|
||||
this.backlogTurns = event.backlogTurns;
|
||||
this.backlogGrowing = event.backlogGrowing;
|
||||
});
|
||||
this.layers.forEach((l) => l.init?.());
|
||||
|
||||
document.body.appendChild(this.canvas);
|
||||
@@ -344,6 +354,28 @@ export class GameRenderer {
|
||||
}
|
||||
|
||||
renderGame() {
|
||||
const now = performance.now();
|
||||
|
||||
if (this.backlogTurns > 0) {
|
||||
const BASE_FPS = 60;
|
||||
const MIN_FPS = 20;
|
||||
const BACKLOG_MAX_TURNS = 50;
|
||||
|
||||
const scale = Math.min(1, this.backlogTurns / BACKLOG_MAX_TURNS);
|
||||
const targetFps = BASE_FPS - scale * (BASE_FPS - MIN_FPS);
|
||||
const minFrameInterval = 1000 / targetFps;
|
||||
|
||||
if (this.lastRenderTime !== 0) {
|
||||
const sinceLast = now - this.lastRenderTime;
|
||||
if (sinceLast < minFrameInterval) {
|
||||
requestAnimationFrame(() => this.renderGame());
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.lastRenderTime = now;
|
||||
|
||||
FrameProfiler.clear();
|
||||
const start = performance.now();
|
||||
// Set background
|
||||
|
||||
Reference in New Issue
Block a user