furhter bug fixes and updates
This commit is contained in:
@@ -92,25 +92,29 @@ export interface MapPopulationPoint {
|
||||
map_id: number;
|
||||
map_name: string;
|
||||
map_start_dt: string;
|
||||
players_online_at_start: number;
|
||||
map_end_dt: string | null;
|
||||
total_players: number;
|
||||
}
|
||||
|
||||
export async function getMapPopulationSeries(limit = 40): Promise<MapPopulationPoint[]> {
|
||||
// Player count at the moment each map period started — one data point per
|
||||
// map, letting the frontend chart whether population trends up or down
|
||||
// across the rotation. Fetched most-recent-first (for the LIMIT), then
|
||||
// the caller should reverse it back to chronological order for display.
|
||||
export async function getMapPopulationSeries(limit = 40, before?: string): Promise<MapPopulationPoint[]> {
|
||||
// Total DISTINCT players who were connected at any point during each map's
|
||||
// full session (not just at its start) — one data point per map. Fetched
|
||||
// most-recent-first (for the LIMIT), then the caller should reverse it
|
||||
// back to chronological order for display.
|
||||
// `before` (a DB-formatted datetime string) lets the caller page further
|
||||
// back into history than the initial batch, for pan-to-load-more charts.
|
||||
const rows = await query<MapPopulationPoint>(
|
||||
`SELECT m.map_id, m.map_name, m.map_start_dt,
|
||||
(SELECT COUNT(*) FROM playtime_display_sessions s
|
||||
WHERE s.session_start_dt < m.map_start_dt
|
||||
`SELECT m.map_id, m.map_name, m.map_start_dt, ${NEXT_MAP_START('m')} AS map_end_dt,
|
||||
(SELECT COUNT(DISTINCT s.steamid) FROM playtime_display_sessions s
|
||||
WHERE s.session_start_dt < COALESCE(${NEXT_MAP_START('m')}, NOW())
|
||||
AND (s.session_end_dt IS NULL OR s.session_end_dt > m.map_start_dt)
|
||||
) AS players_online_at_start
|
||||
) AS total_players
|
||||
FROM playtime_display_map_history m
|
||||
WHERE ${REAL_MAP_PERIOD}
|
||||
${before ? 'AND m.map_start_dt < ?' : ''}
|
||||
ORDER BY m.map_start_dt DESC
|
||||
LIMIT ?`,
|
||||
[limit],
|
||||
before ? [before, limit] : [limit],
|
||||
);
|
||||
return rows.reverse();
|
||||
}
|
||||
@@ -118,17 +122,32 @@ export async function getMapPopulationSeries(limit = 40): Promise<MapPopulationP
|
||||
export interface CountrySummary {
|
||||
current_country: string;
|
||||
player_count: number;
|
||||
total_minutes: number;
|
||||
avg_minutes: number;
|
||||
}
|
||||
|
||||
export async function getCountriesSummary(): Promise<CountrySummary[]> {
|
||||
// Players with no resolved country are excluded — there's no meaningful
|
||||
// "unknown" country page to select.
|
||||
// "unknown" country page to select. Each player's playtime is the same
|
||||
// "latest session counter snapshot" logic used everywhere else, wrapped
|
||||
// in a derived table so it can be aggregated per country.
|
||||
return query<CountrySummary>(
|
||||
`SELECT current_country, COUNT(*) AS player_count
|
||||
FROM playtime_display_players
|
||||
WHERE current_country IS NOT NULL
|
||||
GROUP BY current_country
|
||||
ORDER BY player_count DESC, current_country ASC`,
|
||||
`SELECT p.current_country, COUNT(*) AS player_count,
|
||||
SUM(pt.total_minutes) AS total_minutes,
|
||||
AVG(pt.total_minutes) AS avg_minutes
|
||||
FROM playtime_display_players p
|
||||
JOIN (
|
||||
SELECT p2.steamid,
|
||||
(SELECT COALESCE(s.session_end_playtime_minutes, s.session_start_playtime_minutes)
|
||||
FROM playtime_display_sessions s
|
||||
WHERE s.steamid = p2.steamid
|
||||
ORDER BY s.session_id DESC
|
||||
LIMIT 1) AS total_minutes
|
||||
FROM playtime_display_players p2
|
||||
) pt ON pt.steamid = p.steamid
|
||||
WHERE p.current_country IS NOT NULL
|
||||
GROUP BY p.current_country
|
||||
ORDER BY player_count DESC, p.current_country ASC`,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -164,6 +183,7 @@ export interface MapSummary {
|
||||
map_name: string;
|
||||
times_played: number;
|
||||
last_played: string;
|
||||
total_minutes: number;
|
||||
}
|
||||
|
||||
export interface MapPeriod {
|
||||
@@ -171,6 +191,7 @@ export interface MapPeriod {
|
||||
map_name: string;
|
||||
map_start_dt: string;
|
||||
map_end_dt: string | null;
|
||||
player_count: number;
|
||||
}
|
||||
|
||||
export interface MapPresentPlayer {
|
||||
@@ -194,7 +215,8 @@ export interface MapVoteRow {
|
||||
export async function searchMapNames(q: string, limit = 50): Promise<MapSummary[]> {
|
||||
const like = `%${q}%`;
|
||||
return query<MapSummary>(
|
||||
`SELECT m.map_name, COUNT(*) AS times_played, MAX(m.map_start_dt) AS last_played
|
||||
`SELECT m.map_name, COUNT(*) AS times_played, MAX(m.map_start_dt) AS last_played,
|
||||
SUM(TIMESTAMPDIFF(MINUTE, m.map_start_dt, COALESCE(${NEXT_MAP_START('m')}, NOW()))) AS total_minutes
|
||||
FROM playtime_display_map_history m
|
||||
WHERE m.map_name LIKE ?
|
||||
AND ${REAL_MAP_PERIOD}
|
||||
@@ -207,7 +229,11 @@ export async function searchMapNames(q: string, limit = 50): Promise<MapSummary[
|
||||
|
||||
export async function getMapPeriods(mapName: string): Promise<MapPeriod[]> {
|
||||
return query<MapPeriod>(
|
||||
`SELECT m.map_id, m.map_name, m.map_start_dt, ${NEXT_MAP_START('m')} AS map_end_dt
|
||||
`SELECT m.map_id, m.map_name, m.map_start_dt, ${NEXT_MAP_START('m')} AS map_end_dt,
|
||||
(SELECT COUNT(DISTINCT s.steamid) FROM playtime_display_sessions s
|
||||
WHERE s.session_start_dt < COALESCE(${NEXT_MAP_START('m')}, NOW())
|
||||
AND (s.session_end_dt IS NULL OR s.session_end_dt > m.map_start_dt)
|
||||
) AS player_count
|
||||
FROM playtime_display_map_history m
|
||||
WHERE m.map_name = ?
|
||||
AND ${REAL_MAP_PERIOD}
|
||||
@@ -218,7 +244,11 @@ export async function getMapPeriods(mapName: string): Promise<MapPeriod[]> {
|
||||
|
||||
export async function getMapPeriod(mapId: number): Promise<MapPeriod | null> {
|
||||
const rows = await query<MapPeriod>(
|
||||
`SELECT m.map_id, m.map_name, m.map_start_dt, ${NEXT_MAP_START('m')} AS map_end_dt
|
||||
`SELECT m.map_id, m.map_name, m.map_start_dt, ${NEXT_MAP_START('m')} AS map_end_dt,
|
||||
(SELECT COUNT(DISTINCT s.steamid) FROM playtime_display_sessions s
|
||||
WHERE s.session_start_dt < COALESCE(${NEXT_MAP_START('m')}, NOW())
|
||||
AND (s.session_end_dt IS NULL OR s.session_end_dt > m.map_start_dt)
|
||||
) AS player_count
|
||||
FROM playtime_display_map_history m
|
||||
WHERE m.map_id = ?`,
|
||||
[mapId],
|
||||
|
||||
@@ -15,9 +15,12 @@ export function steamProfileUrl(steamId2: string): string | null {
|
||||
return id64 ? `https://steamcommunity.com/profiles/${id64}` : null;
|
||||
}
|
||||
|
||||
// Formats total minutes as "123h 45m" for display.
|
||||
// Formats total minutes as "123h 45m" for display. Negative values (which
|
||||
// shouldn't be possible, but have shown up from anomalous underlying data —
|
||||
// e.g. a player_time counter that decreased between two session snapshots)
|
||||
// are shown as "—" rather than a nonsensical negative duration.
|
||||
export function formatMinutes(totalMinutes: number | null): string {
|
||||
if (totalMinutes == null || Number.isNaN(totalMinutes)) return '—';
|
||||
if (totalMinutes == null || Number.isNaN(totalMinutes) || totalMinutes < 0) return '—';
|
||||
const h = Math.floor(totalMinutes / 60);
|
||||
const m = totalMinutes % 60;
|
||||
return `${h}h ${m}m`;
|
||||
|
||||
Reference in New Issue
Block a user