diff --git a/Plan/common/src/main/java/com/djrapitops/plan/delivery/domain/TablePlayer.java b/Plan/common/src/main/java/com/djrapitops/plan/delivery/domain/TablePlayer.java new file mode 100644 index 000000000..7ca2f3b87 --- /dev/null +++ b/Plan/common/src/main/java/com/djrapitops/plan/delivery/domain/TablePlayer.java @@ -0,0 +1,182 @@ +/* + * 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.delivery.domain; + +import com.djrapitops.plan.delivery.domain.mutators.ActivityIndex; +import com.djrapitops.plan.gathering.domain.BaseUser; + +import java.util.Objects; +import java.util.Optional; +import java.util.UUID; + +/** + * Represents a player displayed on a player table on players tab or /players page. + * + * @author Rsl1122 + */ +public class TablePlayer implements Comparable { + + private UUID uuid; + private String name; + private ActivityIndex activityIndex; + private Long playtime; + private Integer sessionCount; + private Long registered; + private Long lastSeen; + private String geolocation; + + private boolean banned = false; + + private TablePlayer() { + } + + public static TablePlayer.Builder builder() { + return new TablePlayer.Builder(); + } + + public static TablePlayer.Builder builderFromBaseUser(BaseUser baseUser) { + return new TablePlayer.Builder() + .uuid(baseUser.getUuid()) + .name(baseUser.getName()) + .registered(baseUser.getRegistered()); + } + + public UUID getPlayerUUID() { + return uuid; + } + + public Optional getName() { + return Optional.ofNullable(name); + } + + public Optional getCurrentActivityIndex() { + return Optional.ofNullable(activityIndex); + } + + public Optional getPlaytime() { + return Optional.ofNullable(playtime); + } + + public Optional getSessionCount() { + return Optional.ofNullable(sessionCount); + } + + public Optional getRegistered() { + return Optional.ofNullable(registered); + } + + public Optional getLastSeen() { + return Optional.ofNullable(lastSeen); + } + + public Optional getGeolocation() { + return Optional.ofNullable(geolocation); + } + + public boolean isBanned() { + return banned; + } + + @Override + public int compareTo(TablePlayer other) { + // Most recent first + return Long.compare( + other.lastSeen != null ? other.lastSeen : 0L, + this.lastSeen != null ? this.lastSeen : 0L + ); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof TablePlayer)) return false; + TablePlayer that = (TablePlayer) o; + return playtime == that.playtime && + sessionCount == that.sessionCount && + registered == that.registered && + lastSeen == that.lastSeen && + name.equals(that.name) && + activityIndex.equals(that.activityIndex) && + geolocation.equals(that.geolocation); + } + + @Override + public int hashCode() { + return Objects.hash(name, activityIndex, playtime, sessionCount, registered, lastSeen, geolocation); + } + + public static class Builder { + private final TablePlayer player; + + public Builder() { + player = new TablePlayer(); + } + + public UUID getPlayerUUID() { + return player.uuid; + } + + public Builder uuid(UUID playerUUID) { + player.uuid = playerUUID; + return this; + } + + public Builder name(String name) { + player.name = name; + return this; + } + + public Builder banned() { + player.banned = true; + return this; + } + + public Builder activityIndex(ActivityIndex activityIndex) { + player.activityIndex = activityIndex; + return this; + } + + public Builder playtime(long playtime) { + player.playtime = playtime; + return this; + } + + public Builder sessionCount(int count) { + player.sessionCount = count; + return this; + } + + public Builder registered(long registered) { + player.registered = registered; + return this; + } + + public Builder lastSeen(long lastSeen) { + player.lastSeen = lastSeen; + return this; + } + + public Builder geolocation(String geolocation) { + player.geolocation = geolocation; + return this; + } + + public TablePlayer build() { + return player; + } + } +} \ No newline at end of file diff --git a/Plan/common/src/main/java/com/djrapitops/plan/delivery/rendering/json/JSONFactory.java b/Plan/common/src/main/java/com/djrapitops/plan/delivery/rendering/json/JSONFactory.java index 79fb3f74b..6ec9d9094 100644 --- a/Plan/common/src/main/java/com/djrapitops/plan/delivery/rendering/json/JSONFactory.java +++ b/Plan/common/src/main/java/com/djrapitops/plan/delivery/rendering/json/JSONFactory.java @@ -37,8 +37,6 @@ import com.djrapitops.plan.settings.config.paths.TimeSettings; import com.djrapitops.plan.storage.database.DBSystem; import com.djrapitops.plan.storage.database.Database; import com.djrapitops.plan.storage.database.queries.analysis.PlayerCountQueries; -import com.djrapitops.plan.storage.database.queries.containers.AllPlayerContainersQuery; -import com.djrapitops.plan.storage.database.queries.containers.ServerPlayersTableContainersQuery; import com.djrapitops.plan.storage.database.queries.objects.*; import com.djrapitops.plan.utilities.comparators.SessionStartComparator; @@ -84,9 +82,9 @@ public class JSONFactory { Database database = dbSystem.getDatabase(); return new PlayersTableJSONParser( - database.query(new ServerPlayersTableContainersQuery(serverUUID)), + database.query(new ServerTablePlayersQuery(serverUUID, System.currentTimeMillis(), playtimeThreshold, xMostRecentPlayers)), database.query(new ExtensionServerPlayerDataTableQuery(serverUUID, xMostRecentPlayers)), - xMostRecentPlayers, playtimeThreshold, openPlayerLinksInNewTab, + openPlayerLinksInNewTab, formatters ).toJSONString(); } @@ -99,9 +97,9 @@ public class JSONFactory { Database database = dbSystem.getDatabase(); return new PlayersTableJSONParser( - database.query(new AllPlayerContainersQuery()), // TODO Optimize the heck out of this + Collections.emptyList(),// TODO Replace with new query Collections.emptyMap(), - xMostRecentPlayers, playtimeThreshold, openPlayerLinksInNewTab, + openPlayerLinksInNewTab, formatters ).toJSONString(); } diff --git a/Plan/common/src/main/java/com/djrapitops/plan/delivery/rendering/json/PlayersTableJSONParser.java b/Plan/common/src/main/java/com/djrapitops/plan/delivery/rendering/json/PlayersTableJSONParser.java index 8445d3d02..9d3d54ad0 100644 --- a/Plan/common/src/main/java/com/djrapitops/plan/delivery/rendering/json/PlayersTableJSONParser.java +++ b/Plan/common/src/main/java/com/djrapitops/plan/delivery/rendering/json/PlayersTableJSONParser.java @@ -16,11 +16,8 @@ */ package com.djrapitops.plan.delivery.rendering.json; -import com.djrapitops.plan.delivery.domain.container.PlayerContainer; -import com.djrapitops.plan.delivery.domain.keys.PlayerKeys; +import com.djrapitops.plan.delivery.domain.TablePlayer; import com.djrapitops.plan.delivery.domain.mutators.ActivityIndex; -import com.djrapitops.plan.delivery.domain.mutators.GeoInfoMutator; -import com.djrapitops.plan.delivery.domain.mutators.SessionsMutator; import com.djrapitops.plan.delivery.formatting.Formatter; import com.djrapitops.plan.delivery.formatting.Formatters; import com.djrapitops.plan.delivery.rendering.html.Html; @@ -29,8 +26,6 @@ import com.djrapitops.plan.delivery.rendering.html.icon.Icon; import com.djrapitops.plan.extension.FormatType; import com.djrapitops.plan.extension.icon.Color; import com.djrapitops.plan.extension.implementation.results.*; -import com.djrapitops.plan.gathering.domain.GeoInfo; -import com.djrapitops.plan.utilities.comparators.PlayerContainerLastPlayedComparator; import java.util.*; @@ -43,12 +38,10 @@ import java.util.*; */ public class PlayersTableJSONParser { - private final List players; + private final List players; private final List extensionDescriptives; private final Map extensionData; - private final int maxPlayers; - private final long activeMsThreshold; private final boolean openPlayerPageInNewTab; private Map> numberFormatters; @@ -57,10 +50,10 @@ public class PlayersTableJSONParser { public PlayersTableJSONParser( // Data - List players, + List players, Map extensionData, // Settings - int maxPlayers, long activeMsThreshold, boolean openPlayerPageInNewTab, + boolean openPlayerPageInNewTab, // Formatters Formatters formatters ) { @@ -73,8 +66,6 @@ public class PlayersTableJSONParser { extensionDescriptives.sort((one, two) -> String.CASE_INSENSITIVE_ORDER.compare(one.getName(), two.getName())); // Settings - this.maxPlayers = maxPlayers; - this.activeMsThreshold = activeMsThreshold; this.openPlayerPageInNewTab = openPlayerPageInNewTab; // Formatters numberFormatters = new EnumMap<>(FormatType.class); @@ -107,15 +98,9 @@ public class PlayersTableJSONParser { private String parseData() { StringBuilder dataJSON = new StringBuilder("["); - long now = System.currentTimeMillis(); - players.sort(new PlayerContainerLastPlayedComparator()); - int currentPlayerNumber = 0; - for (PlayerContainer player : players) { - if (currentPlayerNumber >= maxPlayers) { - break; - } - UUID playerUUID = player.getValue(PlayerKeys.UUID).orElse(null); + for (TablePlayer player : players) { + UUID playerUUID = player.getPlayerUUID(); if (playerUUID == null) { continue; } @@ -125,7 +110,7 @@ public class PlayersTableJSONParser { } dataJSON.append('{'); // Start new item - appendPlayerData(dataJSON, now, player); + appendPlayerData(dataJSON, player); appendExtensionData(dataJSON, extensionData.getOrDefault(playerUUID, new ExtensionTabData.Factory(null).build())); dataJSON.append('}'); // Close new item @@ -135,22 +120,21 @@ public class PlayersTableJSONParser { return dataJSON.append(']').toString(); } - private void appendPlayerData(StringBuilder dataJSON, long now, PlayerContainer player) { - String name = player.getValue(PlayerKeys.NAME).orElse("Unknown"); + private void appendPlayerData(StringBuilder dataJSON, TablePlayer player) { + String name = player.getName().orElse(player.getPlayerUUID().toString()); String url = "../player/" + name; - SessionsMutator sessionsMutator = SessionsMutator.forContainer(player); - int loginTimes = sessionsMutator.count(); - long playtime = sessionsMutator.toPlaytime(); - long registered = player.getValue(PlayerKeys.REGISTERED).orElse(0L); - long lastSeen = sessionsMutator.toLastSeen(); + int loginTimes = player.getSessionCount().orElse(0); + long playtime = player.getPlaytime().orElse(-1L); + long registered = player.getRegistered().orElse(-1L); + long lastSeen = player.getLastSeen().orElse(-1L); - ActivityIndex activityIndex = player.getActivityIndex(now, activeMsThreshold); - boolean isBanned = player.getValue(PlayerKeys.BANNED).orElse(false); + ActivityIndex activityIndex = player.getCurrentActivityIndex().orElseGet(() -> new ActivityIndex(0.0, 0)); + boolean isBanned = player.isBanned(); String activityString = activityIndex.getFormattedValue(decimalFormatter) + (isBanned ? " (Banned)" : " (" + activityIndex.getGroup() + ")"); - String geolocation = GeoInfoMutator.forContainer(player).mostRecent().map(GeoInfo::getGeolocation).orElse("-"); + String geolocation = player.getGeolocation().orElse("-"); Html link = openPlayerPageInNewTab ? Html.LINK_EXTERNAL : Html.LINK; diff --git a/Plan/common/src/main/java/com/djrapitops/plan/settings/config/WorldAliasSettings.java b/Plan/common/src/main/java/com/djrapitops/plan/settings/config/WorldAliasSettings.java index 067e45d19..e13a91aad 100644 --- a/Plan/common/src/main/java/com/djrapitops/plan/settings/config/WorldAliasSettings.java +++ b/Plan/common/src/main/java/com/djrapitops/plan/settings/config/WorldAliasSettings.java @@ -112,7 +112,7 @@ public class WorldAliasSettings { String worldName = entry.getKey(); long playtime = entry.getValue(); - if (!aliases.contains(worldName)) { + if (worldName != null && !aliases.contains(worldName)) { addWorld(worldName); } diff --git a/Plan/common/src/main/java/com/djrapitops/plan/storage/database/queries/analysis/ActivityIndexQueries.java b/Plan/common/src/main/java/com/djrapitops/plan/storage/database/queries/analysis/ActivityIndexQueries.java index 866fcb46c..60c27570d 100644 --- a/Plan/common/src/main/java/com/djrapitops/plan/storage/database/queries/analysis/ActivityIndexQueries.java +++ b/Plan/common/src/main/java/com/djrapitops/plan/storage/database/queries/analysis/ActivityIndexQueries.java @@ -27,6 +27,7 @@ import java.sql.ResultSet; import java.sql.SQLException; import java.util.*; import java.util.concurrent.TimeUnit; +import java.util.function.BiConsumer; import static com.djrapitops.plan.storage.database.sql.parsing.Sql.*; @@ -72,7 +73,7 @@ public class ActivityIndexQueries { return fetchActivityGroupCount(date, serverUUID, playtimeThreshold, ActivityIndex.REGULAR, 5.1); } - private static String selectActivityIndexSQL() { + public static String selectActivityIndexSQL() { String selectActivePlaytimeSQL = SELECT + SessionsTable.USER_UUID + ",SUM(" + @@ -93,7 +94,7 @@ public class ActivityIndexQueries { GROUP_BY + "q1." + SessionsTable.USER_UUID; } - private static void setSelectActivityIndexSQLParameters(PreparedStatement statement, int index, long playtimeThreshold, UUID serverUUID, long date) throws SQLException { + public static void setSelectActivityIndexSQLParameters(PreparedStatement statement, int index, long playtimeThreshold, UUID serverUUID, long date) throws SQLException { statement.setDouble(index, Math.PI); statement.setLong(index + 1, playtimeThreshold); @@ -477,4 +478,28 @@ public class ActivityIndexQueries { } }; } + + public static Query activityIndexOnServerToMap(UUID serverUUID, long date, long threshold, BiConsumer consumer) { + String sql = SELECT + "activity_index,n." + UserInfoTable.USER_UUID + + FROM + UserInfoTable.TABLE_NAME + " n" + + LEFT_JOIN + '(' + selectActivityIndexSQL() + ") a on n." + SessionsTable.USER_UUID + "=a." + UserInfoTable.USER_UUID + + WHERE + UserInfoTable.SERVER_UUID + "=?"; + + return new QueryStatement(sql, 1000) { + @Override + public void prepare(PreparedStatement statement) throws SQLException { + setSelectActivityIndexSQLParameters(statement, 1, threshold, serverUUID, date); + statement.setString(2, serverUUID.toString()); + } + + @Override + public Object processResults(ResultSet set) throws SQLException { + while (set.next()) { + double activityIndex = set.getDouble("activity_index"); // Returns 0.0 if missing + consumer.accept(UUID.fromString(set.getString(UserInfoTable.USER_UUID)), activityIndex); + } + return null; + } + }; + } } \ No newline at end of file diff --git a/Plan/common/src/main/java/com/djrapitops/plan/storage/database/queries/containers/ServerPlayersTableContainersQuery.java b/Plan/common/src/main/java/com/djrapitops/plan/storage/database/queries/containers/ServerPlayersTableContainersQuery.java deleted file mode 100644 index 422c1d6f8..000000000 --- a/Plan/common/src/main/java/com/djrapitops/plan/storage/database/queries/containers/ServerPlayersTableContainersQuery.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * 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.storage.database.queries.containers; - -import com.djrapitops.plan.delivery.domain.container.PlayerContainer; -import com.djrapitops.plan.delivery.domain.keys.PlayerKeys; -import com.djrapitops.plan.delivery.domain.mutators.SessionsMutator; -import com.djrapitops.plan.gathering.domain.BaseUser; -import com.djrapitops.plan.gathering.domain.GeoInfo; -import com.djrapitops.plan.gathering.domain.Session; -import com.djrapitops.plan.storage.database.SQLDB; -import com.djrapitops.plan.storage.database.queries.Query; -import com.djrapitops.plan.storage.database.queries.objects.BaseUserQueries; -import com.djrapitops.plan.storage.database.queries.objects.GeoInfoQueries; -import com.djrapitops.plan.storage.database.queries.objects.SessionQueries; -import com.djrapitops.plan.storage.database.queries.objects.UserInfoQueries; - -import java.util.*; - -/** - * Optimized version of {@link ServerPlayerContainersQuery} for /server page Players table. - * - * @author Rsl1122 - * @see com.djrapitops.plan.delivery.rendering.json.PlayersTableJSONParser For what needs to be included. - */ -public class ServerPlayersTableContainersQuery implements Query> { - - private final UUID serverUUID; - - public ServerPlayersTableContainersQuery(UUID serverUUID) { - this.serverUUID = serverUUID; - } - - @Override - public List executeQuery(SQLDB db) { - List containers = new ArrayList<>(); - - Collection baseUsers = db.query(BaseUserQueries.fetchServerBaseUsers(serverUUID)); - - Map> geoInformation = db.query(GeoInfoQueries.fetchServerGeoInformation(serverUUID)); - // TODO Optimize the heck out of this - Map> sessions = db.query(SessionQueries.fetchSessionsOfServer(serverUUID)); - Set bannedUsers = db.query(UserInfoQueries.fetchBannedUUIDsOfServer(serverUUID)); - - for (BaseUser user : baseUsers) { - PlayerContainer container = new PlayerContainer(); - - // BaseUser - UUID uuid = user.getUuid(); - container.putRawData(PlayerKeys.UUID, uuid); - container.putRawData(PlayerKeys.NAME, user.getName()); - container.putRawData(PlayerKeys.REGISTERED, user.getRegistered()); - container.putRawData(PlayerKeys.BANNED, bannedUsers.contains(uuid)); - - // GeoInfo - container.putRawData(PlayerKeys.GEO_INFO, geoInformation.getOrDefault(uuid, new ArrayList<>())); - - container.putCachingSupplier(PlayerKeys.SESSIONS, () -> { - List playerSessions = sessions.getOrDefault(uuid, new ArrayList<>()); - container.getValue(PlayerKeys.ACTIVE_SESSION).ifPresent(playerSessions::add); - return playerSessions; - } - ); - container.putCachingSupplier(PlayerKeys.LAST_SEEN, () -> SessionsMutator.forContainer(container).toLastSeen()); - - containers.add(container); - } - return containers; - } - -} \ No newline at end of file diff --git a/Plan/common/src/main/java/com/djrapitops/plan/storage/database/queries/objects/ServerTablePlayersQuery.java b/Plan/common/src/main/java/com/djrapitops/plan/storage/database/queries/objects/ServerTablePlayersQuery.java new file mode 100644 index 000000000..84b7f42c5 --- /dev/null +++ b/Plan/common/src/main/java/com/djrapitops/plan/storage/database/queries/objects/ServerTablePlayersQuery.java @@ -0,0 +1,134 @@ +/* + * 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.storage.database.queries.objects; + +import com.djrapitops.plan.delivery.domain.TablePlayer; +import com.djrapitops.plan.delivery.domain.mutators.ActivityIndex; +import com.djrapitops.plan.storage.database.SQLDB; +import com.djrapitops.plan.storage.database.queries.Query; +import com.djrapitops.plan.storage.database.queries.QueryStatement; +import com.djrapitops.plan.storage.database.queries.analysis.ActivityIndexQueries; +import com.djrapitops.plan.storage.database.sql.tables.GeoInfoTable; +import com.djrapitops.plan.storage.database.sql.tables.SessionsTable; +import com.djrapitops.plan.storage.database.sql.tables.UserInfoTable; +import com.djrapitops.plan.storage.database.sql.tables.UsersTable; + +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +import static com.djrapitops.plan.storage.database.sql.parsing.Sql.*; + +/** + * Query for displaying players on /server page players tab. + * + * @author Rsl1122 + */ +public class ServerTablePlayersQuery implements Query> { + + private final UUID serverUUID; + private final long date; + private final long activeMsThreshold; + private final int xMostRecentPlayers; + + public ServerTablePlayersQuery(UUID serverUUID, long date, long activeMsThreshold, int xMostRecentPlayers) { + this.serverUUID = serverUUID; + this.date = date; + this.activeMsThreshold = activeMsThreshold; + this.xMostRecentPlayers = xMostRecentPlayers; + } + + @Override + public List executeQuery(SQLDB db) { + String selectGeolocations = SELECT + + GeoInfoTable.USER_UUID + ", " + + GeoInfoTable.GEOLOCATION + ", " + + GeoInfoTable.LAST_USED + + FROM + GeoInfoTable.TABLE_NAME; + String selectLatestGeolocationDate = SELECT + + GeoInfoTable.USER_UUID + ", " + + "MAX(" + GeoInfoTable.LAST_USED + ") as last_used_g" + + FROM + GeoInfoTable.TABLE_NAME + + GROUP_BY + GeoInfoTable.USER_UUID; + String selectLatestGeolocations = SELECT + + "g1." + GeoInfoTable.GEOLOCATION + ',' + + "g1." + GeoInfoTable.USER_UUID + + FROM + "(" + selectGeolocations + ") AS g1" + + INNER_JOIN + "(" + selectLatestGeolocationDate + ") AS g2 ON g1.uuid = g2.uuid" + + WHERE + GeoInfoTable.LAST_USED + "=last_used_g"; + + String selectSessionData = SELECT + "s." + SessionsTable.USER_UUID + ',' + + "MAX(" + SessionsTable.SESSION_END + ") as last_seen," + + "COUNT(1) as count," + + "SUM(" + SessionsTable.SESSION_END + '-' + SessionsTable.SESSION_START + ") as playtime" + + FROM + SessionsTable.TABLE_NAME + " s" + + WHERE + "s." + SessionsTable.SERVER_UUID + "=?" + + GROUP_BY + "s." + SessionsTable.USER_UUID; + + String selectBaseUsers = SELECT + + "u." + UsersTable.USER_UUID + ',' + + "u." + UsersTable.USER_NAME + ',' + + "u." + UsersTable.REGISTERED + ',' + + UserInfoTable.BANNED + ',' + + "geoloc." + GeoInfoTable.GEOLOCATION + ',' + + "ses.last_seen," + + "ses.count," + + "ses.playtime," + + "act.activity_index" + + FROM + UsersTable.TABLE_NAME + " u" + + INNER_JOIN + UserInfoTable.TABLE_NAME + " on u." + UsersTable.USER_UUID + "=" + UserInfoTable.TABLE_NAME + '.' + UserInfoTable.USER_UUID + + LEFT_JOIN + '(' + selectLatestGeolocations + ") geoloc on geoloc." + GeoInfoTable.USER_UUID + "=u." + UsersTable.USER_UUID + + LEFT_JOIN + '(' + selectSessionData + ") ses on ses." + SessionsTable.USER_UUID + "=u." + UsersTable.USER_UUID + + LEFT_JOIN + '(' + ActivityIndexQueries.selectActivityIndexSQL() + ") act on u." + SessionsTable.USER_UUID + "=act." + UserInfoTable.USER_UUID + + WHERE + UserInfoTable.SERVER_UUID + "=?" + + ORDER_BY + "ses.last_seen DESC LIMIT ?"; + + return db.query(new QueryStatement>(selectBaseUsers, 1000) { + @Override + public void prepare(PreparedStatement statement) throws SQLException { + statement.setString(1, serverUUID.toString()); // Session query + ActivityIndexQueries.setSelectActivityIndexSQLParameters(statement, 2, activeMsThreshold, serverUUID, date); + statement.setString(13, serverUUID.toString()); // Session query + statement.setInt(14, xMostRecentPlayers); + } + + @Override + public List processResults(ResultSet set) throws SQLException { + List players = new ArrayList<>(); + while (set.next()) { + TablePlayer.Builder player = TablePlayer.builder() + .uuid(UUID.fromString(set.getString(UsersTable.USER_UUID))) + .name(set.getString(UsersTable.USER_NAME)) + .geolocation(set.getString(GeoInfoTable.GEOLOCATION)) + .registered(set.getLong(UsersTable.REGISTERED)) + .lastSeen(set.getLong("last_seen")) + .sessionCount(set.getInt("count")) + .playtime(set.getLong("playtime")) + .activityIndex(new ActivityIndex(set.getDouble("activity_index"), date)); + if (set.getBoolean(UserInfoTable.BANNED)) { + player.banned(); + } + players.add(player.build()); + } + return players; + } + }); + } +} \ No newline at end of file diff --git a/Plan/common/src/main/java/com/djrapitops/plan/storage/database/queries/objects/SessionQueries.java b/Plan/common/src/main/java/com/djrapitops/plan/storage/database/queries/objects/SessionQueries.java index 2de30cc59..5ba8a6832 100644 --- a/Plan/common/src/main/java/com/djrapitops/plan/storage/database/queries/objects/SessionQueries.java +++ b/Plan/common/src/main/java/com/djrapitops/plan/storage/database/queries/objects/SessionQueries.java @@ -29,7 +29,6 @@ import com.djrapitops.plan.storage.database.queries.QueryStatement; import com.djrapitops.plan.storage.database.sql.parsing.Sql; import com.djrapitops.plan.storage.database.sql.tables.*; import com.djrapitops.plan.utilities.comparators.DateHolderRecentComparator; -import com.djrapitops.plan.utilities.comparators.SessionStartComparator; import java.sql.PreparedStatement; import java.sql.ResultSet; @@ -263,7 +262,7 @@ public class SessionQueries { .flatMap(Collection::stream) .map(SortedMap::values) .flatMap(Collection::stream) - .sorted(new SessionStartComparator()) // Disorder arises + .sorted(dateColderRecentComparator) // Disorder arises .collect(Collectors.toList()); } diff --git a/Plan/common/src/test/java/com/djrapitops/plan/storage/database/DatabaseTest.java b/Plan/common/src/test/java/com/djrapitops/plan/storage/database/DatabaseTest.java index ce8ef6f59..5b75f7462 100644 --- a/Plan/common/src/test/java/com/djrapitops/plan/storage/database/DatabaseTest.java +++ b/Plan/common/src/test/java/com/djrapitops/plan/storage/database/DatabaseTest.java @@ -20,6 +20,7 @@ import com.djrapitops.plan.PlanSystem; import com.djrapitops.plan.data.element.TableContainer; import com.djrapitops.plan.delivery.domain.DateObj; import com.djrapitops.plan.delivery.domain.Nickname; +import com.djrapitops.plan.delivery.domain.TablePlayer; import com.djrapitops.plan.delivery.domain.WebUser; import com.djrapitops.plan.delivery.domain.container.PlayerContainer; import com.djrapitops.plan.delivery.domain.container.ServerContainer; @@ -1406,7 +1407,7 @@ public interface DatabaseTest { } @Test - default void activeTunredInactiveQueryHasAllParametersSet() { + default void activeTurnedInactiveQueryHasAllParametersSet() { Integer result = db().query(ActivityIndexQueries.countRegularPlayersTurnedInactive( 0, System.currentTimeMillis(), serverUUID(), TimeUnit.HOURS.toMillis(2L) @@ -1414,6 +1415,14 @@ public interface DatabaseTest { assertNotNull(result); } + @Test + default void serverTablePlayersQueryQueriesAtLeastOnePlayer() { + sessionsAreStoredWithAllData(); + + List result = db().query(new ServerTablePlayersQuery(serverUUID(), System.currentTimeMillis(), 10L, 1)); + assertNotEquals(Collections.emptyList(), result); + } + @PluginInfo(name = "ConditionalExtension") class ConditionalExtension implements DataExtension {