feat(calculator): support generate PerformanceAttributes & DifficultyAttributes from JSON Schema (#59)

Prepare for custom rulesets.

Schema Genetator: https://github.com/GooGuTeam/custom-rulesets/tree/main/CustomRulesetMetadataGenerator

```bash
dotnet -- schemas path/to/rulesets -o schema.json
```

```bash
python scripts/generate_ruleset_attributes.py schema.json 
```
This commit is contained in:
MingxuanGame
2025-10-25 19:10:53 +08:00
committed by GitHub
parent f792d146b5
commit 2c81e22749
12 changed files with 370 additions and 85 deletions

View File

@@ -10,7 +10,7 @@ from app.dependencies.database import Database, Redis
from app.dependencies.fetcher import Fetcher
from app.models.beatmap import BeatmapRankStatus, Genre, Language
from app.models.mods import int_to_mods
from app.models.performance import OsuBeatmapAttributes
from app.models.performance import OsuDifficultyAttributes
from app.models.score import GameMode
from .router import AllStrModel, router
@@ -196,7 +196,7 @@ async def get_beatmaps(
)
aim_diff = None
speed_diff = None
if isinstance(attrs, OsuBeatmapAttributes):
if isinstance(attrs, OsuDifficultyAttributes):
aim_diff = attrs.aim_difficulty
speed_diff = attrs.speed_difficulty
results.append(await V1Beatmap.from_db(session, beatmap, aim_diff, speed_diff))

View File

@@ -11,7 +11,10 @@ from app.dependencies.fetcher import Fetcher
from app.dependencies.user import get_current_user
from app.helpers.asset_proxy_helper import asset_proxy_response
from app.models.mods import APIMod, int_to_mods
from app.models.performance import BeatmapAttributes, OsuBeatmapAttributes, TaikoBeatmapAttributes
from app.models.performance import (
DifficultyAttributes,
DifficultyAttributesUnion,
)
from app.models.score import (
GameMode,
)
@@ -127,7 +130,7 @@ async def batch_get_beatmaps(
"/beatmaps/{beatmap_id}/attributes",
tags=["谱面"],
name="计算谱面属性",
response_model=BeatmapAttributes | OsuBeatmapAttributes | TaikoBeatmapAttributes,
response_model=DifficultyAttributesUnion,
description=("计算谱面指定 mods / ruleset 下谱面的难度属性 (难度/PP 相关属性)。"),
)
async def get_beatmap_attributes(
@@ -166,7 +169,7 @@ async def get_beatmap_attributes(
f"{hashlib.md5(str(mods_).encode(), usedforsecurity=False).hexdigest()}:attributes"
)
if await redis.exists(key):
return BeatmapAttributes.model_validate_json(await redis.get(key)) # pyright: ignore[reportArgumentType]
return DifficultyAttributes.model_validate_json(await redis.get(key)) # pyright: ignore[reportArgumentType]
try:
return await calculate_beatmap_attributes(beatmap_id, ruleset, mods_, redis, fetcher)
except HTTPStatusError: