feat(multiplayer): supoort abort match

This commit is contained in:
MingxuanGame
2025-08-03 14:00:49 +00:00
parent c2579e86eb
commit 1e304542bd
2 changed files with 68 additions and 0 deletions

View File

@@ -4,6 +4,7 @@ import asyncio
from collections.abc import Awaitable, Callable from collections.abc import Awaitable, Callable
from dataclasses import dataclass, field from dataclasses import dataclass, field
from datetime import UTC, datetime, timedelta from datetime import UTC, datetime, timedelta
from enum import IntEnum
from typing import TYPE_CHECKING, Annotated, Any, ClassVar, Literal from typing import TYPE_CHECKING, Annotated, Any, ClassVar, Literal
from app.database.beatmap import Beatmap from app.database.beatmap import Beatmap
@@ -587,3 +588,8 @@ class CountdownStoppedEvent(_MatchServerEvent):
MatchServerEvent = CountdownStartedEvent | CountdownStoppedEvent MatchServerEvent = CountdownStartedEvent | CountdownStoppedEvent
class GameplayAbortReason(IntEnum):
LOAD_TOOK_TOO_LONG = 0
HOST_ABORTED = 1

View File

@@ -14,6 +14,7 @@ from app.models.mods import APIMod
from app.models.multiplayer_hub import ( from app.models.multiplayer_hub import (
BeatmapAvailability, BeatmapAvailability,
ForceGameplayStartCountdown, ForceGameplayStartCountdown,
GameplayAbortReason,
MatchServerEvent, MatchServerEvent,
MultiplayerClientState, MultiplayerClientState,
MultiplayerQueue, MultiplayerQueue,
@@ -615,6 +616,13 @@ class MultiplayerHub(Hub[MultiplayerClientState]):
playing = True playing = True
await self.change_user_state(room, user, MultiplayerUserState.PLAYING) await self.change_user_state(room, user, MultiplayerUserState.PLAYING)
await self.call_noblock(client, "GameplayStarted") await self.call_noblock(client, "GameplayStarted")
elif user.state == MultiplayerUserState.WAITING_FOR_LOAD:
await self.change_user_state(room, user, MultiplayerUserState.IDLE)
await self.broadcast_group_call(
self.group_id(room.room.room_id),
"GameplayAborted",
GameplayAbortReason.LOAD_TOOK_TOO_LONG,
)
await self.change_room_state( await self.change_room_state(
room, room,
(MultiplayerRoomState.PLAYING if playing else MultiplayerRoomState.OPEN), (MultiplayerRoomState.PLAYING if playing else MultiplayerRoomState.OPEN),
@@ -739,3 +747,57 @@ class MultiplayerHub(Hub[MultiplayerClientState]):
if new_host is None: if new_host is None:
raise InvokeException("User not found in this room") raise InvokeException("User not found in this room")
await self.set_host(server_room, new_host) await self.set_host(server_room, new_host)
async def AbortGameplay(self, client: Client):
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 not user.state.is_playing:
raise InvokeException("Cannot abort gameplay while not in a gameplay state")
await self.change_user_state(
server_room,
user,
MultiplayerUserState.IDLE,
)
await self.update_room_state(server_room)
async def AbortMatch(self, client: Client):
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.PLAYING
or room.state == MultiplayerRoomState.WAITING_FOR_LOAD
):
raise InvokeException("Room is not in a playable state")
await asyncio.gather(
*[
self.change_user_state(server_room, u, MultiplayerUserState.IDLE)
for u in room.users
if u.state.is_playing
]
)
await self.broadcast_group_call(
self.group_id(room.room_id),
"GameplayAborted",
GameplayAbortReason.HOST_ABORTED,
)
await self.update_room_state(server_room)