PvP&PvE numbers to Player page

This commit is contained in:
Rsl1122 2019-07-25 19:02:26 +03:00
parent 5bad66bda0
commit e276252893
7 changed files with 351 additions and 92 deletions

View File

@ -0,0 +1,93 @@
/*
* This file is part of Player Analytics (Plan).
*
* Plan is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License v3 as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Plan is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
*/
package com.djrapitops.plan.data.store.mutators;
import com.djrapitops.plan.data.container.PlayerKill;
import com.djrapitops.plan.data.store.containers.DataContainer;
import com.djrapitops.plan.data.store.keys.PlayerKeys;
import com.djrapitops.plan.data.store.objects.DateHolder;
import com.djrapitops.plan.utilities.Predicates;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Predicate;
import java.util.stream.Collectors;
public class PlayerVersusMutator {
private final SessionsMutator sessionsMutator;
private final List<PlayerKill> kills;
private final List<PlayerKill> deaths;
public PlayerVersusMutator(SessionsMutator sessionsMutator, List<PlayerKill> kills, List<PlayerKill> deaths) {
this.sessionsMutator = sessionsMutator;
this.kills = kills;
this.deaths = deaths;
}
public static PlayerVersusMutator forContainer(DataContainer container) {
return new PlayerVersusMutator(
SessionsMutator.forContainer(container),
container.getValue(PlayerKeys.PLAYER_KILLS).orElse(Collections.emptyList()),
container.getValue(PlayerKeys.PLAYER_DEATHS_KILLS).orElse(Collections.emptyList())
);
}
public PlayerVersusMutator filterBetween(long after, long before) {
Predicate<DateHolder> killWithinDate = Predicates.within(after, before);
return new PlayerVersusMutator(
sessionsMutator.filterSessionsBetween(after, before),
kills.stream().filter(killWithinDate).collect(Collectors.toList()),
deaths.stream().filter(killWithinDate).collect(Collectors.toList())
);
}
public int toPlayerKillCount() {
return kills.size();
}
public int toMobKillCount() {
return sessionsMutator.toMobKillCount();
}
public int toPlayerDeathCount() {
return deaths.size();
}
public int toMobDeathCount() {
return toDeathCount() - toPlayerDeathCount();
}
public int toDeathCount() {
return sessionsMutator.toDeathCount();
}
public List<String> toTopWeapons(int limit) {
return kills.stream()
.map(PlayerKill::getWeapon)
.collect(HashMap<String, Integer>::new, (map, weapon) -> map.put(weapon, map.getOrDefault(weapon, 0) + 1), (mapOne, mapTwo) -> {
}) // Collected to Map with weapon counts
.entrySet().stream()
.sorted((one, two) -> Integer.compare(two.getValue(), one.getValue())) // Highest first
.limit(limit)
.map(Map.Entry::getKey)
.collect(Collectors.toList());
}
}

View File

