Started work on Activity Index

- New settings for Activity index
- HasDate interface
- Deprecated more AnalysisUtils methods
- playerStatus HtmlStructure parser
- Online status to Inspect page #408 #396
- JavaDocs for more comparators
- More work on ServerProfile
  - TPS spike count, playerkills, mob kills, deaths, server worldtimes, player peaks, online/offline players
This commit is contained in:
Rsl1122 2017-11-21 10:40:39 +02:00
parent 7e743a4eaf
commit 0ff2fe89d6
23 changed files with 477 additions and 28 deletions

View File

@ -31,6 +31,8 @@ public enum Settings {
WEBSERVER_PORT("WebServer.Port"),
DB_PORT("Database.MySQL.Port"),
ANALYSIS_AUTO_REFRESH("Analysis.AutoRefreshPeriod"),
ACTIVE_PLAY_THRESHOLD("Analysis.Active.PlaytimeThreshold"),
ACTIVE_LOGIN_THRESHOLD("Analysis.Active.LoginThreshold"),
// String
DEBUG("Plugin.Debug"),

View File

@ -15,7 +15,7 @@ import java.util.Objects;
*
* @author Rsl1122
*/
public class Action {
public class Action implements HasDate {
private final long date;
private final Actions doneAction;
private final String additionalInfo;

View File

@ -11,7 +11,7 @@ import com.google.common.base.Objects;
*
* @author Rsl1122
*/
public class GeoInfo {
public class GeoInfo implements HasDate {
private final String ip;
private final String geolocation;
@ -35,6 +35,11 @@ public class GeoInfo {
return lastUsed;
}
@Override
public long getDate() {
return getLastUsed();
}
@Override
public boolean equals(Object o) {
if (this == o) return true;

View File

@ -0,0 +1,16 @@
/*
* Licence is provided in the jar as license.yml also here:
* https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml
*/
package main.java.com.djrapitops.plan.data;
/**
* //TODO Class Javadoc Comment
*
* @author Rsl1122
*/
public interface HasDate {
long getDate();
}

View File

@ -13,7 +13,7 @@ import java.util.UUID;
*
* @author Rsl1122
*/
public class PlayerKill {
public class PlayerKill implements HasDate {
private final UUID victim;
private final long time;
@ -50,6 +50,11 @@ public class PlayerKill {
return time;
}
@Override
public long getDate() {
return getTime();
}
/**
* Get the Weapon used as string.
*

View File

@ -4,6 +4,8 @@
*/
package main.java.com.djrapitops.plan.data;
import com.djrapitops.plugin.api.TimeAmount;
import main.java.com.djrapitops.plan.Settings;
import main.java.com.djrapitops.plan.data.time.WorldTimes;
import main.java.com.djrapitops.plan.utilities.MiscUtils;
import main.java.com.djrapitops.plan.utilities.comparators.ActionComparator;
@ -51,7 +53,7 @@ public class PlayerProfile implements OfflinePlayer {
private Map<String, String> pluginReplaceMap;
// Value that requires lot of processing
private Double activityIndex;
private Map<Long, Double> activityIndex;
public PlayerProfile(UUID uuid, String name, long registered) {
this.uuid = uuid;
@ -67,19 +69,67 @@ public class PlayerProfile implements OfflinePlayer {
worldTimesMap = new HashMap<>();
pluginReplaceMap = new HashMap<>();
activityIndex = new HashMap<>();
}
// Calculating Getters
public boolean isActive() {
return getActivityIndex() > 1.0;
public boolean isActive(long date) {
return getActivityIndex(date) > 1.0;
}
public double getActivityIndex() {
if (activityIndex != null) {
return activityIndex;
public double getActivityIndex(long date) {
Double activityIndx = activityIndex.get(date);
if (activityIndx != null) {
return activityIndx;
}
return 0.0; // TODO
long week = TimeAmount.WEEK.ms();
long weekAgo = date - week;
long twoWeeksAgo = date - 2L * week;
long threeWeeksAgo = date - 3L * week;
long activePlayThreshold = Settings.ACTIVE_PLAY_THRESHOLD.getNumber() * TimeAmount.MINUTE.ms();
int activeLoginThreshold = Settings.ACTIVE_LOGIN_THRESHOLD.getNumber();
List<Session> sessionsWeek = getSessions(weekAgo, date).collect(Collectors.toList());
List<Session> sessionsWeek2 = getSessions(twoWeeksAgo, weekAgo).collect(Collectors.toList());
List<Session> sessionsWeek3 = getSessions(threeWeeksAgo, twoWeeksAgo).collect(Collectors.toList());
double weekPlay = (PlayerProfile.getPlaytime(sessionsWeek.stream()) * 1.0 / activePlayThreshold);
double week2Play = (PlayerProfile.getPlaytime(sessionsWeek2.stream()) * 1.0 / activePlayThreshold);
double week3Play = (PlayerProfile.getPlaytime(sessionsWeek3.stream()) * 1.0 / activePlayThreshold);
// Reduce the harshness for new players and players who have had a vacation
if (weekPlay > 1 && week3Play > 1 && week2Play == 0.0) {
week2Play = 0.5;
}
if (weekPlay > 1 && week2Play == 0.0) {
week2Play = 0.6;
}
if (weekPlay > 1 && week3Play == 0.0) {
week3Play = 0.75;
}
double playAvg = (weekPlay + week2Play + week3Play) / 3.0;
double weekLogin = sessionsWeek.size() > activeLoginThreshold ? 1.0 : 0.5;
double week2Login = sessionsWeek2.size() > activeLoginThreshold ? 1.0 : 0.5;
double week3Login = sessionsWeek3.size() > activeLoginThreshold ? 1.0 : 0.5;
double extraMultiplier = 1.0;
double loginTotal = weekLogin + week2Login + week3Login;
double loginAvg = loginTotal / 3.0;
if (loginTotal < 2.0) {
extraMultiplier = 0.75;
}
activityIndx = playAvg * loginAvg * extraMultiplier;
activityIndex.put(date, activityIndx);
return activityIndx;
}
/**
@ -232,6 +282,9 @@ public class PlayerProfile implements OfflinePlayer {
}
public GeoInfo getMostRecentGeoInfo() {
if (geoInformation.isEmpty()) {
return new GeoInfo("-", "Not Known", MiscUtils.getTime());
}
geoInformation.sort(new GeoInfoComparator());
return geoInformation.get(0);
}
@ -447,7 +500,7 @@ public class PlayerProfile implements OfflinePlayer {
@Override
public boolean isBanned() {
return bannedOnServers.contains(MiscUtils.getIPlan().getServerUuid());
return bannedOnServers.size() != 0;
}
@Override

View File

@ -4,9 +4,20 @@
*/
package main.java.com.djrapitops.plan.data;
import com.djrapitops.plugin.api.Check;
import main.java.com.djrapitops.plan.Plan;
import main.java.com.djrapitops.plan.PlanBungee;
import main.java.com.djrapitops.plan.Settings;
import main.java.com.djrapitops.plan.data.time.WorldTimes;
import main.java.com.djrapitops.plan.utilities.MiscUtils;
import main.java.com.djrapitops.plan.utilities.analysis.AnalysisUtils;
import main.java.com.djrapitops.plan.utilities.analysis.MathUtils;
import main.java.com.djrapitops.plan.utilities.comparators.PlayerProfileLastPlayedComparator;
import main.java.com.djrapitops.plan.utilities.comparators.TPSComparator;
import main.java.com.djrapitops.plan.utilities.html.tables.PlayersTableCreator;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
@ -25,6 +36,13 @@ public class ServerProfile {
private List<TPS> tps;
private Map<String, Integer> commandUsage;
// Information calculated with SQL
private WorldTimes serverWorldtimes;
private long lastPeakDate;
private int lastPeakPlayers;
private long allTimePeak;
private int allTimePeakPlayers;
// Active information
private int playersOnline;
private int playersMax;
@ -60,6 +78,29 @@ public class ServerProfile {
this.commandUsage = commandUsage;
}
public long getLowSpikeCount(long after, long before) {
List<TPS> tpsData = getTPSData(after, before).sorted(new TPSComparator()).collect(Collectors.toList());
int mediumThreshold = Settings.THEME_GRAPH_TPS_THRESHOLD_MED.getNumber();
boolean wasLow = false;
long spikeCount = 0L;
for (TPS tpsObj : tpsData) {
double tps = tpsObj.getTicksPerSecond();
if (tps < mediumThreshold) {
if (!wasLow) {
spikeCount++;
wasLow = true;
}
} else {
wasLow = false;
}
}
return spikeCount;
}
public double getAverageTPS(long after, long before) {
OptionalDouble average = getTPSData(after, before)
.mapToDouble(TPS::getTicksPerSecond)
@ -136,4 +177,110 @@ public class ServerProfile {
public Stream<TPS> getTPSData(long after, long before) {
return tps.stream().filter(tps -> tps.getDate() >= after && tps.getDate() <= before);
}
public String createPlayersTableBody() {
players.sort(new PlayerProfileLastPlayedComparator());
return PlayersTableCreator.createTable(players);
}
public List<String> getGeoLocations() {
return players.stream()
.map(PlayerProfile::getMostRecentGeoInfo)
.map(GeoInfo::getGeolocation)
.collect(Collectors.toList());
}
public long getTotalPlaytime() {
return serverWorldtimes.getTotal();
}
public long getAveragePlayTime() {
return MathUtils.averageLong(getTotalPlaytime(), getPlayerCount());
}
public long getPlayerCount() {
return players.size();
}
public List<Session> getSessions() {
return players.stream().map(p -> p.getSessions(serverUUID)).flatMap(Collection::stream).collect(Collectors.toList());
}
public List<PlayerKill> getPlayerKills(List<Session> s) {
List<PlayerKill> kills = new ArrayList<>();
for (Session session : s) {
kills.addAll(session.getPlayerKills());
}
return kills;
}
public long getMobKillCount(List<Session> s) {
long total = 0;
for (Session session : s) {
total += session.getMobKills();
}
return total;
}
public long getDeathCount(List<Session> s) {
long total = 0;
for (Session session : s) {
total += session.getDeaths();
}
return total;
}
// Default setters & getters
public WorldTimes getServerWorldtimes() {
return serverWorldtimes;
}
public void setServerWorldtimes(WorldTimes serverWorldtimes) {
this.serverWorldtimes = serverWorldtimes;
}
public long getLastPeakDate() {
return lastPeakDate;
}
public void setLastPeakDate(long lastPeakDate) {
this.lastPeakDate = lastPeakDate;
}
public int getLastPeakPlayers() {
return lastPeakPlayers;
}
public void setLastPeakPlayers(int lastPeakPlayers) {
this.lastPeakPlayers = lastPeakPlayers;
}
public long getAllTimePeak() {
return allTimePeak;
}
public void setAllTimePeak(long allTimePeak) {
this.allTimePeak = allTimePeak;
}
public int getAllTimePeakPlayers() {
return allTimePeakPlayers;
}
public void setAllTimePeakPlayers(int allTimePeakPlayers) {
this.allTimePeakPlayers = allTimePeakPlayers;
}
public int getPlayersOnline() {
if (Check.isBungeeAvailable()) {
return PlanBungee.getInstance().getProxy().getOnlineCount();
} else {
return Plan.getInstance().getServer().getOnlinePlayers().size();
}
}
public int getPlayersMax() {
return MiscUtils.getIPlan().getVariable().getMaxPlayers();
}
}

View File

@ -1,6 +1,7 @@
package main.java.com.djrapitops.plan.data;
import main.java.com.djrapitops.plan.data.time.WorldTimes;
import main.java.com.djrapitops.plan.utilities.MiscUtils;
import org.apache.commons.lang3.builder.ToStringBuilder;
import java.util.ArrayList;
@ -26,7 +27,7 @@ import java.util.Objects;
*
* @author Rsl1122
*/
public class Session {
public class Session implements HasDate {
private final long sessionStart;
private Integer sessionID;
@ -119,6 +120,9 @@ public class Session {
* @return Long in ms.
*/
public long getLength() {
if (sessionEnd == -1) {
return MiscUtils.getTime() - sessionStart;
}
return sessionEnd - sessionStart;
}
@ -212,4 +216,9 @@ public class Session {
.append("deaths", deaths)
.toString();
}
@Override
public long getDate() {
return getSessionStart();
}
}

View File

@ -15,7 +15,7 @@ import java.util.Objects;
* @author Rsl1122
* @since 3.5.0
*/
public class TPS {
public class TPS implements HasDate {
private final long date;
private final double ticksPerSecond;

View File

@ -30,10 +30,7 @@ import main.java.com.djrapitops.plan.utilities.html.graphs.ServerPreferencePieCr
import main.java.com.djrapitops.plan.utilities.html.graphs.WorldPieCreator;
import main.java.com.djrapitops.plan.utilities.html.tables.ActionsTableCreator;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.*;
import java.util.stream.Collectors;
/**
@ -58,6 +55,8 @@ public class InspectPageParser extends PageParser {
Benchmark.start("Inspect Parse, Fetch");
Database db = plugin.getDB();
UUID serverUuid = MiscUtils.getIPlan().getServerUuid();
Map<UUID, String> serverNames = db.getServerTable().getServerNames();
long now = MiscUtils.getTime();
addValue("refresh", FormatUtils.formatTimeStamp(now));
@ -66,6 +65,14 @@ public class InspectPageParser extends PageParser {
PlayerProfile profile = db.getPlayerProfile(uuid);
String online = "Offline";
Optional<Session> activeSession = plugin.getInfoManager().getDataCache().getCachedSession(uuid);
if (activeSession.isPresent()) {
profile.addActiveSession(activeSession.get());
online = serverNames.get(serverUuid);
}
activeSession.ifPresent(profile::addActiveSession);
Benchmark.stop("Inspect Parse, Fetch");
String playerName = profile.getName();
@ -82,8 +89,6 @@ public class InspectPageParser extends PageParser {
addValue("lastSeen", "-");
}
Map<UUID, String> serverNames = db.getServerTable().getServerNames();
Map<UUID, WorldTimes> worldTimesPerServer = profile.getWorldTimesPerServer();
addValue("serverPieSeries", ServerPreferencePieCreator.createSeriesData(serverNames, worldTimesPerServer));
addValue("worldPieColors", Settings.THEME_GRAPH_WORLD_PIE.toString());
@ -211,7 +216,16 @@ public class InspectPageParser extends PageParser {
addValue("mobKillCount", mobKillCount);
addValue("deathCount", deathCount);
boolean isActive = AnalysisUtils.isActive(MiscUtils.getTime(), lastSeen, playtime, sessionCount);
double activityIndex = profile.getActivityIndex(now);
String[] activityIndexFormat = FormatUtils.readableActivityIndex(activityIndex);
addValue("activityIndexNumber", /*FormatUtils.cutDecimals(*/activityIndex);
addValue("activityIndexColor", activityIndexFormat[0]);
addValue("activityIndex", activityIndexFormat[1]);
addValue("playerStatus", HtmlStructure.playerStatus(online, profile.getBannedOnServers(), profile.isOp()));
boolean isActive = profile.isActive(now);
String active = isActive ? "Active" : "Inactive";
playerClassification(profile, active);

View File

@ -211,4 +211,18 @@ public class FormatUtils {
public static String cutDecimals(double d) {
return df.format(d);
}
public static String[] readableActivityIndex(double activityIndex) {
if (activityIndex >= 5.0) {
return new String[]{"green", "Very Active"};
} else if (activityIndex >= 2.0) {
return new String[]{"green", "Active"};
} else if (activityIndex >= 1.0) {
return new String[]{"green", "Regular"};
} else if (activityIndex >= 0.5) {
return new String[]{"amber", "Irregular"};
} else {
return new String[]{"blue-gray", "Inactive"};
}
}
}

View File

@ -32,7 +32,7 @@ public class AnalysisUtils {
}
@Deprecated
public static boolean isActive(long now, long lastPlayed, long playTime, int loginTimes) {
public static boolean isActive(long now, long lastPlayed, long playTime, long loginTimes) {
int timeToActive = 10;
long twoWeeks = 1209600000;
return now - lastPlayed < twoWeeks
@ -175,6 +175,7 @@ public class AnalysisUtils {
* @param scale Scale (milliseconds), time before (Current epoch - scale) will be ignored.
* @return Amount of Unique joins within the time span.
*/
@Deprecated
public static int getUniqueJoins(Map<UUID, List<Session>> sessions, long scale) {
long now = MiscUtils.getTime();
long nowMinusScale = now - scale;
@ -190,6 +191,7 @@ public class AnalysisUtils {
return uniqueJoins.size();
}
@Deprecated
public static int getUniqueJoinsPerDay(Map<UUID, List<Session>> sessions, long scale) {
Map<Integer, Set<UUID>> uniqueJoins = new HashMap<>();
long now = MiscUtils.getTime();
@ -284,7 +286,7 @@ public class AnalysisUtils {
return day.get(Calendar.DAY_OF_YEAR);
}
public double getAveragePerDay(long after, long before, long total) {
public static double getAveragePerDay(long after, long before, long total) {
return total / getNumberOfDaysBetween(after, before);
}

View File

@ -0,0 +1,32 @@
/*
* Licence is provided in the jar as license.yml also here:
* https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml
*/
package main.java.com.djrapitops.plan.utilities.comparators;
import main.java.com.djrapitops.plan.data.HasDate;
import java.util.Comparator;
/**
* Comparator for HasDate interface Objects.
*
* @author Rsl1122
*/
public class HasDateComparator implements Comparator<HasDate> {
private final boolean reversed;
public HasDateComparator() {
this(false);
}
public HasDateComparator(boolean reversed) {
this.reversed = reversed;
}
@Override
public int compare(HasDate o1, HasDate o2) {
return (reversed ? -1 : 1) * Long.compare(o1.getDate(), o2.getDate());
}
}

View File

@ -0,0 +1,23 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package main.java.com.djrapitops.plan.utilities.comparators;
import main.java.com.djrapitops.plan.data.PlayerProfile;
import java.util.Comparator;
/**
* Comparator for PlayerProfile so that most recently seen is first.
*
* @author Rsl1122
*/
public class PlayerProfileLastPlayedComparator implements Comparator<PlayerProfile> {
@Override
public int compare(PlayerProfile u1, PlayerProfile u2) {
return Long.compare(u2.getLastSeen(), u1.getLastSeen());
}
}

View File

@ -0,0 +1,23 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package main.java.com.djrapitops.plan.utilities.comparators;
import main.java.com.djrapitops.plan.data.PlayerProfile;
import java.util.Comparator;
/**
* Comparator for PlayerProfile for Alphabetical Name order.
*
* @author Rsl1122
*/
public class PlayerProfileNameComparator implements Comparator<PlayerProfile> {
@Override
public int compare(PlayerProfile u1, PlayerProfile u2) {
return u1.getName().compareTo(u2.getName());
}
}

View File

@ -5,6 +5,8 @@ import main.java.com.djrapitops.plan.data.TPS;
import java.util.Comparator;
/**
* Compares TPS objects so that earliest is first.
*
* @author Rsl1122
* @since 3.5.0
*/

View File

@ -10,7 +10,9 @@ import main.java.com.djrapitops.plan.data.UserInfo;
import java.util.Comparator;
/**
* @author Risto
* Comparator for UserInfo so that most recently seen is first.
*
* @author Rsl1122
*/
public class UserInfoLastPlayedComparator implements Comparator<UserInfo> {

View File

@ -10,9 +10,11 @@ import main.java.com.djrapitops.plan.data.UserInfo;
import java.util.Comparator;
/**
* @author Risto
* Comparator for UserInfo for Alphabetical Name order.
*
* @author Rsl1122
*/
public class UserDataNameComparator implements Comparator<UserInfo> {
public class UserInfoNameComparator implements Comparator<UserInfo> {
@Override
public int compare(UserInfo u1, UserInfo u2) {

View File

@ -55,6 +55,22 @@ public enum Html {
TABLE_SESSIONS(DIV_W_CLASS_STYLE.parse("box-footer scrollbar", "padding: 2px;",
TABLE_START_4.parse("Player", "Started", "Length", "World - Time") + "${3}" + TABLE_END.parse())
),
TABLE_PLAYERS("<table class=\"table table-bordered table-striped table-hover player-table dataTable\"><thead><tr>" +
"<th><i class=\"fa fa-user\"></i> Name</th>" +
"<th><i class=\"fa fa-check\"></i> Active</th>" +
"<th><i class=\"fa fa-clock-o\"></i> Playtime</th>" +
"<th><i class=\"fa fa-calendar-plus-o\"></i> Sessions</th>" +
"<th><i class=\"fa fa-user-plus\"></i> Registered</th>" +
"<th><i class=\"fa fa-calendar-check-o\"></i> Last Seen</th>" +
"<th><i class=\"fa fa-globe\"></i> Geolocation</th></thead>" +
"<tfoot><tr><th><i class=\"fa fa-user\"></i> Name</th>" +
"<th><i class=\"fa fa-check\"></i> Active</th>" +
"<th><i class=\"fa fa-clock-o\"></i> Playtime</th>" +
"<th><i class=\"fa fa-calendar-plus-o\"></i> Sessions</th>" +
"<th><i class=\"fa fa-user-plus\"></i> Registered</th>" +
"<th><i class=\"fa fa-calendar-check-o\"></i> Last Seen</th>" +
"<th><i class=\"fa fa-globe\"></i> Geolocation</th>" +
"</tr></tfoot><tbody>${0}</tbody></table>"),
TABLE_SESSIONS_START(TABLE_START_3.parse("Session Started", "Session Ended", "Session Length")),
TABLE_KILLS_START(TABLE_START_3.parse(FONT_AWESOME_ICON.parse("clock-o") + " Time", "Killed", "With")),
TABLE_FACTIONS_START(TABLE_START_4.parse(FONT_AWESOME_ICON.parse("flag") + " Faction", FONT_AWESOME_ICON.parse("bolt") + " Power", FONT_AWESOME_ICON.parse("map-o") + " Land", FONT_AWESOME_ICON.parse("user") + " Leader")),

View File

@ -351,4 +351,24 @@ public class HtmlStructure {
String[] split2 = split[1].split("box-footer", 2);
return split[0] + "<p>Offline</p></div><div class=\"box-footer" + split2[1];
}
public static String playerStatus(String online, Set<UUID> banned, boolean op) {
boolean offline = "offline".equalsIgnoreCase(online);
StringBuilder html = new StringBuilder("<p>");
if (offline) {
html.append(Html.FA_COLORED_ICON.parse("red", "ball")).append(" ").append(online);
} else {
html.append(Html.FA_COLORED_ICON.parse("green", "ball")).append(" ").append(online);
}
html.append("</p>");
if (op) {
html.append("<p>").append(Html.FA_COLORED_ICON.parse("blue", "superpowers")).append(" Operator</p>");
}
int bannedOn = banned.size();
if (bannedOn != 0) {
html.append("<p>").append(Html.FA_COLORED_ICON.parse("red", "gavel")).append(" Banned (").append(bannedOn).append(")");
}
return html.toString();
}
}

View File

@ -1,6 +1,9 @@
package main.java.com.djrapitops.plan.utilities.html.tables;
import com.djrapitops.plugin.api.utility.log.Log;
import main.java.com.djrapitops.plan.Plan;
import main.java.com.djrapitops.plan.Settings;
import main.java.com.djrapitops.plan.data.PlayerProfile;
import main.java.com.djrapitops.plan.data.Session;
import main.java.com.djrapitops.plan.data.UserInfo;
import main.java.com.djrapitops.plan.data.analysis.GeolocationPart;
@ -26,6 +29,7 @@ public class PlayersTableCreator {
throw new IllegalStateException("Utility class");
}
@Deprecated
public static String createTable(List<UserInfo> userInfo, JoinInfoPart joinInfoPart, GeolocationPart geolocationPart) {
if (userInfo.isEmpty()) {
return Html.TABLELINE_PLAYERS.parse("<b>No Players</b>", "", "", "", "", "", "", "", "", "");
@ -77,8 +81,10 @@ public class PlayersTableCreator {
String.valueOf(lastSeen), lastSeen != 0 ? FormatUtils.formatTimeStamp(lastSeen) : "-",
String.valueOf(geoLocation)
));
} catch (NullPointerException ignored) {
ignored.printStackTrace(); // TODO IGNORE AGAIN
} catch (NullPointerException e) {
if (Settings.DEV_MODE.isTrue()) {
Log.toLog(PlayersTableCreator.class.getName(), e);
}
}
i++;
@ -98,4 +104,55 @@ public class PlayersTableCreator {
return isActive ? "Active" : "Inactive";
}
public static String createTable(List<PlayerProfile> players) {
if (players.isEmpty()) {
return Html.TABLELINE_PLAYERS.parse("<b>No Players</b>", "", "", "", "", "", "", "", "", "");
}
StringBuilder html = new StringBuilder();
long now = MiscUtils.getTime();
UUID serverUUID = MiscUtils.getIPlan().getServerUuid();
int i = 0;
for (PlayerProfile profile : players) {
if (i >= 2000) {
break;
}
try {
boolean isBanned = profile.isBanned();
long loginTimes = profile.getSessionCount(serverUUID);
long playtime = profile.getPlaytime(serverUUID);
boolean isUnknown = loginTimes <= 1;
long registered = profile.getRegistered();
boolean isActive = AnalysisUtils.isActive(now, profile.getLastSeen(), playtime, loginTimes);
long lastSeen = profile.getLastSeen();
String activityString = getActivityString(isBanned, isUnknown, isActive);
String geoLocation = profile.getMostRecentGeoInfo().getGeolocation();
html.append(Html.TABLELINE_PLAYERS.parse(
Html.LINK.parse(Plan.getPlanAPI().getPlayerInspectPageLink(profile.getName()), profile.getName()),
activityString,
String.valueOf(playtime), FormatUtils.formatTimeAmount(playtime),
String.valueOf(loginTimes),
String.valueOf(registered), FormatUtils.formatTimeStampYear(registered),
String.valueOf(lastSeen), lastSeen != 0 ? FormatUtils.formatTimeStamp(lastSeen) : "-",
String.valueOf(geoLocation)
));
} catch (NullPointerException e) {
if (Settings.DEV_MODE.isTrue()) {
Log.toLog(PlayersTableCreator.class.getName(), e);
}
}
i++;
}
return html.toString();
}
}

View File

@ -52,6 +52,11 @@ Commands:
Analysis:
AutoRefreshPeriod: 60
Active:
# Minutes a player should play per week to be considered active
PlaytimeThreshold: 30
# How many days player should join per week to be considered active
LoginThreshold: 2
LogProgress: true
Export:
Enabled: false

View File

@ -81,7 +81,7 @@ public class ComparatorTest {
List<String> stringValues = userInfo.stream().map(UserInfo::getName).collect(Collectors.toList());
Collections.sort(stringValues);
userInfo.sort(new UserDataNameComparator());
userInfo.sort(new UserInfoNameComparator());
List<String> afterSort = userInfo.stream().map(UserInfo::getName).collect(Collectors.toList());
assertEquals(stringValues, afterSort);