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 dataclasses import dataclass, field
from datetime import UTC, datetime, timedelta
from enum import IntEnum
from typing import TYPE_CHECKING, Annotated, Any, ClassVar, Literal
from app.database.beatmap import Beatmap
@@ -587,3 +588,8 @@ class CountdownStoppedEvent(_MatchServerEvent):
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 (
BeatmapAvailability,
ForceGameplayStartCountdown,
GameplayAbortReason,
MatchServerEvent,
MultiplayerClientState,
MultiplayerQueue,
@@ -615,6 +616,13 @@ class MultiplayerHub(Hub[MultiplayerClientState]):
playing = True
await self.change_user_state(room, user, MultiplayerUserState.PLAYING)
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(
room,
(MultiplayerRoomState.PLAYING if playing else MultiplayerRoomState.OPEN),
@@ -739,3 +747,57 @@ class MultiplayerHub(Hub[MultiplayerClientState]):
if new_host is None:
raise InvokeException("User not found in this room")
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)