fix(playlist): fix user attempts

This commit is contained in:
MingxuanGame
2025-08-09 04:53:20 +00:00
parent 3e3cf27acc
commit d7002374b6
5 changed files with 68 additions and 8 deletions

View File

@@ -16,7 +16,11 @@ from .lazer_user import (
UserResp, UserResp,
) )
from .multiplayer_event import MultiplayerEvent, MultiplayerEventResp from .multiplayer_event import MultiplayerEvent, MultiplayerEventResp
from .playlist_attempts import ItemAttemptsCount, ItemAttemptsResp from .playlist_attempts import (
ItemAttemptsCount,
ItemAttemptsResp,
PlaylistAggregateScore,
)
from .playlist_best_score import PlaylistBestScore from .playlist_best_score import PlaylistBestScore
from .playlists import Playlist, PlaylistResp from .playlists import Playlist, PlaylistResp
from .pp_best_score import PPBestScore from .pp_best_score import PPBestScore
@@ -58,6 +62,7 @@ __all__ = [
"OAuthToken", "OAuthToken",
"PPBestScore", "PPBestScore",
"Playlist", "Playlist",
"PlaylistAggregateScore",
"PlaylistBestScore", "PlaylistBestScore",
"PlaylistResp", "PlaylistResp",
"Relationship", "Relationship",

View File

@@ -1,6 +1,7 @@
from .lazer_user import User, UserResp from .lazer_user import User, UserResp
from .playlist_best_score import PlaylistBestScore from .playlist_best_score import PlaylistBestScore
from pydantic import BaseModel
from sqlmodel import ( from sqlmodel import (
BigInteger, BigInteger,
Column, Column,
@@ -112,3 +113,39 @@ class ItemAttemptsResp(ItemAttemptsCountBase):
resp.position = await item_attempts.get_position(session) resp.position = await item_attempts.get_position(session)
# resp.accuracy *= 100 # resp.accuracy *= 100
return resp return resp
class ItemAttemptsCountForItem(BaseModel):
id: int
attempts: int
passed: bool
class PlaylistAggregateScore(BaseModel):
playlist_item_attempts: list[ItemAttemptsCountForItem] = Field(default_factory=list)
@classmethod
async def from_db(
cls,
room_id: int,
user_id: int,
session: AsyncSession,
) -> "PlaylistAggregateScore":
playlist_scores = (
await session.exec(
select(PlaylistBestScore).where(
PlaylistBestScore.room_id == room_id,
PlaylistBestScore.user_id == user_id,
)
)
).all()
playlist_item_attempts = []
for score in playlist_scores:
playlist_item_attempts.append(
ItemAttemptsCountForItem(
id=score.playlist_id,
attempts=score.attempts,
passed=score.score.passed,
)
)
return cls(playlist_item_attempts=playlist_item_attempts)

View File

@@ -62,20 +62,21 @@ async def process_playlist_best_score(
) )
).first() ).first()
if previous is None: if previous is None:
score = PlaylistBestScore( previous = PlaylistBestScore(
user_id=user_id, user_id=user_id,
score_id=score_id, score_id=score_id,
room_id=room_id, room_id=room_id,
playlist_id=playlist_id, playlist_id=playlist_id,
total_score=total_score, total_score=total_score,
) )
session.add(score) session.add(previous)
else: elif not previous.score.passed or previous.total_score < total_score:
previous.score_id = score_id previous.score_id = score_id
previous.total_score = total_score previous.total_score = total_score
previous.attempts += 1 previous.attempts += 1
await session.commit() await session.commit()
await redis.decr(f"multiplayer:{room_id}:gameplay:players") if await redis.exists(f"multiplayer:{room_id}:gameplay:players"):
await redis.decr(f"multiplayer:{room_id}:gameplay:players")
async def get_position( async def get_position(

View File

@@ -1,5 +1,6 @@
from datetime import UTC, datetime from datetime import UTC, datetime
from app.database.playlist_attempts import PlaylistAggregateScore
from app.models.model import UTCBaseModel from app.models.model import UTCBaseModel
from app.models.multiplayer_hub import ServerMultiplayerRoom from app.models.multiplayer_hub import ServerMultiplayerRoom
from app.models.room import ( from app.models.room import (
@@ -23,6 +24,7 @@ from sqlmodel import (
Relationship, Relationship,
SQLModel, SQLModel,
) )
from sqlmodel.ext.asyncio.session import AsyncSession
class RoomBase(SQLModel, UTCBaseModel): class RoomBase(SQLModel, UTCBaseModel):
@@ -77,9 +79,16 @@ class RoomResp(RoomBase):
playlist_item_stats: RoomPlaylistItemStats | None = None playlist_item_stats: RoomPlaylistItemStats | None = None
difficulty_range: RoomDifficultyRange | None = None difficulty_range: RoomDifficultyRange | None = None
current_playlist_item: PlaylistResp | None = None current_playlist_item: PlaylistResp | None = None
current_user_score: PlaylistAggregateScore | None = None
@classmethod @classmethod
async def from_db(cls, room: Room) -> "RoomResp": async def from_db(
cls,
room: Room,
include: list[str] = [],
session: AsyncSession | None = None,
user: User | None = None,
) -> "RoomResp":
resp = cls.model_validate(room.model_dump()) resp = cls.model_validate(room.model_dump())
stats = RoomPlaylistItemStats(count_active=0, count_total=0) stats = RoomPlaylistItemStats(count_active=0, count_total=0)
@@ -105,6 +114,10 @@ class RoomResp(RoomBase):
resp.difficulty_range = difficulty_range resp.difficulty_range = difficulty_range
resp.current_playlist_item = resp.playlist[-1] if resp.playlist else None resp.current_playlist_item = resp.playlist[-1] if resp.playlist else None
if "current_user_score" in include and user and session:
resp.current_user_score = await PlaylistAggregateScore.from_db(
room.id, user.id, session
)
return resp return resp
@classmethod @classmethod

View File

@@ -116,13 +116,17 @@ async def get_room(
room: int, room: int,
category: str = Query(default=""), category: str = Query(default=""),
db: AsyncSession = Depends(get_db), db: AsyncSession = Depends(get_db),
current_user: User = Depends(get_current_user),
redis: Redis = Depends(get_redis), redis: Redis = Depends(get_redis),
): ):
# 直接从db获取信息毕竟都一样 # 直接从db获取信息毕竟都一样
db_room = (await db.exec(select(Room).where(Room.id == room))).first() db_room = (await db.exec(select(Room).where(Room.id == room))).first()
if db_room is None: if db_room is None:
raise HTTPException(404, "Room not found") raise HTTPException(404, "Room not found")
return await RoomResp.from_db(db_room) resp = await RoomResp.from_db(
db_room, include=["current_user_score"], session=db, user=current_user
)
return resp
@router.delete("/rooms/{room}", tags=["room"]) @router.delete("/rooms/{room}", tags=["room"])