fix(statistics): fix levels
This commit is contained in:
@@ -79,21 +79,152 @@ def calculate_pp(
|
||||
|
||||
|
||||
# https://osu.ppy.sh/wiki/Gameplay/Score/Total_score
|
||||
def calculate_level_to_score(level: int) -> float:
|
||||
if level <= 100:
|
||||
# 55 = 4^3 - 3^2
|
||||
return 5000 / 3 * (55 - level) + 1.25 * math.pow(1.8, level - 60)
|
||||
def calculate_level_to_score(n: int) -> float:
|
||||
if n <= 100:
|
||||
return 5000 / 3 * (4 * n**3 - 3 * n**2 - n) + 1.25 * 1.8 ** (n - 60)
|
||||
else:
|
||||
return 26_931_190_827 + 99_999_999_999 * (level - 100)
|
||||
return 26931190827 + 99999999999 * (n - 100)
|
||||
|
||||
|
||||
def calculate_score_to_level(score: float) -> int:
|
||||
if score < 5000:
|
||||
return int(55 - (3 * score / 5000)) # 55 = 4^3 - 3^2
|
||||
elif score < 26_931_190_827:
|
||||
return int(60 + math.log(score / 1.25, 1.8))
|
||||
else:
|
||||
return int((score - 26_931_190_827) / 99_999_999_999 + 100)
|
||||
# https://github.com/ppy/osu-queue-score-statistics/blob/4bdd479530408de73f3cdd95e097fe126772a65b/osu.Server.Queues.ScoreStatisticsProcessor/Processors/TotalScoreProcessor.cs#L70-L116
|
||||
def calculate_score_to_level(total_score: int) -> float:
|
||||
to_next_level = [
|
||||
30000,
|
||||
100000,
|
||||
210000,
|
||||
360000,
|
||||
550000,
|
||||
780000,
|
||||
1050000,
|
||||
1360000,
|
||||
1710000,
|
||||
2100000,
|
||||
2530000,
|
||||
3000000,
|
||||
3510000,
|
||||
4060000,
|
||||
4650000,
|
||||
5280000,
|
||||
5950000,
|
||||
6660000,
|
||||
7410000,
|
||||
8200000,
|
||||
9030000,
|
||||
9900000,
|
||||
10810000,
|
||||
11760000,
|
||||
12750000,
|
||||
13780000,
|
||||
14850000,
|
||||
15960000,
|
||||
17110000,
|
||||
18300000,
|
||||
19530000,
|
||||
20800000,
|
||||
22110000,
|
||||
23460000,
|
||||
24850000,
|
||||
26280000,
|
||||
27750000,
|
||||
29260000,
|
||||
30810000,
|
||||
32400000,
|
||||
34030000,
|
||||
35700000,
|
||||
37410000,
|
||||
39160000,
|
||||
40950000,
|
||||
42780000,
|
||||
44650000,
|
||||
46560000,
|
||||
48510000,
|
||||
50500000,
|
||||
52530000,
|
||||
54600000,
|
||||
56710000,
|
||||
58860000,
|
||||
61050000,
|
||||
63280000,
|
||||
65550000,
|
||||
67860000,
|
||||
70210001,
|
||||
72600001,
|
||||
75030002,
|
||||
77500003,
|
||||
80010006,
|
||||
82560010,
|
||||
85150019,
|
||||
87780034,
|
||||
90450061,
|
||||
93160110,
|
||||
95910198,
|
||||
98700357,
|
||||
101530643,
|
||||
104401157,
|
||||
107312082,
|
||||
110263748,
|
||||
113256747,
|
||||
116292144,
|
||||
119371859,
|
||||
122499346,
|
||||
125680824,
|
||||
128927482,
|
||||
132259468,
|
||||
135713043,
|
||||
139353477,
|
||||
143298259,
|
||||
147758866,
|
||||
153115959,
|
||||
160054726,
|
||||
169808506,
|
||||
184597311,
|
||||
208417160,
|
||||
248460887,
|
||||
317675597,
|
||||
439366075,
|
||||
655480935,
|
||||
1041527682,
|
||||
1733419828,
|
||||
2975801691,
|
||||
5209033044,
|
||||
9225761479,
|
||||
99999999999,
|
||||
99999999999,
|
||||
99999999999,
|
||||
99999999999,
|
||||
99999999999,
|
||||
99999999999,
|
||||
99999999999,
|
||||
99999999999,
|
||||
99999999999,
|
||||
99999999999,
|
||||
99999999999,
|
||||
99999999999,
|
||||
99999999999,
|
||||
99999999999,
|
||||
99999999999,
|
||||
99999999999,
|
||||
99999999999,
|
||||
99999999999,
|
||||
99999999999,
|
||||
99999999999,
|
||||
99999999999,
|
||||
99999999999,
|
||||
99999999999,
|
||||
99999999999,
|
||||
]
|
||||
|
||||
remaining_score = total_score
|
||||
level = 0.0
|
||||
|
||||
while remaining_score > 0:
|
||||
next_level_requirement = to_next_level[
|
||||
min(len(to_next_level) - 1, round(level))
|
||||
]
|
||||
level += min(1, remaining_score / next_level_requirement)
|
||||
remaining_score -= next_level_requirement
|
||||
|
||||
return level + 1
|
||||
|
||||
|
||||
# https://osu.ppy.sh/wiki/Performance_points/Weighting_system
|
||||
|
||||
@@ -585,7 +585,7 @@ async def process_user(
|
||||
session.add(previous_score_best)
|
||||
|
||||
statistics.ranked_score += difference
|
||||
statistics.level_current = calculate_score_to_level(statistics.ranked_score)
|
||||
statistics.level_current = calculate_score_to_level(statistics.total_score)
|
||||
statistics.maximum_combo = max(statistics.maximum_combo, score.max_combo)
|
||||
if score.passed and ranked:
|
||||
if previous_score_best_mod is not None:
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
from datetime import UTC, datetime
|
||||
import math
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from app.models.score import GameMode
|
||||
@@ -59,8 +60,7 @@ class UserStatistics(UserStatisticsBase, table=True):
|
||||
grade_sh: int = Field(default=0)
|
||||
grade_a: int = Field(default=0)
|
||||
|
||||
level_current: int = Field(default=1)
|
||||
level_progress: int = Field(default=0)
|
||||
level_current: float = Field(default=1)
|
||||
|
||||
user: "User" = Relationship(back_populates="statistics") # type: ignore[valid-type]
|
||||
|
||||
@@ -97,9 +97,10 @@ class UserStatisticsResp(UserStatisticsBase):
|
||||
"a": obj.grade_a,
|
||||
}
|
||||
s.level = {
|
||||
"current": obj.level_current,
|
||||
"progress": obj.level_progress,
|
||||
"current": int(obj.level_current),
|
||||
"progress": int(math.fmod(obj.level_current, 1) * 100),
|
||||
}
|
||||
|
||||
s.global_rank = await get_rank(session, obj)
|
||||
s.country_rank = await get_rank(session, obj, user_country)
|
||||
return s
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
"""statistics: remove level_progress
|
||||
|
||||
Revision ID: 8bab62d764a5
|
||||
Revises: 59c9a0827de0
|
||||
Create Date: 2025-08-13 10:34:03.430039
|
||||
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from collections.abc import Sequence
|
||||
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
from sqlalchemy.dialects import mysql
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision: str = "8bab62d764a5"
|
||||
down_revision: str | Sequence[str] | None = "59c9a0827de0"
|
||||
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.alter_column(
|
||||
"lazer_user_statistics",
|
||||
"level_current",
|
||||
existing_type=mysql.INTEGER(),
|
||||
type_=sa.Float(),
|
||||
existing_nullable=False,
|
||||
)
|
||||
op.drop_column("lazer_user_statistics", "level_progress")
|
||||
# ### end Alembic commands ###
|
||||
|
||||
|
||||
def downgrade() -> None:
|
||||
"""Downgrade schema."""
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.add_column(
|
||||
"lazer_user_statistics",
|
||||
sa.Column(
|
||||
"level_progress", mysql.INTEGER(), autoincrement=False, nullable=False
|
||||
),
|
||||
)
|
||||
op.alter_column(
|
||||
"lazer_user_statistics",
|
||||
"level_current",
|
||||
existing_type=sa.Float(),
|
||||
type_=mysql.INTEGER(),
|
||||
existing_nullable=False,
|
||||
)
|
||||
# ### end Alembic commands ###
|
||||
Reference in New Issue
Block a user