feat(multiplayer): support change settings

This commit is contained in:
MingxuanGame
2025-08-03 15:14:30 +00:00
parent 1e304542bd
commit 34bf2c6b32
2 changed files with 240 additions and 24 deletions

View File

@@ -15,16 +15,20 @@ from app.models.multiplayer_hub import (
BeatmapAvailability,
ForceGameplayStartCountdown,
GameplayAbortReason,
MatchRequest,
MatchServerEvent,
MultiplayerClientState,
MultiplayerQueue,
MultiplayerRoom,
MultiplayerRoomSettings,
MultiplayerRoomUser,
PlaylistItem,
ServerMultiplayerRoom,
StartMatchCountdownRequest,
StopCountdownRequest,
)
from app.models.room import (
DownloadState,
MatchType,
MultiplayerRoomState,
MultiplayerUserState,
RoomCategory,
@@ -88,15 +92,11 @@ class MultiplayerHub(Hub[MultiplayerClientState]):
server_room = ServerMultiplayerRoom(
room=room,
category=RoomCategory.NORMAL,
status=RoomStatus.IDLE,
start_at=starts_at,
hub=self,
)
queue = MultiplayerQueue(
room=server_room,
)
server_room.queue = queue
self.rooms[room.room_id] = server_room
await server_room.set_handler()
return await self.JoinRoomWithPassword(
client, room.room_id, room.settings.password
)
@@ -126,6 +126,7 @@ class MultiplayerHub(Hub[MultiplayerClientState]):
await self.broadcast_group_call(self.group_id(room_id), "UserJoined", user)
room.users.append(user)
self.add_to_group(client, self.group_id(room_id))
await server_room.match_type_handler.handle_join(user)
return room
async def ChangeBeatmapAvailability(
@@ -164,7 +165,7 @@ class MultiplayerHub(Hub[MultiplayerClientState]):
raise InvokeException("Room does not exist")
server_room = self.rooms[store.room_id]
room = server_room.room
assert server_room.queue
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")
@@ -182,7 +183,7 @@ class MultiplayerHub(Hub[MultiplayerClientState]):
raise InvokeException("Room does not exist")
server_room = self.rooms[store.room_id]
room = server_room.room
assert server_room.queue
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")
@@ -200,7 +201,7 @@ class MultiplayerHub(Hub[MultiplayerClientState]):
raise InvokeException("Room does not exist")
server_room = self.rooms[store.room_id]
room = server_room.room
assert server_room.queue
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")
@@ -262,7 +263,6 @@ class MultiplayerHub(Hub[MultiplayerClientState]):
)
async def validate_styles(self, room: ServerMultiplayerRoom):
assert room.queue
if not room.queue.current_item.freestyle:
for user in room.room.users:
await self.change_user_style(
@@ -323,7 +323,6 @@ class MultiplayerHub(Hub[MultiplayerClientState]):
return
if beatmap_id is not None or ruleset_id is not None:
assert room.queue
if not room.queue.current_item.freestyle:
raise InvokeException("Current item does not allow free user styles.")
@@ -388,7 +387,6 @@ class MultiplayerHub(Hub[MultiplayerClientState]):
room: ServerMultiplayerRoom,
user: MultiplayerRoomUser,
):
assert room.queue
is_valid, valid_mods = room.queue.current_item.validate_user_mods(
user, new_mods
)
@@ -418,7 +416,6 @@ class MultiplayerHub(Hub[MultiplayerClientState]):
old: MultiplayerUserState,
new: MultiplayerUserState,
):
assert room.queue
match new:
case MultiplayerUserState.IDLE:
if old.is_playing:
@@ -515,7 +512,6 @@ class MultiplayerHub(Hub[MultiplayerClientState]):
if played_count == ready_count:
await self.start_gameplay(room)
case MultiplayerRoomState.PLAYING:
assert room.queue
if all(
u.state != MultiplayerUserState.PLAYING for u in room.room.users
):
@@ -562,7 +558,6 @@ class MultiplayerHub(Hub[MultiplayerClientState]):
await self.start_match(server_room)
async def start_match(self, room: ServerMultiplayerRoom):
assert room.queue
if room.room.state != MultiplayerRoomState.OPEN:
raise InvokeException("Can't start match when already in a running state.")
if room.queue.current_item.expired:
@@ -598,7 +593,6 @@ class MultiplayerHub(Hub[MultiplayerClientState]):
)
async def start_gameplay(self, room: ServerMultiplayerRoom):
assert room.queue
if room.room.state != MultiplayerRoomState.WAITING_FOR_LOAD:
raise InvokeException("Room is not ready for gameplay")
if room.queue.current_item.expired:
@@ -801,3 +795,69 @@ class MultiplayerHub(Hub[MultiplayerClientState]):
GameplayAbortReason.HOST_ABORTED,
)
await self.update_room_state(server_room)
async def change_user_match_state(
self, room: ServerMultiplayerRoom, user: MultiplayerRoomUser
):
await self.broadcast_group_call(
self.group_id(room.room.room_id),
"MatchUserStateChanged",
user.user_id,
user.match_state,
)
async def change_room_match_state(self, room: ServerMultiplayerRoom):
await self.broadcast_group_call(
self.group_id(room.room.room_id),
"MatchRoomStateChanged",
room.room.match_state,
)
async def ChangeSettings(self, client: Client, settings: MultiplayerRoomSettings):
store = self.get_or_create_state(client)
if store.room_id == 0:
raise InvokeException("You are not in a room")
if store.room_id not in self.rooms:
raise InvokeException("Room does not exist")
server_room = self.rooms[store.room_id]
room = server_room.room
if room.host is None or room.host.user_id != client.user_id:
raise InvokeException("You are not the host of this room")
if room.state != MultiplayerRoomState.OPEN:
raise InvokeException("Cannot change settings while playing")
if settings.match_type == MatchType.PLAYLISTS:
raise InvokeException("Invalid match type selected")
previous_settings = room.settings
room.settings = settings
if previous_settings.match_type != settings.match_type:
await server_room.set_handler()
if previous_settings.queue_mode != settings.queue_mode:
await server_room.queue.update_queue_mode()
await self.setting_changed(server_room, beatmap_changed=False)
await self.update_room_state(server_room)
async def SendMatchRequest(self, client: Client, request: MatchRequest):
store = self.get_or_create_state(client)
if store.room_id == 0:
raise InvokeException("You are not in a room")
if store.room_id not in self.rooms:
raise InvokeException("Room does not exist")
server_room = self.rooms[store.room_id]
room = server_room.room
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")
if isinstance(request, StartMatchCountdownRequest):
# TODO: countdown
...
elif isinstance(request, StopCountdownRequest):
...
else:
await server_room.match_type_handler.handle_request(user, request)