From b99d201f0cee2125c99ba4c001dcb9cd478056ea Mon Sep 17 00:00:00 2001 From: Rsl1122 Date: Sun, 19 Nov 2017 14:30:53 +0200 Subject: [PATCH] PlayerProfile data class that makes data easier to manage as code. --- .../com/djrapitops/plan/data/GeoInfo.java | 52 ++ .../djrapitops/plan/data/PlayerProfile.java | 473 ++++++++++++++++++ .../utilities/analysis/AnalysisUtils.java | 5 + .../comparators/GeoInfoComparator.java | 19 + 4 files changed, 549 insertions(+) create mode 100644 Plan/src/main/java/com/djrapitops/plan/data/GeoInfo.java create mode 100644 Plan/src/main/java/com/djrapitops/plan/data/PlayerProfile.java create mode 100644 Plan/src/main/java/com/djrapitops/plan/utilities/comparators/GeoInfoComparator.java diff --git a/Plan/src/main/java/com/djrapitops/plan/data/GeoInfo.java b/Plan/src/main/java/com/djrapitops/plan/data/GeoInfo.java new file mode 100644 index 000000000..931ad4fae --- /dev/null +++ b/Plan/src/main/java/com/djrapitops/plan/data/GeoInfo.java @@ -0,0 +1,52 @@ +/* + * 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; + +import com.google.common.base.Objects; + +/** + * Data class that contains information about IP and Geolocation. + * + * @author Rsl1122 + */ +public class GeoInfo { + + private final String ip; + private final String geolocation; + private final long lastUsed; + + public GeoInfo(String ip, String geolocation, long lastUsed) { + this.ip = ip; + this.geolocation = geolocation; + this.lastUsed = lastUsed; + } + + public String getIp() { + return ip; + } + + public String getGeolocation() { + return geolocation; + } + + public long getLastUsed() { + return lastUsed; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + GeoInfo geoInfo = (GeoInfo) o; + return lastUsed == geoInfo.lastUsed && + Objects.equal(ip, geoInfo.ip) && + Objects.equal(geolocation, geoInfo.geolocation); + } + + @Override + public int hashCode() { + return Objects.hashCode(ip, geolocation, lastUsed); + } +} \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/data/PlayerProfile.java b/Plan/src/main/java/com/djrapitops/plan/data/PlayerProfile.java new file mode 100644 index 000000000..3bf66b97c --- /dev/null +++ b/Plan/src/main/java/com/djrapitops/plan/data/PlayerProfile.java @@ -0,0 +1,473 @@ +/* + * 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; + +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; +import main.java.com.djrapitops.plan.utilities.comparators.GeoInfoComparator; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.OfflinePlayer; +import org.bukkit.entity.Player; + +import java.io.Serializable; +import java.util.*; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +/** + * Data container object for a single player. + *

+ * Created to streamline analysis and to make it easier to understand. + * + * @author Rsl1122 + */ +public class PlayerProfile implements OfflinePlayer { + + // Identification + private final UUID uuid; + private final String name; + + // Basic information + private final long registered; + private Map registeredMap; + private Set bannedOnServers; + private Set oppedOnServers; + + // Activity related information + private Map> sessions; + private List actions; + private Map worldTimesMap; + + // Extra information + private List nicknames; + private List geoInformation; + + // Plugin data + private Map pluginReplaceMap; + + // Value that requires lot of processing + private Double activityIndex; + + public PlayerProfile(UUID uuid, String name, long registered) { + this.uuid = uuid; + this.name = name; + this.registered = registered; + registeredMap = new HashMap<>(); + + bannedOnServers = new HashSet<>(); + oppedOnServers = new HashSet<>(); + + sessions = new HashMap<>(); + actions = new ArrayList<>(); + worldTimesMap = new HashMap<>(); + + pluginReplaceMap = new HashMap<>(); + } + + // Calculating Getters + + public boolean isActive() { + return getActivityIndex() > 1.0; + } + + public double getActivityIndex() { + if (activityIndex != null) { + return activityIndex; + } + return 0.0; // TODO + } + + /** + * Get the total world times of the player. + * + * @return returns the WorldTimes in the "null" key of the map. + */ + public WorldTimes getWorldTimes() { + return worldTimesMap.getOrDefault(null, new WorldTimes(new HashMap<>())); + } + + /** + * Get world times per server for this player. + * + * @return a copy of the WorldTimes Map without the "null" key. + */ + public Map getWorldTimesPerServer() { + Map map = new HashMap<>(worldTimesMap); + map.remove(null); + return map; + } + + public long getLastSeen() { + return getLastSeen(getAllSessions()); + } + + public long getLastSeen(UUID serverUUID) { + return getLastSeen(getSessions(serverUUID).stream()); + } + + public long getLastSeen(Stream s) { + OptionalLong max = s.mapToLong(Session::getSessionEnd) + .max(); + if (max.isPresent()) { + return max.getAsLong(); + } + return 0; + } + + public long getTotalPlaytime() { + return getPlaytime(-1, MiscUtils.getTime() + 1L); + } + + public long getPlaytime(long after, long before) { + return getPlaytime(getSessions(after, before)); + } + + public long getPlaytime(UUID serverUUID) { + return getPlaytime(getSessions(serverUUID).stream()); + } + + public static long getPlaytime(Stream s) { + return s.map(Session::getLength) + .mapToLong(i -> i) + .sum(); + } + + public long getLongestSession() { + return getLongestSession(-1, MiscUtils.getTime() + 1L); + } + + public long getLongestSession(int after, long before) { + return getLongestSession(getSessions(after, before)); + } + + public long getLongestSession(UUID serverUUID) { + return getLongestSession(getSessions(serverUUID).stream()); + } + + public static long getLongestSession(Stream s) { + OptionalLong longestSession = s.map(Session::getLength) + .mapToLong(i -> i) + .max(); + if (longestSession.isPresent()) { + return longestSession.getAsLong(); + } + return 0L; + } + + public long getSessionMedian() { + return getSessionMedian(-1, MiscUtils.getTime() + 1L); + } + + public long getSessionMedian(int after, long before) { + return getSessionMedian(getSessions(after, before)); + } + + public long getSessionMedian(UUID serverUUID) { + return getSessionMedian(getSessions(serverUUID).stream()); + } + + public static long getSessionMedian(Stream s) { + List sessionLenghts = s.map(Session::getLength) + .sorted() + .collect(Collectors.toList()); + if (sessionLenghts.isEmpty()) { + return 0; + } + return sessionLenghts.get(sessionLenghts.size() / 2); + } + + public long getSessionAverage() { + return getSessionAverage(-1, MiscUtils.getTime() + 1L); + } + + public long getSessionAverage(int after, long before) { + return getSessionAverage(getSessions(after, before)); + } + + public long getSessionAverage(UUID serverUUID) { + return getSessionAverage(getSessions(serverUUID).stream()); + } + + public static long getSessionAverage(Stream s) { + OptionalDouble average = s.map(Session::getLength) + .mapToLong(i -> i) + .average(); + if (average.isPresent()) { + return (long) average.getAsDouble(); + } + return 0L; + } + + + // Special Getters + + public Stream getAllSessions() { + return sessions.values().stream().flatMap(Collection::stream); + } + + public Stream getSessions(long after, long before) { + return getAllSessions() + .filter(session -> session.getSessionStart() > after && session.getSessionEnd() < before); + } + + public GeoInfo getMostRecentGeoInfo() { + geoInformation.sort(new GeoInfoComparator()); + return geoInformation.get(0); + } + + public List getAllActions() { + List actions = new ArrayList<>(this.actions); + getPlayerKills().map(PlayerKill::convertToAction).forEach(actions::add); + actions.sort(new ActionComparator()); + return actions; + } + + public Stream getPlayerKills() { + return getPlayerKills(getAllSessions()); + } + + public Stream getPlayerKills(UUID serverUUID) { + return getPlayerKills(getSessions(serverUUID).stream()); + } + + public static Stream getPlayerKills(Stream s) { + return s.map(Session::getPlayerKills) + .flatMap(Collection::stream); + } + + public long getPlayerKillCount() { + return getPlayerKills().count(); + } + + public long getPlayerKillCount(UUID serverUUID) { + return getPlayerKills(serverUUID).count(); + } + + public long getDeathCount() { + return getDeathCount(getAllSessions()); + } + + public long getDeathCount(UUID serverUUID) { + return getDeathCount(getSessions(serverUUID).stream()); + } + + public static long getDeathCount(Stream s) { + return s.mapToLong(Session::getDeaths) + .sum(); + } + + public long getMobKillCount() { + return getMobKillCount(getAllSessions()); + } + + public long getMobKillCount(UUID serverUUID) { + return getMobKillCount(getSessions(serverUUID).stream()); + } + + public static long getMobKillCount(Stream s) { + return s.mapToLong(Session::getMobKills) + .sum(); + } + + public long getSessionCount() { + return getAllSessions().count(); + } + + public long getSessionCount(UUID serverUUID) { + return getSessions(serverUUID).size(); + } + + public long getRegistered(UUID serverUUID) { + return registeredMap.getOrDefault(serverUUID, -1L); + } + + // Setters & Adders + + public void bannedOnServer(UUID serverUUID) { + bannedOnServers.add(serverUUID); + } + + public void oppedOnServer(UUID serverUUID) { + oppedOnServers.add(serverUUID); + } + + public void bannedOnServer(Collection serverUUIDs) { + bannedOnServers.addAll(serverUUIDs); + } + + public void oppedOnServer(Collection serverUUIDs) { + oppedOnServers.addAll(serverUUIDs); + } + + public void setSessions(UUID serverUUID, List sessions) { + this.sessions.put(serverUUID, sessions); + } + + public void addActiveSession(Session activeSession) { + UUID serverUUID = MiscUtils.getIPlan().getServerUuid(); + List sessions = getSessions(serverUUID); + sessions.add(activeSession); + this.sessions.put(serverUUID, sessions); + } + + public List getSessions(UUID serverUUID) { + return this.sessions.getOrDefault(serverUUID, new ArrayList<>()); + } + + public void addReplaceValue(String placeholder, Serializable value) { + pluginReplaceMap.put(placeholder, value.toString()); + } + + public void setWorldTimes(UUID serverUUID, WorldTimes worldTimes) { + worldTimesMap.put(serverUUID, worldTimes); + } + + public void setWorldTimes(Map worldTimes) { + worldTimesMap.putAll(worldTimes); + } + + public void setTotalWorldTimes(WorldTimes worldTimes) { + worldTimesMap.put(null, worldTimes); + } + + public void setRegistered(UUID serverUUID, long registered) { + registeredMap.put(serverUUID, registered); + } + + // Default Setters + + public void setActions(List actions) { + this.actions = actions; + } + + public void setNicknames(List nicknames) { + this.nicknames = nicknames; + } + + public void setGeoInformation(List geoInformation) { + this.geoInformation = geoInformation; + } + + // Default Getters + + public List getNicknames() { + return nicknames; + } + + public List getGeoInformation() { + return geoInformation; + } + + public UUID getUuid() { + return uuid; + } + + public String getName() { + return name; + } + + public long getRegistered() { + return registered; + } + + public Set getBannedOnServers() { + return bannedOnServers; + } + + public Set getOppedOnServers() { + return oppedOnServers; + } + + public Map> getSessions() { + return sessions; + } + + public List getActions() { + return actions; + } + + public Map getPluginReplaceMap() { + return pluginReplaceMap; + } + + /** + * Get the WorldTimes map. + * + * @return Map that contains WorldTimes for each server and a total in the "null" key. + */ + public Map getWorldTimesMap() { + return worldTimesMap; + } + + // OfflinePlayer methods for possible PluginData analysis + + @Override + public boolean isOnline() { + Player p = getPlayer(); + return p != null && p.isOnline(); + } + + @Override + public UUID getUniqueId() { + return uuid; + } + + @Override + public boolean isBanned() { + return bannedOnServers.contains(MiscUtils.getIPlan().getServerUuid()); + } + + @Override + public boolean isWhitelisted() { + return true; + } + + @Override + public void setWhitelisted(boolean b) { + /* Do nothing */ + } + + @Override + public Player getPlayer() { + return Bukkit.getPlayer(uuid); + } + + @Override + public long getFirstPlayed() { + return registered; + } + + @Override + public long getLastPlayed() { + return getLastSeen(MiscUtils.getIPlan().getServerUuid()); + } + + @Override + public boolean hasPlayedBefore() { + return true; + } + + @Override + public Location getBedSpawnLocation() { + return null; + } + + @Override + public Map serialize() { + return new HashMap<>(); + } + + @Override + public boolean isOp() { + return oppedOnServers.contains(MiscUtils.getIPlan().getServerUuid()); + } + + @Override + public void setOp(boolean b) { + /* Do nothing */ + } +} \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/utilities/analysis/AnalysisUtils.java b/Plan/src/main/java/com/djrapitops/plan/utilities/analysis/AnalysisUtils.java index 14d7bccae..3193e43f3 100644 --- a/Plan/src/main/java/com/djrapitops/plan/utilities/analysis/AnalysisUtils.java +++ b/Plan/src/main/java/com/djrapitops/plan/utilities/analysis/AnalysisUtils.java @@ -30,6 +30,7 @@ public class AnalysisUtils { throw new IllegalStateException("Utility class"); } + @Deprecated public static boolean isActive(long now, long lastPlayed, long playTime, int loginTimes) { int timeToActive = 10; long twoWeeks = 1209600000; @@ -50,6 +51,7 @@ public class AnalysisUtils { return newPlayers; } + @Deprecated public static List transformSessionDataToLengths(Collection data) { return data.stream() .filter(Objects::nonNull) @@ -280,15 +282,18 @@ public class AnalysisUtils { return day.get(Calendar.DAY_OF_YEAR); } + @Deprecated public static long getTotalPlaytime(List sessions) { return sessions.stream().mapToLong(Session::getLength).sum(); } + @Deprecated public static long getLongestSessionLength(List sessions) { Optional longest = sessions.stream().sorted(new SessionLengthComparator()).findFirst(); return longest.map(Session::getLength).orElse(0L); } + @Deprecated public static long getLastSeen(List userSessions) { OptionalLong max = userSessions.stream().mapToLong(Session::getSessionEnd).max(); if (max.isPresent()) { diff --git a/Plan/src/main/java/com/djrapitops/plan/utilities/comparators/GeoInfoComparator.java b/Plan/src/main/java/com/djrapitops/plan/utilities/comparators/GeoInfoComparator.java new file mode 100644 index 000000000..4a4d23ee2 --- /dev/null +++ b/Plan/src/main/java/com/djrapitops/plan/utilities/comparators/GeoInfoComparator.java @@ -0,0 +1,19 @@ +package main.java.com.djrapitops.plan.utilities.comparators; + +import main.java.com.djrapitops.plan.data.GeoInfo; + +import java.util.Comparator; + +/** + * Comparator for comparing Actions so that latest is the first component. + * + * @author Rsl1122 + */ +public class GeoInfoComparator implements Comparator { + + @Override + public int compare(GeoInfo o1, GeoInfo o2) { + return -Long.compare(o1.getLastUsed(), o2.getLastUsed()); + } + +}