Skip to content

Commit 2f3d07f

Browse files
committed
Add UNIQUE_PLAYERS_AVERAGE Datapoint
1 parent 9513478 commit 2f3d07f

13 files changed

Lines changed: 143 additions & 32 deletions

File tree

Plan/common/src/main/java/com/djrapitops/plan/delivery/domain/auth/WebPermission.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -142,8 +142,10 @@ public enum WebPermission implements Supplier<String>, Lang {
142142
DATA_PLAYER_SERVER_PIE("See Server Pie -datapoint of players"),
143143
DATA_SERVER_SERVER_PIE("See Server Pie -datapoint of servers"),
144144
DATA_NETWORK_SERVER_PIE("See Server Pie -datapoint of network"),
145-
DATA_SERVER_UNIQUE_PLAYERS("See Unique players -datapoint of servers"),
146-
DATA_NETWORK_UNIQUE_PLAYERS("See Unique players -datapoint of network"),
145+
DATA_SERVER_UNIQUE_PLAYERS_COUNT("See Unique players -datapoint of servers"),
146+
DATA_NETWORK_UNIQUE_PLAYERS_COUNT("See Unique players -datapoint of network"),
147+
DATA_SERVER_UNIQUE_PLAYERS_AVERAGE("See Unique players average -datapoint of servers"),
148+
DATA_NETWORK_UNIQUE_PLAYERS_AVERAGE("See Unique players average -datapoint of network"),
147149
DATA_SERVER_REGULAR_PLAYERS("See Regular players -datapoint of servers"),
148150
DATA_NETWORK_REGULAR_PLAYERS("See Regular players -datapoint of network"),
149151
DATA_SERVER_NEW_PLAYERS("See New players -datapoint of servers"),

Plan/common/src/main/java/com/djrapitops/plan/delivery/export/NetworkPageExporter.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -141,9 +141,9 @@ public void exportJSON(Path toDirectory, ServerUUID serverUUID) throws IOExcepti
141141
datapointType + DatapointType.MOST_ACTIVE_GAME_MODE + after,
142142
datapointType + DatapointType.WORLD_PIE + after,
143143
datapointType + DatapointType.SERVER_PIE,
144-
datapointType + DatapointType.UNIQUE_PLAYERS + afterMillis + TimeUnit.DAYS.toMillis(30),
145-
datapointType + DatapointType.UNIQUE_PLAYERS + afterMillis + TimeUnit.DAYS.toMillis(7),
146-
datapointType + DatapointType.UNIQUE_PLAYERS + afterMillis + TimeUnit.DAYS.toMillis(1),
144+
datapointType + DatapointType.UNIQUE_PLAYERS_COUNT + afterMillis + TimeUnit.DAYS.toMillis(30),
145+
datapointType + DatapointType.UNIQUE_PLAYERS_COUNT + afterMillis + TimeUnit.DAYS.toMillis(7),
146+
datapointType + DatapointType.UNIQUE_PLAYERS_COUNT + afterMillis + TimeUnit.DAYS.toMillis(1),
147147
datapointType + DatapointType.NEW_PLAYERS,
148148
datapointType + DatapointType.NEW_PLAYERS + afterMillis + TimeUnit.DAYS.toMillis(30),
149149
datapointType + DatapointType.NEW_PLAYERS + afterMillis + TimeUnit.DAYS.toMillis(7),
@@ -161,7 +161,7 @@ public void exportJSON(Path toDirectory, ServerUUID serverUUID) throws IOExcepti
161161
datapointType + DatapointType.DEATHS,
162162
datapointType + DatapointType.UPTIME_CURRENT,
163163
// Week comparison
164-
datapointType + DatapointType.UNIQUE_PLAYERS + afterMillis + TimeUnit.DAYS.toMillis(14) + beforeMillis + TimeUnit.DAYS.toMillis(7L),
164+
datapointType + DatapointType.UNIQUE_PLAYERS_COUNT + afterMillis + TimeUnit.DAYS.toMillis(14) + beforeMillis + TimeUnit.DAYS.toMillis(7L),
165165
datapointType + DatapointType.NEW_PLAYERS + afterMillis + TimeUnit.DAYS.toMillis(14) + beforeMillis + TimeUnit.DAYS.toMillis(7L),
166166
datapointType + DatapointType.REGULAR_PLAYERS + afterMillis + TimeUnit.DAYS.toMillis(14) + beforeMillis + TimeUnit.DAYS.toMillis(7L),
167167
datapointType + DatapointType.PLAYTIME_PER_PLAYER_AVERAGE + afterMillis + TimeUnit.DAYS.toMillis(14) + beforeMillis + TimeUnit.DAYS.toMillis(7L),

Plan/common/src/main/java/com/djrapitops/plan/delivery/export/ServerPageExporter.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -169,8 +169,9 @@ public void exportJSON(Path toDirectory, ServerUUID serverUUID) throws IOExcepti
169169
datapointType + DatapointType.DEATHS + server,
170170
datapointType + DatapointType.UPTIME_CURRENT + server,
171171
datapointType + DatapointType.TPS_AVERAGE + afterMillis + TimeUnit.DAYS.toMillis(7) + server,
172+
datapointType + DatapointType.UNIQUE_PLAYERS_AVERAGE + afterMillis + TimeUnit.DAYS.toMillis(7) + server,
172173
// Week comparison
173-
datapointType + DatapointType.UNIQUE_PLAYERS + afterMillis + TimeUnit.DAYS.toMillis(14) + beforeMillis + TimeUnit.DAYS.toMillis(7L) + server,
174+
datapointType + DatapointType.UNIQUE_PLAYERS_COUNT + afterMillis + TimeUnit.DAYS.toMillis(14) + beforeMillis + TimeUnit.DAYS.toMillis(7L) + server,
174175
datapointType + DatapointType.NEW_PLAYERS + afterMillis + TimeUnit.DAYS.toMillis(14) + beforeMillis + TimeUnit.DAYS.toMillis(7L) + server,
175176
datapointType + DatapointType.REGULAR_PLAYERS + afterMillis + TimeUnit.DAYS.toMillis(14) + beforeMillis + TimeUnit.DAYS.toMillis(7L) + server,
176177
datapointType + DatapointType.PLAYTIME_PER_PLAYER_AVERAGE + afterMillis + TimeUnit.DAYS.toMillis(14) + beforeMillis + TimeUnit.DAYS.toMillis(7L) + server,
@@ -179,7 +180,7 @@ public void exportJSON(Path toDirectory, ServerUUID serverUUID) throws IOExcepti
179180
datapointType + DatapointType.PLAYER_KILLS + afterMillis + TimeUnit.DAYS.toMillis(14) + beforeMillis + TimeUnit.DAYS.toMillis(7L) + server,
180181
datapointType + DatapointType.MOB_KILLS + afterMillis + TimeUnit.DAYS.toMillis(14) + beforeMillis + TimeUnit.DAYS.toMillis(7L) + server,
181182
datapointType + DatapointType.DEATHS + afterMillis + TimeUnit.DAYS.toMillis(14) + beforeMillis + TimeUnit.DAYS.toMillis(7L) + server,
182-
datapointType + DatapointType.UNIQUE_PLAYERS + afterMillis + TimeUnit.DAYS.toMillis(7) + server,
183+
datapointType + DatapointType.UNIQUE_PLAYERS_COUNT + afterMillis + TimeUnit.DAYS.toMillis(7) + server,
183184
datapointType + DatapointType.NEW_PLAYERS + afterMillis + TimeUnit.DAYS.toMillis(7) + server,
184185
datapointType + DatapointType.REGULAR_PLAYERS + afterMillis + TimeUnit.DAYS.toMillis(7) + server,
185186
datapointType + DatapointType.PLAYTIME_PER_PLAYER_AVERAGE + afterMillis + TimeUnit.DAYS.toMillis(7) + server,

Plan/common/src/main/java/com/djrapitops/plan/delivery/rendering/json/datapoint/DatapointType.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ public enum DatapointType {
3737
MOST_ACTIVE_GAME_MODE(MostActiveGameMode.class, DatapointCacheKey.SESSION),
3838
MOST_ACTIVE_WORLD(MostActiveWorld.class, DatapointCacheKey.SESSION),
3939
SERVER_PIE(ServerPie.class, DatapointCacheKey.SESSION),
40-
UNIQUE_PLAYERS(UniquePlayers.class, DatapointCacheKey.SESSION),
40+
UNIQUE_PLAYERS_COUNT(UniquePlayersCount.class, DatapointCacheKey.SESSION),
4141
NEW_PLAYERS(NewPlayers.class, DatapointCacheKey.SESSION),
4242
REGULAR_PLAYERS(RegularPlayers.class, DatapointCacheKey.SESSION),
4343
SESSION_COUNT(SessionCount.class, DatapointCacheKey.SESSION),
@@ -55,7 +55,8 @@ public enum DatapointType {
5555
CPU_AVERAGE(CPUAverage.class, DatapointCacheKey.TPS),
5656
RAM_AVERAGE(RAMAverage.class, DatapointCacheKey.TPS),
5757
ENTITIES_AVERAGE(EntitiesAverage.class, DatapointCacheKey.TPS),
58-
CHUNKS_AVERAGE(ChunksAverage.class, DatapointCacheKey.TPS);
58+
CHUNKS_AVERAGE(ChunksAverage.class, DatapointCacheKey.TPS),
59+
UNIQUE_PLAYERS_AVERAGE(UniquePlayersPerDayAverage.class, DatapointCacheKey.SESSION);
5960

6061
private final Class<? extends Datapoint<?>> datapointClass;
6162
private final DatapointCacheKey[] cacheKeys;

Plan/common/src/main/java/com/djrapitops/plan/delivery/rendering/json/datapoint/types/DatapointModule.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@
2222
import dagger.multibindings.IntoSet;
2323

2424
/**
25+
* Dagger module for registering {@code Set<Datapoint<?>> for use in constructors so that individual ones don't need to be injected.}
26+
*
2527
* @author AuroraLS3
2628
*/
2729
@Module
@@ -62,7 +64,7 @@ public interface DatapointModule {
6264

6365
@Binds
6466
@IntoSet
65-
Datapoint<?> bindUniquePlayers(UniquePlayers uniquePlayers);
67+
Datapoint<?> bindUniquePlayers(UniquePlayersCount uniquePlayersCount);
6668

6769
@Binds
6870
@IntoSet
@@ -135,4 +137,8 @@ public interface DatapointModule {
135137
@Binds
136138
@IntoSet
137139
Datapoint<?> bindChunksAverage(ChunksAverage chunksAverage);
140+
141+
@Binds
142+
@IntoSet
143+
Datapoint<?> bindUniquePlayersAveragePerDay(UniquePlayersPerDayAverage uniquePlayersPerDayAverage);
138144
}

Plan/common/src/main/java/com/djrapitops/plan/delivery/rendering/json/datapoint/types/UniquePlayers.java renamed to Plan/common/src/main/java/com/djrapitops/plan/delivery/rendering/json/datapoint/types/UniquePlayersCount.java

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -30,39 +30,42 @@
3030

3131
/**
3232
* Datapoint for unique player count.
33+
* <p>
34+
* Unique player count is computed by checking if a player has a session within selected timeframe,
35+
* only counting them once even if they have multiple within the timeframe.
3336
*
3437
* @author AuroraLS3
3538
*/
3639
@Singleton
37-
public class UniquePlayers implements Datapoint<Integer> {
40+
public class UniquePlayersCount implements Datapoint<Integer> {
3841

3942
private final DBSystem dbSystem;
4043

4144
@Inject
42-
public UniquePlayers(DBSystem dbSystem) {
45+
public UniquePlayersCount(DBSystem dbSystem) {
4346
this.dbSystem = dbSystem;
4447
}
4548

4649
@Override
4750
public DatapointType getType() {
48-
return DatapointType.UNIQUE_PLAYERS;
51+
return DatapointType.UNIQUE_PLAYERS_COUNT;
4952
}
5053

5154
@Override
5255
public WebPermission getPermission(GenericFilter filter) {
5356
if (filter.getPlayerUUID().isPresent()) {
5457
return WebPermission.DATA_PLAYER;
5558
} else if (!filter.getServerUUIDs().isEmpty()) {
56-
return WebPermission.DATA_SERVER_UNIQUE_PLAYERS;
59+
return WebPermission.DATA_SERVER_UNIQUE_PLAYERS_COUNT;
5760
} else {
58-
return WebPermission.DATA_NETWORK_UNIQUE_PLAYERS;
61+
return WebPermission.DATA_NETWORK_UNIQUE_PLAYERS_COUNT;
5962
}
6063
}
6164

6265
@Override
6366
public Optional<Integer> getValue(GenericFilter filter) {
6467
if (filter.getPlayerUUID().isPresent()) {
65-
throw new BadRequestException("UNIQUE_PLAYERS does not support player parameter");
68+
throw new BadRequestException("UNIQUE_PLAYERS_COUNT does not support player parameter");
6669
}
6770

6871
if (!filter.getServerUUIDs().isEmpty()) {
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
/*
2+
* This file is part of Player Analytics (Plan).
3+
*
4+
* Plan is free software: you can redistribute it and/or modify
5+
* it under the terms of the GNU Lesser General Public License v3 as published by
6+
* the Free Software Foundation, either version 3 of the License, or
7+
* (at your option) any later version.
8+
*
9+
* Plan is distributed in the hope that it will be useful,
10+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
* GNU Lesser General Public License for more details.
13+
*
14+
* You should have received a copy of the GNU Lesser General Public License
15+
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
16+
*/
17+
package com.djrapitops.plan.delivery.rendering.json.datapoint.types;
18+
19+
import com.djrapitops.plan.delivery.domain.auth.WebPermission;
20+
import com.djrapitops.plan.delivery.domain.datatransfer.GenericFilter;
21+
import com.djrapitops.plan.delivery.rendering.json.datapoint.Datapoint;
22+
import com.djrapitops.plan.delivery.rendering.json.datapoint.DatapointType;
23+
import com.djrapitops.plan.delivery.web.resolver.exception.BadRequestException;
24+
import com.djrapitops.plan.settings.config.PlanConfig;
25+
import com.djrapitops.plan.storage.database.DBSystem;
26+
import com.djrapitops.plan.storage.database.queries.analysis.PlayerCountQueries;
27+
28+
import javax.inject.Inject;
29+
import javax.inject.Singleton;
30+
import java.util.Optional;
31+
32+
/**
33+
* Datapoint for Unique players average per day.
34+
* <p>
35+
* Average is computed using the timezone configured in the config,
36+
* splitting day at midnight and counting unique players each day,
37+
* and then averaging the number.
38+
*
39+
* @author AuroraLS3
40+
*/
41+
@Singleton
42+
public class UniquePlayersPerDayAverage implements Datapoint<Integer> {
43+
44+
private final PlanConfig config;
45+
private final DBSystem dbSystem;
46+
47+
@Inject
48+
public UniquePlayersPerDayAverage(PlanConfig config, DBSystem dbSystem) {
49+
this.config = config;
50+
this.dbSystem = dbSystem;
51+
}
52+
53+
@Override
54+
public Optional<Integer> getValue(GenericFilter filter) {
55+
if (filter.getPlayerUUID().isPresent()) {
56+
throw new BadRequestException("UNIQUE_PLAYERS_AVERAGE does not support player parameter");
57+
}
58+
59+
if (!filter.getServerUUIDs().isEmpty()) {
60+
return Optional.of(dbSystem.getDatabase().query(PlayerCountQueries.averageUniquePlayerCount(
61+
filter.getAfter(), filter.getBefore(), config.getTimeZone().getOffset(filter.getBefore()), filter.getServerUUIDs())
62+
));
63+
}
64+
65+
return Optional.of(dbSystem.getDatabase().query(PlayerCountQueries.averageUniquePlayerCount(
66+
filter.getAfter(), filter.getBefore(), config.getTimeZone().getOffset(filter.getBefore()))
67+
));
68+
}
69+
70+
@Override
71+
public WebPermission getPermission(GenericFilter filter) {
72+
if (filter.getPlayerUUID().isPresent()) {
73+
return WebPermission.DATA_PLAYER;
74+
} else if (!filter.getServerUUIDs().isEmpty()) {
75+
return WebPermission.DATA_SERVER_UNIQUE_PLAYERS_AVERAGE;
76+
} else {
77+
return WebPermission.DATA_NETWORK_UNIQUE_PLAYERS_AVERAGE;
78+
}
79+
}
80+
81+
@Override
82+
public DatapointType getType() {
83+
return DatapointType.UNIQUE_PLAYERS_AVERAGE;
84+
}
85+
}

Plan/common/src/main/java/com/djrapitops/plan/storage/database/queries/analysis/PlayerCountQueries.java

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,13 @@ public static Query<NavigableMap<Long, Integer>> hourlyUniquePlayerCounts(long a
214214
}
215215

216216
public static Query<Integer> averageUniquePlayerCount(long after, long before, long timeZoneOffset, ServerUUID serverUUID) {
217+
return averageUniquePlayerCount(after, before, timeZoneOffset, List.of(serverUUID));
218+
}
219+
220+
public static Query<Integer> averageUniquePlayerCount(long after, long before, long timeZoneOffset, List<ServerUUID> serverUUIDs) {
221+
if (serverUUIDs.isEmpty()) {
222+
return averageUniquePlayerCount(after, before, timeZoneOffset);
223+
}
217224
return database -> {
218225
Sql sql = database.getSql();
219226
String selectUniquePlayersPerDay = SELECT +
@@ -224,13 +231,13 @@ public static Query<Integer> averageUniquePlayerCount(long after, long before, l
224231
INNER_JOIN + ServerTable.TABLE_NAME + " s ON s." + ServerTable.ID + "=t." + SessionsTable.SERVER_ID +
225232
WHERE + SessionsTable.SESSION_END + "<=?" +
226233
AND + SessionsTable.SESSION_START + ">=?" +
227-
AND + "s." + ServerTable.SERVER_UUID + "=?" +
234+
AND + "s." + ServerTable.SERVER_UUID + " IN (" + ServerTable.uuids(serverUUIDs) + ")" +
228235
GROUP_BY + "date";
229236
String selectAverage = SELECT + "AVG(" + PLAYER_COUNT + ") as average" + FROM + '(' + selectUniquePlayersPerDay + ") q1";
230237

231238
return database.queryOptional(selectAverage,
232239
set -> (int) set.getDouble("average"),
233-
timeZoneOffset, before, after, serverUUID.toString())
240+
timeZoneOffset, before, after)
234241
.orElse(0);
235242
};
236243
}

Plan/common/src/test/java/com/djrapitops/plan/delivery/webserver/AccessControlTest.java

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -201,9 +201,12 @@ static Stream<Arguments> testCases() {
201201
Arguments.of("/v1/datapoint?type=SERVER_PIE", WebPermission.DATA_NETWORK_SERVER_PIE, 200, 403),
202202
Arguments.of("/v1/datapoint?type=SERVER_PIE&server=" + TestConstants.SERVER_UUID_STRING, WebPermission.DATA_SERVER_SERVER_PIE, 200, 403),
203203
Arguments.of("/v1/datapoint?type=SERVER_PIE&player=" + TestConstants.PLAYER_ONE_UUID_STRING, WebPermission.DATA_PLAYER_SERVER_PIE, 200, 403),
204-
Arguments.of("/v1/datapoint?type=UNIQUE_PLAYERS", WebPermission.DATA_NETWORK_UNIQUE_PLAYERS, 200, 403),
205-
Arguments.of("/v1/datapoint?type=UNIQUE_PLAYERS&server=" + TestConstants.SERVER_UUID_STRING, WebPermission.DATA_SERVER_UNIQUE_PLAYERS, 200, 403),
206-
Arguments.of("/v1/datapoint?type=UNIQUE_PLAYERS&player=" + TestConstants.PLAYER_ONE_UUID_STRING, WebPermission.DATA_PLAYER, 400, 403),
204+
Arguments.of("/v1/datapoint?type=UNIQUE_PLAYERS_COUNT", WebPermission.DATA_NETWORK_UNIQUE_PLAYERS_COUNT, 200, 403),
205+
Arguments.of("/v1/datapoint?type=UNIQUE_PLAYERS_COUNT&server=" + TestConstants.SERVER_UUID_STRING, WebPermission.DATA_SERVER_UNIQUE_PLAYERS_COUNT, 200, 403),
206+
Arguments.of("/v1/datapoint?type=UNIQUE_PLAYERS_COUNT&player=" + TestConstants.PLAYER_ONE_UUID_STRING, WebPermission.DATA_PLAYER, 400, 403),
207+
Arguments.of("/v1/datapoint?type=UNIQUE_PLAYERS_AVERAGE", WebPermission.DATA_NETWORK_UNIQUE_PLAYERS_AVERAGE, 200, 403),
208+
Arguments.of("/v1/datapoint?type=UNIQUE_PLAYERS_AVERAGE&server=" + TestConstants.SERVER_UUID_STRING, WebPermission.DATA_SERVER_UNIQUE_PLAYERS_AVERAGE, 200, 403),
209+
Arguments.of("/v1/datapoint?type=UNIQUE_PLAYERS_AVERAGE&player=" + TestConstants.PLAYER_ONE_UUID_STRING, WebPermission.DATA_PLAYER, 400, 403),
207210
Arguments.of("/v1/datapoint?type=NEW_PLAYERS", WebPermission.DATA_NETWORK_NEW_PLAYERS, 200, 403),
208211
Arguments.of("/v1/datapoint?type=NEW_PLAYERS&server=" + TestConstants.SERVER_UUID_STRING, WebPermission.DATA_SERVER_NEW_PLAYERS, 200, 403),
209212
Arguments.of("/v1/datapoint?type=NEW_PLAYERS&player=" + TestConstants.PLAYER_ONE_UUID_STRING, WebPermission.DATA_PLAYER, 400, 403),

Plan/react/dashboard/src/components/cards/network/RecentPlayersCard.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ export const RecentPlayersCard = () => {
2626
<p>{t('html.label.last24hours')}</p>
2727
<QueryDatapoint icon={faUsers} color="players-unique"
2828
name={t('html.label.uniquePlayers')}
29-
dataType={DatapointType.UNIQUE_PLAYERS}
29+
dataType={DatapointType.UNIQUE_PLAYERS_COUNT}
3030
filter={filter}/>
3131
<QueryDatapoint icon={faUsers} color="players-new"
3232
name={t('html.label.newPlayers')}
@@ -41,7 +41,7 @@ export const RecentPlayersCard = () => {
4141
<p>{t('html.label.last7days')}</p>
4242
<QueryDatapoint icon={faUsers} color="players-unique"
4343
name={t('html.label.uniquePlayers')}
44-
dataType={DatapointType.UNIQUE_PLAYERS}
44+
dataType={DatapointType.UNIQUE_PLAYERS_COUNT}
4545
filter={filter}/>
4646
<QueryDatapoint icon={faUsers} color="players-new"
4747
name={t('html.label.newPlayers')}
@@ -56,7 +56,7 @@ export const RecentPlayersCard = () => {
5656
<p>{t('html.label.last30days')}</p>
5757
<QueryDatapoint icon={faUsers} color="players-unique"
5858
name={t('html.label.uniquePlayers')}
59-
dataType={DatapointType.UNIQUE_PLAYERS}
59+
dataType={DatapointType.UNIQUE_PLAYERS_COUNT}
6060
filter={filter}/>
6161
<QueryDatapoint icon={faUsers} color="players-new"
6262
name={t('html.label.newPlayers')}

0 commit comments

Comments
 (0)