@ -19,10 +19,7 @@ package com.djrapitops.plan.system.json;
import com.djrapitops.plan.data.container.GeoInfo;
import com.djrapitops.plan.data.store.containers.PlayerContainer;
import com.djrapitops.plan.data.store.keys.PlayerKeys;
import com.djrapitops.plan.data.store.mutators.ActivityIndex;
import com.djrapitops.plan.data.store.mutators.PerServerMutator;
import com.djrapitops.plan.data.store.mutators.PingMutator;
import com.djrapitops.plan.data.store.mutators.SessionsMutator;
import com.djrapitops.plan.data.store.mutators.*;
import com.djrapitops.plan.data.time.WorldTimes;
import com.djrapitops.plan.db.Database;
import com.djrapitops.plan.db.access.queries.containers.PlayerContainerQuery;
@ -81,6 +78,7 @@ public class PlayerJSONParser {
Map<String, Object> data = new HashMap<>();
data.put("info", createInfoJSONMap(player, serverNames));
data.put("online_activity", createOnlineActivityJSONMap(sessionsMutator));
data.put("kill_data", createPvPPvEMap(player));
data.put("nicknames", player.getValue(PlayerKeys.NICKNAMES)
.map(nicks -> Nickname.fromDataNicknames(nicks, serverNames, year))
@ -104,28 +102,28 @@ public class PlayerJSONParser {
long now = System.currentTimeMillis();
long monthAgo = now - TimeUnit.DAYS.toMillis(30L);
long weekAgo = now - TimeUnit.DAYS.toMillis(7L);
SessionsMutator sessionsMonth = sessionsMutator.filterSessionsBetween(monthAgo, now);
SessionsMutator sessionsWeek = sessionsMutator.filterSessionsBetween(weekAgo, now);
SessionsMutator sessions30d = sessionsMutator.filterSessionsBetween(monthAgo, now);
SessionsMutator sessions7d = sessions30d.filterSessionsBetween(weekAgo, now);
Map<String, Object> onlineActivity = new HashMap<>();
onlineActivity.put("playtime_30d", timeAmount.apply(sessionsMonth.toPlaytime()));
onlineActivity.put("active_playtime_30d", timeAmount.apply(sessionsMonth.toActivePlaytime()));
onlineActivity.put("afk_time_30d", timeAmount.apply(sessionsMonth.toAfkTime()));
onlineActivity.put("average_session_length_30d", timeAmount.apply(sessionsMonth.toAverageSessionLength()));
onlineActivity.put("session_count_30d", sessionsMonth.count());
onlineActivity.put("player_kill_count_30d", sessionsMonth.toPlayerKillCount());
onlineActivity.put("mob_kill_count_30d", sessionsMonth.toMobKillCount());
onlineActivity.put("death_count_30d", sessionsMonth.toDeathCount());
onlineActivity.put("playtime_30d", timeAmount.apply(sessions30d.toPlaytime()));
onlineActivity.put("active_playtime_30d", timeAmount.apply(sessions30d.toActivePlaytime()));
onlineActivity.put("afk_time_30d", timeAmount.apply(sessions30d.toAfkTime()));
onlineActivity.put("average_session_length_30d", timeAmount.apply(sessions30d.toAverageSessionLength()));
onlineActivity.put("session_count_30d", sessions30d.count());
onlineActivity.put("player_kill_count_30d", sessions30d.toPlayerKillCount());
onlineActivity.put("mob_kill_count_30d", sessions30d.toMobKillCount());
onlineActivity.put("death_count_30d", sessions30d.toDeathCount());
onlineActivity.put("playtime_7d", timeAmount.apply(sessionsWeek.toPlaytime()));
onlineActivity.put("active_playtime_7d", timeAmount.apply(sessionsWeek.toActivePlaytime()));
onlineActivity.put("afk_time_7d", timeAmount.apply(sessionsWeek.toAfkTime()));
onlineActivity.put("average_session_length_7d", timeAmount.apply(sessionsWeek.toAverageSessionLength()));
onlineActivity.put("session_count_7d", sessionsWeek.count());
onlineActivity.put("player_kill_count_7d", sessionsWeek.toPlayerKillCount());
onlineActivity.put("mob_kill_count_7d", sessionsWeek.toMobKillCount());
onlineActivity.put("death_count_7d", sessionsWeek.toDeathCount());
onlineActivity.put("playtime_7d", timeAmount.apply(sessions7d.toPlaytime()));
onlineActivity.put("active_playtime_7d", timeAmount.apply(sessions7d.toActivePlaytime()));
onlineActivity.put("afk_time_7d", timeAmount.apply(sessions7d.toAfkTime()));
onlineActivity.put("average_session_length_7d", timeAmount.apply(sessions7d.toAverageSessionLength()));
onlineActivity.put("session_count_7d", sessions7d.count());
onlineActivity.put("player_kill_count_7d", sessions7d.toPlayerKillCount());
onlineActivity.put("mob_kill_count_7d", sessions7d.toMobKillCount());
onlineActivity.put("death_count_7d", sessions7d.toDeathCount());
return onlineActivity;
}
@ -164,6 +162,78 @@ public class PlayerJSONParser {
return info;
}
private Map<String, Object> createPvPPvEMap(PlayerContainer playerContainer) {
long now = System.currentTimeMillis();
long weekAgo = now - TimeUnit.DAYS.toMillis(7L);
long monthAgo = now - TimeUnit.DAYS.toMillis(30L);
PlayerVersusMutator playerVersus = PlayerVersusMutator.forContainer(playerContainer);
PlayerVersusMutator playerVersus30d = playerVersus.filterBetween(monthAgo, now);
PlayerVersusMutator playerVersus7d = playerVersus30d.filterBetween(weekAgo, now);
Map<String, Object> killData = new HashMap<>();
int pks = playerVersus.toPlayerKillCount();
int pks7d = playerVersus7d.toPlayerKillCount();
int pks30d = playerVersus30d.toPlayerKillCount();
killData.put("player_kills_total", pks);
killData.put("player_kills_30d", pks30d);
killData.put("player_kills_7d", pks7d);
int playerDeaths = playerVersus.toPlayerDeathCount();
int playerDeaths30d = playerVersus30d.toPlayerDeathCount();
int playerDeaths7d = playerVersus7d.toPlayerDeathCount();
killData.put("player_deaths_total", playerDeaths);
killData.put("player_deaths_30d", playerDeaths30d);
killData.put("player_deaths_7d", playerDeaths7d);
double kdr = playerDeaths != 0 ? (double) pks / playerDeaths : pks;
double kdr30d = playerDeaths30d != 0 ? (double) pks30d / playerDeaths30d : pks30d;
double krd7d = playerDeaths7d != 0 ? (double) pks7d / playerDeaths7d : pks7d;
killData.put("player_kdr_total", decimals.apply(kdr));
killData.put("player_kdr_30d", decimals.apply(kdr30d));
killData.put("player_kdr_7d", decimals.apply(krd7d));
int mobKills = playerVersus.toMobKillCount();
int mobKills30d = playerVersus30d.toMobKillCount();
int mobKills7d = playerVersus7d.toMobKillCount();
killData.put("mob_kills_total", mobKills);
killData.put("mob_kills_30d", mobKills30d);
killData.put("mob_kills_7d", mobKills7d);
int deaths = playerVersus.toDeathCount();
int deaths30d = playerVersus30d.toDeathCount();
int deaths7d = playerVersus7d.toDeathCount();
killData.put("deaths_total", deaths);
killData.put("deaths_30d", deaths30d);
killData.put("deaths_7d", deaths7d);
long mobDeaths = deaths - playerDeaths;
long mobDeaths30d = deaths30d - playerDeaths30d;
long mobDeaths7d = deaths7d - playerDeaths7d;
killData.put("mob_deaths_total", mobDeaths);
killData.put("mob_deaths_30d", mobDeaths30d);
killData.put("mob_deaths_7d", mobDeaths7d);
double mobKdr = mobDeaths != 0 ? (double) mobKills / mobDeaths : mobKills;
double mobKdr30d = mobDeaths30d != 0 ? (double) mobKills30d / mobDeaths30d : mobKills30d;
double mobKdr7d = mobDeaths7d != 0 ? (double) mobKills7d / mobDeaths7d : mobKills7d;
killData.put("mob_kdr_total", decimals.apply(mobKdr));
killData.put("mob_kdr_30d", decimals.apply(mobKdr30d));
killData.put("mob_kdr_7d", decimals.apply(mobKdr7d));
List<String> topWeapons = playerVersus.toTopWeapons(3);
killData.put("weapon_1st", getWeapon(topWeapons, 0).orElse("-"));
killData.put("weapon_2nd", getWeapon(topWeapons, 1).orElse("-"));
killData.put("weapon_3rd", getWeapon(topWeapons, 2).orElse("-"));
return killData;
}
private <T> Optional<T> getWeapon(List<T> list, int index) {
return list.size() <= index ? Optional.empty() : Optional.of(list.get(index));
}
public static class Nickname {
private String nickname;
private String server;

View File

@ -37,7 +37,7 @@ public class PvPPvEJSONParser implements TabJSONParser<Map<String, Object>> {
private DBSystem dbSystem;
private Formatter<Double> decimalFormatter;
private Formatter<Double> decimals;
@Inject
public PvPPvEJSONParser(
@ -46,7 +46,7 @@ public class PvPPvEJSONParser implements TabJSONParser<Map<String, Object>> {
) {
this.dbSystem = dbSystem;
decimalFormatter = formatters.decimals();
decimals = formatters.decimals();
}
public Map<String, Object> createJSONAsMap(UUID serverUUID) {
@ -70,9 +70,9 @@ public class PvPPvEJSONParser implements TabJSONParser<Map<String, Object>> {
numbers.put("player_kills_30d", pks30d);
numbers.put("player_kills_7d", pks7d);
numbers.put("player_kdr_avg", decimalFormatter.apply(db.query(KillQueries.averageKDR(0L, now, serverUUID))));
numbers.put("player_kdr_avg_30d", decimalFormatter.apply(db.query(KillQueries.averageKDR(monthAgo, now, serverUUID))));
numbers.put("player_kdr_avg_7d", decimalFormatter.apply(db.query(KillQueries.averageKDR(weekAgo, now, serverUUID))));
numbers.put("player_kdr_avg", decimals.apply(db.query(KillQueries.averageKDR(0L, now, serverUUID))));
numbers.put("player_kdr_avg_30d", decimals.apply(db.query(KillQueries.averageKDR(monthAgo, now, serverUUID))));
numbers.put("player_kdr_avg_7d", decimals.apply(db.query(KillQueries.averageKDR(weekAgo, now, serverUUID))));
Long mobKills = db.query(KillQueries.mobKillCount(0L, now, serverUUID));
Long mobKills30d = db.query(KillQueries.mobKillCount(monthAgo, now, serverUUID));
@ -96,9 +96,12 @@ public class PvPPvEJSONParser implements TabJSONParser<Map<String, Object>> {
numbers.put("mob_deaths_30d", mobDeaths30d);
numbers.put("mob_deaths_7d", mobDeaths7d);
numbers.put("mob_kdr_total", mobDeaths != 0 ? mobKills * 1.0 / mobDeaths : mobKills);
numbers.put("mob_kdr_30d", mobDeaths30d != 0 ? mobKills30d * 1.0 / mobDeaths30d : mobKills30d);
numbers.put("mob_kdr_7d", mobDeaths7d != 0 ? mobKills7d * 1.0 / mobDeaths7d : mobKills7d);
double mobKdr = mobDeaths != 0 ? (double) mobKills / mobDeaths : mobKills;
double mobKdr30d = mobDeaths30d != 0 ? (double) mobKills30d / mobDeaths30d : mobKills30d;
double mobKdr7d = mobDeaths7d != 0 ? (double) mobKills7d / mobDeaths7d : mobKills7d;
numbers.put("mob_kdr_total", decimals.apply(mobKdr));
numbers.put("mob_kdr_30d", decimals.apply(mobKdr30d));
numbers.put("mob_kdr_7d", decimals.apply(mobKdr7d));
return numbers;
}

View File

@ -0,0 +1,37 @@
/*
* This file is part of Player Analytics (Plan).
*
* Plan is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License v3 as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Plan is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
*/
package com.djrapitops.plan.utilities;
import com.djrapitops.plan.data.store.objects.DateHolder;
import java.util.function.Predicate;
/**
* Utility class for different Predicates used in the plugin.
*
* @author Rsl1122
*/
public class Predicates {
public static Predicate<DateHolder> within(long after, long before) {
return holder -> {
long date = holder.getDate();
return after < date && date <= before;
};
}
}

View File

@ -60,6 +60,55 @@ function loadPlayerOverviewValues(json, error) {
$(element).find("#data_deaths_7d").text(data.death_count_7d)
}
/* This function loads PvP & PvE tab */
function loadPvPPvEValues(json, error) {
if (error) {
$('#pvp-pve').addClass('forbidden'); // TODO Figure out 403
return;
}
tab = $('#pvp-pve');
// as Numbers
data = json.kill_data;
element = $(tab).find('#data_numbers');
$(element).find('#data_player_kills_total').text(data.player_kills_total);
$(element).find('#data_player_kills_30d').text(data.player_kills_30d);
$(element).find('#data_player_kills_7d').text(data.player_kills_7d);
$(element).find('#data_player_deaths_total').text(data.player_deaths_total);
$(element).find('#data_player_deaths_30d').text(data.player_deaths_30d);
$(element).find('#data_player_deaths_7d').text(data.player_deaths_7d);
$(element).find('#data_player_kdr_total').text(data.player_kdr_total);
$(element).find('#data_player_kdr_30d').text(data.player_kdr_30d);
$(element).find('#data_player_kdr_7d').text(data.player_kdr_7d);
$(element).find('#data_mob_kills_total').text(data.mob_kills_total);
$(element).find('#data_mob_kills_30d').text(data.mob_kills_30d);
$(element).find('#data_mob_kills_7d').text(data.mob_kills_7d);
$(element).find('#data_mob_deaths_total').text(data.mob_deaths_total);
$(element).find('#data_mob_deaths_30d').text(data.mob_deaths_30d);
$(element).find('#data_mob_deaths_7d').text(data.mob_deaths_7d);
$(element).find('#data_mob_kdr_total').text(data.mob_kdr_total);
$(element).find('#data_mob_kdr_30d').text(data.mob_kdr_30d);
$(element).find('#data_mob_kdr_7d').text(data.mob_kdr_7d);
$(element).find('#data_deaths_total').text(data.deaths_total);
$(element).find('#data_deaths_30d').text(data.deaths_30d);
$(element).find('#data_deaths_7d').text(data.deaths_7d);
// Insights
element = $(tab).find('#data_insights');
$(element).find('#data_weapon_1st').text(data.weapon_1st);
$(element).find('#data_weapon_2nd').text(data.weapon_2nd);
$(element).find('#data_weapon_3rd').text(data.weapon_3rd);
}
function createNicknameTableBody(nicknames) {
var table = '<tbody>';

View File

@ -387,7 +387,7 @@
</div> <!-- /.container-fluid -->
</div> <!-- End of Sessions tab -->
<!-- Begin PvP & PvE Tab -->
<div class="tab">
<div class="tab" id="pvp-pve">
<div class="container-fluid mt-4">
<!-- Page Heading -->
<div class="d-sm-flex align-items-center justify-content-between mb-4">
@ -411,59 +411,62 @@
class="fa fa-fw fa-campground col-red"></i>
PvP & PvE as Numbers</h6>
</div>
<table class="table mb-0">
<table class="table mb-0" id="data_numbers">
<thead>
<th></th>
<th>All Time</th>
<th>Last 30 days</th>
<th>Last 7 days</th>
<tr>
<th></th>
<th>All Time</th>
<th>Last 30 days</th>
<th>Last 7 days</th>
</tr>
</thead>
<tbody>
<tr>
<td><i class="col-red fa fa-fw fa-crosshairs"></i> <b>KDR</b></td>
<td>10.02</td>
<td>5.83</td>
<td>0.97</td>
<td><b><i class="col-red fa fa-fw fa-crosshairs"></i></b> Average KDR / Player
</td>
<td id="data_player_kdr_total"></td>
<td id="data_player_kdr_30d"></td>
<td id="data_player_kdr_7d"></td>
</tr>
<tr>
<td><i class="col-red fa fa-fw fa-crosshairs"></i> Player Kills</td>
<td>342</td>
<td>234</td>
<td>34</td>
<td id="data_player_kills_total"></td>
<td id="data_player_kills_30d"></td>
<td id="data_player_kills_7d"></td>
</tr>
<tr>
<td><i class="col-red fa fa-fw fa-skull"></i> Player Caused Deaths</td>
<td>34</td>
<td>40</td>
<td>35</td>
<td id="data_player_deaths_total"></td>
<td id="data_player_deaths_30d"></td>
<td id="data_player_deaths_7d"></td>
</tr>
</tbody>
<tbody>
<tr>
<td><i class="col-green fa fa-fw fa-crosshairs"></i> <b>Mob KDR</b></td>
<td>2.16</td>
<td>7.21</td>
<td>5.75</td>
<td><b><i class="col-green fa fa-fw fa-crosshairs"></i></b> Average Mob KDR</td>
<td id="data_mob_kdr_total"></td>
<td id="data_mob_kdr_30d"></td>
<td id="data_mob_kdr_7d"></td>
</tr>
<tr>
<td><i class="col-green fa fa-fw fa-crosshairs"></i> Mob Kills</td>
<td>123</td>
<td>44</td>
<td>23</td>
<td id="data_mob_kills_total"></td>
<td id="data_mob_kills_30d"></td>
<td id="data_mob_kills_7d"></td>
</tr>
<tr>
<td><i class="col-green fa fa-fw fa-skull"></i> Mob Caused Deaths</td>
<td>54</td>
<td>6</td>
<td>4</td>
<td id="data_mob_deaths_total"></td>
<td id="data_mob_deaths_30d"></td>
<td id="data_mob_deaths_7d"></td>
</tr>
</tbody>
<tbody>
<tr>
<td><i class="col-black fa fa-fw fa-skull"></i> Deaths</td>
<td>352</td>
<td>123</td>
<td>64</td>
<td id="data_deaths_total"></td>
<td id="data_deaths_30d"></td>
<td id="data_deaths_7d"></td>
</tr>
</tbody>
</table>
@ -477,15 +480,13 @@
class="far fa-fw fa-life-ring col-red"></i>
Insights</h6>
</div>
<div class="card-body">
<div class="card-body" id="data_insights">
<p><i class="col-amber fa fa-fw fa-khanda"></i> Deadliest PvP Weapon
<span class="float-right"><b>Diamond Sword (7 kills)</b></span></p>
<span class="float-right"><b id="data_weapon_1st"></b></span></p>
<p><i class="col-grey fa fa-fw fa-khanda"></i> 2nd PvP Weapon
<span class="float-right"><b>Diamond Axe (4 kills)</b></span></p>
<span class="float-right"><b id="data_weapon_2nd"></b></span></p>
<p><i class="col-brown fa fa-fw fa-khanda"></i> 3rd PvP Weapon
<span class="float-right"><b>Iron Sword (2 kills)</b></span></p>
<p><i class="col-red fa fa-fw fa-skull"></i> Rage Quits
<span class="float-right"><b>4</b></span></p>
<span class="float-right"><b id="data_weapon_3rd"></b></span></p>
</div>
</div>
</div>
@ -1302,6 +1303,7 @@
loadSessionAccordion(json, error);
loadPlayerKills(json, error);
loadPlayerDeaths(json, error);
loadPvPPvEValues(json, error);
if (json) {
var series = {
worldPie: {

View File

@ -2,7 +2,6 @@
<html lang="en">
<head>
<meta charset="utf-8">
<meta content="IE=edge" http-equiv="X-UA-Compatible">
<meta content="width=device-width, initial-scale=1, maximum-scale=1" name="viewport">
@ -14,14 +13,12 @@
<!-- Custom fonts for this template-->
<link crossorigin="anonymous" href="https://use.fontawesome.com/releases/v5.7.1/css/all.css"
integrity="sha384-fnmOCqbTlWIlj8LyTjo7mOUStjsKC4pOpQbqyi7RrhN7udi9RwhKkMHpvLbHG9Sr" rel="stylesheet">
<link
href="https://fonts.googleapis.com/css?family=Nunito:200,200i,300,300i,400,400i,600,600i,700,700i,800,800i,900,900i"
rel="stylesheet">
<link href="https://fonts.googleapis.com/css?family=Nunito:200,200i,300,300i,400,400i,600,600i,700,700i,800,800i,900,900i"
rel="stylesheet">
<!-- Custom styles for this template-->
<link href="css/sb-admin-2.css" rel="stylesheet">
<link href="css/style.css" rel="stylesheet">
</head>
<body id="page-top">
@ -254,13 +251,15 @@
</div>
<table class="table mb-0">
<thead>
<th><i class="text-success fa fa-caret-up"></i><i
class="text-danger fa fa-caret-down"></i>
<small>Comparing 7 days</small>
</th>
<th>7 days before (22.1. - 29.1.)</th>
<th>Last 7 days (29.1. - 5.2.)</th>
<th>Trend</th>
<tr>
<th><i class="text-success fa fa-caret-up"></i><i
class="text-danger fa fa-caret-down"></i>
<small>Comparing 7 days</small>
</th>
<th>7 days before (22.1. - 29.1.)</th>
<th>Last 7 days (29.1. - 5.2.)</th>
<th>Trend</th>
</tr>
</thead>
<tbody id="data_weeks">
<tr>
@ -376,13 +375,15 @@
</div>
<table class="table" id="data_numbers">
<thead>
<td><i class="text-success fa fa-caret-up"></i><i
class="text-danger fa fa-caret-down"></i>
<small>Comparing 15 days</small>
</td>
<th>Last 30 days</th>
<th>Last 7 days</th>
<th>Last 24 hours</th>
<tr>
<td><i class="text-success fa fa-caret-up"></i><i
class="text-danger fa fa-caret-down"></i>
<small>Comparing 15 days</small>
</td>
<th>Last 30 days</th>
<th>Last 7 days</th>
<th>Last 24 hours</th>
</tr>
</thead>
<tbody>
<tr>
@ -512,10 +513,12 @@
</div>
<table class="table mb-0" id="tableAccordion">
<thead>
<th><i class="fa fa-fw fa-user"></i> Player</th>
<th><i class="far fa-fw fa-clock"></i> Session Started</th>
<th><i class="far fa-fw fa-clock"></i> Length</th>
<th><i class="far fa-fw fa-map"></i> Most played World</th>
<tr>
<th><i class="fa fa-fw fa-user"></i> Player</th>
<th><i class="far fa-fw fa-clock"></i> Session Started</th>
<th><i class="far fa-fw fa-clock"></i> Length</th>
<th><i class="far fa-fw fa-map"></i> Most played World</th>
</tr>
</thead>
<tbody>
</tbody>
@ -589,10 +592,12 @@
</div>
<table class="table" id="data_numbers">
<thead>
<th></th>
<th>All Time</th>
<th>Last 30 days</th>
<th>Last 7 days</th>
<tr>
<th></th>
<th>All Time</th>
<th>Last 30 days</th>
<th>Last 7 days</th>
</tr>
</thead>
<tbody>
<tr>