Add player timing and profile links to server scoreboard
This commit is contained in:
@@ -42,7 +42,7 @@ function mapIdentity(handle: Database.Database, report: GameTelemetry) {
|
||||
|
||||
function fingerprint(report: GameTelemetry): string {
|
||||
// Receipt timestamps and roster ordering do not identify new gameplay.
|
||||
const { receivedAt: _receivedAt, ...event } = report;
|
||||
const { receivedAt: _receivedAt, timing: _timing, ...event } = report;
|
||||
const players = [...event.players].sort((a, b) => a.guid.localeCompare(b.guid));
|
||||
return createHash('sha256').update(JSON.stringify({ ...event, players })).digest('hex');
|
||||
}
|
||||
|
||||
@@ -8,11 +8,25 @@ export function listTelemetry(): GameTelemetry[] {
|
||||
return rows.map(row => JSON.parse(row.payload) as GameTelemetry);
|
||||
}
|
||||
|
||||
export function saveTelemetry(report: GameTelemetry): void {
|
||||
export function saveTelemetry(report: GameTelemetry): GameTelemetry {
|
||||
// Keep callers outside the HTTP route atomic too.
|
||||
const handle = db();
|
||||
handle.transaction(() => {
|
||||
return handle.transaction(() => {
|
||||
const row = handle.prepare('SELECT payload FROM server_telemetry WHERE server = ?').get(report.server) as { payload: string | null } | undefined;
|
||||
const previous: GameTelemetry | undefined = row?.payload ? JSON.parse(row.payload) : undefined;
|
||||
recordLeaderboardTelemetry(handle, report);
|
||||
const match = handle.prepare('SELECT id FROM leaderboard_matches WHERE server = ? ORDER BY id DESC LIMIT 1').get(report.server) as { id: number };
|
||||
const sameMatch = previous?.timing?.matchId === match.id;
|
||||
// A gap beyond the normal heartbeat window cannot establish continuity.
|
||||
const continuous = previous && Date.parse(report.receivedAt) - Date.parse(previous.receivedAt) <= 120_000;
|
||||
report = { ...report, timing: { matchId: match.id, players: Object.fromEntries(report.players.map(player => {
|
||||
const prior = continuous ? previous?.timing?.players[player.guid] : undefined;
|
||||
return [player.guid, {
|
||||
serverJoinedAt: prior?.serverJoinedAt ?? report.receivedAt,
|
||||
matchJoinedAt: sameMatch && prior ? prior.matchJoinedAt : report.receivedAt,
|
||||
roundStarted: sameMatch && prior ? prior.roundStarted : report.event === 'game_start' ? 1 : report.round
|
||||
}];
|
||||
})) } };
|
||||
handle.prepare(`INSERT INTO server_telemetry (server, round, players, received_at, payload)
|
||||
VALUES (?, ?, ?, ?, ?) ON CONFLICT(server) DO UPDATE SET
|
||||
round = excluded.round, players = excluded.players, received_at = excluded.received_at, payload = excluded.payload`)
|
||||
@@ -26,5 +40,6 @@ export function saveTelemetry(report: GameTelemetry): void {
|
||||
AND healthy_at <= ? AND beta_id IN (SELECT id FROM betas WHERE state = 'running')`)
|
||||
.run(report.receivedAt, report.server, report.receivedAt);
|
||||
}
|
||||
return report;
|
||||
})();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user