Exclude same-round departures from games played
This commit is contained in:
@@ -0,0 +1,4 @@
|
||||
// Keep legacy participation countable when its joining round is unknown.
|
||||
// A player who stays through game end counts even without a round change.
|
||||
export const countsAsGamePlayed = `CASE WHEN mp.completed = 1 OR mp.first_observed_round IS NULL
|
||||
OR mp.highest_round > mp.first_observed_round THEN 1 ELSE 0 END`;
|
||||
@@ -1,6 +1,7 @@
|
||||
import { db } from '../db/index.js';
|
||||
import { MIN_RECORDED_ROUND } from '../../match-history.js';
|
||||
import { getPersonalBestRecords } from './leaderboard-records.js';
|
||||
import { countsAsGamePlayed } from './leaderboard-participation.js';
|
||||
import { EFFICIENCY_MIN_GAMES, EFFICIENCY_MIN_KILLS, EFFICIENCY_MIN_DOWNS,
|
||||
isEfficiencyMetric } from '../../leaderboard-efficiency.js';
|
||||
import { leaderboardMetrics, type LeaderboardEntry, type LeaderboardMap, type LeaderboardMetric,
|
||||
@@ -74,6 +75,7 @@ function readLeaderboard(options: LeaderboardOptions, exactGuid?: string): Leade
|
||||
const aggregated = `WITH observations AS ${observationStorage} (
|
||||
SELECT mp.match_id, mp.guid, mp.highest_round, mp.kills, mp.rounds_survived,
|
||||
mp.headshots, mp.revives, mp.downs, mp.completed, mp.best_score, mp.last_seen_at,
|
||||
${countsAsGamePlayed} AS counts_as_game,
|
||||
m.started_at AS matchStartedAt, m.last_received_at AS matchUpdatedAt
|
||||
FROM leaderboard_match_players mp JOIN leaderboard_matches m ON m.id = mp.match_id
|
||||
WHERE ${conditions.join(' AND ')}
|
||||
@@ -81,7 +83,7 @@ function readLeaderboard(options: LeaderboardOptions, exactGuid?: string): Leade
|
||||
SELECT guid, MAX(highest_round) AS highestRound,
|
||||
SUM(kills) AS kills, SUM(rounds_survived) AS roundsSurvived,
|
||||
SUM(headshots) AS headshots, SUM(revives) AS revives, SUM(downs) AS downs,
|
||||
COUNT(*) AS gamesPlayed, SUM(completed) AS gamesCompleted,
|
||||
SUM(counts_as_game) AS gamesPlayed, SUM(completed) AS gamesCompleted,
|
||||
MAX(kills) AS bestKills, MAX(best_score) AS bestScore, MAX(last_seen_at) AS lastSeen
|
||||
FROM observations GROUP BY guid
|
||||
), measures AS (
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
import { db } from '../db/index.js';
|
||||
import { MIN_RECORDED_ROUND } from '../../match-history.js';
|
||||
import { getPersonalBestRecords } from './leaderboard-records.js';
|
||||
import { countsAsGamePlayed } from './leaderboard-participation.js';
|
||||
import type { LeaderboardOptions, PlayerProfile, PlayerStats, PlayerMapRecord, PlayerMatch } from '../../leaderboard.js';
|
||||
|
||||
const totals = `MAX(mp.highest_round) AS highestRound, SUM(mp.kills) AS kills,
|
||||
SUM(mp.rounds_survived) AS roundsSurvived, SUM(mp.headshots) AS headshots,
|
||||
SUM(mp.revives) AS revives, SUM(mp.downs) AS downs, COUNT(*) AS gamesPlayed,
|
||||
SUM(mp.revives) AS revives, SUM(mp.downs) AS downs, SUM(${countsAsGamePlayed}) AS gamesPlayed,
|
||||
SUM(mp.completed) AS gamesCompleted, MAX(mp.kills) AS bestKills, MAX(mp.best_score) AS bestScore`;
|
||||
const scope = `FROM leaderboard_match_players mp JOIN leaderboard_matches m ON m.id = mp.match_id
|
||||
WHERE m.game IN ('t5', 't6') AND m.status = 'completed' AND mp.guid = ? AND mp.has_stats = 1
|
||||
@@ -20,8 +21,9 @@ export function getPlayerProfile(guid: string, requestedOffset = 0,
|
||||
WHERE game IN ('t5', 't6') AND guid = ? ORDER BY last_seen_at DESC, game LIMIT 1`)
|
||||
.get(guid) as Pick<PlayerProfile, 'guid' | 'name' | 'firstSeen' | 'lastSeen'> | undefined;
|
||||
if (!player) return null;
|
||||
const stats = handle.prepare(`SELECT ${totals} ${scope}`).get(guid) as PlayerStats;
|
||||
if (!stats.gamesPlayed) return null;
|
||||
const { matchCount, ...stats } = handle.prepare(`SELECT COUNT(*) AS matchCount, ${totals} ${scope}`)
|
||||
.get(guid) as PlayerStats & { matchCount: number };
|
||||
if (!matchCount) return null;
|
||||
const historyParameters: Array<string | number> = [guid];
|
||||
let historyScope = scope;
|
||||
if (options.game) { historyScope += ' AND m.game = ?'; historyParameters.push(options.game); }
|
||||
@@ -29,7 +31,7 @@ export function getPlayerProfile(guid: string, requestedOffset = 0,
|
||||
if (options.players) { historyScope += ' AND m.start_players = ?'; historyParameters.push(options.players); }
|
||||
const matchesTotal = options.game || options.map || options.players
|
||||
? (handle.prepare(`SELECT COUNT(*) AS total ${historyScope}`).get(...historyParameters) as { total: number }).total
|
||||
: stats.gamesPlayed;
|
||||
: matchCount;
|
||||
const limit = 25;
|
||||
const lastOffset = Math.max(0, Math.floor((matchesTotal - 1) / limit) * limit);
|
||||
const offset = Number.isSafeInteger(requestedOffset) ? Math.min(lastOffset, Math.max(0, requestedOffset)) : 0;
|
||||
|
||||
Reference in New Issue
Block a user