From 7bd8eccdf723fac424714014beadd475baba3fdc Mon Sep 17 00:00:00 2001 From: AMelonInsideLemon <166175391+AMelonInsideLemon@users.noreply.github.com> Date: Wed, 26 Mar 2025 21:58:38 +0100 Subject: [PATCH] feat(leaderboard): missions & guilds leaderboard Re #1165 --- .../stats/leaderboardController.ts | 10 +++++- src/models/leaderboardModel.ts | 3 +- src/services/leaderboardService.ts | 21 ++++++++--- src/services/statsService.ts | 35 ++++++++++++++++--- src/types/leaderboardTypes.ts | 1 + 5 files changed, 59 insertions(+), 11 deletions(-) diff --git a/src/controllers/stats/leaderboardController.ts b/src/controllers/stats/leaderboardController.ts index b76e5e16..8576c92d 100644 --- a/src/controllers/stats/leaderboardController.ts +++ b/src/controllers/stats/leaderboardController.ts @@ -6,7 +6,14 @@ export const leaderboardController: RequestHandler = async (req, res) => { logger.debug(`data provided to ${req.path}: ${String(req.body)}`); const payload = JSON.parse(String(req.body)) as ILeaderboardRequest; res.json({ - results: await getLeaderboard(payload.field, payload.before, payload.after, payload.guildId, payload.pivotId) + results: await getLeaderboard( + payload.field, + payload.before, + payload.after, + payload.guildId, + payload.pivotId, + payload.guildTier + ) }); }; @@ -16,4 +23,5 @@ interface ILeaderboardRequest { after: number; guildId?: string; pivotId?: string; + guildTier?: number; } diff --git a/src/models/leaderboardModel.ts b/src/models/leaderboardModel.ts index 5de2f608..0faebddc 100644 --- a/src/models/leaderboardModel.ts +++ b/src/models/leaderboardModel.ts @@ -8,7 +8,8 @@ const leaderboardEntrySchema = new Schema( displayName: { type: String, required: true }, score: { type: Number, required: true }, guildId: Schema.Types.ObjectId, - expiry: { type: Date, required: true } + expiry: { type: Date, required: true }, + guildTier: Number }, { id: false } ); diff --git a/src/services/leaderboardService.ts b/src/services/leaderboardService.ts index afbe1623..097125bb 100644 --- a/src/services/leaderboardService.ts +++ b/src/services/leaderboardService.ts @@ -1,14 +1,15 @@ +import { Guild } from "../models/guildModel"; import { Leaderboard, TLeaderboardEntryDocument } from "../models/leaderboardModel"; import { ILeaderboardEntryClient } from "../types/leaderboardTypes"; export const submitLeaderboardScore = async ( + schedule: "weekly" | "daily", leaderboard: string, ownerId: string, displayName: string, score: number, guildId?: string ): Promise => { - const schedule = leaderboard.split(".")[0] as "daily" | "weekly"; let expiry: Date; if (schedule == "daily") { expiry = new Date(Math.trunc(Date.now() / 86400000) * 86400000 + 86400000); @@ -21,10 +22,18 @@ export const submitLeaderboardScore = async ( expiry = new Date(weekEnd); } await Leaderboard.findOneAndUpdate( - { leaderboard, ownerId }, + { leaderboard: `${schedule}.accounts.${leaderboard}`, ownerId }, { $max: { score }, $set: { displayName, guildId, expiry } }, { upsert: true } ); + if (guildId) { + const guild = (await Guild.findById(guildId, "Name Tier"))!; + await Leaderboard.findOneAndUpdate( + { leaderboard: `${schedule}.guilds.${leaderboard}`, ownerId: guildId }, + { $max: { score }, $set: { displayName: guild.Name, guildTier: guild.Tier, expiry } }, + { upsert: true } + ); + } }; export const getLeaderboard = async ( @@ -32,12 +41,16 @@ export const getLeaderboard = async ( before: number, after: number, guildId?: string, - pivotId?: string + pivotId?: string, + guildTier?: number ): Promise => { - const filter: { leaderboard: string; guildId?: string } = { leaderboard }; + const filter: { leaderboard: string; guildId?: string; guildTier?: number } = { leaderboard }; if (guildId) { filter.guildId = guildId; } + if (guildTier) { + filter.guildTier = guildTier; + } let entries: TLeaderboardEntryDocument[]; let r: number; diff --git a/src/services/statsService.ts b/src/services/statsService.ts index a6ca826c..601aae7b 100644 --- a/src/services/statsService.ts +++ b/src/services/statsService.ts @@ -286,6 +286,15 @@ export const updateStats = async (accountOwnerId: string, payload: IStatsUpdate) } else { playerStats.Missions.push({ type: type, highScore }); } + await submitLeaderboardScore( + "weekly", + type, + accountOwnerId, + payload.displayName, + highScore, + payload.guildId + ); + break; } break; @@ -304,27 +313,42 @@ export const updateStats = async (accountOwnerId: string, payload: IStatsUpdate) } await submitLeaderboardScore( - "daily.accounts." + race, + "daily", + race, accountOwnerId, payload.displayName, - highScore + highScore, + payload.guildId ); } break; case "ZephyrScore": - case "SentinelGameScore": case "CaliberChicksScore": playerStats[category] ??= 0; if (data > playerStats[category]) playerStats[category] = data as number; break; + case "SentinelGameScore": + playerStats[category] ??= 0; + if (data > playerStats[category]) playerStats[category] = data as number; + await submitLeaderboardScore( + "weekly", + category, + accountOwnerId, + payload.displayName, + data as number, + payload.guildId + ); + break; + case "DojoObstacleScore": playerStats[category] ??= 0; if (data > playerStats[category]) playerStats[category] = data as number; await submitLeaderboardScore( - "weekly.accounts." + category, + "weekly", + category, accountOwnerId, payload.displayName, data as number, @@ -350,7 +374,8 @@ export const updateStats = async (accountOwnerId: string, payload: IStatsUpdate) } if (data > playerStats[category]) playerStats[category] = data as number; await submitLeaderboardScore( - "weekly.accounts." + category, + "weekly", + category, accountOwnerId, payload.displayName, data as number diff --git a/src/types/leaderboardTypes.ts b/src/types/leaderboardTypes.ts index 5173a3a3..ed14c94d 100644 --- a/src/types/leaderboardTypes.ts +++ b/src/types/leaderboardTypes.ts @@ -7,6 +7,7 @@ export interface ILeaderboardEntryDatabase { score: number; guildId?: Types.ObjectId; expiry: Date; + guildTier?: number; } export interface ILeaderboardEntryClient {