Optimised snapshot traffic and map rendering
This commit is contained in:
+44
-1
@@ -9,6 +9,11 @@ import { LoginManager } from "../shared/login_manager.js";
|
||||
import { CIVILISATIONS } from "../shared/data.js";
|
||||
import { dateString } from "../shared/game_clock.js";
|
||||
|
||||
// The large per-tile arrays a delta snapshot may leave out when their version
|
||||
// has not moved since the last one sent to that peer. The viewer keeps the
|
||||
// previous copy until it changes.
|
||||
const DELTA_COLLECTIONS = ["territory", "regions", "population", "tileEthnicity"];
|
||||
|
||||
export class GameServer extends EventEmitter {
|
||||
constructor(network) {
|
||||
super();
|
||||
@@ -24,6 +29,10 @@ export class GameServer extends EventEmitter {
|
||||
this.identityCiv = new Map();
|
||||
this._configured = false;
|
||||
this._stateDirty = false;
|
||||
// Per-peer delta bookkeeping: the versions last sent and how many explored
|
||||
// tiles the viewer already has.
|
||||
this._peerSnapshotVersions = new Map();
|
||||
this._peerExploredSent = new Map();
|
||||
}
|
||||
|
||||
isConfigured() {
|
||||
@@ -265,6 +274,10 @@ export class GameServer extends EventEmitter {
|
||||
}
|
||||
|
||||
onPeerJoined(peerId, playerName = "") {
|
||||
// A fresh connection must receive a full snapshot, never a delta against a
|
||||
// previous peer that happened to reuse the id.
|
||||
this._peerSnapshotVersions.delete(peerId);
|
||||
this._peerExploredSent.delete(peerId);
|
||||
if (!this._configured) return;
|
||||
// A returning player keeps the nation they claimed before.
|
||||
if (this._reclaimIdentity(peerId, playerName)) {
|
||||
@@ -284,6 +297,8 @@ export class GameServer extends EventEmitter {
|
||||
onPeerLeft(peerId) {
|
||||
this.peerCiv.delete(peerId);
|
||||
this.peerNames.delete(peerId);
|
||||
this._peerSnapshotVersions.delete(peerId);
|
||||
this._peerExploredSent.delete(peerId);
|
||||
}
|
||||
|
||||
// Indices of the civilisations no connected peer has claimed.
|
||||
@@ -379,12 +394,40 @@ export class GameServer extends EventEmitter {
|
||||
for (const peerId of this.network.getPeerIds()) {
|
||||
const civ = this.peerCiv.has(peerId) ? this.peerCiv.get(peerId) : -1;
|
||||
if (!statsCache.has(civ)) statsCache.set(civ, this.state.viewerStats(civ));
|
||||
const snapshot = this.state.viewerSnapshot(shared, civ, statsCache.get(civ));
|
||||
this.network.send(peerId, {
|
||||
t: "game_state",
|
||||
state: this.state.viewerSnapshot(shared, civ, statsCache.get(civ)),
|
||||
state: this._deltaState(peerId, snapshot),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Trims a viewer snapshot down to what changed since the last one sent to this
|
||||
// peer: the large per-tile arrays are left out while their version is
|
||||
// unchanged, and only the newly explored tiles are shipped. The first
|
||||
// snapshot to a peer (and after a reconnect) is always full.
|
||||
_deltaState(peerId, snapshot) {
|
||||
const versions = snapshot.versions;
|
||||
const previous = this._peerSnapshotVersions.get(peerId);
|
||||
if (!previous) {
|
||||
this._peerSnapshotVersions.set(peerId, versions);
|
||||
this._peerExploredSent.set(peerId, (snapshot.explored || []).length);
|
||||
return { ...snapshot, delta: false };
|
||||
}
|
||||
const state = { ...snapshot, delta: true };
|
||||
for (const key of DELTA_COLLECTIONS) {
|
||||
if (previous[key] === versions[key]) delete state[key];
|
||||
}
|
||||
const explored = snapshot.explored || [];
|
||||
const sent = this._peerExploredSent.get(peerId) || 0;
|
||||
if (explored.length > sent) {
|
||||
state.exploredAdded = explored.slice(sent);
|
||||
this._peerExploredSent.set(peerId, explored.length);
|
||||
}
|
||||
delete state.explored;
|
||||
this._peerSnapshotVersions.set(peerId, versions);
|
||||
return state;
|
||||
}
|
||||
}
|
||||
|
||||
function coordsOf(value) {
|
||||
|
||||
Reference in New Issue
Block a user