fix(score): return user score & remove duplicated scores
This commit is contained in:
@@ -2,6 +2,7 @@ from collections.abc import Sequence
|
|||||||
from datetime import UTC, date, datetime
|
from datetime import UTC, date, datetime
|
||||||
import json
|
import json
|
||||||
import math
|
import math
|
||||||
|
import sys
|
||||||
from typing import TYPE_CHECKING, Any
|
from typing import TYPE_CHECKING, Any
|
||||||
|
|
||||||
from app.calculator import (
|
from app.calculator import (
|
||||||
@@ -328,22 +329,39 @@ async def get_leaderboard(
|
|||||||
mods: list[str] | None = None,
|
mods: list[str] | None = None,
|
||||||
user: User | None = None,
|
user: User | None = None,
|
||||||
limit: int = 50,
|
limit: int = 50,
|
||||||
) -> tuple[list[Score], Score | None]:
|
) -> tuple[list[Score], Score | None, int]:
|
||||||
mods = mods or []
|
mods = mods or []
|
||||||
mode = mode.to_special_mode(mods)
|
mode = mode.to_special_mode(mods)
|
||||||
|
|
||||||
wheres = await _score_where(type, beatmap, mode, mods, user)
|
wheres = await _score_where(type, beatmap, mode, mods, user)
|
||||||
if wheres is None:
|
if wheres is None:
|
||||||
return [], None
|
return [], None, 0
|
||||||
|
count = (await session.exec(select(func.count()).where(*wheres))).one()
|
||||||
|
scores: dict[int, Score] = {}
|
||||||
|
max_score = sys.maxsize
|
||||||
|
while limit > 0:
|
||||||
query = (
|
query = (
|
||||||
select(BestScore)
|
select(BestScore)
|
||||||
.where(*wheres)
|
.where(*wheres, BestScore.total_score < max_score)
|
||||||
.limit(limit)
|
.limit(limit)
|
||||||
.order_by(col(BestScore.total_score).desc())
|
.order_by(col(BestScore.total_score).desc())
|
||||||
)
|
)
|
||||||
if mods:
|
if mods:
|
||||||
query = query.params(w=json.dumps(mods))
|
query = query.params(w=json.dumps(mods))
|
||||||
scores = [s.score for s in await session.exec(query)]
|
extra_need = 0
|
||||||
|
for s in await session.exec(query):
|
||||||
|
if s.user_id in scores:
|
||||||
|
extra_need += 1
|
||||||
|
count -= 1
|
||||||
|
if s.total_score > scores[s.user_id].total_score:
|
||||||
|
scores[s.user_id] = s.score
|
||||||
|
else:
|
||||||
|
scores[s.user_id] = s.score
|
||||||
|
if max_score > s.total_score:
|
||||||
|
max_score = s.total_score
|
||||||
|
limit = extra_need
|
||||||
|
|
||||||
|
result_scores = sorted(scores.values(), key=lambda u: u.total_score, reverse=True)
|
||||||
user_score = None
|
user_score = None
|
||||||
if user:
|
if user:
|
||||||
self_query = (
|
self_query = (
|
||||||
@@ -366,9 +384,9 @@ async def get_leaderboard(
|
|||||||
user_bs = (await session.exec(self_query)).first()
|
user_bs = (await session.exec(self_query)).first()
|
||||||
if user_bs:
|
if user_bs:
|
||||||
user_score = user_bs.score
|
user_score = user_bs.score
|
||||||
if user_score and user_score not in scores:
|
if user_score and user_score not in result_scores:
|
||||||
scores.append(user_score)
|
result_scores.append(user_score)
|
||||||
return scores, user_score
|
return result_scores, user_score, count
|
||||||
|
|
||||||
|
|
||||||
async def get_score_position_by_user(
|
async def get_score_position_by_user(
|
||||||
@@ -719,6 +737,7 @@ async def process_user(
|
|||||||
statistics.hit_accuracy = acc_sum
|
statistics.hit_accuracy = acc_sum
|
||||||
if add_to_db:
|
if add_to_db:
|
||||||
session.add(mouthly_playcount)
|
session.add(mouthly_playcount)
|
||||||
|
with session.no_autoflush:
|
||||||
await process_beatmap_playcount(session, user.id, score.beatmap_id)
|
await process_beatmap_playcount(session, user.id, score.beatmap_id)
|
||||||
await session.commit()
|
await session.commit()
|
||||||
await session.refresh(user)
|
await session.refresh(user)
|
||||||
|
|||||||
@@ -167,7 +167,7 @@ async def get_scores(
|
|||||||
)
|
)
|
||||||
).all()
|
).all()
|
||||||
else:
|
else:
|
||||||
scores, _ = await get_leaderboard(
|
scores, _, _ = await get_leaderboard(
|
||||||
session,
|
session,
|
||||||
beatmap_id,
|
beatmap_id,
|
||||||
GameMode.from_int_extra(ruleset_id),
|
GameMode.from_int_extra(ruleset_id),
|
||||||
|
|||||||
@@ -169,7 +169,8 @@ async def submit_score(
|
|||||||
|
|
||||||
class BeatmapScores(BaseModel):
|
class BeatmapScores(BaseModel):
|
||||||
scores: list[ScoreResp]
|
scores: list[ScoreResp]
|
||||||
userScore: ScoreResp | None = None
|
user_score: BeatmapUserScore | None = None
|
||||||
|
score_count: int = 0
|
||||||
|
|
||||||
|
|
||||||
@router.get(
|
@router.get(
|
||||||
@@ -201,14 +202,21 @@ async def get_beatmap_scores(
|
|||||||
status_code=404, detail="this server only contains lazer scores"
|
status_code=404, detail="this server only contains lazer scores"
|
||||||
)
|
)
|
||||||
|
|
||||||
all_scores, user_score = await get_leaderboard(
|
all_scores, user_score, count = await get_leaderboard(
|
||||||
db, beatmap_id, mode, type=type, user=current_user, limit=limit, mods=mods
|
db, beatmap_id, mode, type=type, user=current_user, limit=limit, mods=mods
|
||||||
)
|
)
|
||||||
|
|
||||||
return BeatmapScores(
|
user_score_resp = await ScoreResp.from_db(db, user_score) if user_score else None
|
||||||
|
resp = BeatmapScores(
|
||||||
scores=[await ScoreResp.from_db(db, score) for score in all_scores],
|
scores=[await ScoreResp.from_db(db, score) for score in all_scores],
|
||||||
userScore=await ScoreResp.from_db(db, user_score) if user_score else None,
|
user_score=BeatmapUserScore(
|
||||||
|
score=user_score_resp, position=user_score_resp.rank_global or 0
|
||||||
)
|
)
|
||||||
|
if user_score_resp
|
||||||
|
else None,
|
||||||
|
score_count=count,
|
||||||
|
)
|
||||||
|
return resp
|
||||||
|
|
||||||
|
|
||||||
class BeatmapUserScore(BaseModel):
|
class BeatmapUserScore(BaseModel):
|
||||||
|
|||||||
Reference in New Issue
Block a user