From 5c936df3f65b3f647f04ffda8c94eb0cd9b0c98c Mon Sep 17 00:00:00 2001 From: ari melody Date: Fri, 30 Aug 2024 12:30:53 +0100 Subject: [PATCH] (hopefully) improved reconciliation --- client/js/main.js | 127 +++++++++++++++++++++++++++++++++------------- server/ws.js | 4 ++ 2 files changed, 95 insertions(+), 36 deletions(-) diff --git a/client/js/main.js b/client/js/main.js index de9d254..4325f9d 100644 --- a/client/js/main.js +++ b/client/js/main.js @@ -109,23 +109,32 @@ function start() { break; case "update": { server_tick = data.tick; + var prediction = predictions[data.tick]; + if (prediction) { + Object.keys(predictions).forEach(tick => { + if (tick < data.tick) delete predictions[tick]; + }); + server_ping = new Date() - prediction.time; + } Object.keys(data.players).forEach(id => { const player = players[id]; const update = data.players[id]; - // this should never be true, but just in case - if (!player) return; if (id == client_id) { - // clear all predictions prior to this tick - Object.keys(predictions).forEach(tick => { - if (tick < data.tick) delete predictions[tick]; - }); - var prediction = predictions[data.tick]; if (!prediction) return; - server_ping = new Date() - prediction.time; - if (Math.abs(prediction.x - update.x) > 1) - players[client_id].x = update.x; - if (Math.abs(prediction.y - update.y) > 1) - players[client_id].y = update.y; + const predicted = prediction.player; + // clear all predictions prior to this tick + if (predicted != update) { + var diff_x = predicted.x - update.x; + var diff_y = predicted.y - update.y; + // apply difference to all predictions + Object.values(predictions).forEach(p => { + p.x -= diff_x; + p.y -= diff_y; + }); + // update client state to reflect + player.x -= diff_x; + player.y -= diff_y; + } delete predictions[data.tick]; } else { player.x = update.x; @@ -135,9 +144,33 @@ function start() { Object.keys(data.props).forEach(id => { const prop = props[id]; const update = data.props[id]; + if (!prediction) { + prop.x = update.x; + prop.y = update.y; + prop.xv = update.xv; + prop.yv = update.yv; + return; + } - prop.x = update.x; - prop.y = update.y; + const predicted = prediction.props[id]; + if (predicted != update) { + var diff_x = predicted.x - update.x; + var diff_y = predicted.y - update.y; + var diff_xv = predicted.xv - update.xv; + var diff_yv = predicted.yv - update.yv; + // apply difference to all predictions + Object.values(predictions).forEach(p => { + p.x -= diff_x; + p.y -= diff_y; + p.xv -= diff_xv; + p.yv -= diff_yv; + }); + // update client state to reflect + prop.x -= diff_x; + prop.y -= diff_y; + prop.xv -= diff_xv; + prop.yv -= diff_yv; + } }); break; } @@ -211,6 +244,10 @@ function start() { canvas.addEventListener("keypress", event => { switch (event.key.toLowerCase()) { + case 'i': + enable_interpolation.update(val => !val); + interpolationToggle.checked = enable_interpolation.get(); + break; case 'p': console.log(predictions); break; @@ -288,31 +325,49 @@ function sendChat(msg) { } function update(delta) { + const prediction = { + time: new Date(), + player: {}, + props: {}, + }; + const clientPlayer = players[client_id]; - if (clientPlayer) { - clientPlayer.in_x = input.move_right - input.move_left; - clientPlayer.in_y = input.move_down - input.move_up; + if (!clientPlayer) return; - clientPlayer.update(delta); + clientPlayer.in_x = input.move_right - input.move_left; + clientPlayer.in_y = input.move_down - input.move_up; - // insert prediction for the next server tick - predictions[ticks] = { - time: new Date(), - x: clientPlayer.x, - y: clientPlayer.y, + clientPlayer.update(delta); + + // insert prediction for the next server tick + prediction.player = { + x: clientPlayer.x, + y: clientPlayer.y, + }; + + var t = ticks; + setTimeout(() => { + if (!ws) return; + ws.send(JSON.stringify({ + type: "update", + tick: t, + x: input.move_right - input.move_left, + y: input.move_down - input.move_up, + })); + }, fake_ping.get() / 2); + + Object.keys(props).forEach(id => { + const prop = props[id]; + prop.update(delta, Object.values(players)); + prediction.props[id] = { + x: prop.x, + y: prop.y, + xv: prop.xv, + yv: prop.yv, }; + }); - var t = ticks; - setTimeout(() => { - if (!ws) return; - ws.send(JSON.stringify({ - type: "update", - tick: t, - x: input.move_right - input.move_left, - y: input.move_down - input.move_up, - })); - }, fake_ping.get() / 2); - } + predictions[ticks] = prediction; ticks++; } @@ -337,8 +392,8 @@ function draw() { const server_state = Object.values(predictions)[0]; ctx.fillStyle = "#208020"; ctx.beginPath(); - ctx.rect(server_state.x - Player.SIZE / 2, - server_state.y - Player.SIZE / 2, + ctx.rect(server_state.player.x - Player.SIZE / 2, + server_state.player.y - Player.SIZE / 2, Player.SIZE, Player.SIZE); ctx.stroke(); } diff --git a/server/ws.js b/server/ws.js index a387592..f383cb5 100644 --- a/server/ws.js +++ b/server/ws.js @@ -88,6 +88,8 @@ export function init(http_server) { name: prop.name, x: prop.x, y: prop.y, + xv: prop.xv, + yv: prop.yv, col: prop.colour, sprite: prop.sprite, } @@ -193,6 +195,8 @@ function update() { frame_props[id] = { x: prop.x, y: prop.y, + xv: prop.xv, + yv: prop.yv, } });