implement scoresaber score tracking (for previous scores)
This commit is contained in:
parent
3c4406c4b7
commit
d42c888e82
BIN
bun.lockb
BIN
bun.lockb
Binary file not shown.
@ -14,6 +14,7 @@
|
||||
"@elysiajs/swagger": "^1.1.3",
|
||||
"@ssr/common": "workspace:common",
|
||||
"@tqman/nice-logger": "^1.0.1",
|
||||
"@typegoose/auto-increment": "^4.7.0",
|
||||
"@typegoose/typegoose": "^12.8.0",
|
||||
"@typescript-eslint/eslint-plugin": "^8.9.0",
|
||||
"@typescript-eslint/parser": "^8.9.0",
|
||||
|
@ -8,7 +8,6 @@ import { etag } from "@bogeychan/elysia-etag";
|
||||
import AppController from "./controller/app.controller";
|
||||
import * as dotenv from "@dotenvx/dotenvx";
|
||||
import mongoose from "mongoose";
|
||||
import { setLogLevel } from "@typegoose/typegoose";
|
||||
import PlayerController from "./controller/player.controller";
|
||||
import { PlayerService } from "./service/player.service";
|
||||
import { cron } from "@elysiajs/cron";
|
||||
@ -33,9 +32,10 @@ dotenv.config({
|
||||
override: true,
|
||||
});
|
||||
|
||||
// Connect to Mongo
|
||||
await mongoose.connect(Config.mongoUri!); // Connect to MongoDB
|
||||
setLogLevel("DEBUG");
|
||||
|
||||
// Connect to websockets
|
||||
connectScoresaberWebsocket({
|
||||
onScore: async score => {
|
||||
await ScoreService.trackScoreSaberScore(score);
|
||||
|
@ -7,7 +7,6 @@ import BeatSaverService from "./beatsaver.service";
|
||||
import ScoreSaberLeaderboard, {
|
||||
getScoreSaberLeaderboardFromToken,
|
||||
} from "@ssr/common/leaderboard/impl/scoresaber-leaderboard";
|
||||
import { getScoreSaberScoreFromToken } from "@ssr/common/score/impl/scoresaber-score";
|
||||
import { scoresaberService } from "@ssr/common/service/impl/scoresaber";
|
||||
import { ScoreSort } from "@ssr/common/score/score-sort";
|
||||
import { Leaderboards } from "@ssr/common/leaderboard";
|
||||
@ -16,7 +15,6 @@ import LeaderboardService from "./leaderboard.service";
|
||||
import { BeatSaverMap } from "@ssr/common/model/beatsaver/map";
|
||||
import { PlayerScore } from "@ssr/common/score/player-score";
|
||||
import LeaderboardScoresResponse from "@ssr/common/response/leaderboard-scores-response";
|
||||
import Score from "@ssr/common/score/score";
|
||||
import PlayerScoresResponse from "@ssr/common/response/player-scores-response";
|
||||
import { DiscordChannels, logToChannel } from "../bot/bot";
|
||||
import { EmbedBuilder } from "discord.js";
|
||||
@ -30,6 +28,8 @@ import {
|
||||
AdditionalScoreDataModel,
|
||||
} from "@ssr/common/model/additional-score-data/additional-score-data";
|
||||
import { BeatLeaderScoreImprovementToken } from "@ssr/common/types/token/beatleader/score/score-improvement";
|
||||
import { getScoreSaberScoreFromToken, ScoreSaberScoreModel } from "@ssr/common/model/score/impl/scoresaber-score";
|
||||
import { ScoreType } from "@ssr/common/model/score/score";
|
||||
|
||||
const playerScoresCache = new SSRCache({
|
||||
ttl: 1000 * 60, // 1 minute
|
||||
@ -52,7 +52,7 @@ export class ScoreService {
|
||||
}
|
||||
|
||||
const { score: scoreToken, leaderboard: leaderboardToken } = playerScore;
|
||||
const score = getScoreSaberScoreFromToken(scoreToken, leaderboardToken);
|
||||
const score = getScoreSaberScoreFromToken(scoreToken, leaderboardToken, scoreToken.leaderboardPlayerInfo.id);
|
||||
const leaderboard = getScoreSaberLeaderboardFromToken(leaderboardToken);
|
||||
const playerInfo = score.playerInfo;
|
||||
|
||||
@ -153,8 +153,13 @@ export class ScoreService {
|
||||
player.markModified("statisticHistory");
|
||||
await player.save();
|
||||
|
||||
const scoreToken = getScoreSaberScoreFromToken(score, leaderboard, playerId);
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-expect-error
|
||||
delete scoreToken.playerInfo;
|
||||
await ScoreSaberScoreModel.create(scoreToken);
|
||||
console.log(
|
||||
`Updated scores set statistic for "${playerName}"(${playerId}), scores today: ${scores.rankedScores} ranked, ${scores.unrankedScores} unranked`
|
||||
`Tracked score and updated scores set statistic for "${playerName}"(${playerId}), scores today: ${scores.rankedScores} ranked, ${scores.unrankedScores} unranked`
|
||||
);
|
||||
}
|
||||
|
||||
@ -268,7 +273,7 @@ export class ScoreService {
|
||||
* Gets scores for a player.
|
||||
*
|
||||
* @param leaderboardName the leaderboard to get the scores from
|
||||
* @param id the players id
|
||||
* @param playerId the players id
|
||||
* @param page the page to get
|
||||
* @param sort the sort to use
|
||||
* @param search the search to use
|
||||
@ -276,14 +281,14 @@ export class ScoreService {
|
||||
*/
|
||||
public static async getPlayerScores(
|
||||
leaderboardName: Leaderboards,
|
||||
id: string,
|
||||
playerId: string,
|
||||
page: number,
|
||||
sort: string,
|
||||
search?: string
|
||||
): Promise<PlayerScoresResponse<unknown, unknown> | undefined> {
|
||||
return fetchWithCache(
|
||||
playerScoresCache,
|
||||
`player-scores-${leaderboardName}-${id}-${page}-${sort}-${search}`,
|
||||
`player-scores-${leaderboardName}-${playerId}-${page}-${sort}-${search}`,
|
||||
async () => {
|
||||
const scores: PlayerScore<unknown, unknown>[] | undefined = [];
|
||||
let metadata: Metadata = new Metadata(0, 0, 0, 0); // Default values
|
||||
@ -291,7 +296,7 @@ export class ScoreService {
|
||||
switch (leaderboardName) {
|
||||
case "scoresaber": {
|
||||
const leaderboardScores = await scoresaberService.lookupPlayerScores({
|
||||
playerId: id,
|
||||
playerId: playerId,
|
||||
page: page,
|
||||
sort: sort as ScoreSort,
|
||||
search: search,
|
||||
@ -308,17 +313,18 @@ export class ScoreService {
|
||||
);
|
||||
|
||||
for (const token of leaderboardScores.playerScores) {
|
||||
const score = getScoreSaberScoreFromToken(token.score, token.leaderboard);
|
||||
const score = getScoreSaberScoreFromToken(token.score, token.leaderboard, playerId);
|
||||
if (score == undefined) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const leaderboard = getScoreSaberLeaderboardFromToken(token.leaderboard);
|
||||
if (leaderboard == undefined) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const additionalData = await this.getAdditionalScoreData(
|
||||
id,
|
||||
playerId,
|
||||
leaderboard.songHash,
|
||||
`${leaderboard.difficulty.difficulty}-${leaderboard.difficulty.characteristic}`,
|
||||
score.score
|
||||
@ -352,65 +358,73 @@ export class ScoreService {
|
||||
* Gets scores for a leaderboard.
|
||||
*
|
||||
* @param leaderboardName the leaderboard to get the scores from
|
||||
* @param id the leaderboard id
|
||||
* @param leaderboardId the leaderboard id
|
||||
* @param page the page to get
|
||||
* @returns the scores
|
||||
*/
|
||||
public static async getLeaderboardScores(
|
||||
leaderboardName: Leaderboards,
|
||||
id: string,
|
||||
leaderboardId: string,
|
||||
page: number
|
||||
): Promise<LeaderboardScoresResponse<unknown, unknown> | undefined> {
|
||||
return fetchWithCache(leaderboardScoresCache, `leaderboard-scores-${leaderboardName}-${id}-${page}`, async () => {
|
||||
const scores: Score[] = [];
|
||||
let leaderboard: Leaderboard | undefined;
|
||||
let beatSaverMap: BeatSaverMap | undefined;
|
||||
let metadata: Metadata = new Metadata(0, 0, 0, 0); // Default values
|
||||
return fetchWithCache(
|
||||
leaderboardScoresCache,
|
||||
`leaderboard-scores-${leaderboardName}-${leaderboardId}-${page}`,
|
||||
async () => {
|
||||
const scores: ScoreType[] = [];
|
||||
let leaderboard: Leaderboard | undefined;
|
||||
let beatSaverMap: BeatSaverMap | undefined;
|
||||
let metadata: Metadata = new Metadata(0, 0, 0, 0); // Default values
|
||||
|
||||
switch (leaderboardName) {
|
||||
case "scoresaber": {
|
||||
const leaderboardResponse = await LeaderboardService.getLeaderboard<ScoreSaberLeaderboard>(
|
||||
leaderboardName,
|
||||
id
|
||||
);
|
||||
if (leaderboardResponse == undefined) {
|
||||
throw new NotFoundError(`Leaderboard "${leaderboardName}" not found`);
|
||||
}
|
||||
leaderboard = leaderboardResponse.leaderboard;
|
||||
beatSaverMap = leaderboardResponse.beatsaver;
|
||||
switch (leaderboardName) {
|
||||
case "scoresaber": {
|
||||
const leaderboardResponse = await LeaderboardService.getLeaderboard<ScoreSaberLeaderboard>(
|
||||
leaderboardName,
|
||||
leaderboardId
|
||||
);
|
||||
if (leaderboardResponse == undefined) {
|
||||
throw new NotFoundError(`Leaderboard "${leaderboardName}" not found`);
|
||||
}
|
||||
leaderboard = leaderboardResponse.leaderboard;
|
||||
beatSaverMap = leaderboardResponse.beatsaver;
|
||||
|
||||
const leaderboardScores = await scoresaberService.lookupLeaderboardScores(id, page);
|
||||
if (leaderboardScores == undefined) {
|
||||
const leaderboardScores = await scoresaberService.lookupLeaderboardScores(leaderboardId, page);
|
||||
if (leaderboardScores == undefined) {
|
||||
break;
|
||||
}
|
||||
|
||||
for (const token of leaderboardScores.scores) {
|
||||
const score = getScoreSaberScoreFromToken(
|
||||
token,
|
||||
leaderboardResponse.leaderboard,
|
||||
token.leaderboardPlayerInfo.id
|
||||
);
|
||||
if (score == undefined) {
|
||||
continue;
|
||||
}
|
||||
scores.push(score);
|
||||
}
|
||||
|
||||
metadata = new Metadata(
|
||||
Math.ceil(leaderboardScores.metadata.total / leaderboardScores.metadata.itemsPerPage),
|
||||
leaderboardScores.metadata.total,
|
||||
leaderboardScores.metadata.page,
|
||||
leaderboardScores.metadata.itemsPerPage
|
||||
);
|
||||
break;
|
||||
}
|
||||
|
||||
for (const token of leaderboardScores.scores) {
|
||||
const score = getScoreSaberScoreFromToken(token, leaderboardResponse.leaderboard);
|
||||
if (score == undefined) {
|
||||
continue;
|
||||
}
|
||||
scores.push(score);
|
||||
default: {
|
||||
throw new NotFoundError(`Leaderboard "${leaderboardName}" not found`);
|
||||
}
|
||||
}
|
||||
|
||||
metadata = new Metadata(
|
||||
Math.ceil(leaderboardScores.metadata.total / leaderboardScores.metadata.itemsPerPage),
|
||||
leaderboardScores.metadata.total,
|
||||
leaderboardScores.metadata.page,
|
||||
leaderboardScores.metadata.itemsPerPage
|
||||
);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
throw new NotFoundError(`Leaderboard "${leaderboardName}" not found`);
|
||||
}
|
||||
return {
|
||||
scores: scores,
|
||||
leaderboard: leaderboard,
|
||||
beatSaver: beatSaverMap,
|
||||
metadata: metadata,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
scores: scores,
|
||||
leaderboard: leaderboard,
|
||||
beatSaver: beatSaverMap,
|
||||
metadata: metadata,
|
||||
};
|
||||
});
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -19,6 +19,7 @@
|
||||
"typescript": "^5"
|
||||
},
|
||||
"dependencies": {
|
||||
"@typegoose/auto-increment": "^4.7.0",
|
||||
"@typegoose/typegoose": "^12.8.0",
|
||||
"ky": "^1.7.2",
|
||||
"ws": "^8.18.0"
|
||||
|
@ -4,7 +4,7 @@ import { HandAccuracy } from "./hand-accuracy";
|
||||
import { Misses } from "./misses";
|
||||
|
||||
/**
|
||||
* The model for a BeatSaver map.
|
||||
* The model for additional score data.
|
||||
*/
|
||||
@modelOptions({
|
||||
options: { allowMixed: Severity.ALLOW },
|
||||
|
123
projects/common/src/model/score/impl/scoresaber-score.ts
Normal file
123
projects/common/src/model/score/impl/scoresaber-score.ts
Normal file
@ -0,0 +1,123 @@
|
||||
import { getModelForClass, modelOptions, plugin, Prop, ReturnModelType, Severity } from "@typegoose/typegoose";
|
||||
import Score from "../score";
|
||||
import { Modifier } from "../../../score/modifier";
|
||||
import ScoreSaberScoreToken from "../../../types/token/scoresaber/score-saber-score-token";
|
||||
import ScoreSaberLeaderboardToken from "../../../types/token/scoresaber/score-saber-leaderboard-token";
|
||||
import ScoreSaberLeaderboard from "../../../leaderboard/impl/scoresaber-leaderboard";
|
||||
import { type ScoreSaberLeaderboardPlayerInfoToken } from "../../../types/token/scoresaber/score-saber-leaderboard-player-info-token";
|
||||
import { Document } from "mongoose";
|
||||
import { AutoIncrementID } from "@typegoose/auto-increment";
|
||||
|
||||
@modelOptions({
|
||||
options: { allowMixed: Severity.ALLOW },
|
||||
schemaOptions: {
|
||||
collection: "scoresaber-scores",
|
||||
toObject: {
|
||||
virtuals: true,
|
||||
transform: function (_, ret) {
|
||||
ret.id = ret._id;
|
||||
delete ret._id;
|
||||
delete ret.__v;
|
||||
return ret;
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
@plugin(AutoIncrementID, {
|
||||
field: "_id",
|
||||
startAt: 1,
|
||||
trackerModelName: "scores",
|
||||
trackerCollection: "increments",
|
||||
overwriteModelName: "scoresaber-scores",
|
||||
})
|
||||
export class ScoreSaberScoreInternal extends Score {
|
||||
/**
|
||||
* The score's id.
|
||||
*/
|
||||
@Prop({ required: true, index: true })
|
||||
public readonly scoreId!: string;
|
||||
|
||||
/**
|
||||
* The leaderboard the score was set on.
|
||||
*/
|
||||
@Prop({ required: true, index: true })
|
||||
public readonly leaderboardId!: number;
|
||||
|
||||
/**
|
||||
* The amount of pp for the score.
|
||||
* @private
|
||||
*/
|
||||
@Prop({ required: true })
|
||||
public readonly pp!: number;
|
||||
|
||||
/**
|
||||
* The weight of the score, or undefined if not ranked.
|
||||
* @private
|
||||
*/
|
||||
@Prop()
|
||||
public readonly weight?: number;
|
||||
|
||||
/**
|
||||
* The max combo of the score.
|
||||
*/
|
||||
@Prop({ required: true })
|
||||
public readonly maxCombo!: number;
|
||||
}
|
||||
|
||||
class ScoreSaberScorePublic extends ScoreSaberScoreInternal {
|
||||
/**
|
||||
* The player who set the score.
|
||||
*/
|
||||
public playerInfo!: ScoreSaberLeaderboardPlayerInfoToken;
|
||||
}
|
||||
|
||||
export type ScoreSaberScore = InstanceType<typeof ScoreSaberScorePublic>;
|
||||
|
||||
/**
|
||||
* Gets a {@link ScoreSaberScore} from a {@link ScoreSaberScoreToken}.
|
||||
*
|
||||
* @param token the token to convert
|
||||
* @param playerId the id of the player who set the score
|
||||
* @param leaderboard the leaderboard the score was set on
|
||||
*/
|
||||
export function getScoreSaberScoreFromToken(
|
||||
token: ScoreSaberScoreToken,
|
||||
leaderboard: ScoreSaberLeaderboardToken | ScoreSaberLeaderboard,
|
||||
playerId?: string
|
||||
): ScoreSaberScore {
|
||||
const modifiers: Modifier[] =
|
||||
token.modifiers == undefined || token.modifiers === ""
|
||||
? []
|
||||
: token.modifiers.split(",").map(mod => {
|
||||
mod = mod.toUpperCase();
|
||||
const modifier = Modifier[mod as keyof typeof Modifier];
|
||||
if (modifier === undefined) {
|
||||
throw new Error(`Unknown modifier: ${mod}`);
|
||||
}
|
||||
return modifier;
|
||||
});
|
||||
|
||||
return {
|
||||
leaderboard: "scoresaber",
|
||||
playerId: playerId || token.leaderboardPlayerInfo.id,
|
||||
leaderboardId: leaderboard.id,
|
||||
score: token.baseScore,
|
||||
accuracy: (token.baseScore / leaderboard.maxScore) * 100,
|
||||
rank: token.rank,
|
||||
modifiers: modifiers,
|
||||
misses: token.missedNotes + token.badCuts,
|
||||
missedNotes: token.missedNotes,
|
||||
badCuts: token.badCuts,
|
||||
fullCombo: token.fullCombo,
|
||||
timestamp: new Date(token.timeSet),
|
||||
scoreId: token.id,
|
||||
pp: token.pp,
|
||||
weight: token.weight,
|
||||
maxCombo: token.maxCombo,
|
||||
playerInfo: token.leaderboardPlayerInfo,
|
||||
};
|
||||
}
|
||||
|
||||
export type ScoreSaberScoreDocument = ScoreSaberScore & Document;
|
||||
export const ScoreSaberScoreModel: ReturnModelType<typeof ScoreSaberScoreInternal> =
|
||||
getModelForClass(ScoreSaberScoreInternal);
|
96
projects/common/src/model/score/score.ts
Normal file
96
projects/common/src/model/score/score.ts
Normal file
@ -0,0 +1,96 @@
|
||||
import { Modifier } from "../../score/modifier";
|
||||
import { AdditionalScoreData } from "../additional-score-data/additional-score-data";
|
||||
import { type Leaderboards } from "../../leaderboard";
|
||||
import { prop } from "@typegoose/typegoose";
|
||||
|
||||
/**
|
||||
* The model for a score.
|
||||
*/
|
||||
export default class Score {
|
||||
/**
|
||||
* The internal score id.
|
||||
*/
|
||||
@prop()
|
||||
private _id?: number;
|
||||
|
||||
/**
|
||||
* The leaderboard the score is from.
|
||||
*/
|
||||
@prop({ required: true })
|
||||
public readonly leaderboard!: Leaderboards;
|
||||
|
||||
/**
|
||||
* The id of the player who set the score.
|
||||
* @private
|
||||
*/
|
||||
@prop({ required: true, index: true })
|
||||
public readonly playerId!: string;
|
||||
|
||||
/**
|
||||
* The base score for the score.
|
||||
* @private
|
||||
*/
|
||||
@prop({ required: true })
|
||||
public readonly score!: number;
|
||||
|
||||
/**
|
||||
* The accuracy of the score.
|
||||
*/
|
||||
@prop({ required: true })
|
||||
public readonly accuracy!: number;
|
||||
|
||||
/**
|
||||
* The rank for the score.
|
||||
* @private
|
||||
*/
|
||||
@prop({ required: true })
|
||||
public readonly rank!: number;
|
||||
|
||||
/**
|
||||
* The modifiers used on the score.
|
||||
* @private
|
||||
*/
|
||||
@prop({ enum: () => Modifier, type: String, required: true })
|
||||
public readonly modifiers!: Modifier[];
|
||||
|
||||
/**
|
||||
* The total amount of misses.
|
||||
* @private
|
||||
*/
|
||||
@prop({ required: true })
|
||||
public readonly misses!: number;
|
||||
|
||||
/**
|
||||
* The amount of missed notes.
|
||||
*/
|
||||
@prop({ required: true })
|
||||
public readonly missedNotes!: number;
|
||||
|
||||
/**
|
||||
* The amount of bad cuts.
|
||||
* @private
|
||||
*/
|
||||
@prop({ required: true })
|
||||
public readonly badCuts!: number;
|
||||
|
||||
/**
|
||||
* Whether every note was hit.
|
||||
* @private
|
||||
*/
|
||||
@prop({ required: true })
|
||||
public readonly fullCombo!: boolean;
|
||||
|
||||
/**
|
||||
* The additional data for the score.
|
||||
*/
|
||||
public additionalData?: AdditionalScoreData;
|
||||
|
||||
/**
|
||||
* The time the score was set.
|
||||
* @private
|
||||
*/
|
||||
@prop({ required: true })
|
||||
public readonly timestamp!: Date;
|
||||
}
|
||||
|
||||
export type ScoreType = InstanceType<typeof Score>;
|
@ -1,76 +0,0 @@
|
||||
import Score from "../score";
|
||||
import { Modifier } from "../modifier";
|
||||
import ScoreSaberScoreToken from "../../types/token/scoresaber/score-saber-score-token";
|
||||
import ScoreSaberLeaderboardPlayerInfoToken from "../../types/token/scoresaber/score-saber-leaderboard-player-info-token";
|
||||
import ScoreSaberLeaderboardToken from "../../types/token/scoresaber/score-saber-leaderboard-token";
|
||||
import ScoreSaberLeaderboard from "../../leaderboard/impl/scoresaber-leaderboard";
|
||||
|
||||
export default interface ScoreSaberScore extends Score {
|
||||
/**
|
||||
* The score's id.
|
||||
*/
|
||||
readonly id: string;
|
||||
|
||||
/**
|
||||
* The amount of pp for the score.
|
||||
* @private
|
||||
*/
|
||||
readonly pp: number;
|
||||
|
||||
/**
|
||||
* The weight of the score, or undefined if not ranked.s
|
||||
* @private
|
||||
*/
|
||||
readonly weight?: number;
|
||||
|
||||
/**
|
||||
* The max combo of the score.
|
||||
*/
|
||||
readonly maxCombo: number;
|
||||
|
||||
/**
|
||||
* The player who set the score
|
||||
*/
|
||||
readonly playerInfo: ScoreSaberLeaderboardPlayerInfoToken;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a {@link ScoreSaberScore} from a {@link ScoreSaberScoreToken}.
|
||||
*
|
||||
* @param token the token to convert
|
||||
* @param leaderboard the leaderboard the score was set on
|
||||
*/
|
||||
export function getScoreSaberScoreFromToken(
|
||||
token: ScoreSaberScoreToken,
|
||||
leaderboard?: ScoreSaberLeaderboardToken | ScoreSaberLeaderboard
|
||||
): ScoreSaberScore {
|
||||
const modifiers: Modifier[] =
|
||||
token.modifiers == undefined || token.modifiers === ""
|
||||
? []
|
||||
: token.modifiers.split(",").map(mod => {
|
||||
mod = mod.toUpperCase();
|
||||
const modifier = Modifier[mod as keyof typeof Modifier];
|
||||
if (modifier === undefined) {
|
||||
throw new Error(`Unknown modifier: ${mod}`);
|
||||
}
|
||||
return modifier;
|
||||
});
|
||||
|
||||
return {
|
||||
leaderboard: "scoresaber",
|
||||
score: token.baseScore,
|
||||
accuracy: leaderboard ? (token.baseScore / leaderboard.maxScore) * 100 : Infinity,
|
||||
rank: token.rank,
|
||||
modifiers: modifiers,
|
||||
misses: token.missedNotes + token.badCuts,
|
||||
missedNotes: token.missedNotes,
|
||||
badCuts: token.badCuts,
|
||||
fullCombo: token.fullCombo,
|
||||
timestamp: new Date(token.timeSet),
|
||||
id: token.id,
|
||||
pp: token.pp,
|
||||
weight: token.weight,
|
||||
maxCombo: token.maxCombo,
|
||||
playerInfo: token.leaderboardPlayerInfo,
|
||||
};
|
||||
}
|
@ -1,67 +0,0 @@
|
||||
import { Modifier } from "./modifier";
|
||||
import { Leaderboards } from "../leaderboard";
|
||||
import { AdditionalScoreData } from "../model/additional-score-data/additional-score-data";
|
||||
|
||||
export default interface Score {
|
||||
/**
|
||||
* The leaderboard the score is from.
|
||||
*/
|
||||
readonly leaderboard: Leaderboards;
|
||||
|
||||
/**
|
||||
* The base score for the score.
|
||||
* @private
|
||||
*/
|
||||
readonly score: number;
|
||||
|
||||
/**
|
||||
* The accuracy of the score.
|
||||
*/
|
||||
readonly accuracy: number;
|
||||
|
||||
/**
|
||||
* The rank for the score.
|
||||
* @private
|
||||
*/
|
||||
readonly rank: number;
|
||||
|
||||
/**
|
||||
* The modifiers used on the score.
|
||||
* @private
|
||||
*/
|
||||
readonly modifiers: Modifier[];
|
||||
|
||||
/**
|
||||
* The amount total amount of misses.
|
||||
* @private
|
||||
*/
|
||||
readonly misses: number;
|
||||
|
||||
/**
|
||||
* The amount of missed notes.
|
||||
*/
|
||||
readonly missedNotes: number;
|
||||
|
||||
/**
|
||||
* The amount of bad cuts.
|
||||
* @private
|
||||
*/
|
||||
readonly badCuts: number;
|
||||
|
||||
/**
|
||||
* Whether every note was hit.
|
||||
* @private
|
||||
*/
|
||||
readonly fullCombo: boolean;
|
||||
|
||||
/**
|
||||
* The additional data for the score.
|
||||
*/
|
||||
additionalData?: AdditionalScoreData;
|
||||
|
||||
/**
|
||||
* The time the score was set.
|
||||
* @private
|
||||
*/
|
||||
readonly timestamp: Date;
|
||||
}
|
@ -1,8 +1,8 @@
|
||||
export default interface ScoreSaberLeaderboardPlayerInfoToken {
|
||||
export type ScoreSaberLeaderboardPlayerInfoToken = {
|
||||
id: string;
|
||||
name: string;
|
||||
profilePicture: string;
|
||||
country: string;
|
||||
permissions: number;
|
||||
role: string;
|
||||
}
|
||||
};
|
||||
|
@ -1,5 +1,5 @@
|
||||
import ScoreSaberLeaderboardToken from "./score-saber-leaderboard-token";
|
||||
import ScoreSaberLeaderboardPlayerInfoToken from "./score-saber-leaderboard-player-info-token";
|
||||
import { ScoreSaberLeaderboardPlayerInfoToken } from "./score-saber-leaderboard-player-info-token";
|
||||
|
||||
export default interface ScoreSaberScoreToken {
|
||||
id: string;
|
||||
|
@ -1,6 +1,6 @@
|
||||
import ScoreSaberPlayerToken from "../types/token/scoresaber/score-saber-player-token";
|
||||
import ScoreSaberLeaderboardPlayerInfoToken from "../types/token/scoresaber/score-saber-leaderboard-player-info-token";
|
||||
import ScoreSaberPlayer from "../player/impl/scoresaber-player";
|
||||
import { ScoreSaberLeaderboardPlayerInfoToken } from "../types/token/scoresaber/score-saber-leaderboard-player-info-token";
|
||||
|
||||
export type ScoreSaberRole = {
|
||||
/**
|
||||
|
@ -4,7 +4,7 @@ import { Colors } from "@/common/colors";
|
||||
import { getAverageColor } from "@/common/image-utils";
|
||||
import { LeaderboardData } from "@/components/leaderboard/leaderboard-data";
|
||||
import { Config } from "@ssr/common/config";
|
||||
import ScoreSaberScore from "@ssr/common/score/impl/scoresaber-score";
|
||||
import { ScoreSaberScore } from "@ssr/common/model/score/impl/scoresaber-score";
|
||||
import { LeaderboardResponse } from "@ssr/common/response/leaderboard-response";
|
||||
import ScoreSaberLeaderboard from "@ssr/common/leaderboard/impl/scoresaber-leaderboard";
|
||||
import { fetchLeaderboard } from "@ssr/common/utils/leaderboard.util";
|
||||
|
@ -8,7 +8,7 @@ import { getCookieValue } from "@ssr/common/utils/cookie-utils";
|
||||
import { Config } from "@ssr/common/config";
|
||||
import ScoreSaberPlayer, { getScoreSaberPlayerFromToken } from "@ssr/common/player/impl/scoresaber-player";
|
||||
import { ScoreSort } from "@ssr/common/score/score-sort";
|
||||
import ScoreSaberScore from "@ssr/common/score/impl/scoresaber-score";
|
||||
import { ScoreSaberScore } from "@ssr/common/model/score/impl/scoresaber-score";
|
||||
import ScoreSaberLeaderboard from "@ssr/common/leaderboard/impl/scoresaber-leaderboard";
|
||||
import { fetchPlayerScores } from "@ssr/common/utils/score-utils";
|
||||
import PlayerScoresResponse from "@ssr/common/response/player-scores-response";
|
||||
|
@ -1,6 +1,5 @@
|
||||
"use client";
|
||||
|
||||
import ScoreSaberScore from "@ssr/common/score/impl/scoresaber-score";
|
||||
import { ScoreStatsToken } from "@ssr/common/types/token/beatleader/score-stats/score-stats";
|
||||
import { formatTime } from "@ssr/common/utils/time-utils";
|
||||
import GenericChart, { DatasetConfig } from "@/components/chart/generic-chart";
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
import LeaderboardScores from "@/components/leaderboard/leaderboard-scores";
|
||||
import { LeaderboardInfo } from "@/components/leaderboard/leaderboard-info";
|
||||
import ScoreSaberScore from "@ssr/common/score/impl/scoresaber-score";
|
||||
import { ScoreSaberScore } from "@ssr/common/model/score/impl/scoresaber-score";
|
||||
import ScoreSaberLeaderboard from "@ssr/common/leaderboard/impl/scoresaber-leaderboard";
|
||||
import { LeaderboardResponse } from "@ssr/common/response/leaderboard-response";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
|
@ -1,4 +1,4 @@
|
||||
import ScoreSaberScore from "@ssr/common/score/impl/scoresaber-score";
|
||||
import { ScoreSaberScore } from "@ssr/common/model/score/impl/scoresaber-score";
|
||||
import { formatNumberWithCommas, formatPp } from "@ssr/common/utils/number-utils";
|
||||
import ScoreSaberPlayerToken from "@ssr/common/types/token/scoresaber/score-saber-player-token";
|
||||
import { PlayerInfo } from "@/components/player/player-info";
|
||||
|
@ -10,7 +10,7 @@ import { scoreAnimation } from "@/components/score/score-animation";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { getDifficulty } from "@/common/song-utils";
|
||||
import { fetchLeaderboardScores } from "@ssr/common/utils/score-utils";
|
||||
import ScoreSaberScore from "@ssr/common/score/impl/scoresaber-score";
|
||||
import { ScoreSaberScore } from "@ssr/common/model/score/impl/scoresaber-score";
|
||||
import ScoreSaberLeaderboard from "@ssr/common/leaderboard/impl/scoresaber-leaderboard";
|
||||
import LeaderboardScoresResponse from "@ssr/common/response/leaderboard-scores-response";
|
||||
import useDatabase from "@/hooks/use-database";
|
||||
|
@ -15,7 +15,7 @@ import useDatabase from "@/hooks/use-database";
|
||||
import { useLiveQuery } from "dexie-react-hooks";
|
||||
import ScoreSaberPlayer, { getScoreSaberPlayerFromToken } from "@ssr/common/player/impl/scoresaber-player";
|
||||
import { ScoreSort } from "@ssr/common/score/score-sort";
|
||||
import ScoreSaberScore from "@ssr/common/score/impl/scoresaber-score";
|
||||
import { ScoreSaberScore } from "@ssr/common/model/score/impl/scoresaber-score";
|
||||
import ScoreSaberLeaderboard from "@ssr/common/leaderboard/impl/scoresaber-leaderboard";
|
||||
import PlayerScoresResponse from "@ssr/common/response/player-scores-response";
|
||||
|
||||
|
@ -15,7 +15,7 @@ import { scoreAnimation } from "@/components/score/score-animation";
|
||||
import ScoreSaberPlayer from "@ssr/common/player/impl/scoresaber-player";
|
||||
import { ScoreSort } from "@ssr/common/score/score-sort";
|
||||
import { setCookieValue } from "@ssr/common/utils/cookie-utils";
|
||||
import ScoreSaberScore from "@ssr/common/score/impl/scoresaber-score";
|
||||
import { ScoreSaberScore } from "@ssr/common/model/score/impl/scoresaber-score";
|
||||
import ScoreSaberLeaderboard from "@ssr/common/leaderboard/impl/scoresaber-leaderboard";
|
||||
import { fetchPlayerScores } from "@ssr/common/utils/score-utils";
|
||||
import PlayerScoresResponse from "@ssr/common/response/player-scores-response";
|
||||
|
@ -1,4 +1,4 @@
|
||||
import ScoreSaberScore from "@ssr/common/score/impl/scoresaber-score";
|
||||
import { ScoreSaberScore } from "@ssr/common/model/score/impl/scoresaber-score";
|
||||
|
||||
export type ScoreBadgeProps = {
|
||||
/**
|
||||
|
@ -1,5 +1,5 @@
|
||||
import StatValue from "@/components/stat-value";
|
||||
import ScoreSaberScore from "@ssr/common/score/impl/scoresaber-score";
|
||||
import { ScoreSaberScore } from "@ssr/common/model/score/impl/scoresaber-score";
|
||||
import ScoreSaberLeaderboard from "@ssr/common/leaderboard/impl/scoresaber-leaderboard";
|
||||
|
||||
/**
|
||||
|
@ -10,7 +10,7 @@ import { copyToClipboard } from "@/common/browser-utils";
|
||||
import { ArrowDownIcon } from "@heroicons/react/24/solid";
|
||||
import clsx from "clsx";
|
||||
import ScoreEditorButton from "@/components/score/score-editor-button";
|
||||
import ScoreSaberScore from "@ssr/common/score/impl/scoresaber-score";
|
||||
import { ScoreSaberScore } from "@ssr/common/model/score/impl/scoresaber-score";
|
||||
import ScoreSaberLeaderboard from "@ssr/common/leaderboard/impl/scoresaber-leaderboard";
|
||||
import { BeatSaverMap } from "@ssr/common/model/beatsaver/map";
|
||||
import BeatSaberPepeLogo from "@/components/logos/beatsaber-pepe-logo";
|
||||
|
@ -6,7 +6,7 @@ import { Slider } from "@/components/ui/slider";
|
||||
import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover";
|
||||
import { ResetIcon } from "@radix-ui/react-icons";
|
||||
import Tooltip from "@/components/tooltip";
|
||||
import ScoreSaberScore from "@ssr/common/score/impl/scoresaber-score";
|
||||
import { ScoreSaberScore } from "@ssr/common/model/score/impl/scoresaber-score";
|
||||
import ScoreSaberLeaderboard from "@ssr/common/leaderboard/impl/scoresaber-leaderboard";
|
||||
|
||||
type ScoreEditorButtonProps = {
|
||||
|
@ -7,7 +7,7 @@ import { parseDate } from "@ssr/common/utils/time-utils";
|
||||
import Link from "next/link";
|
||||
import useWebSocket, { ReadyState } from "react-use-websocket";
|
||||
import { ScoreSaberWebsocketMessageToken } from "@ssr/common/types/token/scoresaber/websocket/scoresaber-websocket-message";
|
||||
import { getScoreSaberScoreFromToken } from "@ssr/common/score/impl/scoresaber-score";
|
||||
import { getScoreSaberScoreFromToken } from "@ssr/common/model/score/impl/scoresaber-score";
|
||||
import { getScoreSaberLeaderboardFromToken } from "@ssr/common/leaderboard/impl/scoresaber-leaderboard";
|
||||
|
||||
export default function ScoreFeed() {
|
||||
|
@ -1,4 +1,4 @@
|
||||
import ScoreSaberScore from "@ssr/common/score/impl/scoresaber-score";
|
||||
import { ScoreSaberScore } from "@ssr/common/model/score/impl/scoresaber-score";
|
||||
import { Modifier } from "@ssr/common/score/modifier";
|
||||
|
||||
type ScoreModifiersProps = {
|
||||
|
@ -2,7 +2,7 @@ import { formatNumberWithCommas } from "@ssr/common/utils/number-utils";
|
||||
import { GlobeAmericasIcon } from "@heroicons/react/24/solid";
|
||||
import Link from "next/link";
|
||||
import { getPageFromRank } from "@ssr/common/utils/utils";
|
||||
import ScoreSaberScore from "@ssr/common/score/impl/scoresaber-score";
|
||||
import { ScoreSaberScore } from "@ssr/common/model/score/impl/scoresaber-score";
|
||||
import ScoreSaberLeaderboard from "@ssr/common/leaderboard/impl/scoresaber-leaderboard";
|
||||
import { ScoreTimeSet } from "@/components/score/score-time-set";
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { getScoreBadgeFromAccuracy } from "@/common/song-utils";
|
||||
import { ScoreBadge, ScoreBadges } from "@/components/score/score-badge";
|
||||
import ScoreSaberScore from "@ssr/common/score/impl/scoresaber-score";
|
||||
import { ScoreSaberScore } from "@ssr/common/model/score/impl/scoresaber-score";
|
||||
import ScoreSaberLeaderboard from "@ssr/common/leaderboard/impl/scoresaber-leaderboard";
|
||||
import ScoreMissesBadge from "@/components/score/badges/score-misses";
|
||||
import { HandAccuracyBadge } from "@/components/score/badges/hand-accuracy";
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { format } from "@formkit/tempo";
|
||||
import { timeAgo } from "@ssr/common/utils/time-utils";
|
||||
import Tooltip from "@/components/tooltip";
|
||||
import ScoreSaberScore from "@ssr/common/score/impl/scoresaber-score";
|
||||
import { ScoreSaberScore } from "@ssr/common/model/score/impl/scoresaber-score";
|
||||
|
||||
type ScoreTimeSetProps = {
|
||||
/**
|
||||
|
@ -9,7 +9,7 @@ import ScoreStats from "./score-stats";
|
||||
import { motion } from "framer-motion";
|
||||
import { getPageFromRank } from "@ssr/common/utils/utils";
|
||||
import { scoresaberService } from "@ssr/common/service/impl/scoresaber";
|
||||
import ScoreSaberScore from "@ssr/common/score/impl/scoresaber-score";
|
||||
import { ScoreSaberScore } from "@ssr/common/model/score/impl/scoresaber-score";
|
||||
import ScoreSaberLeaderboard from "@ssr/common/leaderboard/impl/scoresaber-leaderboard";
|
||||
import { BeatSaverMap } from "@ssr/common/model/beatsaver/map";
|
||||
import { useIsMobile } from "@/hooks/use-is-mobile";
|
||||
|
Reference in New Issue
Block a user