UNPKG

@rpgjs/physic

Version:

A deterministic 2D top-down physics library for RPG, sandbox and MMO games

89 lines (88 loc) 2.64 kB
class PredictionController { constructor(config) { this.config = config; this.frameCounter = 0; this.history = []; this.pendingSnapshot = null; this.lastAckFrame = 0; this.lastAckTick = 0; this.correctionThreshold = config.correctionThreshold ?? 5; this.historyTtlMs = config.historyTtlMs ?? 2e3; this.maxHistoryEntries = config.maxHistoryEntries ?? 200; } recordInput(direction, timestamp) { const frame = ++this.frameCounter; const tick = this.config.getPhysicsTick(); this.history.push({ frame, tick, timestamp, direction }); this.trimHistory(timestamp); return { frame, tick }; } attachPredictedState(frame, state) { const entry = this.history.find((item) => item.frame === frame); if (entry) { entry.state = state; } } hasPendingInputs() { return this.history.length > 0; } queueServerSnapshot(snapshot) { if (this.hasPendingInputs()) { this.pendingSnapshot = snapshot; return; } this.applySnapshot(snapshot); } tryApplyPendingSnapshot() { if (!this.pendingSnapshot || this.hasPendingInputs()) { return; } this.applySnapshot(this.pendingSnapshot); this.pendingSnapshot = null; } applyServerAck(ack) { if (typeof ack.frame !== "number") { return; } this.lastAckFrame = Math.max(this.lastAckFrame, ack.frame); if (typeof ack.serverTick === "number") { this.lastAckTick = Math.max(this.lastAckTick, ack.serverTick); } this.history = this.history.filter((entry) => entry.frame > this.lastAckFrame); if (ack.state && !this.hasPendingInputs()) { this.applySnapshot(ack.state); this.pendingSnapshot = null; return; } if (this.pendingSnapshot && !this.hasPendingInputs()) { this.applySnapshot(this.pendingSnapshot); this.pendingSnapshot = null; } } cleanup(now) { this.trimHistory(now); } trimHistory(now) { const cutoff = now - this.historyTtlMs; this.history = this.history.filter((entry) => entry.timestamp >= cutoff); if (this.history.length > this.maxHistoryEntries) { this.history = this.history.slice(-this.maxHistoryEntries); } } applySnapshot(snapshot) { const current = this.config.getCurrentState(); const dx = current.x - snapshot.x; const dy = current.y - snapshot.y; const distance = Math.hypot(dx, dy); if (distance > this.correctionThreshold) { this.config.setAuthoritativeState(snapshot); this.history = []; return; } this.history = []; } } export { PredictionController }; //# sourceMappingURL=index44.js.map