Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion TODO.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
- infinite use invite codes (no multi-use support, only single-use)

## Bugs
- server-wide stats page has no PMC/Scav raid breakdown (per-user profile already tracks both)
- restarting a headless client from the main headless page causes you to end up at that headless' info page
- headless client start/stop/restart buttons on `/quma/headless` go past the card length
- currency items (USD, EUR) displayed as roubles instead of as currency balances (Stash)
Expand Down
38 changes: 38 additions & 0 deletions src/db/raids.rs
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,10 @@ pub struct ServerRaidStats {
pub total_raids: i64,
pub unique_players: i64,
pub overall_survival_rate: f64,
pub pmc_raids: i64,
pub scav_raids: i64,
pub pmc_survival_rate: f64,
pub scav_survival_rate: f64,
pub map_counts: Vec<(String, i64)>,
pub top_killers: Vec<(String, i64)>,
pub recent_raids: Vec<(Raid, String)>,
Expand Down Expand Up @@ -513,6 +517,36 @@ impl Database {
0.0
};

// PMC stats
let (pmc_raids, pmc_survived): (i64, i64) = self.conn.query_row(
"SELECT COUNT(*), COALESCE(SUM(CASE WHEN r.exit_status = 'Survived' THEN 1 ELSE 0 END), 0)
FROM raids r JOIN users u ON r.user_id = u.id
WHERE u.is_headless = 0 AND r.player_side = 'Pmc'",
[],
|row| Ok((row.get(0)?, row.get(1)?)),
)?;

let pmc_survival_rate = if pmc_raids > 0 {
(pmc_survived as f64 / pmc_raids as f64) * 100.0
} else {
0.0
};

// Scav stats
let (scav_raids, scav_survived): (i64, i64) = self.conn.query_row(
"SELECT COUNT(*), COALESCE(SUM(CASE WHEN r.exit_status = 'Survived' THEN 1 ELSE 0 END), 0)
FROM raids r JOIN users u ON r.user_id = u.id
WHERE u.is_headless = 0 AND r.player_side = 'Savage'",
[],
|row| Ok((row.get(0)?, row.get(1)?)),
)?;

let scav_survival_rate = if scav_raids > 0 {
(scav_survived as f64 / scav_raids as f64) * 100.0
} else {
0.0
};

let mut map_stmt = self.conn.prepare(
"SELECT r.map, COUNT(DISTINCT COALESCE(r.server_id, 'solo_' || r.id)) as count FROM raids r JOIN users u ON r.user_id = u.id WHERE u.is_headless = 0 GROUP BY r.map ORDER BY count DESC",
)?;
Expand Down Expand Up @@ -540,6 +574,10 @@ impl Database {
total_raids,
unique_players,
overall_survival_rate,
pmc_raids,
scav_raids,
pmc_survival_rate,
scav_survival_rate,
map_counts,
top_killers,
recent_raids,
Expand Down
29 changes: 29 additions & 0 deletions templates/stats.html
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,35 @@ <h1>Stats</h1>
</div>
</div>

<div style="display:grid;grid-template-columns:1fr 1fr;gap:1.5rem;margin-bottom:1.5rem">
<div class="card">
<h2>PMC</h2>
<div class="stat-card-grid">
<div class="stat-card">
<div class="stat-label">Raids</div>
<div class="stat-value">{{ raid_stats.pmc_raids }}</div>
</div>
<div class="stat-card">
<div class="stat-label">Survival Rate</div>
<div class="stat-value">{{ raid_stats.pmc_survival_rate|fmt_pct }}</div>
</div>
</div>
</div>
<div class="card">
<h2>Scav</h2>
<div class="stat-card-grid">
<div class="stat-card">
<div class="stat-label">Raids</div>
<div class="stat-value">{{ raid_stats.scav_raids }}</div>
</div>
<div class="stat-card">
<div class="stat-label">Survival Rate</div>
<div class="stat-value">{{ raid_stats.scav_survival_rate|fmt_pct }}</div>
</div>
</div>
</div>
</div>

<div class="card" style="margin-bottom:1.5rem">
<h2>Active Raids</h2>
<div id="active-raids" hx-get="/quma/api/raids/active" hx-trigger="sse:raidStarted, sse:raidEnded" hx-swap="innerHTML">
Expand Down
Loading