mirror of
https://github.com/plan-player-analytics/Plan.git
synced 2024-12-15 05:41:51 +08:00
Rewrote Unique player and new player counters for #560
This commit is contained in:
parent
9369a863b2
commit
0549ce32f5
@ -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() {
|
||||||
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -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() {
|
||||||
|
@ -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 ("
|
||||||
|
Loading…
Reference in New Issue
Block a user