From d0644858af875d995d365d012537920565aa74aa Mon Sep 17 00:00:00 2001 From: cha0s Date: Wed, 7 Aug 2024 14:29:05 -0500 Subject: [PATCH] feat: heartbeat/rtt --- app/net/client.js | 10 +++++-- app/net/packets/heartbeat.js | 3 +++ app/react/components/devtools.jsx | 5 ++-- app/server/engine.js | 43 +++++++++++++++++++++++++------ 4 files changed, 49 insertions(+), 12 deletions(-) create mode 100644 app/net/packets/heartbeat.js diff --git a/app/net/client.js b/app/net/client.js index f7be2a1..9e71108 100644 --- a/app/net/client.js +++ b/app/net/client.js @@ -1,8 +1,9 @@ -import {CLIENT_LATENCY} from '@/util/constants.js'; +import {CLIENT_LATENCY, CLIENT_PREDICTION} from '@/util/constants.js'; import EventEmitter from '@/util/event-emitter.js'; export default class Client { emitter = new EventEmitter(); + rtt = 0; throughput = {$$down: 0, down: 0, $$up: 0, up: 0}; constructor() { setInterval(() => { @@ -13,6 +14,11 @@ export default class Client { }, 250); } accept(packet) { + if ('Heartbeat' === packet.type) { + this.rtt = packet.payload.rtt; + this.send(packet); + return; + } this.emitter.invoke(packet.type, packet.payload); } addPacketListener(type, listener) { @@ -22,7 +28,7 @@ export default class Client { this.emitter.removeListener(type, listener); } send(packet) { - if (CLIENT_LATENCY > 0) { + if (CLIENT_LATENCY > 0 && !CLIENT_PREDICTION) { setTimeout(() => { this.transmit(packet); }, CLIENT_LATENCY); diff --git a/app/net/packets/heartbeat.js b/app/net/packets/heartbeat.js new file mode 100644 index 0000000..f50a1c2 --- /dev/null +++ b/app/net/packets/heartbeat.js @@ -0,0 +1,3 @@ +import Packet from '@/net/packet.js'; + +export default class Heartbeat extends Packet {} diff --git a/app/react/components/devtools.jsx b/app/react/components/devtools.jsx index 4896bbd..42fc095 100644 --- a/app/react/components/devtools.jsx +++ b/app/react/components/devtools.jsx @@ -34,8 +34,9 @@ export default function Devtools({
-
{Math.round(((client.throughput.down * 8) / 1024) * 10) / 10}kb/s
-
{Math.round(((client.throughput.up * 8) / 1024) * 10) / 10}kb/s
+
{Math.round(client.rtt * 100) / 100}rtt
+
{Math.round(((client.throughput.down * 8) / 1024) * 10) / 10}kb/s down
+
{Math.round(((client.throughput.up * 8) / 1024) * 10) / 10}kb/s up
{mainEntityJson}
diff --git a/app/server/engine.js b/app/server/engine.js index 797fca1..305fdcd 100644 --- a/app/server/engine.js +++ b/app/server/engine.js @@ -117,6 +117,24 @@ export default class Engine { } this.incomingActions.get(connection).push(payload); }); + this.server.addPacketListener('Heartbeat', (connection) => { + const playerData = this.connectedPlayers.get(connection); + const {distance} = playerData; + const now = performance.now(); + distance.rtt = (now - distance.last) / 1000; + playerData.heartbeat = setTimeout(() => { + distance.last = performance.now(); + this.server.send( + connection, + { + type: 'Heartbeat', + payload: { + rtt: distance.rtt, + }, + }, + ); + }, 1000); + }); } acceptActions() { @@ -239,18 +257,26 @@ export default class Engine { } const ecs = this.ecses[entityJson.Ecs.path]; const entity = ecs.get(await ecs.create(entityJson)); - entity.Player.id = id - this.connectedPlayers.set( + entity.Player.id = id; + const playerData = { + distance: {last: performance.now(), rtt: 0}, + entity, + id, + memory: { + chunks: new Map(), + nearby: new Set(), + }, + }; + this.server.send( connection, { - entity, - id, - memory: { - chunks: new Map(), - nearby: new Set(), + type: 'Heartbeat', + payload: { + rtt: 0, }, }, ); + this.connectedPlayers.set(connection, playerData); } createEcs() { @@ -264,7 +290,8 @@ export default class Engine { } this.connectedPlayers.delete(connection); this.incomingActions.delete(connection); - const {entity, id} = connectedPlayer; + const {entity, heartbeat, id} = connectedPlayer; + clearTimeout(heartbeat); const json = entity.toJSON(); const ecs = this.ecses[entity.Ecs.path]; return Promise.all([