feat(matchmaking): support matchmaking (#48)

This commit is contained in:
咕谷酱
2025-10-19 00:05:06 +08:00
committed by GitHub
parent b180d3f39d
commit a4dbb9a167
7 changed files with 229 additions and 8 deletions

View File

@@ -33,6 +33,11 @@ from .item_attempts_count import (
ItemAttemptsResp,
PlaylistAggregateScore,
)
from .matchmaking import (
MatchmakingPool,
MatchmakingPoolBeatmap,
MatchmakingUserStats,
)
from .multiplayer_event import MultiplayerEvent, MultiplayerEventResp
from .notification import Notification, UserNotification
from .password_reset import PasswordReset
@@ -98,6 +103,9 @@ __all__ = [
"ItemAttemptsResp",
"LoginSession",
"LoginSessionResp",
"MatchmakingPool",
"MatchmakingPoolBeatmap",
"MatchmakingUserStats",
"MeResp",
"MonthlyPlaycounts",
"MultiplayerEvent",

106
app/database/matchmaking.py Normal file
View File

@@ -0,0 +1,106 @@
from datetime import datetime
from typing import TYPE_CHECKING, Any, Optional
from app.models.model import UTCBaseModel
from app.models.mods import APIMod
from sqlalchemy import Column, DateTime, ForeignKey, Index, SmallInteger
from sqlmodel import (
JSON,
BigInteger,
Field,
Relationship,
SQLModel,
func,
)
if TYPE_CHECKING:
from .beatmap import Beatmap
from .user import User
class MatchmakingUserStatsBase(SQLModel, UTCBaseModel):
user_id: int = Field(
default=None,
sa_column=Column(BigInteger, ForeignKey("lazer_users.id"), primary_key=True),
)
ruleset_id: int = Field(
default=None,
sa_column=Column(SmallInteger, primary_key=True),
)
first_placements: int = Field(default=0, ge=0)
total_points: int = Field(default=0, ge=0)
elo_data: dict[str, Any] | None = Field(default=None, sa_column=Column(JSON))
created_at: datetime | None = Field(
default=None,
sa_column=Column(DateTime(timezone=True), server_default=func.now()),
)
updated_at: datetime | None = Field(
default=None,
sa_column=Column(DateTime(timezone=True), server_default=func.now(), onupdate=func.now()),
)
class MatchmakingUserStats(MatchmakingUserStatsBase, table=True):
__tablename__: str = "matchmaking_user_stats"
user: "User" = Relationship(back_populates="matchmaking_stats", sa_relationship_kwargs={"lazy": "joined"})
class MatchmakingPoolBase(SQLModel, UTCBaseModel):
id: int | None = Field(default=None, primary_key=True)
ruleset_id: int = Field(
default=0,
sa_column=Column(SmallInteger, nullable=False),
)
variant_id: int = Field(
default=0,
ge=0,
sa_column=Column(SmallInteger, nullable=False, server_default="0"),
)
name: str = Field(max_length=255)
active: bool = Field(default=True)
created_at: datetime | None = Field(
default=None,
sa_column=Column(DateTime(timezone=True), server_default=func.now()),
)
updated_at: datetime | None = Field(
default=None,
sa_column=Column(DateTime(timezone=True), server_default=func.now(), onupdate=func.now()),
)
class MatchmakingPool(MatchmakingPoolBase, table=True):
__tablename__: str = "matchmaking_pools"
__table_args__ = (Index("matchmaking_pools_ruleset_variant_active_idx", "ruleset_id", "variant_id", "active"),)
beatmaps: list["MatchmakingPoolBeatmap"] = Relationship(
back_populates="pool",
# sa_relationship_kwargs={
# "lazy": "selectin",
# },
)
class MatchmakingPoolBeatmapBase(SQLModel, UTCBaseModel):
id: int | None = Field(default=None, primary_key=True)
pool_id: int = Field(
default=None,
sa_column=Column(ForeignKey("matchmaking_pools.id"), nullable=False, index=True),
)
beatmap_id: int = Field(
default=None,
sa_column=Column(ForeignKey("beatmaps.id"), nullable=False),
)
mods: list[APIMod] | None = Field(default=None, sa_column=Column(JSON))
rating: int = Field(default=1500)
selection_count: int = Field(default=0)
class MatchmakingPoolBeatmap(MatchmakingPoolBeatmapBase, table=True):
__tablename__: str = "matchmaking_pool_beatmaps"
pool: MatchmakingPool = Relationship(back_populates="beatmaps")
beatmap: Optional["Beatmap"] = Relationship(
# sa_relationship_kwargs={"lazy": "joined"},
)

View File

@@ -42,6 +42,7 @@ from sqlmodel.ext.asyncio.session import AsyncSession
if TYPE_CHECKING:
from .favourite_beatmapset import FavouriteBeatmapset
from .matchmaking import MatchmakingUserStats
from .relationship import RelationshipResp
@@ -154,6 +155,7 @@ class User(AsyncAttrs, UserBase, table=True):
achievement: list[UserAchievement] = Relationship(back_populates="user")
team_membership: TeamMember | None = Relationship(back_populates="user")
daily_challenge_stats: DailyChallengeStats | None = Relationship(back_populates="user")
matchmaking_stats: list["MatchmakingUserStats"] = Relationship(back_populates="user")
monthly_playcounts: list[MonthlyPlaycounts] = Relationship(back_populates="user")
replays_watched_counts: list[ReplayWatchedCount] = Relationship(back_populates="user")
favourite_beatmapsets: list["FavouriteBeatmapset"] = Relationship(back_populates="user")