返回提交历史
Modified
src/controllers/stats/leaderboardController.ts
+9
-1
Modified
src/models/leaderboardModel.ts
+2
-1
Modified
src/services/leaderboardService.ts
+17
-4
Modified
src/services/statsService.ts
+30
-5
Modified
src/types/leaderboardTypes.ts
+1
-0
XFEstudio/XFESpaceNinjaServer
feat(leaderboard): missions & guilds leaderboard (#1338)
Reviewed-on: https://onlyg.it/OpenWF/SpaceNinjaServer/pulls/1338 Reviewed-by: Sainan <sainan@calamity.inc> Co-authored-by: AMelonInsideLemon <166175391+AMelonInsideLemon@users.noreply.github.com> Co-committed-by: AMelonInsideLemon <166175391+AMelonInsideLemon@users.noreply.github.com>
049f7097
代码差异
5 个文件
+59
-11
@@ -6,7 +6,14 @@ export const leaderboardController: RequestHandler = async (req, res) => {
6
6
logger.debug(`data provided to ${req.path}: ${String(req.body)}`);
7
7
const payload = JSON.parse(String(req.body)) as ILeaderboardRequest;
8
8
res.json({
9
results: await getLeaderboard(payload.field, payload.before, payload.after, payload.guildId, payload.pivotId)
9
results: await getLeaderboard(
10
payload.field,
11
payload.before,
12
payload.after,
13
payload.guildId,
14
payload.pivotId,
15
payload.guildTier
16
)
10
17
});
11
18
};
12
19
@@ -16,4 +23,5 @@ interface ILeaderboardRequest {
16
23
after: number;
17
24
guildId?: string;
18
25
pivotId?: string;
26
guildTier?: number;
19
27
}
@@ -8,7 +8,8 @@ const leaderboardEntrySchema = new Schema<ILeaderboardEntryDatabase>(
8
8
displayName: { type: String, required: true },
9
9
score: { type: Number, required: true },
10
10
guildId: Schema.Types.ObjectId,
11
expiry: { type: Date, required: true }
11
expiry: { type: Date, required: true },
12
guildTier: Number
12
13
},
13
14
{ id: false }
14
15
);
@@ -1,14 +1,15 @@
1
import { Guild } from "../models/guildModel";
1
2
import { Leaderboard, TLeaderboardEntryDocument } from "../models/leaderboardModel";
2
3
import { ILeaderboardEntryClient } from "../types/leaderboardTypes";
3
4
4
5
export const submitLeaderboardScore = async (
6
schedule: "weekly" | "daily",
5
7
leaderboard: string,
6
8
ownerId: string,
7
9
displayName: string,
8
10
score: number,
9
11
guildId?: string
10
12
): Promise<void> => {
11
const schedule = leaderboard.split(".")[0] as "daily" | "weekly";
12
13
let expiry: Date;
13
14
if (schedule == "daily") {
14
15
expiry = new Date(Math.trunc(Date.now() / 86400000) * 86400000 + 86400000);
@@ -21,10 +22,18 @@ export const submitLeaderboardScore = async (
21
22
expiry = new Date(weekEnd);
22
23
}
23
24
await Leaderboard.findOneAndUpdate(
24
{ leaderboard, ownerId },
25
{ leaderboard: `${schedule}.accounts.${leaderboard}`, ownerId },
25
26
{ $max: { score }, $set: { displayName, guildId, expiry } },
26
27
{ upsert: true }
27
28
);
29
if (guildId) {
30
const guild = (await Guild.findById(guildId, "Name Tier"))!;
31
await Leaderboard.findOneAndUpdate(
32
{ leaderboard: `${schedule}.guilds.${leaderboard}`, ownerId: guildId },
33
{ $max: { score }, $set: { displayName: guild.Name, guildTier: guild.Tier, expiry } },
34
{ upsert: true }
35
);
36
}
28
37
};
29
38
30
39
export const getLeaderboard = async (
@@ -32,12 +41,16 @@ export const getLeaderboard = async (
32
41
before: number,
33
42
after: number,
34
43
guildId?: string,
35
pivotId?: string
44
pivotId?: string,
45
guildTier?: number
36
46
): Promise<ILeaderboardEntryClient[]> => {
37
const filter: { leaderboard: string; guildId?: string } = { leaderboard };
47
const filter: { leaderboard: string; guildId?: string; guildTier?: number } = { leaderboard };
38
48
if (guildId) {
39
49
filter.guildId = guildId;
40
50
}
51
if (guildTier) {
52
filter.guildTier = guildTier;
53
}
41
54
42
55
let entries: TLeaderboardEntryDocument[];
43
56
let r: number;
@@ -286,6 +286,15 @@ export const updateStats = async (accountOwnerId: string, payload: IStatsUpdate)
286
286
} else {
287
287
playerStats.Missions.push({ type: type, highScore });
288
288
}
289
await submitLeaderboardScore(
290
"weekly",
291
type,
292
accountOwnerId,
293
payload.displayName,
294
highScore,
295
payload.guildId
296
);
297
break;
289
298
}
290
299
break;
291
300
@@ -304,27 +313,42 @@ export const updateStats = async (accountOwnerId: string, payload: IStatsUpdate)
304
313
}
305
314
306
315
await submitLeaderboardScore(
307
"daily.accounts." + race,
316
"daily",
317
race,
308
318
accountOwnerId,
309
319
payload.displayName,
310
highScore
320
highScore,
321
payload.guildId
311
322
);
312
323
}
313
324
314
325
break;
315
326
316
327
case "ZephyrScore":
317
case "SentinelGameScore":
318
328
case "CaliberChicksScore":
319
329
playerStats[category] ??= 0;
320
330
if (data > playerStats[category]) playerStats[category] = data as number;
321
331
break;
322
332
333
case "SentinelGameScore":
334
playerStats[category] ??= 0;
335
if (data > playerStats[category]) playerStats[category] = data as number;
336
await submitLeaderboardScore(
337
"weekly",
338
category,
339
accountOwnerId,
340
payload.displayName,
341
data as number,
342
payload.guildId
343
);
344
break;
345
323
346
case "DojoObstacleScore":
324
347
playerStats[category] ??= 0;
325
348
if (data > playerStats[category]) playerStats[category] = data as number;
326
349
await submitLeaderboardScore(
327
"weekly.accounts." + category,
350
"weekly",
351
category,
328
352
accountOwnerId,
329
353
payload.displayName,
330
354
data as number,
@@ -350,7 +374,8 @@ export const updateStats = async (accountOwnerId: string, payload: IStatsUpdate)
350
374
}
351
375
if (data > playerStats[category]) playerStats[category] = data as number;
352
376
await submitLeaderboardScore(
353
"weekly.accounts." + category,
377
"weekly",
378
category,
354
379
accountOwnerId,
355
380
payload.displayName,
356
381
data as number
@@ -7,6 +7,7 @@ export interface ILeaderboardEntryDatabase {
7
7
score: number;
8
8
guildId?: Types.ObjectId;
9
9
expiry: Date;
10
guildTier?: number;
10
11
}
11
12
12
13
export interface ILeaderboardEntryClient {