From 69e9927ea0460e196a0df631dd117c7f49cc4413 Mon Sep 17 00:00:00 2001 From: MingxuanGame Date: Wed, 13 Aug 2025 04:01:19 +0000 Subject: [PATCH] fix(score): fix incomplete statistics in leaderboard & wrong statistics in replay --- app/database/score.py | 14 ++----- app/models/score.py | 41 ++++++++++--------- ...1ac7ca01d5_score_add_maximum_statistics.py | 34 +++++++++++++++ 3 files changed, 59 insertions(+), 30 deletions(-) create mode 100644 migrations/versions/881ac7ca01d5_score_add_maximum_statistics.py diff --git a/app/database/score.py b/app/database/score.py index 719b1d6..479a4e4 100644 --- a/app/database/score.py +++ b/app/database/score.py @@ -96,10 +96,12 @@ class ScoreBase(AsyncAttrs, SQLModel, UTCBaseModel): ) type: str beatmap_id: int = Field(index=True, foreign_key="beatmaps.id") + maximum_statistics: ScoreStatistics = Field( + sa_column=Column(JSON), default_factory=dict + ) # optional # TODO: current_user_attributes - # position: int | None = Field(default=None) # multiplayer class Score(ScoreBase, table=True): @@ -206,14 +208,6 @@ class ScoreResp(ScoreBase): s.statistics[HitResult.SMALL_TICK_HIT] = score.nsmall_tick_hit if score.nlarge_tick_hit is not None: s.statistics[HitResult.LARGE_TICK_HIT] = score.nlarge_tick_hit - if score.gamemode == GameMode.MANIA: - s.maximum_statistics = { - HitResult.PERFECT: score.beatmap.max_combo, - } - else: - s.maximum_statistics = { - HitResult.GREAT: score.beatmap.max_combo, - } s.user = await UserResp.from_db( score.user, session, @@ -667,7 +661,6 @@ async def process_score( score = Score( accuracy=info.accuracy, max_combo=info.max_combo, - # maximum_statistics=info.maximum_statistics, mods=info.mods, passed=info.passed, rank=info.rank, @@ -694,6 +687,7 @@ async def process_score( nslider_tail_hit=info.statistics.get(HitResult.SLIDER_TAIL_HIT, 0), playlist_item_id=item_id, room_id=room_id, + maximum_statistics=info.maximum_statistics, ) if can_get_pp: beatmap_raw = await fetcher.get_or_fetch_beatmap_raw(redis, beatmap_id) diff --git a/app/models/score.py b/app/models/score.py index ab968e9..273c0c6 100644 --- a/app/models/score.py +++ b/app/models/score.py @@ -68,29 +68,30 @@ class Rank(str, Enum): # https://github.com/ppy/osu/blob/master/osu.Game/Rulesets/Scoring/HitResult.cs class HitResult(str, Enum): - PERFECT = "perfect" # [Order(0)] - GREAT = "great" # [Order(1)] - GOOD = "good" # [Order(2)] - OK = "ok" # [Order(3)] - MEH = "meh" # [Order(4)] - MISS = "miss" # [Order(5)] - - LARGE_TICK_HIT = "large_tick_hit" # [Order(6)] - SMALL_TICK_HIT = "small_tick_hit" # [Order(7)] - SLIDER_TAIL_HIT = "slider_tail_hit" # [Order(8)] - - LARGE_BONUS = "large_bonus" # [Order(9)] - SMALL_BONUS = "small_bonus" # [Order(10)] - - LARGE_TICK_MISS = "large_tick_miss" # [Order(11)] - SMALL_TICK_MISS = "small_tick_miss" # [Order(12)] - - IGNORE_HIT = "ignore_hit" # [Order(13)] - IGNORE_MISS = "ignore_miss" # [Order(14)] - NONE = "none" # [Order(15)] + + MISS = "miss" # [Order(5)] + MEH = "meh" # [Order(4)] + OK = "ok" # [Order(3)] + GOOD = "good" # [Order(2)] + GREAT = "great" # [Order(1)] + PERFECT = "perfect" # [Order(0)] + + SMALL_TICK_MISS = "small_tick_miss" # [Order(12)] + SMALL_TICK_HIT = "small_tick_hit" # [Order(7)] + LARGE_TICK_MISS = "large_tick_miss" # [Order(11)] + LARGE_TICK_HIT = "large_tick_hit" # [Order(6)] + + SMALL_BONUS = "small_bonus" # [Order(10)] + LARGE_BONUS = "large_bonus" # [Order(9)] + + IGNORE_MISS = "ignore_miss" # [Order(14)] + IGNORE_HIT = "ignore_hit" # [Order(13)] + COMBO_BREAK = "combo_break" # [Order(16)] + SLIDER_TAIL_HIT = "slider_tail_hit" # [Order(8)] + LEGACY_COMBO_INCREASE = "legacy_combo_increase" # [Order(99)] @deprecated def is_hit(self) -> bool: diff --git a/migrations/versions/881ac7ca01d5_score_add_maximum_statistics.py b/migrations/versions/881ac7ca01d5_score_add_maximum_statistics.py new file mode 100644 index 0000000..125c6da --- /dev/null +++ b/migrations/versions/881ac7ca01d5_score_add_maximum_statistics.py @@ -0,0 +1,34 @@ +"""score: add maximum_statistics + +Revision ID: 881ac7ca01d5 +Revises: 198227d190b8 +Create Date: 2025-08-13 03:54:12.283468 + +""" + +from __future__ import annotations + +from collections.abc import Sequence + +from alembic import op +import sqlalchemy as sa + +# revision identifiers, used by Alembic. +revision: str = "881ac7ca01d5" +down_revision: str | Sequence[str] | None = "198227d190b8" +branch_labels: str | Sequence[str] | None = None +depends_on: str | Sequence[str] | None = None + + +def upgrade() -> None: + """Upgrade schema.""" + # ### commands auto generated by Alembic - please adjust! ### + op.add_column("scores", sa.Column("maximum_statistics", sa.JSON(), nullable=True)) + # ### end Alembic commands ### + + +def downgrade() -> None: + """Downgrade schema.""" + # ### commands auto generated by Alembic - please adjust! ### + op.drop_column("scores", "maximum_statistics") + # ### end Alembic commands ###