diff --git a/src/main/java/com/webgame/webgamebackend/service/impl/GameServiceImpl.java b/src/main/java/com/webgame/webgamebackend/service/impl/GameServiceImpl.java index 37f0f18..11ffe33 100644 --- a/src/main/java/com/webgame/webgamebackend/service/impl/GameServiceImpl.java +++ b/src/main/java/com/webgame/webgamebackend/service/impl/GameServiceImpl.java @@ -6,6 +6,8 @@ import com.webgame.webgamebackend.common.exception.BusinessException; import com.webgame.webgamebackend.common.exception.ErrorCode; import com.webgame.webgamebackend.entities.*; import com.webgame.webgamebackend.repository.*; +import com.webgame.webgamebackend.common.event.SseEventPublisher; +import com.webgame.webgamebackend.common.event.SseEventType; import com.webgame.webgamebackend.service.GameService; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -32,6 +34,7 @@ public class GameServiceImpl implements GameService { private final RoomPlayerRepository roomPlayerRepository; private final UserRepository userRepository; private final BCryptPasswordEncoder passwordEncoder; + private final SseEventPublisher sseEventPublisher; @Override public GameListResponse getGameList() { @@ -144,6 +147,10 @@ public class GameServiceImpl implements GameService { RoomItemResponse roomResponse = RoomItemResponse.from(room, players, gameConfig.getIcon(), creatorName); log.info("[游戏服务] 创建房间成功, roomId={}, gameId={}, creatorId={}", room.getId(), request.gameId(), creatorId); + + // 通知所有在线用户:新房间创建 + sseEventPublisher.broadcast(SseEventType.ROOM_CREATED, roomResponse); + return new CreateRoomResponse(roomResponse); } @@ -206,7 +213,11 @@ public class GameServiceImpl implements GameService { String creatorName = getNickname(room.getCreatorId()); log.info("[游戏服务] 玩家加入房间, roomId={}, userId={}", room.getId(), userId); - return RoomItemResponse.from(room, players, gameConfig.getIcon(), creatorName); + + RoomItemResponse response = RoomItemResponse.from(room, players, gameConfig.getIcon(), creatorName); + // 通知所有在线用户:房间信息更新 + sseEventPublisher.broadcast(SseEventType.ROOM_UPDATED, response); + return response; } @Override @@ -221,6 +232,7 @@ public class GameServiceImpl implements GameService { roomPlayerRepository.delete(player); + // remaining 需要在后面的 SSE 推送中用到,提取到方法级 List remaining = roomPlayerRepository.findByRoomId(roomId); if (remaining.isEmpty()) { @@ -240,6 +252,20 @@ public class GameServiceImpl implements GameService { } log.info("[游戏服务] 玩家离开房间, roomId={}, userId={}", roomId, userId); + + // 获取剩余玩家重新组装房间信息并推送事件 + if (remaining.isEmpty()) { + sseEventPublisher.broadcast(SseEventType.ROOM_REMOVED, + Map.of("roomId", roomId)); + } else { + List players = buildRoomPlayers(roomId); + GameConfigEntity gameConfig = gameConfigRepository.findByGameId(room.getGameId()) + .orElse(null); + String icon = gameConfig != null ? gameConfig.getIcon() : ""; + String creatorName = getNickname(room.getCreatorId()); + RoomItemResponse response = RoomItemResponse.from(room, players, icon, creatorName); + sseEventPublisher.broadcast(SseEventType.ROOM_UPDATED, response); + } } @Override @@ -264,6 +290,18 @@ public class GameServiceImpl implements GameService { roomPlayerRepository.delete(target); log.info("[游戏服务] 房主踢出玩家, roomId={}, targetUserId={}", roomId, targetUserId); + + // 通知被踢玩家 + sseEventPublisher.sendTo(targetUserId, SseEventType.KICKED, + Map.of("roomId", roomId)); + // 通知房间内其他玩家:房间更新 + List players = buildRoomPlayers(roomId); + GameConfigEntity gameConfig = gameConfigRepository.findByGameId(room.getGameId()) + .orElse(null); + String icon = gameConfig != null ? gameConfig.getIcon() : ""; + String creatorName = getNickname(room.getCreatorId()); + RoomItemResponse response = RoomItemResponse.from(room, players, icon, creatorName); + sseEventPublisher.broadcast(SseEventType.ROOM_UPDATED, response); } @Override @@ -284,6 +322,16 @@ public class GameServiceImpl implements GameService { roomPlayerRepository.save(player); log.info("[游戏服务] 玩家{}准备, roomId={}, userId={}", newStatus ? "" : "取消", roomId, userId); + + // 通知房间更新 + List players = buildRoomPlayers(roomId); + GameConfigEntity gameConfig = gameConfigRepository.findByGameId(room.getGameId()) + .orElse(null); + String icon = gameConfig != null ? gameConfig.getIcon() : ""; + String creatorName = getNickname(room.getCreatorId()); + RoomItemResponse response = RoomItemResponse.from(room, players, icon, creatorName); + sseEventPublisher.broadcast(SseEventType.ROOM_UPDATED, response); + return newStatus; } @@ -344,6 +392,37 @@ public class GameServiceImpl implements GameService { gameRoomRepository.save(room); log.info("[游戏服务] 游戏开始, roomId={}, 参与人数={}, 底注={}", roomId, players.size(), room.getStakes()); + + // 通知房间状态更新 + List allPlayers = buildRoomPlayers(roomId); + GameConfigEntity gameConfig = gameConfigRepository.findByGameId(room.getGameId()) + .orElse(null); + String icon = gameConfig != null ? gameConfig.getIcon() : ""; + String creatorName = getNickname(room.getCreatorId()); + RoomItemResponse response = RoomItemResponse.from(room, allPlayers, icon, creatorName); + sseEventPublisher.broadcast(SseEventType.ROOM_UPDATED, response); + + // 通知房间内每个玩家游戏已开始 + for (RoomPlayerEntity player : players) { + sseEventPublisher.sendTo(player.getUserId(), SseEventType.GAME_STARTED, + Map.of("roomId", roomId)); + } + + // 通知余额变动(房主已在前面扣除了底注) + ownerUser = userRepository.findByAccountId(ownerId).orElse(null); + if (ownerUser != null) { + sseEventPublisher.sendTo(ownerId, SseEventType.BALANCE_CHG, + Map.of("balance", ownerUser.getBalance(), "delta", -room.getStakes())); + } + for (RoomPlayerEntity player : players) { + if (!player.getUserId().equals(ownerId)) { + UserEntity user = userRepository.findByAccountId(player.getUserId()).orElse(null); + if (user != null) { + sseEventPublisher.sendTo(player.getUserId(), SseEventType.BALANCE_CHG, + Map.of("balance", user.getBalance(), "delta", -room.getStakes())); + } + } + } } // ==================== 私有辅助方法 ====================