refactor(project): make pyright & ruff happy

This commit is contained in:
MingxuanGame
2025-08-22 08:21:52 +00:00
parent 3b1d7a2234
commit 598fcc8b38
157 changed files with 2382 additions and 4590 deletions

View File

@@ -114,9 +114,7 @@ class MultiplayerEventLogger:
)
await self.log_event(event)
async def game_started(
self, room_id: int, playlist_item_id: int, details: MatchStartedEventDetail
):
async def game_started(self, room_id: int, playlist_item_id: int, details: MatchStartedEventDetail):
event = MultiplayerEvent(
room_id=room_id,
playlist_item_id=playlist_item_id,
@@ -166,6 +164,7 @@ class MultiplayerHub(Hub[MultiplayerClientState]):
# Use centralized offline status management
from app.service.online_status_manager import online_status_manager
await online_status_manager.set_user_offline(user_id)
if state.room_id != 0 and state.room_id in self.rooms:
@@ -173,9 +172,7 @@ class MultiplayerHub(Hub[MultiplayerClientState]):
room = server_room.room
user = next((u for u in room.users if u.user_id == user_id), None)
if user is not None:
await self.make_user_leave(
self.get_client_by_id(str(user_id)), server_room, user
)
await self.make_user_leave(self.get_client_by_id(str(user_id)), server_room, user)
async def on_client_connect(self, client: Client) -> None:
"""Track online users when connecting to multiplayer hub"""
@@ -183,6 +180,7 @@ class MultiplayerHub(Hub[MultiplayerClientState]):
# Use centralized online status management
from app.service.online_status_manager import online_status_manager
await online_status_manager.set_user_online(client.user_id, "multiplayer")
def _ensure_in_room(self, client: Client) -> ServerMultiplayerRoom:
@@ -212,9 +210,7 @@ class MultiplayerHub(Hub[MultiplayerClientState]):
type=room.settings.match_type,
queue_mode=room.settings.queue_mode,
auto_skip=room.settings.auto_skip,
auto_start_duration=int(
room.settings.auto_start_duration.total_seconds()
),
auto_start_duration=int(room.settings.auto_start_duration.total_seconds()),
host_id=client.user_id,
status=RoomStatus.IDLE,
)
@@ -231,26 +227,20 @@ class MultiplayerHub(Hub[MultiplayerClientState]):
await session.commit()
await session.refresh(channel)
await session.refresh(db_room)
room.channel_id = channel.channel_id # pyright: ignore[reportAttributeAccessIssue]
room.channel_id = channel.channel_id
db_room.channel_id = channel.channel_id
item = room.playlist[0]
item.owner_id = client.user_id
room.room_id = db_room.id
starts_at = db_room.starts_at or datetime.now(UTC)
beatmap_exists = await session.exec(
select(exists().where(col(Beatmap.id) == item.beatmap_id))
)
beatmap_exists = await session.exec(select(exists().where(col(Beatmap.id) == item.beatmap_id)))
if not beatmap_exists.one():
fetcher = await get_fetcher()
try:
await Beatmap.get_or_fetch(
session, fetcher, bid=item.beatmap_id
)
await Beatmap.get_or_fetch(session, fetcher, bid=item.beatmap_id)
except HTTPError:
raise InvokeException(
"Failed to fetch beatmap, please retry later"
)
raise InvokeException("Failed to fetch beatmap, please retry later")
await Playlist.add_to_db(item, room.room_id, session)
server_room = ServerMultiplayerRoom(
@@ -262,9 +252,7 @@ class MultiplayerHub(Hub[MultiplayerClientState]):
self.rooms[room.room_id] = server_room
await server_room.set_handler()
await self.event_logger.room_created(room.room_id, client.user_id)
return await self.JoinRoomWithPassword(
client, room.room_id, room.settings.password
)
return await self.JoinRoomWithPassword(client, room.room_id, room.settings.password)
async def JoinRoom(self, client: Client, room_id: int):
return self.JoinRoomWithPassword(client, room_id, "")
@@ -350,9 +338,7 @@ class MultiplayerHub(Hub[MultiplayerClientState]):
beatmap_availability,
)
async def ChangeBeatmapAvailability(
self, client: Client, beatmap_availability: BeatmapAvailability
):
async def ChangeBeatmapAvailability(self, client: Client, beatmap_availability: BeatmapAvailability):
server_room = self._ensure_in_room(client)
room = server_room.room
user = next((u for u in room.users if u.user_id == client.user_id), None)
@@ -371,10 +357,7 @@ class MultiplayerHub(Hub[MultiplayerClientState]):
user = next((u for u in room.users if u.user_id == client.user_id), None)
if user is None:
raise InvokeException("You are not in this room")
logger.info(
f"[MultiplayerHub] {client.user_id} adding "
f"beatmap {item.beatmap_id} to room {room.room_id}"
)
logger.info(f"[MultiplayerHub] {client.user_id} adding beatmap {item.beatmap_id} to room {room.room_id}")
await server_room.queue.add_item(
item,
user,
@@ -388,10 +371,7 @@ class MultiplayerHub(Hub[MultiplayerClientState]):
if user is None:
raise InvokeException("You are not in this room")
logger.info(
f"[MultiplayerHub] {client.user_id} editing "
f"item {item.id} in room {room.room_id}"
)
logger.info(f"[MultiplayerHub] {client.user_id} editing item {item.id} in room {room.room_id}")
await server_room.queue.edit_item(
item,
user,
@@ -405,10 +385,7 @@ class MultiplayerHub(Hub[MultiplayerClientState]):
if user is None:
raise InvokeException("You are not in this room")
logger.info(
f"[MultiplayerHub] {client.user_id} removing "
f"item {item_id} from room {room.room_id}"
)
logger.info(f"[MultiplayerHub] {client.user_id} removing item {item_id} from room {room.room_id}")
await server_room.queue.remove_item(
item_id,
user,
@@ -424,9 +401,7 @@ class MultiplayerHub(Hub[MultiplayerClientState]):
type=room.room.settings.match_type,
queue_mode=room.room.settings.queue_mode,
auto_skip=room.room.settings.auto_skip,
auto_start_duration=int(
room.room.settings.auto_start_duration.total_seconds()
),
auto_start_duration=int(room.room.settings.auto_start_duration.total_seconds()),
host_id=room.room.host.user_id if room.room.host else None,
)
)
@@ -456,9 +431,7 @@ class MultiplayerHub(Hub[MultiplayerClientState]):
item_id,
)
async def playlist_changed(
self, room: ServerMultiplayerRoom, item: PlaylistItem, beatmap_changed: bool
):
async def playlist_changed(self, room: ServerMultiplayerRoom, item: PlaylistItem, beatmap_changed: bool):
if item.id == room.room.settings.playlist_item_id:
await self.validate_styles(room)
await self.unready_all_users(room, beatmap_changed)
@@ -468,9 +441,7 @@ class MultiplayerHub(Hub[MultiplayerClientState]):
item,
)
async def ChangeUserStyle(
self, client: Client, beatmap_id: int | None, ruleset_id: int | None
):
async def ChangeUserStyle(self, client: Client, beatmap_id: int | None, ruleset_id: int | None):
server_room = self._ensure_in_room(client)
room = server_room.room
user = next((u for u in room.users if u.user_id == client.user_id), None)
@@ -496,9 +467,7 @@ class MultiplayerHub(Hub[MultiplayerClientState]):
)
async with with_db() as session:
try:
beatmap = await Beatmap.get_or_fetch(
session, fetcher, bid=room.queue.current_item.beatmap_id
)
beatmap = await Beatmap.get_or_fetch(session, fetcher, bid=room.queue.current_item.beatmap_id)
except HTTPError:
raise InvokeException("Current item beatmap not found")
beatmap_ids = (
@@ -518,11 +487,7 @@ class MultiplayerHub(Hub[MultiplayerClientState]):
if beatmap_id is not None and user_beatmap is None:
beatmap_id = None
beatmap_ruleset = user_beatmap[1] if user_beatmap else beatmap.mode
if (
ruleset_id is not None
and beatmap_ruleset != GameMode.OSU
and ruleset_id != beatmap_ruleset
):
if ruleset_id is not None and beatmap_ruleset != GameMode.OSU and ruleset_id != beatmap_ruleset:
ruleset_id = None
await self.change_user_style(
beatmap_id,
@@ -532,9 +497,7 @@ class MultiplayerHub(Hub[MultiplayerClientState]):
)
for user in room.room.users:
is_valid, valid_mods = room.queue.current_item.validate_user_mods(
user, user.mods
)
is_valid, valid_mods = room.queue.current_item.validate_user_mods(user, user.mods)
if not is_valid:
await self.change_user_mods(valid_mods, room, user)
@@ -553,34 +516,24 @@ class MultiplayerHub(Hub[MultiplayerClientState]):
raise InvokeException("Current item does not allow free user styles.")
async with with_db() as session:
item_beatmap = await session.get(
Beatmap, room.queue.current_item.beatmap_id
)
item_beatmap = await session.get(Beatmap, room.queue.current_item.beatmap_id)
if item_beatmap is None:
raise InvokeException("Item beatmap not found")
user_beatmap = (
item_beatmap
if beatmap_id is None
else await session.get(Beatmap, beatmap_id)
)
user_beatmap = item_beatmap if beatmap_id is None else await session.get(Beatmap, beatmap_id)
if user_beatmap is None:
raise InvokeException("Invalid beatmap selected.")
if user_beatmap.beatmapset_id != item_beatmap.beatmapset_id:
raise InvokeException(
"Selected beatmap is not from the same beatmap set."
)
raise InvokeException("Selected beatmap is not from the same beatmap set.")
if (
ruleset_id is not None
and user_beatmap.mode != GameMode.OSU
and ruleset_id != int(user_beatmap.mode)
):
raise InvokeException(
"Selected ruleset is not supported for the given beatmap."
)
raise InvokeException("Selected ruleset is not supported for the given beatmap.")
user.beatmap_id = beatmap_id
user.ruleset_id = ruleset_id
@@ -608,16 +561,10 @@ class MultiplayerHub(Hub[MultiplayerClientState]):
room: ServerMultiplayerRoom,
user: MultiplayerRoomUser,
):
is_valid, valid_mods = room.queue.current_item.validate_user_mods(
user, new_mods
)
is_valid, valid_mods = room.queue.current_item.validate_user_mods(user, new_mods)
if not is_valid:
incompatible_mods = [
mod["acronym"] for mod in new_mods if mod not in valid_mods
]
raise InvokeException(
f"Incompatible mods were selected: {','.join(incompatible_mods)}"
)
incompatible_mods = [mod["acronym"] for mod in new_mods if mod not in valid_mods]
raise InvokeException(f"Incompatible mods were selected: {','.join(incompatible_mods)}")
if user.mods == valid_mods:
return
@@ -640,16 +587,12 @@ class MultiplayerHub(Hub[MultiplayerClientState]):
match new:
case MultiplayerUserState.IDLE:
if old.is_playing:
raise InvokeException(
"Cannot return to idle without aborting gameplay."
)
raise InvokeException("Cannot return to idle without aborting gameplay.")
case MultiplayerUserState.READY:
if old != MultiplayerUserState.IDLE:
raise InvokeException(f"Cannot change state from {old} to {new}")
if room.queue.current_item.expired:
raise InvokeException(
"Cannot ready up while all items have been played."
)
raise InvokeException("Cannot ready up while all items have been played.")
case MultiplayerUserState.WAITING_FOR_LOAD:
raise InvokeException(f"Cannot change state from {old} to {new}")
case MultiplayerUserState.LOADED:
@@ -688,9 +631,7 @@ class MultiplayerHub(Hub[MultiplayerClientState]):
MultiplayerRoomState.PLAYING,
)
):
raise InvokeException(
f"Cannot change state from {old} to {new}"
)
raise InvokeException(f"Cannot change state from {old} to {new}")
case _:
raise InvokeException(f"Invalid state transition from {old} to {new}")
@@ -713,9 +654,7 @@ class MultiplayerHub(Hub[MultiplayerClientState]):
if not user.state.is_playing:
return
logger.info(
f"[MultiplayerHub] User {user.user_id} changing state from {user.state} to {state}"
)
logger.info(f"[MultiplayerHub] User {user.user_id} changing state from {user.state} to {state}")
await self.validate_user_stare(
server_room,
@@ -737,10 +676,7 @@ class MultiplayerHub(Hub[MultiplayerClientState]):
user: MultiplayerRoomUser,
state: MultiplayerUserState,
):
logger.info(
f"[MultiplayerHub] {user.user_id}'s state "
f"changed from {user.state} to {state}"
)
logger.info(f"[MultiplayerHub] {user.user_id}'s state changed from {user.state} to {state}")
user.state = state
await self.broadcast_group_call(
self.group_id(room.room.room_id),
@@ -760,23 +696,17 @@ class MultiplayerHub(Hub[MultiplayerClientState]):
# If switching to spectating during gameplay, immediately request load
if room_state == MultiplayerRoomState.WAITING_FOR_LOAD:
logger.info(
f"[MultiplayerHub] Spectator {user.user_id} joining during load phase"
)
logger.info(f"[MultiplayerHub] Spectator {user.user_id} joining during load phase")
await self.call_noblock(client, "LoadRequested")
elif room_state == MultiplayerRoomState.PLAYING:
logger.info(
f"[MultiplayerHub] Spectator {user.user_id} joining during active gameplay"
)
logger.info(f"[MultiplayerHub] Spectator {user.user_id} joining during active gameplay")
await self.call_noblock(client, "LoadRequested")
# Also sync the spectator with current game state
await self._send_current_gameplay_state_to_spectator(client, room)
async def _send_current_gameplay_state_to_spectator(
self, client: Client, room: ServerMultiplayerRoom
):
async def _send_current_gameplay_state_to_spectator(self, client: Client, room: ServerMultiplayerRoom):
"""
Send current gameplay state information to a newly joined spectator.
This helps spectators sync with ongoing gameplay.
@@ -794,27 +724,20 @@ class MultiplayerHub(Hub[MultiplayerClientState]):
room_user.user_id,
room_user.state,
)
# If the room is in OPEN state but we have users in RESULTS state,
# this means the game just finished and we should send ResultsReady
if (room.room.state == MultiplayerRoomState.OPEN and
any(u.state == MultiplayerUserState.RESULTS for u in room.room.users)):
logger.debug(
f"[MultiplayerHub] Sending ResultsReady to new spectator {client.user_id}"
)
if room.room.state == MultiplayerRoomState.OPEN and any(
u.state == MultiplayerUserState.RESULTS for u in room.room.users
):
logger.debug(f"[MultiplayerHub] Sending ResultsReady to new spectator {client.user_id}")
await self.call_noblock(client, "ResultsReady")
logger.debug(
f"[MultiplayerHub] Sent current gameplay state to spectator {client.user_id}"
)
logger.debug(f"[MultiplayerHub] Sent current gameplay state to spectator {client.user_id}")
except Exception as e:
logger.error(
f"[MultiplayerHub] Failed to send gameplay state to spectator {client.user_id}: {e}"
)
logger.error(f"[MultiplayerHub] Failed to send gameplay state to spectator {client.user_id}: {e}")
async def _send_room_state_to_new_user(
self, client: Client, room: ServerMultiplayerRoom
):
async def _send_room_state_to_new_user(self, client: Client, room: ServerMultiplayerRoom):
"""
Send complete room state to a newly joined user.
Critical for spectators joining ongoing games.
@@ -847,28 +770,21 @@ class MultiplayerHub(Hub[MultiplayerClientState]):
# Critical fix: If room is OPEN but has users in RESULTS state,
# send ResultsReady to new joiners (including spectators)
if (room.room.state == MultiplayerRoomState.OPEN and
any(u.state == MultiplayerUserState.RESULTS for u in room.room.users)):
logger.info(
f"[MultiplayerHub] Sending ResultsReady to newly joined user {client.user_id}"
)
if room.room.state == MultiplayerRoomState.OPEN and any(
u.state == MultiplayerUserState.RESULTS for u in room.room.users
):
logger.info(f"[MultiplayerHub] Sending ResultsReady to newly joined user {client.user_id}")
await self.call_noblock(client, "ResultsReady")
# Critical addition: Send current playing users to SpectatorHub for cross-hub sync
# This ensures spectators can watch multiplayer players properly
await self._sync_with_spectator_hub(client, room)
logger.debug(
f"[MultiplayerHub] Sent complete room state to new user {client.user_id}"
)
logger.debug(f"[MultiplayerHub] Sent complete room state to new user {client.user_id}")
except Exception as e:
logger.error(
f"[MultiplayerHub] Failed to send room state to user {client.user_id}: {e}"
)
logger.error(f"[MultiplayerHub] Failed to send room state to user {client.user_id}: {e}")
async def _sync_with_spectator_hub(
self, client: Client, room: ServerMultiplayerRoom
):
async def _sync_with_spectator_hub(self, client: Client, room: ServerMultiplayerRoom):
"""
Sync with SpectatorHub to ensure cross-hub spectating works properly.
This is crucial for users watching multiplayer players from other pages.
@@ -893,13 +809,16 @@ class MultiplayerHub(Hub[MultiplayerClientState]):
f"[MultiplayerHub] Synced spectator state for user {room_user.user_id} "
f"to new client {client.user_id}"
)
# Critical addition: Notify SpectatorHub about users in RESULTS state
elif room_user.state == MultiplayerUserState.RESULTS:
# Create a synthetic finished state for cross-hub spectating
try:
from app.models.spectator_hub import SpectatedUserState, SpectatorState
from app.models.spectator_hub import (
SpectatedUserState,
SpectatorState,
)
finished_state = SpectatorState(
beatmap_id=room.queue.current_item.beatmap_id,
ruleset_id=room_user.ruleset_id or 0,
@@ -919,9 +838,7 @@ class MultiplayerHub(Hub[MultiplayerClientState]):
f"to client {client.user_id}"
)
except Exception as e:
logger.debug(
f"[MultiplayerHub] Failed to create synthetic finished state: {e}"
)
logger.debug(f"[MultiplayerHub] Failed to create synthetic finished state: {e}")
except Exception as e:
logger.debug(f"[MultiplayerHub] Failed to sync with SpectatorHub: {e}")
@@ -933,75 +850,55 @@ class MultiplayerHub(Hub[MultiplayerClientState]):
if room.room.settings.auto_start_enabled:
if (
not room.queue.current_item.expired
and any(
u.state == MultiplayerUserState.READY
for u in room.room.users
)
and any(u.state == MultiplayerUserState.READY for u in room.room.users)
and not any(
isinstance(countdown, MatchStartCountdown)
for countdown in room.room.active_countdowns
isinstance(countdown, MatchStartCountdown) for countdown in room.room.active_countdowns
)
):
await room.start_countdown(
MatchStartCountdown(
time_remaining=room.room.settings.auto_start_duration
),
MatchStartCountdown(time_remaining=room.room.settings.auto_start_duration),
self.start_match,
)
case MultiplayerRoomState.WAITING_FOR_LOAD:
played_count = len(
[True for user in room.room.users if user.state.is_playing]
)
played_count = len([True for user in room.room.users if user.state.is_playing])
ready_count = len(
[
True
for user in room.room.users
if user.state == MultiplayerUserState.READY_FOR_GAMEPLAY
]
[True for user in room.room.users if user.state == MultiplayerUserState.READY_FOR_GAMEPLAY]
)
if played_count == ready_count:
await self.start_gameplay(room)
case MultiplayerRoomState.PLAYING:
if all(
u.state != MultiplayerUserState.PLAYING for u in room.room.users
):
if all(u.state != MultiplayerUserState.PLAYING for u in room.room.users):
any_user_finished_playing = False
# Handle finished players first
for u in filter(
lambda u: u.state == MultiplayerUserState.FINISHED_PLAY,
room.room.users,
):
any_user_finished_playing = True
await self.change_user_state(
room, u, MultiplayerUserState.RESULTS
)
await self.change_user_state(room, u, MultiplayerUserState.RESULTS)
# Critical fix: Handle spectators who should also see results
# Move spectators to RESULTS state so they can see the results screen
for u in filter(
lambda u: u.state == MultiplayerUserState.SPECTATING,
room.room.users,
):
logger.debug(
f"[MultiplayerHub] Moving spectator {u.user_id} to RESULTS state"
)
await self.change_user_state(
room, u, MultiplayerUserState.RESULTS
)
logger.debug(f"[MultiplayerHub] Moving spectator {u.user_id} to RESULTS state")
await self.change_user_state(room, u, MultiplayerUserState.RESULTS)
await self.change_room_state(room, MultiplayerRoomState.OPEN)
# Send ResultsReady to all room members
await self.broadcast_group_call(
self.group_id(room.room.room_id),
"ResultsReady",
)
# Critical addition: Notify SpectatorHub about finished games
# This ensures cross-hub spectating works properly
await self._notify_spectator_hub_game_ended(room)
if any_user_finished_playing:
await self.event_logger.game_completed(
room.room.room_id,
@@ -1014,13 +911,8 @@ class MultiplayerHub(Hub[MultiplayerClientState]):
)
await room.queue.finish_current_item()
async def change_room_state(
self, room: ServerMultiplayerRoom, state: MultiplayerRoomState
):
logger.debug(
f"[MultiplayerHub] Room {room.room.room_id} state "
f"changed from {room.room.state} to {state}"
)
async def change_room_state(self, room: ServerMultiplayerRoom, state: MultiplayerRoomState):
logger.debug(f"[MultiplayerHub] Room {room.room.room_id} state changed from {room.room.state} to {state}")
room.room.state = state
await self.broadcast_group_call(
self.group_id(room.room.room_id),
@@ -1064,10 +956,7 @@ class MultiplayerHub(Hub[MultiplayerClientState]):
u
for u in room.room.users
if u.availability.state == DownloadState.LOCALLY_AVAILABLE
and (
u.state == MultiplayerUserState.READY
or u.state == MultiplayerUserState.IDLE
)
and (u.state == MultiplayerUserState.READY or u.state == MultiplayerUserState.IDLE)
]
for u in ready_users:
await self.change_user_state(room, u, MultiplayerUserState.WAITING_FOR_LOAD)
@@ -1080,9 +969,7 @@ class MultiplayerHub(Hub[MultiplayerClientState]):
"LoadRequested",
)
await room.start_countdown(
ForceGameplayStartCountdown(
time_remaining=timedelta(seconds=GAMEPLAY_LOAD_TIMEOUT)
),
ForceGameplayStartCountdown(time_remaining=timedelta(seconds=GAMEPLAY_LOAD_TIMEOUT)),
self.start_gameplay,
)
await self.event_logger.game_started(
@@ -1133,9 +1020,7 @@ class MultiplayerHub(Hub[MultiplayerClientState]):
else:
await room.queue.finish_current_item()
async def send_match_event(
self, room: ServerMultiplayerRoom, event: MatchServerEvent
):
async def send_match_event(self, room: ServerMultiplayerRoom, event: MatchServerEvent):
await self.broadcast_group_call(
self.group_id(room.room.room_id),
"MatchEvent",
@@ -1183,24 +1068,16 @@ class MultiplayerHub(Hub[MultiplayerClientState]):
await self.end_room(room)
return
await self.update_room_state(room)
if (
len(room.room.users) != 0
and room.room.host
and room.room.host.user_id == user.user_id
):
if len(room.room.users) != 0 and room.room.host and room.room.host.user_id == user.user_id:
next_host = room.room.users[0]
await self.set_host(room, next_host)
if kicked:
if client:
await self.call_noblock(client, "UserKicked", user)
await self.broadcast_group_call(
self.group_id(room.room.room_id), "UserKicked", user
)
await self.broadcast_group_call(self.group_id(room.room.room_id), "UserKicked", user)
else:
await self.broadcast_group_call(
self.group_id(room.room.room_id), "UserLeft", user
)
await self.broadcast_group_call(self.group_id(room.room.room_id), "UserLeft", user)
async def end_room(self, room: ServerMultiplayerRoom):
assert room.room.host
@@ -1214,9 +1091,7 @@ class MultiplayerHub(Hub[MultiplayerClientState]):
type=room.room.settings.match_type,
queue_mode=room.room.settings.queue_mode,
auto_skip=room.room.settings.auto_skip,
auto_start_duration=int(
room.room.settings.auto_start_duration.total_seconds()
),
auto_start_duration=int(room.room.settings.auto_start_duration.total_seconds()),
host_id=room.room.host.user_id,
)
)
@@ -1262,10 +1137,7 @@ class MultiplayerHub(Hub[MultiplayerClientState]):
)
target_client = self.get_client_by_id(str(user.user_id))
await self.make_user_leave(target_client, server_room, user, kicked=True)
logger.info(
f"[MultiplayerHub] {user.user_id} was kicked from room {room.room_id}"
f"by {client.user_id}"
)
logger.info(f"[MultiplayerHub] {user.user_id} was kicked from room {room.room_id}by {client.user_id}")
async def set_host(self, room: ServerMultiplayerRoom, user: MultiplayerRoomUser):
room.room.host = user
@@ -1289,10 +1161,7 @@ class MultiplayerHub(Hub[MultiplayerClientState]):
new_host.user_id,
)
await self.set_host(server_room, new_host)
logger.info(
f"[MultiplayerHub] {client.user_id} transferred host to {new_host.user_id}"
f" in room {room.room_id}"
)
logger.info(f"[MultiplayerHub] {client.user_id} transferred host to {new_host.user_id} in room {room.room_id}")
async def AbortGameplay(self, client: Client):
server_room = self._ensure_in_room(client)
@@ -1316,10 +1185,7 @@ class MultiplayerHub(Hub[MultiplayerClientState]):
room = server_room.room
self._ensure_host(client, server_room)
if (
room.state != MultiplayerRoomState.PLAYING
and room.state != MultiplayerRoomState.WAITING_FOR_LOAD
):
if room.state != MultiplayerRoomState.PLAYING and room.state != MultiplayerRoomState.WAITING_FOR_LOAD:
raise InvokeException("Cannot abort a match that hasn't started.")
await asyncio.gather(
@@ -1335,13 +1201,9 @@ class MultiplayerHub(Hub[MultiplayerClientState]):
GameplayAbortReason.HOST_ABORTED,
)
await self.update_room_state(server_room)
logger.info(
f"[MultiplayerHub] {client.user_id} aborted match in room {room.room_id}"
)
logger.info(f"[MultiplayerHub] {client.user_id} aborted match in room {room.room_id}")
async def change_user_match_state(
self, room: ServerMultiplayerRoom, user: MultiplayerRoomUser
):
async def change_user_match_state(self, room: ServerMultiplayerRoom, user: MultiplayerRoomUser):
await self.broadcast_group_call(
self.group_id(room.room.room_id),
"MatchUserStateChanged",
@@ -1402,10 +1264,7 @@ class MultiplayerHub(Hub[MultiplayerClientState]):
)
if countdown is None:
return
if (
isinstance(countdown, MatchStartCountdown)
and room.settings.auto_start_enabled
) or isinstance(
if (isinstance(countdown, MatchStartCountdown) and room.settings.auto_start_enabled) or isinstance(
countdown, (ForceGameplayStartCountdown | ServerShuttingDownCountdown)
):
raise InvokeException("Cannot stop the requested countdown")
@@ -1447,25 +1306,16 @@ class MultiplayerHub(Hub[MultiplayerClientState]):
raise InvokeException("User already invited")
if db_user.is_restricted:
raise InvokeException("User is restricted")
if (
inviter_relationship
and inviter_relationship.type == RelationshipType.BLOCK
):
if inviter_relationship and inviter_relationship.type == RelationshipType.BLOCK:
raise InvokeException("Cannot perform action due to user being blocked")
if (
target_relationship
and target_relationship.type == RelationshipType.BLOCK
):
if target_relationship and target_relationship.type == RelationshipType.BLOCK:
raise InvokeException("Cannot perform action due to user being blocked")
if (
db_user.pm_friends_only
and target_relationship is not None
and target_relationship.type != RelationshipType.FOLLOW
):
raise InvokeException(
"Cannot perform action "
"because user has disabled non-friend communications"
)
raise InvokeException("Cannot perform action because user has disabled non-friend communications")
target_client = self.get_client_by_id(str(user_id))
if target_client is None:
@@ -1478,9 +1328,7 @@ class MultiplayerHub(Hub[MultiplayerClientState]):
room.settings.password,
)
async def unready_all_users(
self, room: ServerMultiplayerRoom, reset_beatmap_availability: bool
):
async def unready_all_users(self, room: ServerMultiplayerRoom, reset_beatmap_availability: bool):
await asyncio.gather(
*[
self.change_user_state(
@@ -1512,8 +1360,8 @@ class MultiplayerHub(Hub[MultiplayerClientState]):
"""
try:
# Import here to avoid circular imports
from app.signalr.hub import SpectatorHubs
from app.models.spectator_hub import SpectatedUserState, SpectatorState
from app.signalr.hub import SpectatorHubs
# For each user who finished the game, notify SpectatorHub
for room_user in room.room.users:
@@ -1534,13 +1382,9 @@ class MultiplayerHub(Hub[MultiplayerClientState]):
room_user.user_id,
finished_state,
)
logger.debug(
f"[MultiplayerHub] Notified SpectatorHub that user {room_user.user_id} finished game"
)
logger.debug(f"[MultiplayerHub] Notified SpectatorHub that user {room_user.user_id} finished game")
except Exception as e:
logger.debug(
f"[MultiplayerHub] Failed to notify SpectatorHub about game end: {e}"
)
logger.debug(f"[MultiplayerHub] Failed to notify SpectatorHub about game end: {e}")
# This is not critical, so we don't raise the exception