feat: 重构游戏房间架构

This commit is contained in:
2026-06-30 11:54:21 +08:00
parent 0d61038e67
commit a5fe28e536
4 changed files with 25 additions and 7 deletions

View File

@@ -22,7 +22,7 @@ public record UserInfoResponse(
*/ */
public static UserInfoResponse from(UserEntity user) { public static UserInfoResponse from(UserEntity user) {
return new UserInfoResponse( return new UserInfoResponse(
user.getId(), user.getAccount().getId(),
user.getNickName(), user.getNickName(),
user.getAvatar(), user.getAvatar(),
user.getSignature(), user.getSignature(),

View File

@@ -34,8 +34,16 @@ public class GameRecordEntity extends UUIDBaseEntity {
@Column(name = "winner_id", length = 64) @Column(name = "winner_id", length = 64)
private String winnerId; private String winnerId;
/** 结果类型win一方获胜、draw平局、resign认输 */ /**
@Column(name = "result_type", nullable = false, length = 16) * 结果类型
* <ul>
* <li>{@code pending} — 对局进行中,尚未产生结果(游戏开始时设置)</li>
* <li>{@code win} — 一方获胜</li>
* <li>{@code draw} — 平局</li>
* <li>{@code resign} — 一方认输</li>
* </ul>
*/
@Column(name = "result_type", length = 16)
private String resultType; private String resultType;
/** 对局开始时间 */ /** 对局开始时间 */

View File

@@ -18,6 +18,7 @@ import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Scheduled; import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.socket.TextMessage; import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession; import org.springframework.web.socket.WebSocketSession;
@@ -95,6 +96,7 @@ public class RoomManager {
* @param creatorId 房主 accountId * @param creatorId 房主 accountId
* @return 创建结果 * @return 创建结果
*/ */
@Transactional
public CreateRoomResponse createRoom(CreateRoomRequest request, String creatorId) { public CreateRoomResponse createRoom(CreateRoomRequest request, String creatorId) {
// 校验游戏存在且启用 // 校验游戏存在且启用
GameConfigEntity gameConfig = gameConfigRepository.findByGameId(request.gameId()) GameConfigEntity gameConfig = gameConfigRepository.findByGameId(request.gameId())
@@ -172,6 +174,7 @@ public class RoomManager {
* @param userId 用户 accountId * @param userId 用户 accountId
* @return 房间信息 * @return 房间信息
*/ */
@Transactional
public RoomItemResponse joinRoom(JoinRoomRequest request, String userId) { public RoomItemResponse joinRoom(JoinRoomRequest request, String userId) {
GameRoomEntity room = gameRoomRepository.findById(request.roomId()) GameRoomEntity room = gameRoomRepository.findById(request.roomId())
.orElseThrow(() -> new BusinessException(ErrorCode.ROOM_NOT_FOUND)); .orElseThrow(() -> new BusinessException(ErrorCode.ROOM_NOT_FOUND));
@@ -236,6 +239,7 @@ public class RoomManager {
* @param roomId 房间 ID * @param roomId 房间 ID
* @param userId 用户 accountId * @param userId 用户 accountId
*/ */
@Transactional
public void leaveRoom(String roomId, String userId) { public void leaveRoom(String roomId, String userId) {
GameRoomEntity room = gameRoomRepository.findById(roomId) GameRoomEntity room = gameRoomRepository.findById(roomId)
.orElseThrow(() -> new BusinessException(ErrorCode.ROOM_NOT_FOUND)); .orElseThrow(() -> new BusinessException(ErrorCode.ROOM_NOT_FOUND));
@@ -286,6 +290,7 @@ public class RoomManager {
* @param roomId 房间 ID * @param roomId 房间 ID
* @param ownerId 房主 accountId * @param ownerId 房主 accountId
*/ */
@Transactional
public void disbandRoom(String roomId, String ownerId) { public void disbandRoom(String roomId, String ownerId) {
GameRoomEntity room = gameRoomRepository.findById(roomId) GameRoomEntity room = gameRoomRepository.findById(roomId)
.orElseThrow(() -> new BusinessException(ErrorCode.ROOM_NOT_FOUND)); .orElseThrow(() -> new BusinessException(ErrorCode.ROOM_NOT_FOUND));
@@ -324,6 +329,7 @@ public class RoomManager {
* @param ownerId 房主 accountId * @param ownerId 房主 accountId
* @param targetUserId 目标用户 accountId * @param targetUserId 目标用户 accountId
*/ */
@Transactional
public void kickPlayer(String roomId, String ownerId, String targetUserId) { public void kickPlayer(String roomId, String ownerId, String targetUserId) {
GameRoomEntity room = gameRoomRepository.findById(roomId) GameRoomEntity room = gameRoomRepository.findById(roomId)
.orElseThrow(() -> new BusinessException(ErrorCode.ROOM_NOT_FOUND)); .orElseThrow(() -> new BusinessException(ErrorCode.ROOM_NOT_FOUND));
@@ -366,6 +372,7 @@ public class RoomManager {
* @param userId 用户 accountId * @param userId 用户 accountId
* @return 新的准备状态 * @return 新的准备状态
*/ */
@Transactional
public boolean toggleReady(String roomId, String userId) { public boolean toggleReady(String roomId, String userId) {
GameRoomEntity room = gameRoomRepository.findById(roomId) GameRoomEntity room = gameRoomRepository.findById(roomId)
.orElseThrow(() -> new BusinessException(ErrorCode.ROOM_NOT_FOUND)); .orElseThrow(() -> new BusinessException(ErrorCode.ROOM_NOT_FOUND));
@@ -400,6 +407,7 @@ public class RoomManager {
* @param roomId 房间 ID * @param roomId 房间 ID
* @param userId 操作者 accountId必须是房主 * @param userId 操作者 accountId必须是房主
*/ */
@Transactional
public void startGame(String roomId, String userId) { public void startGame(String roomId, String userId) {
GameRoomEntity room = gameRoomRepository.findById(roomId) GameRoomEntity room = gameRoomRepository.findById(roomId)
.orElseThrow(() -> new BusinessException(ErrorCode.ROOM_NOT_FOUND)); .orElseThrow(() -> new BusinessException(ErrorCode.ROOM_NOT_FOUND));
@@ -430,9 +438,10 @@ public class RoomManager {
room.setStatus("playing"); room.setStatus("playing");
gameRoomRepository.save(room); gameRoomRepository.save(room);
// 创建游戏记录 // 创建游戏记录resultType 初始为 pending游戏结束时由 onGameOver 更新)
GameRecordEntity record = new GameRecordEntity() GameRecordEntity record = new GameRecordEntity()
.setRoomId(roomId) .setRoomId(roomId)
.setResultType("pending")
.setStartedAt(LocalDateTime.now()); .setStartedAt(LocalDateTime.now());
gameRecordRepository.save(record); gameRecordRepository.save(record);
@@ -637,6 +646,7 @@ public class RoomManager {
* @param winnerId 胜者 accountIdnull 表示平局) * @param winnerId 胜者 accountIdnull 表示平局)
* @param resultType 结果类型win/draw/resign * @param resultType 结果类型win/draw/resign
*/ */
@Transactional
public void onGameOver(String roomId, String winnerId, String resultType) { public void onGameOver(String roomId, String winnerId, String resultType) {
GameRoomEntity room = gameRoomRepository.findById(roomId).orElse(null); GameRoomEntity room = gameRoomRepository.findById(roomId).orElse(null);
if (room == null) return; if (room == null) return;

View File

@@ -133,12 +133,12 @@ public class RoomWebSocketHandler extends TextWebSocketHandler {
return; return;
} }
// 处理重连(在注册会话之前,避免广播到尚未完成握手的当前 session
roomManager.handleReconnect(roomId, userId);
// 注册会话 // 注册会话
sessionManager.addSession(roomId, userId, session); sessionManager.addSession(roomId, userId, session);
// 处理重连
roomManager.handleReconnect(roomId, userId);
log.info("[WS] 连接建立, roomId={}, userId={}, sessionId={}", roomId, userId, session.getId()); log.info("[WS] 连接建立, roomId={}, userId={}, sessionId={}", roomId, userId, session.getId());
} }