Adding support for displaying competitive format stats in the server info

This commit is contained in:
Christian 'ketura' McCarty
2023-01-07 00:27:08 -06:00
parent b6817f3c30
commit ac09a1158d
9 changed files with 140 additions and 63 deletions

View File

@@ -1,21 +1,17 @@
package com.gempukku.lotro.async.handler;
import com.alibaba.fastjson.JSON;
import com.gempukku.lotro.async.HttpProcessingException;
import com.gempukku.lotro.async.ResponseWriter;
import com.gempukku.lotro.common.JSONDefs;
import com.gempukku.lotro.game.GameHistoryService;
import com.gempukku.lotro.game.GameHistoryStatistics;
import com.gempukku.lotro.game.Player;
import io.netty.handler.codec.http.HttpMethod;
import io.netty.handler.codec.http.HttpRequest;
import io.netty.handler.codec.http.QueryStringDecoder;
import org.apache.log4j.Logger;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.lang.reflect.Type;
import java.text.DecimalFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
@@ -56,32 +52,14 @@ public class ServerStatsRequestHandler extends LotroServerRequestHandler impleme
}
long duration = to.getTime() - from;
int activePlayers = _gameHistoryService.getActivePlayersCount(from, duration);
int gamesCount = _gameHistoryService.getGamesPlayedCount(from, duration);
var stats = new JSONDefs.PlayHistoryStats();
stats.ActivePlayers = _gameHistoryService.getActivePlayersCount(from, duration);
stats.GamesCount = _gameHistoryService.getGamesPlayedCount(from, duration);
stats.StartDate = format.format(new Date(from));
stats.EndDate = format.format(new Date(from + duration - 1));
stats.Stats = _gameHistoryService.getGameHistoryStatistics(from, duration);
GameHistoryStatistics gameHistoryStatistics = _gameHistoryService.getGameHistoryStatistics(from, duration);
DecimalFormat percFormat = new DecimalFormat("#0.0%");
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
Document doc = documentBuilder.newDocument();
Element stats = doc.createElement("stats");
stats.setAttribute("activePlayers", String.valueOf(activePlayers));
stats.setAttribute("gamesCount", String.valueOf(gamesCount));
stats.setAttribute("start", format.format(new Date(from)));
stats.setAttribute("end", format.format(new Date(from + duration - 1)));
for (GameHistoryStatistics.FormatStat formatStat : gameHistoryStatistics.getFormatStats()) {
Element formatStatElem = doc.createElement("formatStat");
formatStatElem.setAttribute("format", formatStat.getFormat());
formatStatElem.setAttribute("count", String.valueOf(formatStat.getCount()));
formatStatElem.setAttribute("perc", percFormat.format(formatStat.getPercentage()));
stats.appendChild(formatStatElem);
}
doc.appendChild(stats);
responseWriter.writeXmlResponse(doc);
responseWriter.writeJsonResponse(JSON.toJSONString(stats));
} catch (ParseException exp) {
logHttpError(_log, 400, request.uri(), exp);
throw new HttpProcessingException(400);

View File

@@ -35,7 +35,36 @@
</span>
<input class='getStats' type='button' value='Display Stats'>
</div>
<div id="stats"></div>
<div id="stats">
<div class='period'>Stats for <span id="startDateSpan"></span> - <span id="endDateSpan"></span> </div>
<div class='activePlayers'>Active players: <span id="activePlayersStat"></span></div>
<div class='gamesCount'>All games count: <span id="gamesCountStat"></span></div>
<table class='tables' id="competitiveStatsTable">
<caption>Competitive Games by Format</caption>
<thead>
<tr>
<th>Format name</th>
<th># of games</th>
<th>% of competitive</th>
<th>% of total</th>
</tr>
</thead>
<tbody></tbody>
</table>
<br>
<table class='tables' id="casualStatsTable">
<caption>Casual Games by Format</caption>
<thead>
<tr>
<th>Format name</th>
<th># of games</th>
<th>% of casual</th>
<th>% of total</th>
</tr>
</thead>
<tbody></tbody>
</table>
</div>
</div>
<div id="about" >

View File

@@ -79,7 +79,7 @@ var GempLotrCommunication = Class.extend({
participantId:getUrlParam("participantId") },
success:this.deliveryCheck(callback),
error:this.errorCheck(errorMap),
dataType:"xml"
dataType:"json"
});
},

View File

