From e4f91b4b5a406cc6531595698e973d125a0687d8 Mon Sep 17 00:00:00 2001 From: DeathByDenim Date: Sun, 7 May 2023 12:15:21 -0400 Subject: [PATCH] Add ranking to Xonotic scripts and clean up names --- website/js/xonscore.js | 186 ++++++++++++++++++++++++---------------- website/tournament.html | 3 + 2 files changed, 115 insertions(+), 74 deletions(-) diff --git a/website/js/xonscore.js b/website/js/xonscore.js index c9fc8c9..63a2db0 100644 --- a/website/js/xonscore.js +++ b/website/js/xonscore.js @@ -1,97 +1,135 @@ +// Parse the Xonotic score log format and return a JSON +// The returned data contains data for the individual +// rounds as well as totals async function xonoticGetScores() { const data = await fetch("xonscore.txt"); const text = await data.text(); - let stats = []; + let stats = { + rounds: [], + totals: [] + }; let map_name = "[unknown]"; let duration_in_seconds = 0; let labels = []; let round_stats = []; text.split("\n").forEach((row) => { - const fields = row.split(":"); - if(fields.length > 1) { - const verb = fields[1] - switch(verb) { - case "scores": - map_name = fields[2]; - duration_in_seconds = fields[3]; - break; - case "labels": - if(fields[2] === "player") { - labels = fields[3].split(","); + const fields = row.split(":"); + if(fields.length > 1) { + const verb = fields[1] + switch(verb) { + case "scores": + map_name = fields[2]; + duration_in_seconds = fields[3]; + break; + case "labels": + if(fields[2] === "player") { + labels = fields[3].split(","); + } + break; + case "player": + if(fields[2] === "see-labels") { + if(fields[5] === "spectator") { + break; + } + let split_fields = fields[3].split(","); + let player_name = fields[6] + .replace(/\^.../g, "") + .replaceAll("^7", ""); + let player_stats = {name: player_name}; + for(let i = 0; i < labels.length; i++) { + if(labels[i] != "") { + player_stats[labels[i]] = split_fields[i] + } + } + round_stats.push(player_stats); + } + break; + case "end": + if(round_stats.length > 0) { + round_stats = round_stats.sort((a,b) => +a["score!!"] < +b["score!!"]); + stats.rounds.push({ + map_name: map_name, + duration_in_seconds: duration_in_seconds, + stats: round_stats + }) + } + round_stats = []; + labels = []; + duration_in_seconds = 0; + map_name = ""; + break; } - break; - case "player": - if(fields[2] === "see-labels") { - let split_fields = fields[3].split(","); - let player_stats = {name: fields[6]}; - for(let i = 0; i < labels.length; i++) { - if(labels[i] != "") { - player_stats[labels[i]] = split_fields[i] - } - } - round_stats.push(player_stats); - } - break; - case "end": - if(round_stats.length > 0) { - round_stats = round_stats.sort((a,b) => +a["score!!"] < +b["score!!"]); - stats.push({ - map_name: map_name, - duration_in_seconds: duration_in_seconds, - stats: round_stats - }) - } - round_stats = []; - labels = []; - duration_in_seconds = 0; - map_name = ""; - break; } - } }) + let final = {}; + stats.rounds.forEach((map) => { + map.stats.forEach((stat) => { + if(stat.name in final) { + final[stat.name] += +stat["score!!"] + } + else { + final[stat.name] = +stat["score!!"] + } + }); + }); + + Object.keys(final).forEach(name => { + stats.totals.push({ + name: name, + score: final[name] + }) + }); + stats.totals = stats.totals.sort((a,b) => a.score < b.score); + return stats; } function xonoticScoreUpdate() { xonoticGetScores().then((data) => { - let tables = d3.select("#xonotic-results") - .selectAll("table") - .data(data) - .join( - (enter) => { - let table = enter.append("table"); - let thead = table.append("thead"); - thead.append("tr") - .append("th") - .attr("colspan", 5) - .text((d) => "Map name: " + d.map_name); - let headerrows = thead.append("tr"); + d3.select("#xonotic-ranking") + .selectAll("li") + .data(data.totals) + .join("li") + .text(d => d.name + " (" + d.score + ")"); - ["Name", "Score", "Kills", "Deaths", "Suicides"].forEach((col) => { - headerrows.append("th").text(col); - }) + let tables = d3.select("#xonotic-results") + .selectAll("table") + .data(data.rounds) + .join( + (enter) => { + let table = enter.append("table"); + let thead = table.append("thead"); + thead.append("tr") + .append("th") + .attr("colspan", 5) + .text((d) => "Map name: " + d.map_name); + let headerrows = thead.append("tr"); - table.append("tbody"); - return table; - }, - (update) => { - let u = update; - u.select("th").text((d) => "Map name: " + d.map_name); - return u; - }, - (exit) => exit.remove() - ) - .classed("table", true); + ["Name", "Score", "Kills", "Deaths", "Suicides"].forEach((col) => { + headerrows.append("th").text(col); + }) - let tbodies = tables.select('tbody'); - tbodies.selectAll("tr") - .data((d) => d.stats) - .join("tr") - .selectAll("td") - .data((d) => ["name", "score!!", "kills", "deaths<", "suicides<"].map((col) => d[col])) - .join("td") - .text((d) => d); + table.append("tbody"); + return table; + }, + (update) => { + let u = update; + u.select("th").text((d) => "Map name: " + d.map_name); + return u; + }, + (exit) => exit.remove() + ) + .classed("table", true); + + let tbodies = tables.select('tbody'); + tbodies.selectAll("tr") + .data((d) => d.stats) + .join("tr") + .selectAll("td") + .data((d) => ["name", "score!!", "kills", "deaths<", "suicides<"].map((col) => d[col])) + .join("td") + .text((d) => d); }); } diff --git a/website/tournament.html b/website/tournament.html index d525b04..5d8677d 100644 --- a/website/tournament.html +++ b/website/tournament.html @@ -24,6 +24,9 @@ nav_pill: tournament {% endif %} {% endfor %} +

Ranking

+
    +

    Rounds