Automatic score updating for Xonotic tournament

This commit is contained in:
DeathByDenim 2023-04-23 12:00:42 -04:00
parent 55fa2a41d1
commit cbf6cd07e6
Signed by: DeathByDenim
GPG Key ID: 4A475283D925365B
3 changed files with 113 additions and 1 deletions

View File

@ -53,7 +53,7 @@ sv_vote_call 1
sv_weaponstats_file http://www.xonotic.org/weaponbalance/
sv_logscores_console 1
sv_logscores_file 1
sv_logscores_filename xonotic-scores.log
sv_logscores_filename xonscore.txt
EOF
cat > /etc/systemd/system/xonotic.service <<EOF
@ -85,4 +85,8 @@ location /xonotic {
}
EOF
if ! [ -h /var/www/html/xonscore.txt ]; then
ln -s "${systemuserhome}"/xonotic/data/data/xonscore.txt /var/www/html
fi
firewall-cmd --zone=public --add-port=26000/udp --permanent

96
website/js/xonscore.js Normal file
View File

@ -0,0 +1,96 @@
async function xonoticGetScores() {
const data = await fetch("xonscore.txt");
const text = await data.text();
let stats = [];
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(",");
}
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) {
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;
}
}
})
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");
["Name", "Score", "Kills", "Deaths", "Suicides"].forEach((col) => {
headerrows.append("th").text(col);
})
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);
});
}

View File

@ -2,6 +2,7 @@
layout: default
nav_pill: tournament
---
<script src="js/xonscore.js"></script>
<h1>Tournament</h1>
{% assign sitetime = site.time | date: "%FT%T" %}
{% assign nextevent = site.data.events | where_exp: "item", "item.date >= sitetime" | last %}
@ -23,6 +24,17 @@ nav_pill: tournament
{% endif %}
{% endfor %}
</ul>
<div id="xonotic-results"></div>
<script>
if(typeof d3 === 'undefined') {
document.write('<p><a href="xonscore.csv">Results</a> (allow access to d3js.org for dynamic updates)</p>');
}
else {
xonoticScoreUpdate();
setInterval(xonoticScoreUpdate, 10000);
}
</script>
<noscript><p><a href="xonscore.csv">Results</a> (Enable JavaScript for dynamic updates)</p></noscript>
{% else %}
<p>No tournaments have been planned for the next event.</p>
{% endif %}