169 lines
4.3 KiB
Python
169 lines
4.3 KiB
Python
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
|