Files
electric-cherry/src/lib/leaderboard.ts
T

134 lines
3.6 KiB
TypeScript

import { efficiencyMetrics, type EfficiencyMetric } from './leaderboard-efficiency.js';
export const playerStatMetrics = [
{ key: 'highestRound', label: 'Highest round' },
{ key: 'kills', label: 'Total kills' },
{ key: 'roundsSurvived', label: 'Total rounds' },
{ key: 'headshots', label: 'Headshots' },
{ key: 'revives', label: 'Revives' },
{ key: 'downs', label: 'Downs' },
{ key: 'gamesPlayed', label: 'Games played' },
{ key: 'gamesCompleted', label: 'Games completed' },
{ key: 'bestKills', label: 'Best game kills' },
{ key: 'bestScore', label: 'Highest reported score' }
] as const;
export const leaderboardMetrics = [...playerStatMetrics, ...efficiencyMetrics] as const;
export type LeaderboardMetric = typeof leaderboardMetrics[number]['key'];
export type PlayerStatMetric = typeof playerStatMetrics[number]['key'];
export type PlayerStats = Record<PlayerStatMetric, number>;
export type PersonalBestMetric = 'highestRound' | 'bestKills' | 'bestScore';
export interface RecordEvidence {
matchId: number;
game: string;
mapKey: string;
mapName: string;
server: string;
startedAt: string;
endedAt: string | null;
startObserved: boolean;
presentAtStart: boolean | null;
firstObservedRound: number | null;
value: number;
}
export type PersonalBestRecords = Record<PersonalBestMetric, RecordEvidence>;
export interface PlayerMapRecord extends PlayerStats {
game: string;
key: string;
name: string;
lastSeen: string;
records: PersonalBestRecords;
ranks: Record<PersonalBestMetric, number>;
}
export interface PlayerMatch {
id: number;
game: string;
server: string;
server_deleted_at?: string | null;
mapName: string;
startedAt: string;
lastSeen: string;
status: 'active' | 'completed' | 'interrupted';
completed: number;
highestRound: number;
roundsSurvived: number;
kills: number;
headshots: number;
revives: number;
downs: number;
bestScore: number;
}
export interface PlayerProfile {
guid: string;
name: string;
firstSeen: string;
lastSeen: string;
stats: PlayerStats;
records: PersonalBestRecords;
maps: PlayerMapRecord[];
matches: PlayerMatch[];
matchesTotal: number;
offset: number;
limit: number;
}
export function playerProfileHref(guid: string): string {
return `/leaderboard/players/${encodeURIComponent(guid)}`;
}
export interface LeaderboardEntry extends Record<EfficiencyMetric, number | null> {
rank: number;
guid: string;
name: string;
highestRound: number;
kills: number;
roundsSurvived: number;
headshots: number;
revives: number;
downs: number;
gamesPlayed: number;
gamesCompleted: number;
bestKills: number;
bestScore: number;
lastSeen: string;
records: PersonalBestRecords;
}
export interface LeaderboardMap {
key: string;
game: string;
map: string;
name: string;
}
export type LeaderboardPlayerCount = 1 | 2 | 3 | 4;
export interface LeaderboardOptions {
game?: string;
map?: string;
players?: LeaderboardPlayerCount;
metric?: LeaderboardMetric;
q?: string;
limit?: number;
offset?: number;
}
export interface LeaderboardResponse {
entries: LeaderboardEntry[];
maps: LeaderboardMap[];
total: number;
limit: number;
offset: number;
metric: LeaderboardMetric;
summary: {
players: number;
matches: number;
kills: number;
roundsSurvived: number;
highestRound: number;
firstTrackedAt: string | null;
updatedAt: string | null;
};
}