Rewrote Unique player and new player counters for #560

This commit is contained in:
Rsl1122 2018-07-13 15:27:06 +03:00
parent 9369a863b2
commit 0549ce32f5
7 changed files with 123 additions and 58 deletions

View File

@ -168,13 +168,13 @@ public class AnalysisContainer extends DataContainer {
.filterRegisteredBetween(getUnsafe(AnalysisKeys.ANALYSIS_TIME_MONTH_AGO), getUnsafe(AnalysisKeys.ANALYSIS_TIME)) .filterRegisteredBetween(getUnsafe(AnalysisKeys.ANALYSIS_TIME_MONTH_AGO), getUnsafe(AnalysisKeys.ANALYSIS_TIME))
); );
putSupplier(uniqueDay, () -> getUnsafe(AnalysisKeys.PLAYERS_MUTATOR) putSupplier(uniqueDay, () -> getUnsafe(AnalysisKeys.PLAYERS_MUTATOR)
.filterRegisteredBetween(getUnsafe(AnalysisKeys.ANALYSIS_TIME_DAY_AGO), getUnsafe(AnalysisKeys.ANALYSIS_TIME)) .filterPlayedBetween(getUnsafe(AnalysisKeys.ANALYSIS_TIME_DAY_AGO), getUnsafe(AnalysisKeys.ANALYSIS_TIME))
); );
putSupplier(uniqueWeek, () -> getUnsafe(AnalysisKeys.PLAYERS_MUTATOR) putSupplier(uniqueWeek, () -> getUnsafe(AnalysisKeys.PLAYERS_MUTATOR)
.filterRegisteredBetween(getUnsafe(AnalysisKeys.ANALYSIS_TIME_WEEK_AGO), getUnsafe(AnalysisKeys.ANALYSIS_TIME)) .filterPlayedBetween(getUnsafe(AnalysisKeys.ANALYSIS_TIME_WEEK_AGO), getUnsafe(AnalysisKeys.ANALYSIS_TIME))
); );
putSupplier(uniqueMonth, () -> getUnsafe(AnalysisKeys.PLAYERS_MUTATOR) putSupplier(uniqueMonth, () -> getUnsafe(AnalysisKeys.PLAYERS_MUTATOR)
.filterRegisteredBetween(getUnsafe(AnalysisKeys.ANALYSIS_TIME_MONTH_AGO), getUnsafe(AnalysisKeys.ANALYSIS_TIME)) .filterPlayedBetween(getUnsafe(AnalysisKeys.ANALYSIS_TIME_MONTH_AGO), getUnsafe(AnalysisKeys.ANALYSIS_TIME))
); );
putSupplier(AnalysisKeys.PLAYERS_NEW_DAY, () -> getUnsafe(newDay).count()); putSupplier(AnalysisKeys.PLAYERS_NEW_DAY, () -> getUnsafe(newDay).count());
@ -183,10 +183,10 @@ public class AnalysisContainer extends DataContainer {
putSupplier(AnalysisKeys.PLAYERS_DAY, () -> getUnsafe(uniqueDay).count()); putSupplier(AnalysisKeys.PLAYERS_DAY, () -> getUnsafe(uniqueDay).count());
putSupplier(AnalysisKeys.PLAYERS_WEEK, () -> getUnsafe(uniqueWeek).count()); putSupplier(AnalysisKeys.PLAYERS_WEEK, () -> getUnsafe(uniqueWeek).count());
putSupplier(AnalysisKeys.PLAYERS_MONTH, () -> getUnsafe(uniqueMonth).count()); putSupplier(AnalysisKeys.PLAYERS_MONTH, () -> getUnsafe(uniqueMonth).count());
putSupplier(AnalysisKeys.AVG_PLAYERS_NEW, () -> getUnsafe(AnalysisKeys.PLAYERS_MUTATOR).newPerDay()); putSupplier(AnalysisKeys.AVG_PLAYERS_NEW, () -> getUnsafe(AnalysisKeys.PLAYERS_MUTATOR).averageNewPerDay());
putSupplier(AnalysisKeys.AVG_PLAYERS_NEW_DAY, () -> getUnsafe(uniqueDay).newPerDay()); putSupplier(AnalysisKeys.AVG_PLAYERS_NEW_DAY, () -> getUnsafe(newDay).averageNewPerDay());
putSupplier(AnalysisKeys.AVG_PLAYERS_NEW_WEEK, () -> getUnsafe(uniqueWeek).newPerDay()); putSupplier(AnalysisKeys.AVG_PLAYERS_NEW_WEEK, () -> getUnsafe(newWeek).averageNewPerDay());
putSupplier(AnalysisKeys.AVG_PLAYERS_NEW_MONTH, () -> getUnsafe(uniqueMonth).newPerDay()); putSupplier(AnalysisKeys.AVG_PLAYERS_NEW_MONTH, () -> getUnsafe(newMonth).averageNewPerDay());
Key<Integer> retentionDay = new Key<>(Integer.class, "RETENTION_DAY"); Key<Integer> retentionDay = new Key<>(Integer.class, "RETENTION_DAY");
// compareAndFindThoseLikelyToBeRetained can throw exception. // compareAndFindThoseLikelyToBeRetained can throw exception.
@ -290,10 +290,10 @@ public class AnalysisContainer extends DataContainer {
); );
putSupplier(AnalysisKeys.PUNCHCARD_SERIES, () -> new PunchCardGraph(getUnsafe(sessionsMonth).all()).toHighChartsSeries()); putSupplier(AnalysisKeys.PUNCHCARD_SERIES, () -> new PunchCardGraph(getUnsafe(sessionsMonth).all()).toHighChartsSeries());
putSupplier(AnalysisKeys.AVG_PLAYERS, () -> getUnsafe(AnalysisKeys.SESSIONS_MUTATOR).toUniqueJoinsPerDay()); putSupplier(AnalysisKeys.AVG_PLAYERS, () -> getUnsafe(AnalysisKeys.SESSIONS_MUTATOR).toAverageUniqueJoinsPerDay());
putSupplier(AnalysisKeys.AVG_PLAYERS_DAY, () -> getUnsafe(sessionsDay).toUniqueJoinsPerDay()); putSupplier(AnalysisKeys.AVG_PLAYERS_DAY, () -> getUnsafe(sessionsDay).toAverageUniqueJoinsPerDay());
putSupplier(AnalysisKeys.AVG_PLAYERS_WEEK, () -> getUnsafe(sessionsWeek).toUniqueJoinsPerDay()); putSupplier(AnalysisKeys.AVG_PLAYERS_WEEK, () -> getUnsafe(sessionsWeek).toAverageUniqueJoinsPerDay());
putSupplier(AnalysisKeys.AVG_PLAYERS_MONTH, () -> getUnsafe(sessionsMonth).toUniqueJoinsPerDay()); putSupplier(AnalysisKeys.AVG_PLAYERS_MONTH, () -> getUnsafe(sessionsMonth).toAverageUniqueJoinsPerDay());
} }
private void addGraphSuppliers() { private void addGraphSuppliers() {

View File

@ -0,0 +1,39 @@
package com.djrapitops.plan.data.store.mutators;
import com.djrapitops.plan.data.store.objects.DateHolder;
import com.djrapitops.plugin.api.TimeAmount;
import java.util.ArrayList;
import java.util.List;
import java.util.TreeMap;
public class DateHoldersMutator<T extends DateHolder> {
private final List<T> dateHolders;
public DateHoldersMutator(List<T> dateHolders) {
this.dateHolders = dateHolders;
}
public TreeMap<Long, List<T>> groupByStartOfDay() {
TreeMap<Long, List<T>> map = new TreeMap<>();
long twentyFourHours = 24L * TimeAmount.HOUR.ms();
for (T holder : dateHolders) {
long date = holder.getDate();
long startOfDate = date - (date % twentyFourHours);
List<T> list = map.getOrDefault(startOfDate, new ArrayList<>());
list.add(holder);
map.put(startOfDate, list);
}
// Add missing in-between dates
for (long date = map.firstKey(); date < map.lastKey(); date += twentyFourHours) {
map.putIfAbsent(date, new ArrayList<>());
}
return map;
}
}

View File

@ -0,0 +1,24 @@
package com.djrapitops.plan.data.store.mutators;
import com.djrapitops.plan.utilities.html.graphs.line.Point;
import java.util.List;
import java.util.Map;
import java.util.NavigableMap;
import java.util.stream.Collectors;
public class MutatorFunctions {
public static List<Point> toPoints(NavigableMap<Long, Integer> map) {
return map.entrySet().stream()
.map(entry -> new Point(entry.getKey(), entry.getValue()))
.collect(Collectors.toList());
}
public static int average(Map<Long, Integer> map) {
return (int) map.values().stream()
.mapToInt(i -> i)
.average().orElse(0);
}
}

View File

@ -7,13 +7,12 @@ import com.djrapitops.plan.data.store.containers.PlayerContainer;
import com.djrapitops.plan.data.store.keys.PlayerKeys; import com.djrapitops.plan.data.store.keys.PlayerKeys;
import com.djrapitops.plan.data.store.keys.ServerKeys; import com.djrapitops.plan.data.store.keys.ServerKeys;
import com.djrapitops.plan.data.store.keys.SessionKeys; import com.djrapitops.plan.data.store.keys.SessionKeys;
import com.djrapitops.plan.data.store.mutators.formatting.Formatters; import com.djrapitops.plan.data.store.objects.DateObj;
import com.djrapitops.plan.utilities.analysis.AnalysisUtils; import com.djrapitops.plan.utilities.analysis.AnalysisUtils;
import com.djrapitops.plugin.api.TimeAmount; import com.djrapitops.plugin.api.TimeAmount;
import com.djrapitops.plugin.api.utility.log.Log; import com.djrapitops.plugin.api.utility.log.Log;
import java.util.*; import java.util.*;
import java.util.function.Function;
import java.util.function.Predicate; import java.util.function.Predicate;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ -128,22 +127,22 @@ public class PlayersMutator {
return players.size(); return players.size();
} }
public int newPerDay() { public int averageNewPerDay() {
List<Long> registerDates = registerDates(); return MutatorFunctions.average(newPerDay());
int total = 0; }
Function<Long, Integer> formatter = Formatters.dayOfYear();
Set<Integer> days = new HashSet<>();
for (Long date : registerDates) {
int day = formatter.apply(date);
days.add(day);
total++;
}
int numberOfDays = days.size();
if (numberOfDays == 0) { public TreeMap<Long, Integer> newPerDay() {
return 0; List<DateObj> registerDates = registerDates().stream()
.map(value -> new DateObj<>(value, value))
.collect(Collectors.toList());
TreeMap<Long, List<DateObj>> byDay = new DateHoldersMutator<>(registerDates).groupByStartOfDay();
TreeMap<Long, Integer> byDayCounts = new TreeMap<>();
for (Map.Entry<Long, List<DateObj>> entry : byDay.entrySet()) {
byDayCounts.put(entry.getKey(), entry.getValue().size());
} }
return total / numberOfDays;
return byDayCounts;
} }
/** /**

View File

@ -2,7 +2,10 @@ package com.djrapitops.plan.data.store.mutators;
import com.djrapitops.plan.utilities.html.graphs.line.Point; import com.djrapitops.plan.utilities.html.graphs.line.Point;
import java.util.*; import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.TreeMap;
/** /**
* Resolves dates into players online numbers with a help of a NavigableMap. * Resolves dates into players online numbers with a help of a NavigableMap.
@ -11,22 +14,19 @@ import java.util.*;
* *
* @author Rsl1122 * @author Rsl1122
*/ */
public class PlayersOnlineResolver { public class PlayersOnlineResolver extends TreeMap<Long, Integer> {
private final NavigableMap<Long, Integer> onlineNumberMap;
public PlayersOnlineResolver(TPSMutator mutator) { public PlayersOnlineResolver(TPSMutator mutator) {
List<Point> points = mutator.playersOnlinePoints(); List<Point> points = mutator.playersOnlinePoints();
onlineNumberMap = new TreeMap<>();
for (Point point : points) { for (Point point : points) {
double date = point.getX(); double date = point.getX();
double value = point.getY(); double value = point.getY();
onlineNumberMap.put((long) date, (int) value); put((long) date, (int) value);
} }
} }
public Optional<Integer> getOnlineOn(long date) { public Optional<Integer> getOnlineOn(long date) {
Map.Entry<Long, Integer> entry = onlineNumberMap.floorEntry(date); Map.Entry<Long, Integer> entry = floorEntry(date);
if (entry == null) { if (entry == null) {
return Optional.empty(); return Optional.empty();
} }
@ -34,7 +34,7 @@ public class PlayersOnlineResolver {
} }
public boolean isServerOnline(long date, long timeLimit) { public boolean isServerOnline(long date, long timeLimit) {
Long lastEntry = onlineNumberMap.floorKey(date); Long lastEntry = floorKey(date);
return date - lastEntry < timeLimit; return date - lastEntry < timeLimit;
} }
} }

View File

@ -6,12 +6,10 @@ import com.djrapitops.plan.data.container.Session;
import com.djrapitops.plan.data.store.containers.DataContainer; import com.djrapitops.plan.data.store.containers.DataContainer;
import com.djrapitops.plan.data.store.keys.CommonKeys; import com.djrapitops.plan.data.store.keys.CommonKeys;
import com.djrapitops.plan.data.store.keys.SessionKeys; 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.data.time.WorldTimes;
import com.djrapitops.plugin.api.utility.log.Log; import com.djrapitops.plugin.api.utility.log.Log;
import java.util.*; import java.util.*;
import java.util.function.Function;
import java.util.function.Predicate; import java.util.function.Predicate;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ -51,6 +49,10 @@ public class SessionsMutator {
.collect(Collectors.toList())); .collect(Collectors.toList()));
} }
public DateHoldersMutator<Session> toDateHoldersMutator() {
return new DateHoldersMutator<>(sessions);
}
public WorldTimes toTotalWorldTimes() { public WorldTimes toTotalWorldTimes() {
WorldTimes total = new WorldTimes(new HashMap<>()); WorldTimes total = new WorldTimes(new HashMap<>());
@ -141,30 +143,29 @@ public class SessionsMutator {
return sessionLengths.get(sessionLengths.size() / 2); return sessionLengths.get(sessionLengths.size() / 2);
} }
public int toUniqueJoinsPerDay() { public int toAverageUniqueJoinsPerDay() {
Map<Integer, Set<UUID>> uniqueJoins = new HashMap<>(); return MutatorFunctions.average(uniqueJoinsPerDay());
Function<Long, Integer> function = Formatters.dayOfYear(); }
for (Session session : sessions) { public TreeMap<Long, Integer> uniqueJoinsPerDay() {
Optional<UUID> uuidValue = session.getValue(SessionKeys.UUID); TreeMap<Long, List<Session>> byStartOfDay = toDateHoldersMutator().groupByStartOfDay();
if (!uuidValue.isPresent()) {
continue;
}
UUID uuid = uuidValue.get();
int day = function.apply(session.getUnsafe(SessionKeys.START));
uniqueJoins.computeIfAbsent(day, computedDay -> new HashSet<>()); TreeMap<Long, Integer> uniqueJoins = new TreeMap<>();
uniqueJoins.get(day).add(uuid); for (Map.Entry<Long, List<Session>> entry : byStartOfDay.entrySet()) {
uniqueJoins.put(
entry.getKey(),
new SessionsMutator(entry.getValue()).toUniquePlayers()
);
} }
int total = (int) uniqueJoins.values().stream().mapToInt(Set::size).count(); return uniqueJoins;
int numberOfDays = uniqueJoins.size(); }
if (numberOfDays == 0) { public int toUniquePlayers() {
return 0; return (int) sessions.stream()
} .map(session -> session.getUnsafe(SessionKeys.UUID))
.distinct()
return total / numberOfDays; .count();
} }
public int count() { public int count() {

View File

@ -18,6 +18,7 @@ import com.djrapitops.plan.utilities.html.Html;
import com.djrapitops.plugin.api.TimeAmount; import com.djrapitops.plugin.api.TimeAmount;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Optional;
/** /**
* Server Health analysis mutator. * Server Health analysis mutator.
@ -59,8 +60,9 @@ public class HealthInformation extends AbstractHealthInfo {
PlayersOnlineResolver onlineResolver = analysisContainer.getUnsafe(AnalysisKeys.PLAYERS_ONLINE_RESOLVER); PlayersOnlineResolver onlineResolver = analysisContainer.getUnsafe(AnalysisKeys.PLAYERS_ONLINE_RESOLVER);
double avgOnlineOnRegister = newPlayersMonth.registerDates().stream() double avgOnlineOnRegister = newPlayersMonth.registerDates().stream()
.mapToInt(date -> onlineResolver.getOnlineOn(date).orElse(-1)) .map(onlineResolver::getOnlineOn)
.filter(value -> value != -1) .filter(Optional::isPresent)
.mapToInt(Optional::get)
.average().orElse(0); .average().orElse(0);
if (avgOnlineOnRegister >= 1) { if (avgOnlineOnRegister >= 1) {
notes.add("<p>" + Html.GREEN_THUMB.parse() + " New Players have players to play with when they join (" notes.add("<p>" + Html.GREEN_THUMB.parse() + " New Players have players to play with when they join ("