Skip to content

Commit 8f91b3a

Browse files
committed
playtimetop command
1 parent 555fed5 commit 8f91b3a

File tree

5 files changed

+147
-9
lines changed

5 files changed

+147
-9
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ Invite link: [bot.2b2t.vc](https://bot.2b2t.vc)
1717
* `/kills` -> Prints a player's kill history
1818
* `/killsmonth` -> Leaderboard for top kills in the last 30 days
1919
* `/playtime` -> Gets a player's total playtime
20+
* `playtimetop` -> Leaderboard for all time top playtime on 2b2t
2021
* `/playtimemonth` -> Leaderboard for top playtime in the last 30 days
2122
* `/tablist` -> Prints all online players right now on 2b2t
2223
* `/data` -> Dumps all data on a player as a CSV file

openapi/api.2b2t.vc.openapi.json

Lines changed: 53 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,29 @@
227227
}
228228
}
229229
},
230+
"/playtime/top": {
231+
"get": {
232+
"tags": [
233+
"Playtime"
234+
],
235+
"operationId": "playtimeTopAllTime",
236+
"responses": {
237+
"200": {
238+
"description": "Top playtime all time",
239+
"content": {
240+
"application/json": {
241+
"schema": {
242+
"$ref": "#/components/schemas/PlaytimeAllTimeResponse"
243+
}
244+
}
245+
}
246+
},
247+
"204": {
248+
"description": "No data"
249+
}
250+
}
251+
}
252+
},
230253
"/playtime/top/month": {
231254
"get": {
232255
"tags": [
@@ -245,7 +268,7 @@
245268
}
246269
},
247270
"204": {
248-
"description": "No data for player"
271+
"description": "No data"
249272
}
250273
}
251274
}
@@ -949,7 +972,34 @@
949972
}
950973
}
951974
},
952-
"PlayerPlaytimeData": {
975+
"PlayerPlaytimeSecondsData": {
976+
"type": "object",
977+
"properties": {
978+
"uuid": {
979+
"type": "string",
980+
"format": "uuid"
981+
},
982+
"playerName": {
983+
"type": "string"
984+
},
985+
"playtimeSeconds": {
986+
"type": "integer",
987+
"format": "int64"
988+
}
989+
}
990+
},
991+
"PlaytimeAllTimeResponse": {
992+
"type": "object",
993+
"properties": {
994+
"players": {
995+
"type": "array",
996+
"items": {
997+
"$ref": "#/components/schemas/PlayerPlaytimeSecondsData"
998+
}
999+
}
1000+
}
1001+
},
1002+
"PlayerPlaytimeDaysData": {
9531003
"type": "object",
9541004
"properties": {
9551005
"uuid": {
@@ -971,7 +1021,7 @@
9711021
"players": {
9721022
"type": "array",
9731023
"items": {
974-
"$ref": "#/components/schemas/PlayerPlaytimeData"
1024+
"$ref": "#/components/schemas/PlayerPlaytimeDaysData"
9751025
}
9761026
}
9771027
}

src/main/java/vc/commands/PlaytimeCommand.java

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@
1616
import vc.openapi.model.PlaytimeResponse;
1717
import vc.util.PlayerLookup;
1818

19+
import java.util.ArrayList;
20+
import java.util.List;
21+
1922
import static java.util.Objects.isNull;
2023
import static org.slf4j.LoggerFactory.getLogger;
2124

@@ -83,11 +86,11 @@ private String formatDuration(long durationInSeconds) {
8386
var months = (durationInSeconds % secondsInYear) / secondsInMonth;
8487
var days = (durationInSeconds % secondsInMonth) / secondsInDay;
8588
var hours = (durationInSeconds % secondsInDay) / secondsInHour;
86-
final StringBuilder sb = new StringBuilder();
87-
sb.append((years > 0) ? years + " year" + (years != 1 ? "s" : "") + ", " : "");
88-
sb.append((months > 0) ? months + " month" + (months != 1 ? "s" : "") + ", " : "");
89-
sb.append((days > 0) ? days + " day" + (days != 1 ? "s" : "") + ", " : "");
90-
sb.append(hours + " hour" + (hours != 1 ? "s" : ""));
91-
return sb.toString();
89+
List<String> entries = new ArrayList<>(4);
90+
if (years > 0) entries.add(years + " year" + (years != 1 ? "s" : ""));
91+
if (months > 0) entries.add(months + " month" + (months != 1 ? "s" : ""));
92+
if (days > 0) entries.add(days + " day" + (days != 1 ? "s" : ""));
93+
if (hours > 0) entries.add(hours + " hour" + (hours != 1 ? "s" : ""));
94+
return String.join(", ", entries);
9295
}
9396
}
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
package vc.commands;
2+
3+
import discord4j.core.event.domain.interaction.ChatInputInteractionEvent;
4+
import discord4j.core.object.entity.Message;
5+
import discord4j.core.spec.EmbedCreateSpec;
6+
import discord4j.rest.util.Color;
7+
import org.slf4j.Logger;
8+
import org.slf4j.LoggerFactory;
9+
import org.springframework.stereotype.Component;
10+
import reactor.core.publisher.Mono;
11+
import vc.openapi.handler.PlaytimeApi;
12+
import vc.openapi.model.PlaytimeAllTimeResponse;
13+
14+
import java.util.ArrayList;
15+
import java.util.List;
16+
17+
@Component
18+
public class PlaytimeTopCommand implements SlashCommand {
19+
private static final Logger LOGGER = LoggerFactory.getLogger(PlaytimeTopCommand.class);
20+
private final PlaytimeApi playtimeApi;
21+
22+
public PlaytimeTopCommand(final PlaytimeApi playtimeApi) {
23+
this.playtimeApi = playtimeApi;
24+
}
25+
26+
@Override
27+
public String getName() {
28+
return "playtimetop";
29+
}
30+
31+
@Override
32+
public Mono<Message> handle(final ChatInputInteractionEvent event) {
33+
return Mono.defer(() -> {
34+
PlaytimeAllTimeResponse response = null;
35+
try {
36+
response = playtimeApi.playtimeTopAllTime();
37+
} catch (final Exception e) {
38+
LOGGER.error("Failed to get playtime top all time", e);
39+
}
40+
if (response == null || response.getPlayers() == null || response.getPlayers().isEmpty())
41+
return error(event, "Unable to resolve playtime top data");
42+
StringBuilder result = new StringBuilder();
43+
for (int i = 0, ptListSize = Math.min(50, response.getPlayers().size()); i < ptListSize; i++) {
44+
var player = response.getPlayers().get(i);
45+
var seconds = player.getPlaytimeSeconds();
46+
var s = "**" + escape(player.getPlayerName()) + "**: " + formatDuration(seconds);
47+
if (result.length() + s.length() > 4090) {
48+
break;
49+
}
50+
result.append("*#").append(i + 1).append(":* ").append(s).append("\n");
51+
}
52+
if (!result.isEmpty()) {
53+
result.deleteCharAt(result.length() - 1);
54+
}
55+
return event.createFollowup()
56+
.withEmbeds(EmbedCreateSpec.builder()
57+
.title("Top Playtime")
58+
.color(Color.CYAN)
59+
.description(result.toString())
60+
.build());
61+
});
62+
}
63+
64+
private String formatDuration(long durationInSeconds) {
65+
var secondsInMinute = 60L;
66+
var secondsInHour = secondsInMinute * 60L;
67+
var secondsInDay = secondsInHour * 24L;
68+
var secondsInMonth = secondsInDay * 30L; // assuming 30 days per month
69+
var secondsInYear = secondsInMonth * 12L;
70+
71+
var years = durationInSeconds / secondsInYear;
72+
var months = (durationInSeconds % secondsInYear) / secondsInMonth;
73+
var days = (durationInSeconds % secondsInMonth) / secondsInDay;
74+
List<String> entries = new ArrayList<>(3);
75+
if (years > 0) entries.add(years + " year" + (years != 1 ? "s" : ""));
76+
if (months > 0) entries.add(months + " month" + (months != 1 ? "s" : ""));
77+
if (days > 0) entries.add(days + " day" + (days != 1 ? "s" : ""));
78+
return String.join(", ", entries);
79+
}
80+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"name": "playtimetop",
3+
"description": "Top playtime over all time"
4+
}

0 commit comments

Comments
 (0)