diff --git a/Plan/common/src/main/java/com/djrapitops/plan/db/access/queries/objects/SessionQueries.java b/Plan/common/src/main/java/com/djrapitops/plan/db/access/queries/objects/SessionQueries.java index 73cd1990e..7c2ce1aaa 100644 --- a/Plan/common/src/main/java/com/djrapitops/plan/db/access/queries/objects/SessionQueries.java +++ b/Plan/common/src/main/java/com/djrapitops/plan/db/access/queries/objects/SessionQueries.java @@ -375,6 +375,25 @@ public class SessionQueries { }; } + public static Query sessionCount(long after, long before) { + String sql = SELECT + "COUNT(1) as count" + + FROM + SessionsTable.TABLE_NAME + + WHERE + SessionsTable.SESSION_END + ">=?" + + AND + SessionsTable.SESSION_START + "<=?"; + return new QueryStatement(sql) { + @Override + public void prepare(PreparedStatement statement) throws SQLException { + statement.setLong(1, after); + statement.setLong(2, before); + } + + @Override + public Long processResults(ResultSet set) throws SQLException { + return set.next() ? set.getLong("count") : 0L; + } + }; + } + public static Query> sessionCountPerDay(long after, long before, long timeZoneOffset, UUID serverUUID) { return database -> { Sql sql = database.getSql(); @@ -430,6 +449,25 @@ public class SessionQueries { }; } + public static Query playtime(long after, long before) { + String sql = SELECT + "SUM(" + SessionsTable.SESSION_END + '-' + SessionsTable.SESSION_START + ") as playtime" + + FROM + SessionsTable.TABLE_NAME + + WHERE + SessionsTable.SESSION_END + ">=?" + + AND + SessionsTable.SESSION_START + "<=?"; + return new QueryStatement(sql) { + @Override + public void prepare(PreparedStatement statement) throws SQLException { + statement.setLong(1, after); + statement.setLong(2, before); + } + + @Override + public Long processResults(ResultSet set) throws SQLException { + return set.next() ? set.getLong("playtime") : 0L; + } + }; + } + public static Query> playtimePerDay(long after, long before, long timeZoneOffset, UUID serverUUID) { return database -> { Sql sql = database.getSql(); diff --git a/Plan/common/src/main/java/com/djrapitops/plan/system/json/network/NetworkOverviewJSONParser.java b/Plan/common/src/main/java/com/djrapitops/plan/system/json/network/NetworkOverviewJSONParser.java new file mode 100644 index 000000000..a4ac36d4f --- /dev/null +++ b/Plan/common/src/main/java/com/djrapitops/plan/system/json/network/NetworkOverviewJSONParser.java @@ -0,0 +1,195 @@ +/* + * 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 . + */ +package com.djrapitops.plan.system.json.network; + +import com.djrapitops.plan.data.store.objects.DateHolder; +import com.djrapitops.plan.data.store.objects.DateObj; +import com.djrapitops.plan.db.Database; +import com.djrapitops.plan.db.access.queries.analysis.NetworkActivityIndexQueries; +import com.djrapitops.plan.db.access.queries.analysis.PlayerCountQueries; +import com.djrapitops.plan.db.access.queries.objects.SessionQueries; +import com.djrapitops.plan.db.access.queries.objects.TPSQueries; +import com.djrapitops.plan.system.database.DBSystem; +import com.djrapitops.plan.system.info.server.ServerInfo; +import com.djrapitops.plan.system.json.Trend; +import com.djrapitops.plan.system.settings.config.PlanConfig; +import com.djrapitops.plan.system.settings.paths.TimeSettings; +import com.djrapitops.plan.utilities.formatting.Formatter; +import com.djrapitops.plan.utilities.formatting.Formatters; + +import javax.inject.Inject; +import javax.inject.Singleton; +import java.util.*; +import java.util.concurrent.TimeUnit; + +/** + * Parses JSON payload for /server-page Server Overview tab. + * + * @author Rsl1122 + */ +@Singleton +public class NetworkOverviewJSONParser implements NetworkTabJSONParser> { + + private final Formatter day; + private final TimeZone timeZone; + private PlanConfig config; + private DBSystem dbSystem; + private ServerInfo serverInfo; + private Formatter timeAmount; + private Formatter decimals; + private Formatter percentage; + private Formatter year; + + @Inject + public NetworkOverviewJSONParser( + PlanConfig config, + DBSystem dbSystem, + ServerInfo serverInfo, + Formatters formatters + ) { + this.config = config; + this.dbSystem = dbSystem; + this.serverInfo = serverInfo; + + year = formatters.year(); + day = formatters.dayLong(); + timeAmount = formatters.timeAmount(); + decimals = formatters.decimals(); + percentage = formatters.percentage(); + this.timeZone = config.getTimeZone(); + } + + public Map createJSONAsMap() { + Map serverOverview = new HashMap<>(); + serverOverview.put("players", createPlayersMap()); + serverOverview.put("numbers", createNumbersMap()); + serverOverview.put("weeks", createWeeksMap()); + return serverOverview; + } + + private Map createPlayersMap() { + Database db = dbSystem.getDatabase(); + long now = System.currentTimeMillis(); + long dayAgo = now - TimeUnit.DAYS.toMillis(1L); + long weekAgo = now - TimeUnit.DAYS.toMillis(7L); + long monthAgo = now - TimeUnit.DAYS.toMillis(30L); + + Map sevenDays = new HashMap<>(); + + sevenDays.put("unique_players_1d", db.query(PlayerCountQueries.uniquePlayerCount(dayAgo, now))); + sevenDays.put("unique_players_7d", db.query(PlayerCountQueries.uniquePlayerCount(weekAgo, now))); + sevenDays.put("unique_players_30d", db.query(PlayerCountQueries.uniquePlayerCount(monthAgo, now))); + + sevenDays.put("new_players_1d", db.query(PlayerCountQueries.newPlayerCount(dayAgo, now))); + sevenDays.put("new_players_7d", db.query(PlayerCountQueries.newPlayerCount(weekAgo, now))); + sevenDays.put("new_players_30d", db.query(PlayerCountQueries.newPlayerCount(monthAgo, now))); + + return sevenDays; + } + + private Map createNumbersMap() { + Database db = dbSystem.getDatabase(); + long now = System.currentTimeMillis(); + long twoDaysAgo = now - TimeUnit.DAYS.toMillis(2L); + Long playtimeThreshold = config.get(TimeSettings.ACTIVE_PLAY_THRESHOLD); + + Map numbers = new HashMap<>(); + + Integer userCount = db.query(PlayerCountQueries.newPlayerCount(0L, now)); + numbers.put("total_players", userCount); + numbers.put("regular_players", db.query(NetworkActivityIndexQueries.fetchRegularPlayerCount(now, playtimeThreshold))); + numbers.put("online_players", getOnlinePlayers()); + UUID serverUUID = serverInfo.getServerUUID(); + Optional> lastPeak = db.query(TPSQueries.fetchPeakPlayerCount(serverUUID, twoDaysAgo)); + Optional> allTimePeak = db.query(TPSQueries.fetchAllTimePeakPlayerCount(serverUUID)); + numbers.put("last_peak_date", lastPeak.map(year).orElse("-")); + numbers.put("last_peak_players", lastPeak.map(dateObj -> dateObj.getValue().toString()).orElse("-")); + numbers.put("best_peak_date", allTimePeak.map(year).orElse("-")); + numbers.put("best_peak_players", allTimePeak.map(dateObj -> dateObj.getValue().toString()).orElse("-")); + Long totalPlaytime = db.query(SessionQueries.playtime(0L, now)); + numbers.put("playtime", timeAmount.apply(totalPlaytime)); + numbers.put("player_playtime", userCount != 0 ? timeAmount.apply(totalPlaytime / userCount) : "-"); + Long sessionCount = db.query(SessionQueries.sessionCount(0L, now)); + numbers.put("sessions", sessionCount); + numbers.put("session_length_avg", sessionCount != 0 ? timeAmount.apply(totalPlaytime / sessionCount) : "-"); + + return numbers; + } + + private Object getOnlinePlayers() { + return serverInfo.getServerProperties().getOnlinePlayers(); + } + + private Map createWeeksMap() { + Database db = dbSystem.getDatabase(); + long now = System.currentTimeMillis(); + long oneWeekAgo = now - TimeUnit.DAYS.toMillis(7L); + long twoWeeksAgo = now - TimeUnit.DAYS.toMillis(14L); + Long playtimeThreshold = config.get(TimeSettings.ACTIVE_PLAY_THRESHOLD); + + Map weeks = new HashMap<>(); + + weeks.put("start", day.apply(twoWeeksAgo)); + weeks.put("midpoint", day.apply(oneWeekAgo)); + weeks.put("end", day.apply(now)); + + Integer uniqueBefore = db.query(PlayerCountQueries.uniquePlayerCount(twoWeeksAgo, oneWeekAgo)); + Integer uniqueAfter = db.query(PlayerCountQueries.uniquePlayerCount(oneWeekAgo, now)); + Trend uniqueTrend = new Trend(uniqueBefore, uniqueAfter, false); + weeks.put("unique_before", uniqueBefore); + weeks.put("unique_after", uniqueAfter); + weeks.put("unique_trend", uniqueTrend); + + Integer newBefore = db.query(PlayerCountQueries.newPlayerCount(twoWeeksAgo, oneWeekAgo)); + Integer newAfter = db.query(PlayerCountQueries.newPlayerCount(oneWeekAgo, now)); + Trend newTrend = new Trend(newBefore, newAfter, false); + weeks.put("new_before", newBefore); + weeks.put("new_after", newAfter); + weeks.put("new_trend", newTrend); + + int regularBefore = db.query(NetworkActivityIndexQueries.fetchRegularPlayerCount(oneWeekAgo, playtimeThreshold)); + int regularAfter = db.query(NetworkActivityIndexQueries.fetchRegularPlayerCount(now, playtimeThreshold)); + weeks.put("regular_before", regularBefore); + weeks.put("regular_after", regularAfter); + weeks.put("regular_trend", new Trend(regularBefore, regularAfter, false)); + + Long playtimeBefore = db.query(SessionQueries.playtime(twoWeeksAgo, oneWeekAgo)); + Long playtimeAfter = db.query(SessionQueries.playtime(oneWeekAgo, now)); + long avgPlaytimeBefore = uniqueBefore != 0 ? playtimeBefore / uniqueBefore : 0L; + long avgPlaytimeAfter = uniqueAfter != 0 ? playtimeAfter / uniqueAfter : 0L; + Trend avgPlaytimeTrend = new Trend(avgPlaytimeBefore, avgPlaytimeAfter, false, timeAmount); + weeks.put("average_playtime_before", timeAmount.apply(avgPlaytimeBefore)); + weeks.put("average_playtime_after", timeAmount.apply(avgPlaytimeAfter)); + weeks.put("average_playtime_trend", avgPlaytimeTrend); + + Long sessionsBefore = db.query(SessionQueries.sessionCount(twoWeeksAgo, oneWeekAgo)); + Long sessionsAfter = db.query(SessionQueries.sessionCount(oneWeekAgo, now)); + Trend sessionsTrend = new Trend(sessionsBefore, sessionsAfter, false); + weeks.put("sessions_before", sessionsBefore); + weeks.put("sessions_after", sessionsAfter); + weeks.put("sessions_trend", sessionsTrend); + + long avgSessionLengthBefore = sessionsBefore != 0 ? playtimeBefore / sessionsBefore : 0; + long avgSessionLengthAfter = sessionsAfter != 0 ? playtimeAfter / sessionsAfter : 0; + Trend avgSessionLengthTrend = new Trend(avgSessionLengthBefore, avgSessionLengthAfter, false, timeAmount); + weeks.put("session_length_average_before", timeAmount.apply(avgSessionLengthBefore)); + weeks.put("session_length_average_after", timeAmount.apply(avgSessionLengthAfter)); + weeks.put("session_length_average_trend", avgSessionLengthTrend); + + return weeks; + } +} \ No newline at end of file diff --git a/Plan/common/src/main/java/com/djrapitops/plan/system/webserver/pages/json/NeworkJSONHandler.java b/Plan/common/src/main/java/com/djrapitops/plan/system/webserver/pages/json/NeworkJSONHandler.java index d0c6ac0fa..f68982624 100644 --- a/Plan/common/src/main/java/com/djrapitops/plan/system/webserver/pages/json/NeworkJSONHandler.java +++ b/Plan/common/src/main/java/com/djrapitops/plan/system/webserver/pages/json/NeworkJSONHandler.java @@ -17,6 +17,7 @@ package com.djrapitops.plan.system.webserver.pages.json; import com.djrapitops.plan.api.exceptions.WebUserAuthException; +import com.djrapitops.plan.system.json.network.NetworkOverviewJSONParser; import com.djrapitops.plan.system.json.network.NetworkPlayerBaseOverviewJSONParser; import com.djrapitops.plan.system.json.network.NetworkTabJSONParser; import com.djrapitops.plan.system.webserver.RequestTarget; @@ -38,10 +39,12 @@ public class NeworkJSONHandler extends TreePageHandler { @Inject public NeworkJSONHandler( ResponseFactory responseFactory, + NetworkOverviewJSONParser networkOverviewJSONParser, NetworkPlayerBaseOverviewJSONParser playerBaseOverviewJSONParser ) { super(responseFactory); + registerPage("overview", networkOverviewJSONParser); registerPage("playerbaseOverview", playerBaseOverviewJSONParser); } diff --git a/Plan/common/src/main/resources/assets/plan/web/js/network-values.js b/Plan/common/src/main/resources/assets/plan/web/js/network-values.js index 02b777310..562a944eb 100644 --- a/Plan/common/src/main/resources/assets/plan/web/js/network-values.js +++ b/Plan/common/src/main/resources/assets/plan/web/js/network-values.js @@ -36,28 +36,25 @@ function smallTrend(trend) { } } -/* This function loads Server Overview tab */ -function loadServerOverviewValues(json, error) { +/* This function loads Network Overview tab */ +function loadNetworkOverviewValues(json, error) { if (error) { - $('#server-overview').addClass('forbidden'); // TODO Figure out 403 + $('#network-overview').addClass('forbidden'); // TODO Figure out 403 return; } - tab = $('#server-overview'); + tab = $('#network-overview'); // Last 7 Days - data = json.last_7_days; - element = $(tab).find('#data_7_days'); + data = json.players; + element = $(tab).find('#data_players'); - $(element).find('#data_unique').text(data.unique_players); - $(element).find('#data_unique_day').text(data.unique_players_day); - $(element).find('#data_new').text(data.new_players); - $(element).find('#data_retention').text('(' + data.new_players_retention + '/' + data.new_players + ')'); - $(element).find('#data_retention_perc').text(data.new_players_retention_perc); - - $(element).find('#data_avg_tps').text(data.average_tps); - $(element).find('#data_low_tps_spikes').text(data.low_tps_spikes); - $(element).find('#data_downtime').text(data.downtime); + $(element).find('#data_unique_players_1d').text(data.unique_players_1d); + $(element).find('#data_unique_players_7d').text(data.unique_players_7d); + $(element).find('#data_unique_players_30d').text(data.unique_players_30d); + $(element).find('#data_new_players_1d').text(data.new_players_1d); + $(element).find('#data_new_players_7d').text(data.new_players_7d); + $(element).find('#data_new_players_30d').text(data.new_players_30d); // Server As Numbers data = json.numbers; @@ -74,12 +71,9 @@ function loadServerOverviewValues(json, error) { $(element).find('#data_playtime').text(data.playtime); $(element).find('#data_player_playtime').text(data.player_playtime); + $(element).find('#data_session_length_avg').text(data.session_length_avg); $(element).find('#data_sessions').text(data.sessions); - $(element).find('#data_player_kills').text(data.player_kills); - $(element).find('#data_mob_kills').text(data.mob_kills); - $(element).find('#data_deaths').text(data.deaths); - // Week Comparison data = json.weeks; element = $(tab).find('#data_weeks'); @@ -94,22 +88,16 @@ function loadServerOverviewValues(json, error) { $(element).find('#data_regular_after').text(data.regular_after); $(element).find('#data_regular_trend').replaceWith(trend(data.regular_trend)); - $(element).find('#data_playtime_before').text(data.playtime_before); - $(element).find('#data_playtime_after').text(data.playtime_after); - $(element).find('#data_playtime_trend').replaceWith(trend(data.playtime_trend)); + $(element).find('#data_average_playtime_before').text(data.average_playtime_before); + $(element).find('#data_average_playtime_after').text(data.average_playtime_after); + $(element).find('#data_average_playtime_trend').replaceWith(trend(data.average_playtime_trend)); $(element).find('#data_sessions_before').text(data.sessions_before); $(element).find('#data_sessions_after').text(data.sessions_after); $(element).find('#data_sessions_trend').replaceWith(trend(data.sessions_trend)); + $(element).find('#data_session_length_average_before').text(data.session_length_average_before); + $(element).find('#data_session_length_average_after').text(data.session_length_average_after); + $(element).find('#data_session_length_average_trend').replaceWith(trend(data.session_length_average_trend)); - $(element).find('#data_player_kills_before').text(data.player_kills_before); - $(element).find('#data_player_kills_after').text(data.player_kills_after); - $(element).find('#data_player_kills_trend').replaceWith(trend(data.player_kills_trend)); - $(element).find('#data_mob_kills_before').text(data.mob_kills_before); - $(element).find('#data_mob_kills_after').text(data.mob_kills_after); - $(element).find('#data_mob_kills_trend').replaceWith(trend(data.mob_kills_trend)); - $(element).find('#data_deaths_before').text(data.deaths_before); - $(element).find('#data_deaths_after').text(data.deaths_after); - $(element).find('#data_deaths_trend').replaceWith(trend(data.deaths_trend)) } /* This function loads Online Activity Overview tab */ diff --git a/Plan/common/src/main/resources/assets/plan/web/network.html b/Plan/common/src/main/resources/assets/plan/web/network.html index be34b4209..c7bbba0d1 100644 --- a/Plan/common/src/main/resources/assets/plan/web/network.html +++ b/Plan/common/src/main/resources/assets/plan/web/network.html @@ -140,7 +140,7 @@
-
+
@@ -190,22 +190,22 @@ class="card-header py-3 d-flex flex-row align-items-center justify-content-between">
Players
-
+

Last 24 Hours

Unique Players0

+ class="float-right">

New Players0

+ class="float-right">

Last 7 Days

Unique Players0

+ class="float-right">

New Players0

+ class="float-right">

Last 30 Days

Unique Players0

+ class="float-right">

New Players0

+ class="float-right">

@@ -244,18 +244,6 @@ class="float-right" id="data_session_length_avg">

Sessions

-
-

Total Playtime - 8h 5m 56s

-

Average Playtime / Player - 0s

-

Average Session Length - 0s

-

Sessions98

@@ -269,13 +257,15 @@ - - - - + + + + + + @@ -300,15 +290,15 @@ - - - + + + - - - - + + + + @@ -1303,6 +1293,7 @@
- Comparing 7 days - 7 days before (22.1. - 29.1.)Last 7 days (29.1. - 5.2.)Trend
+ Comparing 7 days + 7 days before (22.1. - 29.1.)Last 7 days (29.1. - 5.2.)Trend
Average Playtime / Player
Sessions Average Session Length
Sessions