feat(multiplay): support CreateRoom hub method
This commit is contained in:
168
app/models/multiplayer_hub.py
Normal file
168
app/models/multiplayer_hub.py
Normal file
@@ -0,0 +1,168 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import datetime
|
||||
from typing import Annotated, Any, Literal
|
||||
|
||||
from .room import (
|
||||
DownloadState,
|
||||
MatchType,
|
||||
MultiplayerRoomState,
|
||||
MultiplayerUserState,
|
||||
QueueMode,
|
||||
RoomCategory,
|
||||
RoomStatus,
|
||||
)
|
||||
from .signalr import (
|
||||
EnumByIndex,
|
||||
MessagePackArrayModel,
|
||||
UserState,
|
||||
msgpack_union,
|
||||
msgpack_union_dump,
|
||||
)
|
||||
|
||||
from msgpack_lazer_api import APIMod
|
||||
from pydantic import BaseModel, Field, field_serializer, field_validator
|
||||
|
||||
|
||||
class MultiplayerClientState(UserState):
|
||||
room_id: int = 0
|
||||
|
||||
|
||||
class MultiplayerRoomSettings(MessagePackArrayModel):
|
||||
name: str = "Unnamed Room"
|
||||
playlist_item_id: int = 0
|
||||
password: str = ""
|
||||
match_type: Annotated[MatchType, EnumByIndex(MatchType)] = MatchType.HEAD_TO_HEAD
|
||||
queue_mode: Annotated[QueueMode, EnumByIndex(QueueMode)] = QueueMode.HOST_ONLY
|
||||
auto_start_duration: int = 0
|
||||
auto_skip: bool = False
|
||||
|
||||
|
||||
class BeatmapAvailability(MessagePackArrayModel):
|
||||
state: Annotated[DownloadState, EnumByIndex(DownloadState)] = DownloadState.UNKNOWN
|
||||
progress: float | None = None
|
||||
|
||||
|
||||
class _MatchUserState(MessagePackArrayModel): ...
|
||||
|
||||
|
||||
class TeamVersusUserState(_MatchUserState):
|
||||
team_id: int
|
||||
|
||||
type: Literal[0] = Field(0, exclude=True)
|
||||
|
||||
|
||||
MatchUserState = TeamVersusUserState
|
||||
|
||||
|
||||
class _MatchRoomState(MessagePackArrayModel): ...
|
||||
|
||||
|
||||
class MultiplayerTeam(MessagePackArrayModel):
|
||||
id: int
|
||||
name: str
|
||||
|
||||
|
||||
class TeamVersusRoomState(_MatchRoomState):
|
||||
teams: list[MultiplayerTeam] = Field(
|
||||
default_factory=lambda: [
|
||||
MultiplayerTeam(id=0, name="Team Red"),
|
||||
MultiplayerTeam(id=1, name="Team Blue"),
|
||||
]
|
||||
)
|
||||
|
||||
type: Literal[0] = Field(0, exclude=True)
|
||||
|
||||
|
||||
MatchRoomState = TeamVersusRoomState
|
||||
|
||||
|
||||
class PlaylistItem(MessagePackArrayModel):
|
||||
id: int
|
||||
owner_id: int
|
||||
beatmap_id: int
|
||||
checksum: str
|
||||
ruleset_id: int
|
||||
required_mods: list[APIMod] = Field(default_factory=list)
|
||||
allowed_mods: list[APIMod] = Field(default_factory=list)
|
||||
expired: bool
|
||||
order: int
|
||||
played_at: datetime.datetime | None = None
|
||||
star: float
|
||||
freestyle: bool
|
||||
|
||||
|
||||
class _MultiplayerCountdown(MessagePackArrayModel):
|
||||
id: int
|
||||
remaining: int
|
||||
is_exclusive: bool
|
||||
|
||||
|
||||
class MatchStartCountdown(_MultiplayerCountdown):
|
||||
type: Literal[0] = Field(0, exclude=True)
|
||||
|
||||
|
||||
class ForceGameplayStartCountdown(_MultiplayerCountdown):
|
||||
type: Literal[1] = Field(1, exclude=True)
|
||||
|
||||
|
||||
class ServerShuttingDownCountdown(_MultiplayerCountdown):
|
||||
type: Literal[2] = Field(2, exclude=True)
|
||||
|
||||
|
||||
MultiplayerCountdown = (
|
||||
MatchStartCountdown | ForceGameplayStartCountdown | ServerShuttingDownCountdown
|
||||
)
|
||||
|
||||
|
||||
class MultiplayerRoomUser(MessagePackArrayModel):
|
||||
user_id: int
|
||||
state: Annotated[MultiplayerUserState, EnumByIndex(MultiplayerUserState)] = (
|
||||
MultiplayerUserState.IDLE
|
||||
)
|
||||
availability: BeatmapAvailability = BeatmapAvailability(
|
||||
state=DownloadState.UNKNOWN, progress=None
|
||||
)
|
||||
mods: list[APIMod] = Field(default_factory=list)
|
||||
match_state: MatchUserState | None = None
|
||||
ruleset_id: int | None = None # freestyle
|
||||
beatmap_id: int | None = None # freestyle
|
||||
|
||||
@field_validator("match_state", mode="before")
|
||||
def union_validate(v: Any):
|
||||
if isinstance(v, list):
|
||||
return msgpack_union(v)
|
||||
return v
|
||||
|
||||
@field_serializer("match_state")
|
||||
def union_serialize(v: Any):
|
||||
return msgpack_union_dump(v)
|
||||
|
||||
|
||||
class MultiplayerRoom(MessagePackArrayModel):
|
||||
room_id: int
|
||||
state: Annotated[MultiplayerRoomState, EnumByIndex(MultiplayerRoomState)]
|
||||
settings: MultiplayerRoomSettings
|
||||
users: list[MultiplayerRoomUser] = Field(default_factory=list)
|
||||
host: MultiplayerRoomUser | None = None
|
||||
match_state: MatchRoomState | None = None
|
||||
playlist: list[PlaylistItem] = Field(default_factory=list)
|
||||
active_cooldowns: list[MultiplayerCountdown] = Field(default_factory=list)
|
||||
channel_id: int
|
||||
|
||||
@field_validator("match_state", mode="before")
|
||||
def union_validate(v: Any):
|
||||
if isinstance(v, list):
|
||||
return msgpack_union(v)
|
||||
return v
|
||||
|
||||
@field_serializer("match_state")
|
||||
def union_serialize(v: Any):
|
||||
return msgpack_union_dump(v)
|
||||
|
||||
|
||||
class ServerMultiplayerRoom(BaseModel):
|
||||
room: MultiplayerRoom
|
||||
category: RoomCategory
|
||||
status: RoomStatus
|
||||
start_at: datetime.datetime
|
||||
Reference in New Issue
Block a user