feat(statistics): store ranked_score & total_score under classic scoring mode (#68)

* Initial plan

* feat(calculator): add classic score simulator and scoring mode support

- Add ScoringMode enum with STANDARDISED and CLASSIC modes
- Add scoring_mode configuration to game settings
- Implement GetDisplayScore function in calculator.py
- Add get_display_score method to Score model
- Update score statistics to use display scores based on scoring mode

Co-authored-by: MingxuanGame <68982190+MingxuanGame@users.noreply.github.com>

* fix(calculator): apply scoring mode to TotalScoreBestScore delete method

- Update delete method to use display score for consistency
- Ensures all UserStatistics modifications use configured scoring mode

Co-authored-by: MingxuanGame <68982190+MingxuanGame@users.noreply.github.com>

* refactor(calculator): address code review feedback

- Move MAX_SCORE constant to app/const.py
- Implement is_basic() as method in HitResult enum
- Move imports to top of file in Score model
- Revert TotalScoreBestScore storage to use standardised score
- Apply display score calculation in tools/recalculate.py
- Keep display score usage in UserStatistics modifications

Co-authored-by: MingxuanGame <68982190+MingxuanGame@users.noreply.github.com>

* chore(linter): auto fix by pre-commit hooks

* Don't use forward-ref for `ScoringMode`

* chore(linter): auto fix by pre-commit hooks

* fix(calculator): update HitResult usage in get_display_score and adjust ruleset value in PerformanceServerPerformanceCalculator

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Co-authored-by: MingxuanGame <MingxuanGame@outlook.com>
This commit is contained in:
Copilot
2025-11-08 20:56:29 +08:00
committed by GitHub
parent ef3a900de0
commit d9d26d0523
9 changed files with 144 additions and 9 deletions

View File

@@ -251,6 +251,28 @@ class HitResult(str, Enum):
HitResult.IGNORE_MISS,
)
def is_basic(self) -> bool:
"""
Check if a HitResult is a basic (non-tick, non-bonus) result.
Based on: https://github.com/ppy/osu/blob/master/osu.Game/Rulesets/Scoring/HitResult.cs
"""
if self in {HitResult.LEGACY_COMBO_INCREASE, HitResult.COMBO_BREAK}:
return False
# Check if it's scorable and not a tick or bonus
is_tick = self in {
HitResult.LARGE_TICK_HIT,
HitResult.LARGE_TICK_MISS,
HitResult.SMALL_TICK_HIT,
HitResult.SMALL_TICK_MISS,
HitResult.SLIDER_TAIL_HIT,
}
is_bonus = self in {HitResult.SMALL_BONUS, HitResult.LARGE_BONUS}
return self.is_scorable() and not is_tick and not is_bonus
class LeaderboardType(Enum):
GLOBAL = "global"

View File

@@ -0,0 +1,13 @@
from enum import Enum
class ScoringMode(str, Enum):
"""
Scoring mode for calculating scores.
STANDARDISED: Modern scoring mode used in current osu!lazer
CLASSIC: Legacy scoring mode for backward compatibility
"""
STANDARDISED = "standardised"
CLASSIC = "classic"