@@ -35,38 +35,66 @@ var StatsUI = Class.extend({
})
});
},
getPercentage:function (num1, num2) {
return Number(num1 / num2).toLocaleString(undefined, {style: 'percent', minimumFractionDigits:2});
},
loadedStats:function (xml) {
loadedStats:function (json) {
var that = this;
log(xml);
var root = xml.documentElement;
if (root.tagName == 'stats') {
$("#stats").html("");
log(json);
var getPercentage = (num1, num2) => Number(num1 / num2).toLocaleString(undefined, {style: 'percent', minimumFractionDigits:2});
var stats = root;
$("#startDateSpan").html(json["StartDate"]);
$("#endDateSpan").html(json["EndDate"]);
$("#activePlayersStat").html(json["ActivePlayers"]);
$("#gamesCountStat").html(json["GamesCount"]);
var activePlayers = stats.getAttribute("activePlayers");
var gamesCount = stats.getAttribute("gamesCount");
var start = stats.getAttribute("start");
var end = stats.getAttribute("end");
$("#stats").append("<div class='period'>Stats for " + start + " - " + end + "</div>");
$("#stats").append("<div class='activePlayers'>Active players: " + activePlayers + "</div>");
$("#stats").append("<div class='gamesCount'>All games count: " + gamesCount + "</div>");
var formatStats = stats.getElementsByTagName("formatStat");
if (formatStats.length > 0) {
$("#stats").append("<div class='tableHeader'>Casual games per format</div>");
var table = $("<table class='tables'></table>");
table.append("<tr><th>Format name</th><th># of games</th><th>% of casual</th></tr>");
for (var i = 0; i < formatStats.length; i++) {
var formatStat = formatStats[i];
table.append("<tr><td>" + formatStat.getAttribute("format") + "</td><td>" + formatStat.getAttribute("count") + "</td><td>" + formatStat.getAttribute("perc") + "</td></tr>");
var formatStats = json["Stats"];
if (formatStats.length > 0) {
var casualStats = $("#casualStatsTable");
var compStats = $("#competitiveStatsTable");
$("#casualStatsTable > tbody").empty();
$("#competitiveStatsTable > tbody").empty();
var casuals = 0;
var comps = 0;
var total = 0;
json["Stats"].forEach(item => {
if(item.Casual) {
casuals += item.Count;
}
else {
comps += item.Count;
}
total += item.Count;
});
json["Stats"].forEach(item => {
var test = getPercentage(item.Count, total);
if(item.Casual) {
casualStats.append("<tr>"
+ "<td>" + item.Format + "</td>"
+ "<td>" + item.Count + "</td>"
+ "<td>" + getPercentage(item.Count, casuals) + "</td>"
+ "<td>" + getPercentage(item.Count, total) + "</td>"
+ "</tr>");
}
else {
compStats.append("<tr>"
+ "<td>" + item.Format + "</td>"
+ "<td>" + item.Count + "</td>"
+ "<td>" + getPercentage(item.Count, comps) + "</td>"
+ "<td>" + getPercentage(item.Count, total) + "</td>"
+ "</tr>");
}
});
$("#stats").append(table);
}
}
}
});

View File

@@ -65,4 +65,10 @@ public class DBDefs {
public int id;
public String name;
}
public static class FormatStats {
public String Format;
public int Count;
public boolean Casual;
}
}

View File

@@ -73,4 +73,12 @@ public class JSONDefs {
public Map<String, String> ErrataIDs;
}
public static class PlayHistoryStats {
public List<DBDefs.FormatStats> Stats;
public int ActivePlayers;
public int GamesCount;
public String StartDate;
public String EndDate;
}
}

View File

@@ -174,6 +174,34 @@ public class DbGameHistoryDAO implements GameHistoryDAO {
}
}
public List<DBDefs.FormatStats> GetAllGameFormatData(long from, long duration) {
try {
Sql2o db = new Sql2o(_dbAccess.getDataSource());
try (org.sql2o.Connection conn = db.open()) {
String sql = """
SELECT
COUNT(*) AS Count
,format_name AS Format
,CASE WHEN tournament IS NULL OR tournament LIKE 'Casual %' THEN 1 ELSE 0 END AS Casual
FROM game_history
WHERE end_date >= :from
AND end_date < :to
GROUP BY format_name, CASE WHEN tournament IS NULL OR tournament LIKE 'Casual %' THEN 1 ELSE 0 END
""";
List<DBDefs.FormatStats> result = conn.createQuery(sql)
.addParameter("from", from)
.addParameter("to", from + duration)
.executeAndFetch(DBDefs.FormatStats.class);
return result;
}
} catch (Exception ex) {
throw new RuntimeException("Unable to retrieve format stats", ex);
}
}
public List<PlayerStatistic> getCasualPlayerStatistics(Player player) {
try {
try (Connection connection = _dbAccess.getDataSource().getConnection()) {

View File

@@ -22,6 +22,8 @@ public interface GameHistoryDAO {
public Map<String, Integer> getCasualGamesPlayedPerFormat(long from, long duration);
public List<DBDefs.FormatStats> GetAllGameFormatData(long from, long duration);
public List<PlayerStatistic> getCasualPlayerStatistics(Player player);
public List<PlayerStatistic> getCompetitivePlayerStatistics(Player player);

View File

@@ -56,10 +56,8 @@ public class GameHistoryService {
return _gameHistoryDAO.getGamesPlayedCount(from, duration);
}
public GameHistoryStatistics getGameHistoryStatistics(long from, long duration) {
GameHistoryStatistics stats = new GameHistoryStatistics(from, duration);
stats.init(_gameHistoryDAO);
return stats;
public List<DBDefs.FormatStats> getGameHistoryStatistics(long from, long duration) {
return _gameHistoryDAO.GetAllGameFormatData(from, duration);
}
public List<PlayerStatistic> getCasualPlayerStatistics(Player player) {