feat(leaderboard): missions & guilds leaderboard #1338

Merged
Sainan merged 3 commits from AMelonInsideLemon/SpaceNinjaServer:missions-leaderbord into main 2025-03-26 14:21:22 -07:00
5 changed files with 59 additions and 11 deletions

View File

@ -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;
}

View File

@ -8,7 +8,8 @@ const leaderboardEntrySchema = new Schema<ILeaderboardEntryDatabase>(
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 }
);

View File

@ -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<void> => {
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<ILeaderboardEntryClient[]> => {
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;

View File

@ -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
Sainan marked this conversation as resolved Outdated

You should revert this change, it is not correct or faithful.

You should revert this change, it is not correct or faithful.

K-drive races have clans leaderboard in ESC menu

K-drive races have clans leaderboard in ESC menu

But not for clan tiers I mean. Also, the guildId is undefined in the upload request for K-Drive races, so this is wrong either way.

But not for clan tiers I mean. Also, the `guildId` is undefined in the upload request for K-Drive races, so this is wrong either way.

They have buttons for that leaderboards but seams missing guildId is bug image.pngimage.png

They have buttons for that leaderboards but seams missing `guildId` is bug ![image.png](/attachments/dd4f0163-cfd0-4567-8b29-f9add939f7a2)![image.png](/attachments/6ea7747b-2424-49a6-b720-5a76d7dc30c6)
3.2 MiB
3.3 MiB

Yeah exactly. Then again, maybe the bug is in the way the client sends the request...

Yeah exactly. Then again, maybe the bug is in the way the client sends the request...
);
}
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

View File

@ -7,6 +7,7 @@ export interface ILeaderboardEntryDatabase {
score: number;
guildId?: Types.ObjectId;
expiry: Date;
guildTier?: number;
}
export interface ILeaderboardEntryClient {