diff --git a/Plan/src/main/java/com/djrapitops/plan/data/container/Session.java b/Plan/src/main/java/com/djrapitops/plan/data/container/Session.java index 6a9fff349..b9dacbb92 100644 --- a/Plan/src/main/java/com/djrapitops/plan/data/container/Session.java +++ b/Plan/src/main/java/com/djrapitops/plan/data/container/Session.java @@ -130,9 +130,8 @@ public class Session extends DataContainer implements DateHolder { * * @return Long in ms. */ - @Deprecated public long getLength() { - return getUnsafe(SessionKeys.LENGTH); + return getValue(SessionKeys.LENGTH).orElse(0L); } @Override diff --git a/Plan/src/main/java/com/djrapitops/plan/data/store/containers/AnalysisContainer.java b/Plan/src/main/java/com/djrapitops/plan/data/store/containers/AnalysisContainer.java index 99f03cd5f..450f51e99 100644 --- a/Plan/src/main/java/com/djrapitops/plan/data/store/containers/AnalysisContainer.java +++ b/Plan/src/main/java/com/djrapitops/plan/data/store/containers/AnalysisContainer.java @@ -132,14 +132,58 @@ public class AnalysisContainer extends DataContainer { putSupplier(AnalysisKeys.PLAYERS_TABLE, () -> PlayersTable.forServerPage(getUnsafe(AnalysisKeys.PLAYERS_MUTATOR).all()).parseHtml() ); + + newAndUniquePlayerCounts(); + } + + private void newAndUniquePlayerCounts() { + Key newDay = new Key<>(PlayersMutator.class, "NEW_DAY"); + Key newWeek = new Key<>(PlayersMutator.class, "NEW_WEEK"); + Key newMonth = new Key<>(PlayersMutator.class, "NEW_MONTH"); + Key uniqueDay = new Key<>(PlayersMutator.class, "NEW_DAY"); + Key uniqueWeek = new Key<>(PlayersMutator.class, "NEW_WEEK"); + Key uniqueMonth = new Key<>(PlayersMutator.class, "NEW_MONTH"); + putSupplier(newDay, () -> PlayersMutator.copyOf(getUnsafe(AnalysisKeys.PLAYERS_MUTATOR)) + .filterRegisteredBetween(getUnsafe(AnalysisKeys.ANALYSIS_TIME_DAY_AGO), getUnsafe(AnalysisKeys.ANALYSIS_TIME)) + ); + putSupplier(newWeek, () -> PlayersMutator.copyOf(getUnsafe(AnalysisKeys.PLAYERS_MUTATOR)) + .filterRegisteredBetween(getUnsafe(AnalysisKeys.ANALYSIS_TIME_WEEK_AGO), getUnsafe(AnalysisKeys.ANALYSIS_TIME)) + ); + putSupplier(newMonth, () -> PlayersMutator.copyOf(getUnsafe(AnalysisKeys.PLAYERS_MUTATOR)) + .filterRegisteredBetween(getUnsafe(AnalysisKeys.ANALYSIS_TIME_MONTH_AGO), getUnsafe(AnalysisKeys.ANALYSIS_TIME)) + ); + putSupplier(uniqueDay, () -> PlayersMutator.copyOf(getUnsafe(AnalysisKeys.PLAYERS_MUTATOR)) + .filterRegisteredBetween(getUnsafe(AnalysisKeys.ANALYSIS_TIME_DAY_AGO), getUnsafe(AnalysisKeys.ANALYSIS_TIME)) + ); + putSupplier(uniqueWeek, () -> PlayersMutator.copyOf(getUnsafe(AnalysisKeys.PLAYERS_MUTATOR)) + .filterRegisteredBetween(getUnsafe(AnalysisKeys.ANALYSIS_TIME_WEEK_AGO), getUnsafe(AnalysisKeys.ANALYSIS_TIME)) + ); + putSupplier(uniqueMonth, () -> PlayersMutator.copyOf(getUnsafe(AnalysisKeys.PLAYERS_MUTATOR)) + .filterRegisteredBetween(getUnsafe(AnalysisKeys.ANALYSIS_TIME_MONTH_AGO), getUnsafe(AnalysisKeys.ANALYSIS_TIME)) + ); + + putSupplier(AnalysisKeys.PLAYERS_NEW_DAY, () -> getUnsafe(newDay).count()); + putSupplier(AnalysisKeys.PLAYERS_NEW_WEEK, () -> getUnsafe(newWeek).count()); + putSupplier(AnalysisKeys.PLAYERS_NEW_MONTH, () -> getUnsafe(newMonth).count()); + putSupplier(AnalysisKeys.PLAYERS_DAY, () -> getUnsafe(uniqueDay).count()); + putSupplier(AnalysisKeys.PLAYERS_WEEK, () -> getUnsafe(uniqueWeek).count()); + putSupplier(AnalysisKeys.PLAYERS_MONTH, () -> getUnsafe(uniqueMonth).count()); + putSupplier(AnalysisKeys.AVG_PLAYERS_NEW, () -> getUnsafe(AnalysisKeys.PLAYERS_MUTATOR).newPerDay()); + putSupplier(AnalysisKeys.AVG_PLAYERS_NEW_DAY, () -> getUnsafe(uniqueDay).newPerDay()); + putSupplier(AnalysisKeys.AVG_PLAYERS_NEW_WEEK, () -> getUnsafe(uniqueWeek).newPerDay()); + putSupplier(AnalysisKeys.AVG_PLAYERS_NEW_MONTH, () -> getUnsafe(uniqueMonth).newPerDay()); } private void addSessionSuppliers() { - putSupplier(AnalysisKeys.SESSION_ACCORDION, () -> SessionAccordion.forServer( + Key sessionAccordion = new Key<>(SessionAccordion.class, "SESSION_ACCORDION"); + putSupplier(sessionAccordion, () -> SessionAccordion.forServer( getUnsafe(AnalysisKeys.SESSIONS_MUTATOR).all(), () -> Database.getActive().fetch().getServerNames(), () -> getUnsafe(AnalysisKeys.PLAYER_NAMES) )); + putSupplier(AnalysisKeys.SESSION_ACCORDION_HTML, () -> getUnsafe(sessionAccordion).toHtml()); + putSupplier(AnalysisKeys.SESSION_ACCORDION_FUNCTIONS, () -> getUnsafe(sessionAccordion).toViewScript()); + putSupplier(AnalysisKeys.RECENT_LOGINS, () -> new RecentLoginList( serverContainer.getValue(ServerKeys.PLAYERS).orElse(new ArrayList<>()) ).toHtml() @@ -147,8 +191,6 @@ public class AnalysisContainer extends DataContainer { putSupplier(AnalysisKeys.SESSION_TABLE, () -> new ServerSessionTable( getUnsafe(AnalysisKeys.PLAYER_NAMES), getUnsafe(AnalysisKeys.SESSIONS_MUTATOR).all()).parseHtml() ); - putSupplier(AnalysisKeys.SESSION_ACCORDION_HTML, () -> getUnsafe(AnalysisKeys.SESSION_ACCORDION).toHtml()); - putSupplier(AnalysisKeys.SESSION_ACCORDION_FUNCTIONS, () -> getUnsafe(AnalysisKeys.SESSION_ACCORDION).toViewScript()); putSupplier(AnalysisKeys.AVERAGE_SESSION_LENGTH_F, () -> Formatters.timeAmount() .apply(getUnsafe(AnalysisKeys.SESSIONS_MUTATOR).toAverageSessionLength()) @@ -167,13 +209,25 @@ public class AnalysisContainer extends DataContainer { putSupplier(AnalysisKeys.AVERAGE_SESSION_LENGTH_F, () -> Formatters.timeAmount() .apply(getUnsafe(AnalysisKeys.SESSIONS_MUTATOR).toAverageSessionLength()) ); - putSupplier(AnalysisKeys.PUNCHCARD_SERIES, () -> new PunchCardGraph( - SessionsMutator.copyOf(getUnsafe(AnalysisKeys.SESSIONS_MUTATOR) - .filterSessionsBetween( - getUnsafe(AnalysisKeys.ANALYSIS_TIME_MONTH_AGO), - getUnsafe(AnalysisKeys.ANALYSIS_TIME)) - ).all()).toHighChartsSeries() + + Key sessionsDay = new Key<>(SessionsMutator.class, "SESSIONS_DAY"); + Key sessionsWeek = new Key<>(SessionsMutator.class, "SESSIONS_WEEK"); + Key sessionsMonth = new Key<>(SessionsMutator.class, "SESSIONS_MONTH"); + putSupplier(sessionsDay, () -> SessionsMutator.copyOf(getUnsafe(AnalysisKeys.SESSIONS_MUTATOR)) + .filterSessionsBetween(getUnsafe(AnalysisKeys.ANALYSIS_TIME_DAY_AGO), getUnsafe(AnalysisKeys.ANALYSIS_TIME)) ); + putSupplier(sessionsWeek, () -> SessionsMutator.copyOf(getUnsafe(AnalysisKeys.SESSIONS_MUTATOR)) + .filterSessionsBetween(getUnsafe(AnalysisKeys.ANALYSIS_TIME_WEEK_AGO), getUnsafe(AnalysisKeys.ANALYSIS_TIME)) + ); + putSupplier(sessionsMonth, () -> SessionsMutator.copyOf(getUnsafe(AnalysisKeys.SESSIONS_MUTATOR)) + .filterSessionsBetween(getUnsafe(AnalysisKeys.ANALYSIS_TIME_MONTH_AGO), getUnsafe(AnalysisKeys.ANALYSIS_TIME)) + ); + + putSupplier(AnalysisKeys.PUNCHCARD_SERIES, () -> new PunchCardGraph(getUnsafe(sessionsMonth).all()).toHighChartsSeries()); + putSupplier(AnalysisKeys.AVG_PLAYERS, () -> getUnsafe(AnalysisKeys.SESSIONS_MUTATOR).toUniqueJoinsPerDay()); + putSupplier(AnalysisKeys.AVG_PLAYERS_DAY, () -> getUnsafe(sessionsDay).toUniqueJoinsPerDay()); + putSupplier(AnalysisKeys.AVG_PLAYERS_WEEK, () -> getUnsafe(sessionsWeek).toUniqueJoinsPerDay()); + putSupplier(AnalysisKeys.AVG_PLAYERS_MONTH, () -> getUnsafe(sessionsMonth).toUniqueJoinsPerDay()); } private void addGraphSuppliers() { diff --git a/Plan/src/main/java/com/djrapitops/plan/data/store/keys/AnalysisKeys.java b/Plan/src/main/java/com/djrapitops/plan/data/store/keys/AnalysisKeys.java index 334aede97..c8266edd2 100644 --- a/Plan/src/main/java/com/djrapitops/plan/data/store/keys/AnalysisKeys.java +++ b/Plan/src/main/java/com/djrapitops/plan/data/store/keys/AnalysisKeys.java @@ -6,7 +6,6 @@ import com.djrapitops.plan.data.store.Type; import com.djrapitops.plan.data.store.mutators.PlayersMutator; import com.djrapitops.plan.data.store.mutators.SessionsMutator; import com.djrapitops.plan.data.store.mutators.TPSMutator; -import com.djrapitops.plan.utilities.html.structure.SessionAccordion; import java.util.Map; import java.util.Set; @@ -136,7 +135,6 @@ public class AnalysisKeys { public static final Key ANALYSIS_TIME_DAY_AGO = new Key<>(Long.class, "ANALYSIS_TIME_DAY_AGO"); public static final Key ANALYSIS_TIME_WEEK_AGO = new Key<>(Long.class, "ANALYSIS_TIME_WEEK_AGO"); public static final Key ANALYSIS_TIME_MONTH_AGO = new Key<>(Long.class, "ANALYSIS_TIME_MONTH_AGO"); - public static final Key SESSION_ACCORDION = new Key<>(SessionAccordion.class, "SESSION_ACCORDION"); public static final Key> PLAYER_NAMES = new Key<>(new Type>() {}, "PLAYER_NAMES"); public static final Key>>> ACTIVITY_DATA = new Key<>(new Type>>>() {}, "ACTIVITY_DATA"); diff --git a/Plan/src/main/java/com/djrapitops/plan/data/store/mutators/PlayersMutator.java b/Plan/src/main/java/com/djrapitops/plan/data/store/mutators/PlayersMutator.java index 2aaca2717..ad354a9b7 100644 --- a/Plan/src/main/java/com/djrapitops/plan/data/store/mutators/PlayersMutator.java +++ b/Plan/src/main/java/com/djrapitops/plan/data/store/mutators/PlayersMutator.java @@ -6,9 +6,13 @@ import com.djrapitops.plan.data.store.containers.DataContainer; import com.djrapitops.plan.data.store.containers.PlayerContainer; import com.djrapitops.plan.data.store.keys.PlayerKeys; import com.djrapitops.plan.data.store.keys.ServerKeys; +import com.djrapitops.plan.data.store.keys.SessionKeys; +import com.djrapitops.plan.data.store.mutators.formatting.Formatters; import com.djrapitops.plugin.api.TimeAmount; import java.util.*; +import java.util.function.Function; +import java.util.stream.Collectors; /** * Mutator for a bunch of {@link com.djrapitops.plan.data.store.containers.PlayerContainer}s. @@ -31,10 +35,37 @@ public class PlayersMutator { return new PlayersMutator(container.getValue(ServerKeys.PLAYERS).orElse(new ArrayList<>())); } + public PlayersMutator filterPlayedBetween(long after, long before) { + players = players.stream().filter(player -> + player.getValue(PlayerKeys.SESSIONS) + .map(sessions -> sessions.stream().anyMatch(session -> { + long start = session.getValue(SessionKeys.START).orElse(-1L); + long end = session.getValue(SessionKeys.END).orElse(-1L); + return (after <= start && start <= before) || (after <= end && end <= before); + })).orElse(false) + ).collect(Collectors.toList()); + return this; + } + + public PlayersMutator filterRegisteredBetween(long after, long before) { + players = players.stream().filter(player -> + player.getValue(PlayerKeys.REGISTERED).map(date -> after <= date && date <= before).orElse(false) + ).collect(Collectors.toList()); + return this; + } + public List all() { return players; } + public List registerDates() { + List registerDates = new ArrayList<>(); + for (PlayerContainer player : players) { + registerDates.add(player.getValue(PlayerKeys.REGISTERED).orElse(-1L)); + } + return registerDates; + } + public List getGeolocations() { List geolocations = new ArrayList<>(); @@ -64,4 +95,26 @@ public class PlayersMutator { } return activityData; } + + public int count() { + return players.size(); + } + + public int newPerDay() { + List registerDates = registerDates(); + int total = 0; + Function formatter = Formatters.dayOfYear(); + Set days = new HashSet<>(); + for (Long date : registerDates) { + int day = formatter.apply(date); + days.add(day); + total++; + } + int numberOfDays = days.size(); + + if (numberOfDays == 0) { + return 0; + } + return total / numberOfDays; + } } \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/data/store/mutators/SessionsMutator.java b/Plan/src/main/java/com/djrapitops/plan/data/store/mutators/SessionsMutator.java index 79d7bda12..83a85109b 100644 --- a/Plan/src/main/java/com/djrapitops/plan/data/store/mutators/SessionsMutator.java +++ b/Plan/src/main/java/com/djrapitops/plan/data/store/mutators/SessionsMutator.java @@ -4,9 +4,13 @@ import com.djrapitops.plan.data.container.PlayerKill; import com.djrapitops.plan.data.container.Session; import com.djrapitops.plan.data.store.containers.DataContainer; import com.djrapitops.plan.data.store.keys.CommonKeys; +import com.djrapitops.plan.data.store.keys.SessionKeys; +import com.djrapitops.plan.data.store.mutators.formatting.Formatters; import com.djrapitops.plan.data.time.WorldTimes; +import com.djrapitops.plan.utilities.analysis.MathUtils; import java.util.*; +import java.util.function.Function; import java.util.stream.Collectors; /** @@ -38,7 +42,8 @@ public class SessionsMutator { public SessionsMutator filterSessionsBetween(long after, long before) { sessions = sessions.stream() - .filter(session -> session.getSessionEnd() >= after && session.getSessionStart() <= before) + .filter(session -> after <= session.getValue(SessionKeys.END).orElse(System.currentTimeMillis()) + && session.getUnsafe(SessionKeys.START) <= before) .collect(Collectors.toList()); return this; } @@ -47,8 +52,7 @@ public class SessionsMutator { WorldTimes total = new WorldTimes(new HashMap<>()); for (Session session : sessions) { - WorldTimes worldTimes = session.getWorldTimes(); - total.add(worldTimes); + session.getValue(SessionKeys.WORLD_TIMES).ifPresent(total::add); } return total; @@ -56,20 +60,20 @@ public class SessionsMutator { public List toPlayerKillList() { return sessions.stream() - .map(Session::getPlayerKills) + .map(session -> session.getValue(SessionKeys.PLAYER_KILLS).orElse(new ArrayList<>())) .flatMap(Collection::stream) .collect(Collectors.toList()); } public int toMobKillCount() { return sessions.stream() - .mapToInt(Session::getMobKills) + .mapToInt(session -> session.getValue(SessionKeys.MOB_KILL_COUNT).orElse(0)) .sum(); } public int toDeathCount() { return sessions.stream() - .mapToInt(Session::getDeaths) + .mapToInt(session -> session.getValue(SessionKeys.DEATH_COUNT).orElse(0)) .sum(); } @@ -81,20 +85,22 @@ public class SessionsMutator { public long toAfkTime() { return sessions.stream() - .mapToLong(Session::getAfkLength) + .mapToLong(session -> session.getValue(SessionKeys.AFK_TIME).orElse(0L)) .sum(); } public long toActivePlaytime() { return sessions.stream() - .mapToLong(Session::getActiveLength) + .mapToLong(session -> session.getValue(SessionKeys.ACTIVE_TIME).orElse(0L)) .sum(); } public long toLastSeen() { return sessions.stream() - .mapToLong(session -> Math.max(session.getSessionStart(), session.getSessionEnd())) - .max().orElse(-1); + .mapToLong(session -> Math.max(session.getUnsafe( + SessionKeys.START), + session.getValue(SessionKeys.END).orElse(System.currentTimeMillis())) + ).max().orElse(-1); } public long toLongestSessionLength() { @@ -125,6 +131,32 @@ public class SessionsMutator { return sessionLengths.get(sessionLengths.size() / 2); } + public int toUniqueJoinsPerDay() { + Map> uniqueJoins = new HashMap<>(); + Function function = Formatters.dayOfYear(); + + for (Session session : sessions) { + Optional uuidValue = session.getValue(SessionKeys.UUID); + if (!uuidValue.isPresent()) { + continue; + } + UUID uuid = uuidValue.get(); + int day = function.apply(session.getUnsafe(SessionKeys.START)); + + uniqueJoins.computeIfAbsent(day, computedDay -> new HashSet<>()); + uniqueJoins.get(day).add(uuid); + } + + int total = MathUtils.sumInt(uniqueJoins.values().stream().map(Set::size)); + int numberOfDays = uniqueJoins.size(); + + if (numberOfDays == 0) { + return 0; + } + + return total / numberOfDays; + } + public int count() { return sessions.size(); } diff --git a/Plan/src/main/java/com/djrapitops/plan/data/store/mutators/formatting/Formatters.java b/Plan/src/main/java/com/djrapitops/plan/data/store/mutators/formatting/Formatters.java index 107187510..ec83e3100 100644 --- a/Plan/src/main/java/com/djrapitops/plan/data/store/mutators/formatting/Formatters.java +++ b/Plan/src/main/java/com/djrapitops/plan/data/store/mutators/formatting/Formatters.java @@ -3,6 +3,9 @@ package com.djrapitops.plan.data.store.mutators.formatting; import com.djrapitops.plan.data.store.objects.DateHolder; import com.djrapitops.plan.utilities.FormatUtils; +import java.util.Calendar; +import java.util.function.Function; + /** * Class that holds static methods for getting new instances of different {@link Formatter}s. * @@ -55,4 +58,12 @@ public class Formatters { public static Formatter timeAmount() { return new TimeAmountFormatter(); } + + public static Function dayOfYear() { + return date -> { + Calendar day = Calendar.getInstance(); + day.setTimeInMillis(date); + return day.get(Calendar.DAY_OF_YEAR); + }; + } } \ 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 792de41c8..0bc21cbb5 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 @@ -54,6 +54,7 @@ public class AnalysisUtils { return uuids.size(); } + @Deprecated public static int getUniqueJoinsPerDay(Map> sessions, long after) { Map> uniqueJoins = new HashMap<>();