From 79637a3c821181f08de35deef014218c8f8aa232 Mon Sep 17 00:00:00 2001 From: zhouwei <849588297@qq.com> Date: Fri, 6 Mar 2026 11:54:52 +0800 Subject: [PATCH] =?UTF-8?q?1.=E4=BF=AE=E5=A4=8D=E7=BA=A2=E4=B8=AD=E6=9C=BA?= =?UTF-8?q?=E5=99=A8=E4=BA=BA=E5=8A=A0=E5=85=A5=E6=88=BF=E9=97=B4=E4=B8=8D?= =?UTF-8?q?=E5=87=86=E5=A4=87=E9=97=AE=E9=A2=98=202.=E4=BF=AE=E5=A4=8D?= =?UTF-8?q?=E4=B8=A4=E7=9C=9F=E4=BA=BA=E7=8E=A9=E5=AE=B6=E4=BC=9A=E5=AF=BC?= =?UTF-8?q?=E8=87=B4=E7=BA=BF=E7=A8=8B=E5=8D=A0=E7=94=A8=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/robot/mj/Config.java | 5 +- .../main/java/robot/mj/EXGameController.java | 389 +++++++++++++----- .../java/robot/mj/RobotConnectionManager.java | 42 +- .../java/robot/mj/handler/HuNanHongZhong.java | 60 +-- 4 files changed, 354 insertions(+), 142 deletions(-) diff --git a/robots/majiang/robot_mj_hz/src/main/java/robot/mj/Config.java b/robots/majiang/robot_mj_hz/src/main/java/robot/mj/Config.java index 964c55c..684ded3 100644 --- a/robots/majiang/robot_mj_hz/src/main/java/robot/mj/Config.java +++ b/robots/majiang/robot_mj_hz/src/main/java/robot/mj/Config.java @@ -34,6 +34,9 @@ public class Config { //==================== 游戏服务器配置 ==================== /** 游戏服务器主机地址 */ + /*public static final String GAME_SERVER_HOST = "8.134.76.43"; + public static final String DEFAULT_GROUP_ID = "762479";*/ + public static final String DEFAULT_GROUP_ID = "426149"; public static final String GAME_SERVER_HOST = "127.0.0.1"; /** 游戏服务器端口 */ @@ -45,7 +48,5 @@ public class Config { /** 默认PID */ public static final String DEFAULT_PID = "22"; - /** 默认群组ID */ - public static final String DEFAULT_GROUP_ID = "330800"; } \ No newline at end of file diff --git a/robots/majiang/robot_mj_hz/src/main/java/robot/mj/EXGameController.java b/robots/majiang/robot_mj_hz/src/main/java/robot/mj/EXGameController.java index 8de058a..2af2725 100644 --- a/robots/majiang/robot_mj_hz/src/main/java/robot/mj/EXGameController.java +++ b/robots/majiang/robot_mj_hz/src/main/java/robot/mj/EXGameController.java @@ -7,9 +7,8 @@ import com.taurus.core.entity.ITObject; import com.taurus.core.entity.TObject; import com.taurus.core.plugin.redis.Redis; import com.taurus.core.routes.ActionKey; +import com.taurus.core.util.Logger; import com.taurus.permanent.data.Session; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import redis.clients.jedis.Jedis; import robot.mj.info.RobotUser; import robot.mj.thread.ThreadPoolConfig; @@ -31,7 +30,7 @@ import static robot.mj.thread.ThreadPoolConfig.scheduleDelay; * 红中麻将游戏控制器 - 处理游戏协议 */ public class EXGameController extends GameController { - private static final Logger log = LoggerFactory.getLogger(EXGameController.class); + private static final Logger log = Logger.getLogger(EXGameController.class); private static final RobotConnectionManager robotConnectionManager = new RobotConnectionManager(); @@ -238,61 +237,60 @@ public class EXGameController extends GameController { int robotId = params.getInt("robotid"); String roomId = params.getString("roomid"); int groupId = params.getInt("groupid"); - - //检查机器人是否已经在房间中 - RobotUser existingUser = getRobotRoomInfo(String.valueOf(robotId)); - if (existingUser != null && existingUser.getCurrentRoomId() > 0) { - String existingConnecId = existingUser.getCurrentRoomId() + "_" + robotId; - log.warn("机器人{}已在房间{}中,connecId: {}", robotId, existingUser.getCurrentRoomId(), existingConnecId); - - //检查现有连接状态 - TaurusClient existingClient = existingUser.getClient(); - if (existingClient == null || !existingClient.isConnected()) { - log.warn("现有连接不健康,准备清理并重新加入"); - robotConnectionManager.disconnectFromGameServer(existingConnecId); + + String lockKey = "room_lock:" + roomId; + synchronized (lockKey.intern()) { + if (checkRobotInRoomRedis(roomId, String.valueOf(robotId))) { + log.info("机器人{"+robotId+"}已在房间{"+roomId+"}中(Redis 中存在),直接允许加入"); } else { - log.info("现有连接健康,跳过重复加入"); - //返回成功响应 - ITObject response = TObject.newInstance(); - response.putString("status", "success"); - response.putString("message", "机器人已在房间中"); - MainServer.instance.sendResponse(gid, 0, response, session); - return; - } - } - - //检查Redis中该房间是否真的包含当前机器人 - if (!checkRobotInRoomRedis(roomId, String.valueOf(robotId))) { - //Redis中不存在该机器人 清理本地可能的错误映射 - List robotUsers = getRobotUsersByRoomId(Integer.parseInt(roomId)); - if (!robotUsers.isEmpty()) { - synchronized (robotUsers) { - RobotUser robotUser = robotUsers.get(0); - log.error("房间{}中Redis未找到机器人{},但本地映射存在{}", roomId, robotId, robotId); - robotRoomMapping.remove(robotUser.getConnecId()); - robotRoomMapping.remove(robotUser.getRobotId()); - } - } - } else { - //Redis中存在该机器人 检查是否是不同机器人的冲突 - List robotUsers = getRobotUsersByRoomId(Integer.parseInt(roomId)); - if (!robotUsers.isEmpty()) { - synchronized (robotUsers) { - RobotUser robotUser = robotUsers.get(0); - int existingRobotId = Integer.parseInt(robotUser.getRobotId()); - - if (robotId != existingRobotId) { - //不同机器人的冲突 - log.error("房间{}中Redis已存在机器人{},当前机器人{}不执行加入逻辑", roomId, existingRobotId, robotId); + RobotUser existingRobotUser = getRobotRoomInfo(String.valueOf(robotId)); + if (existingRobotUser != null && existingRobotUser.getCurrentRoomId() == Integer.parseInt(roomId)) { + log.info("机器人{"+robotId+"}已在房间{"+roomId+"}中(本地映射存在),直接允许加入"); + } else { + if (isPlayerIdConflictInRoom(roomId, robotId)) { + log.warn("检测到机器人{"+robotId+"}与房间{"+roomId+"}中的真人玩家 ID 冲突,拒绝加入"); + ITObject errorResponse = TObject.newInstance(); + errorResponse.putString("status", "failed"); + errorResponse.putString("message", "机器人 ID 与房间内玩家冲突"); + MainServer.instance.sendResponse(gid, 1, errorResponse, session); return; } } } + + //检查Redis中该房间是否真的包含当前机器人 + if (!checkRobotInRoomRedis(roomId, String.valueOf(robotId))) { + //Redis中不存在该机器人 清理本地可能的错误映射 + List robotUsers = getRobotUsersByRoomId(Integer.parseInt(roomId)); + if (!robotUsers.isEmpty()) { + synchronized (robotUsers) { + RobotUser robotUser = robotUsers.get(0); + log.warn("房间{"+roomId+"}中Redis未找到机器人{"+robotId+"},但本地映射存在{"+robotUser.getRobotId()+"},清理本地映射"); + robotRoomMapping.remove(robotUser.getConnecId()); + robotRoomMapping.remove(robotUser.getRobotId()); + } + } + } else { + //Redis中存在该机器人 检查是否是不同机器人的冲突 + List robotUsers = getRobotUsersByRoomId(Integer.parseInt(roomId)); + if (!robotUsers.isEmpty()) { + synchronized (robotUsers) { + RobotUser robotUser = robotUsers.get(0); + int existingRobotId = Integer.parseInt(robotUser.getRobotId()); + + if (robotId != existingRobotId) { + //不同机器人的冲突 + log.warn("房间{"+roomId+"}中Redis已存在机器人{"+existingRobotId+"},当前机器人{"+robotId+"}不执行加入逻辑"); + return; + } + } + } + } + log.info("225 开始进房间:room:{"+roomId+"} robot:{"+robotId+"}"); + //加入房间 + joinRoomCommon(robotId, roomId, groupId, params); + log.info("225 已进入房间准备成功:room:{"+roomId+"} robot:{"+robotId+"}"); } - log.info("225开始进房间: room:{} robot:{}", roomId, robotId); - //加入房间 - joinRoomCommon(robotId, roomId, groupId, params); - log.info("225已进入房间准备成功: room:{} robot:{}", roomId, robotId); } /** @@ -302,10 +300,10 @@ public class EXGameController extends GameController { public void webGroupActive(Session session, ITObject params, int gid) { int robotId = params.getInt("robotid"); String roomId = params.getString("roomid"); - log.info("226开始进房间 room: {} robot: {}", roomId, robotId); + log.info("226开始进房间 room: {"+roomId+"} robot:{"+robotId+"}"); //加入房间 joinRoomCommon(params.getInt("robotid"), params.getString("roomid"), params.getInt("groupid"), params); - log.info("226已进入房间准备成功: room:{} robot:{}", roomId, robotId); + log.info("226已进入房间准备成功 room: {"+roomId+"} robot:{"+robotId+"}"); } /** @@ -332,12 +330,12 @@ public class EXGameController extends GameController { return; } - log.info("重启后开始进房间: room:{}robot:{}", robotUser.getCurrentRoomId(), robotUser.getRobotId()); + log.info("重启后开始进房间: room:{"+robotUser.getCurrentRoomId()+"}robot:{"+robotUser.getRobotId()+"}"); ITObject params = new TObject(); params.putString("session", "{user}:" + robotUser.getRobotId() + "," + robotSession); //加入房间 joinRoomCommon(Integer.parseInt(robotUser.getRobotId()), String.valueOf(robotUser.getCurrentRoomId()), Integer.parseInt(robotUser.getRobotGroupid()), params); - log.info("重启后已进入房间准备成功: room:{} robot:{}", robotUser.getCurrentRoomId(), robotUser.getRobotId()); + log.info("重启后已进入房间准备成功: room:{"+robotUser.getCurrentRoomId()+"}robot:{"+robotUser.getRobotId()+"}"); } catch (Exception e) { log.error("重启后进房间时发生错误", e); } finally { @@ -354,22 +352,22 @@ public class EXGameController extends GameController { Jedis jedis2 = Redis.use("group1_db2").getJedis(); try { Set robotTokens = jedis0.smembers("{user}:" + robotId + "_token"); - String robotSession = null; + String robotSession = robotTokens.stream().filter(jedis0::exists).findFirst().orElse(null); - for (String token : robotTokens) { - if (jedis0.exists(token)) { - robotSession = token; - break; - } - } - - log.info("开始进房间: room:{}robot:{}", roomId, robotId); - log.info("开始进房间: {user}:{}", robotId); + log.info("开始进房间:room:{"+roomId+"}"); + log.info("开始进房间:{user}:{"+robotId+"}"); + //建立 TCP 连接 TaurusClient client = getCsMjGameServerConnection(roomId + "_" + robotId); - GroupRoomBusiness.joinRoom(groupId, "room:" + roomId, "{user}:" + robotId, null); - - //机器人房间映射关系 + if (client == null) { + log.error("机器人{"+robotId+"}连接游戏服务器失败,connecId:{"+roomId + "_" + robotId+"}"); + return; + } + + ITObject joinResult = GroupRoomBusiness.joinRoom(groupId, "room:" + roomId, "{user}:" + robotId, null); + log.info("GroupRoomBusiness.joinRoom 结果:robotId:{"+robotId+"}, roomId:{"+roomId+"}, result:{"+joinResult+"}"); + + log.info("机器人{"+robotId+"}准备发送 JOIN_ROOM_CS(1002) 协议"); RobotUser robotUser = getRobotRoomInfo(String.valueOf(robotId)); String connecId = roomId + "_" + robotId; if (robotUser.getCurrentRoomId() == 0) { @@ -377,56 +375,158 @@ public class EXGameController extends GameController { robotUser.setClient(client); robotUser.setConnecId(connecId); } + //先不放入映射 等确认加入成功后再放入 - //robotRoomMapping.put(robotUser.getConnecId(), robotUser); robotRoomMapping.remove(robotUser.getRobotId()); - //非阻塞延迟替代Thread.sleep - scheduleDelay(() -> { - - }, 2, TimeUnit.SECONDS); + params.putString("session", "{user}:" + robotId + "," + robotSession); - - //发送加入房间请求到game_mj_cs + + //发送 JOIN_ROOM_CS(1002) 到 game_mj_cs client.send(Config.JOIN_ROOM_CS, params, response -> { - //成功响应后才建立映射关系 - robotRoomMapping.put(robotUser.getConnecId(), robotUser); - robotConnectionManager.reconnectToGameServer(response, robotUser, client); + try { + log.info("JOIN_ROOM_CS(1002) 响应:{"+response+"}"); + + // 检查响应是否成功 + if (response == null || response.messageData == null || response.messageData.param == null) { + log.error("机器人{"+robotId+"}加入房间{"+roomId+"}失败:game_mj_cs 返回 null"); + cleanupFailedRobot(robotUser, connecId, roomId); + return; + } + + ITObject responseParam = response.messageData.param; + int responseCode = responseParam.containsKey("code") ? responseParam.getInt("code") : 0; + if (responseCode != 0) { + log.error("机器人{"+robotId+"}加入房间{"+roomId+"}失败:game_mj_cs 返回错误码{"+responseCode+"}, response:{"+response+"}"); + cleanupFailedRobot(robotUser, connecId, roomId); + return; + } + + //1002 响应成功后,添加短暂延迟等待服务器将机器人加入 Redis + scheduleDelay(() -> { + try { + //验证机器人是否真的进入了房间(检查 Redis) + if (!checkRobotInRoomRedis(roomId, String.valueOf(robotId))) { + log.error("机器人{"+robotId+"}加入房间{"+roomId+"}失败:1002 响应成功但 Redis 中未找到机器人,清理资源"); + cleanupFailedRobot(robotUser, connecId, roomId); + return; + } + + log.info("机器人{"+robotId+"}Redis 验证成功,建立映射关系"); + + //成功响应后才建立映射关系 + synchronized (robotRoomMapping) { + robotRoomMapping.put(robotUser.getConnecId(), robotUser); + } + + log.info("机器人{"+robotId+"}已成功加入房间{"+roomId+"},建立映射关系"); + + //发送准备协议 + scheduleDelay(() -> { + try { + if (client != null && client.isConnected()) { + client.send(Config.GAME_READY_CS, params, readyResponse -> { + try { + log.info("GAME_READY 响应:{"+readyResponse+"}"); + + //设置准备状态 + robotUser.setStatus(ROBOTEventType.ROBOT_INTOROOM_READY); + robotConnectionManager.setSessionAndToken("{user}:" + robotId, robotSession, robotUser.getConnecId()); + + //标记机器人为可用状态 + jedis2.hset("gallrobot", String.valueOf(robotUser.getRobotId()), "1"); + robotUser.setIntoRoomTime(robotConnectionManager.getTime()); + + log.info("机器人{"+robotId+"}准备成功,房间:{"+roomId+"}"); + } catch (Exception e) { + log.error("机器人{"+robotId+"}设置准备状态失败"+ e); + cleanupFailedRobot(robotUser, connecId, roomId); + } + }); + } + } catch (Exception e) { + log.error("机器人{"+robotId+"}发送准备协议失败"+ e); + cleanupFailedRobot(robotUser, connecId, roomId); + } + }, 1000, TimeUnit.MILLISECONDS); + } catch (Exception e) { + log.error("机器人{"+robotId+"}Redis 验证失败"+ e); + cleanupFailedRobot(robotUser, connecId, roomId); + } + }, 500, TimeUnit.MILLISECONDS); + + } catch (Exception e) { + log.error("处理 JOIN_ROOM_CS 响应时发生异常", e); + cleanupFailedRobot(robotUser, connecId, roomId); + } }); - log.info("已进入房间成功: {}", connecId); - Thread.sleep(1000); - if (client.isConnected()) { - client.send(Config.GAME_READY_CS, params, response -> { - log.info("1003: {}", response); - }); - jedis2.hset("gallrobot", String.valueOf(robotUser.getRobotId()), "1"); - robotUser.setStatus(ROBOTEventType.ROBOT_INTOROOM_READY); - robotConnectionManager.setSessionAndToken("{user}:" + robotId, robotSession, robotUser.getConnecId()); - } - //添加超时检查机制 + log.info("已进入房间成功:{"+robotUser.getConnecId()+"}"); + + /*//添加超时检查机制(15 秒) CompletableFuture.runAsync(() -> { try { - //定时任务替代Thread.sleep + //定时任务替代 Thread.sleep scheduleDelay(() -> { - //15秒后还没有建立映射关系 加入可能失败 - if (robotRoomMapping.get(robotUser.getConnecId()) == null) { - log.info("机器人{{}}加入房间{{}}超时,清理临时状态", robotId, roomId); - robotConnectionManager.disconnectFromGameServer(connecId); + //15 秒后还没有建立映射关系或状态不是准备状态,说明加入失败 + RobotUser currentUser = robotRoomMapping.get(connecId); + if (currentUser == null || currentUser.getStatus() != ROBOTEventType.ROBOT_INTOROOM_READY) { + log.warn("机器人{}加入房间{}超时(15 秒),清理临时状态", robotId, roomId); + cleanupFailedRobot(robotUser, connecId, roomId); } }, 15, TimeUnit.SECONDS); } catch (Exception e) { - log.error("机器人加入房间超时", e); + log.error("机器人{}加入房间超时检查异常", robotId, e); } - }, ThreadPoolConfig.getBusinessThreadPool());//指定自定义线程池 - robotUser.setIntoRoomTime(robotConnectionManager.getTime()); - log.info("已进入房间成功: {}", robotUser.getConnecId()); + }, ThreadPoolConfig.getBusinessThreadPool());*/ + log.info("已进入房间准备成功:{"+robotUser.getConnecId()+"}"); } catch (Exception e) { - log.error("机器人加入房间失败", e); + log.error("加入房间时发生错误", e); + //发生异常时清理资源 + String failedConnecId = roomId + "_" + robotId; + cleanupFailedRobot(null, failedConnecId, roomId); } finally { jedis0.close(); jedis2.close(); } } + + /** + * 清理加入失败的机器人资源 + */ + private void cleanupFailedRobot(RobotUser robotUser, String connecId, String roomId) { + try { + String robotId = robotUser != null ? robotUser.getRobotId() : "unknown"; + log.info("开始清理失败机器人资源:robotId:{"+robotId+"}, connecId:{"+connecId+"}, roomId:{"+roomId+"}"); + + // 清理映射关系 + if (robotUser != null) { + robotRoomMapping.remove(robotUser.getConnecId()); + robotRoomMapping.remove(robotUser.getRobotId()); + } else { + robotRoomMapping.remove(connecId); + if (connecId != null && connecId.contains("_")) { + String[] parts = connecId.split("_"); + if (parts.length >= 2) { + robotRoomMapping.remove(parts[1]); + } + } + } + + // 断开 TCP 连接 + TaurusClient client = robotUser != null ? robotUser.getClient() : null; + if (client != null && client.isConnected()) { + client.killConnection(); + log.info("已清理失败机器人{"+robotId+"}的 TCP 连接"); + } + + // 通知连接管理器清理资源 + robotConnectionManager.disconnectFromGameServer(connecId); + + log.info("完成失败机器人资源的清理:connecId:{"+connecId+"}, roomId:{"+roomId+"}"); + } catch (Exception e) { + log.error("清理失败机器人资源时发生异常", e); + } + } /** * 根据机器人ID获取其所在的房间信息 @@ -474,7 +574,7 @@ public class EXGameController extends GameController { lastAccessTime.remove(removedUser.getConnecId()); } - log.info("已删除机器人房间信息: {}", robotId); + log.info("已删除机器人房间信息: {"+robotId+"}"); } /** @@ -500,7 +600,7 @@ public class EXGameController extends GameController { for (String connecId : expiredConnections) { RobotUser robotUser = robotRoomMapping.get(connecId); if (robotUser != null) { - log.info("清理超时连接{}已超时,, 机器人ID: {}", connecId, robotUser.getRobotId()); + log.info("清理超时连接{"+connecId+"}已超时,, 机器人ID: {"+robotUser.getRobotId()+"}"); robotConnectionManager.disconnectFromGameServer(connecId); } robotRoomMapping.remove(connecId); @@ -508,7 +608,7 @@ public class EXGameController extends GameController { } if (!expiredConnections.isEmpty()) { - log.info("本次清理了 {} 个超时连接", expiredConnections.size()); + log.info("本次清理了 {"+expiredConnections.size()+"} 个超时连接"); } } @@ -518,9 +618,9 @@ public class EXGameController extends GameController { */ public static TaurusClient getCsMjGameServerConnection(String connecId) { TaurusClient taurusClient = robotConnectionManager.getGameClient(connecId); - log.info("根据机器人ID和连接ID获取红中麻将游戏服务器连接 connecId: {}", connecId); + log.info("根据机器人ID和连接ID获取红中麻将游戏服务器连接 connecId: {"+connecId+"}"); if (taurusClient != null) { - log.info("成功获取游戏服务器连接,connecId: {}", connecId); + log.info("成功获取游戏服务器连接,connecId: {"+connecId+"}"); return taurusClient; } taurusClient = robotConnectionManager.connectToGameServer(connecId); @@ -555,11 +655,88 @@ public class EXGameController extends GameController { } return false; } catch (Exception e) { - log.error("检查Redis房间玩家信息时发生错误,roomId: {}, robotId: {}", roomId, robotId, e); + log.error("检查Redis房间玩家信息时发生错误,roomId: {"+roomId+"}, robotId: {"+robotId+"}"+ e); return false; } finally { jedis.close(); } } + /** + * 检查机器人 ID 是否与房间内已有玩家冲突 + */ + private boolean isPlayerIdConflictInRoom(String roomId, int robotId) { + Jedis jedis = Redis.use().getJedis(); + Jedis jedis2 = Redis.use("group1_db2").getJedis(); + try { + //查询该房间的玩家信息 + String playersStr = jedis.hget("room:" + roomId, "players"); + if (playersStr == null || playersStr.equals("[]")) { + log.info("房间{"+roomId+"}为空,机器人{"+robotId+"}可以加入"); + return false; + } + + String players = playersStr.substring(1, playersStr.length() - 1); + String[] playerIds = players.split(","); + + //统计房间中的真人数量和机器人数量 + int realPlayerCount = 0; + int robotCount = 0; + boolean hasSameRobot = false; + + for (String playerIdStr : playerIds) { + try { + int playerId = Integer.parseInt(playerIdStr.trim()); + + String robotData = jedis2.hget("{robot}:" + playerId, "password"); + boolean isRobot = (robotData != null); + + if (isRobot) { + robotCount++; + //检查是否是相同的机器人 ID + if (playerId == robotId) { + hasSameRobot = true; + } + } else { + realPlayerCount++; + } + } catch (NumberFormatException e) { + log.error("解析玩家 ID 失败:"+playerIdStr); + } + } + + if (hasSameRobot) { + log.info("房间{"+roomId+"}中已有相同机器人{"+robotId+"},允许重复加入"); + return false; + } + + if (realPlayerCount >= 2) { + log.warn("房间{"+roomId+"}中已有{"+realPlayerCount+"}个真人玩家,拒绝机器人{"+robotId+"}加入"); + return true; + } + + if (realPlayerCount == 1) { + if (robotCount == 0) { + log.info("房间{"+roomId+"}中有 1 个真人玩家,允许第一个机器人{"+robotId+"}加入陪打"); + return false; + } + log.info("房间{"+roomId+"}中已有 1 个真人 +1 个机器人,拒绝额外机器人{"+robotId+"}"); + return true; + } + + if (robotCount >= 2) { + log.warn("房间{"+roomId+"}中已有{"+robotCount+"}个机器人,不再添加新机器人{"+robotId+"}"); + return true; + } + + log.info("房间{"+roomId+"}当前状态:真人{"+realPlayerCount+"}人,机器人{"+robotCount+"}个,允许机器人{"+robotId+"}加入"); + return false; + } catch (Exception e) { + log.error("检查房间人数时发生异常,roomId:{"+roomId+"}, robotId:{"+robotId+"}" + e); + return false; + } finally { + jedis.close(); + jedis2.close(); + } + } } \ No newline at end of file diff --git a/robots/majiang/robot_mj_hz/src/main/java/robot/mj/RobotConnectionManager.java b/robots/majiang/robot_mj_hz/src/main/java/robot/mj/RobotConnectionManager.java index a1cb25c..dac1d3b 100644 --- a/robots/majiang/robot_mj_hz/src/main/java/robot/mj/RobotConnectionManager.java +++ b/robots/majiang/robot_mj_hz/src/main/java/robot/mj/RobotConnectionManager.java @@ -32,8 +32,8 @@ import static robot.mj.thread.ThreadPoolConfig.scheduleDelay; */ public class RobotConnectionManager { - private final Map huNanHongZhongInstances = new ConcurrentHashMap<>(); private static final Logger log = LoggerFactory.getLogger(RobotConnectionManager.class); + private static final Map huNanHongZhongInstances = new ConcurrentHashMap<>(); //记录活跃连接 用于资源清理判断 private static final Set activeConnections = ConcurrentHashMap.newKeySet(); @@ -41,7 +41,7 @@ public class RobotConnectionManager { //记录连接创建时间 private static final Map connectionCreationTime = new ConcurrentHashMap<>(); - //连接最大生存时间(5分钟) + //连接最大生存时间(5 分钟) private static final long MAX_CONNECTION_LIFETIME = 5 * 60 * 1000; private final EXGameController exGameController; @@ -97,9 +97,13 @@ public class RobotConnectionManager { */ public TaurusClient connectToGameServer(String connecId) { try { - //创建Taurus客户端 - TaurusClient client = new TaurusClient(host + ":" + port, "game", TaurusClient.ConnectionProtocol.Tcp); + int index = connecId.lastIndexOf("_"); + String robotId = connecId.substring(index + 1); + String clientId = "robot_" + connecId; + //创建Taurus客户端 + TaurusClient client = new TaurusClient(host + ":" + port, clientId, TaurusClient.ConnectionProtocol.Tcp); + //设置事件监听器 setupEventListeners(client, connecId); @@ -240,8 +244,16 @@ public class RobotConnectionManager { */ public void reconnectToGameServer(MessageResponse response, RobotUser robotUser, TaurusClient client) { String connecId = robotUser.getCurrentRoomId()+"_"+robotUser.getRobotId(); + //先设置机器人状态为准备状态 + robotUser.setStatus(ROBOTEventType.ROBOT_INTOROOM_READY); + if(client.isConnected()){ try { + log.info(String.valueOf(response.messageData.param)); + if (response.messageData.param==null) { + log.info("警告:reconnectToGameServer 重连时未获取到参数"); + return; + } ITObject obj = response.messageData.param.getTObject("tableInfo"); ITObject reloadInfo = response.messageData.param.getTObject("reloadInfo"); if (obj != null) { @@ -323,12 +335,22 @@ public class RobotConnectionManager { try { currentInstance.outCard(client); log.info("断线重连后成功执行出牌操作"); + //出牌成功后,根据是否有手牌判断状态 + if (hcard.size() > 0) { + robotUser.setStatus(ROBOTEventType.ROBOT_INTOROOM_WORKING); + } } catch (Exception e) { log.error("断线重连后执行出牌操作时发生异常", e); - //即使出牌失败,也要确保连接状态正确 + //出牌失败,保持在准备状态或设置为工作状态 try { if (robotUser != null) { - robotUser.setStatus(ROBOTEventType.ROBOT_INTOROOM_READY); + //如果有手牌,说明还在游戏中,设置为工作状态 + if (hcard.size() > 0) { + robotUser.setStatus(ROBOTEventType.ROBOT_INTOROOM_WORKING); + } else { + //无手牌,保持在准备状态 + robotUser.setStatus(ROBOTEventType.ROBOT_INTOROOM_READY); + } } } catch (Exception statusEx) { log.error("更新机器人状态时发生异常", statusEx); @@ -443,11 +465,12 @@ public class RobotConnectionManager { //玩家加入房间 else if ("2001".equalsIgnoreCase(command)) { scheduleDelay(() -> { + Jedis jedis = Redis.use().getJedis(); try { String roomKey = String.valueOf(robotUser.getCurrentRoomId()); //查询该房间的玩家信息 - String playersStr = jedis0.hget("room:"+roomKey, "players"); + String playersStr = jedis.hget("room:"+roomKey, "players"); if (!playersStr.equals("[]")) { String players = playersStr.substring(1, playersStr.length() - 1); String[] playerIds = players.split(","); @@ -471,6 +494,11 @@ public class RobotConnectionManager { } } catch (Exception e) { log.error("处理玩家加入房间检查时发生异常", e); + } finally { + //确保Jedis连接关闭 + if (jedis != null) { + jedis.close(); + } } }, 6, TimeUnit.SECONDS); log.info("玩家{"+ robotUser.getCurrentRoomId()+"}加入房间:"+ param); diff --git a/robots/majiang/robot_mj_hz/src/main/java/robot/mj/handler/HuNanHongZhong.java b/robots/majiang/robot_mj_hz/src/main/java/robot/mj/handler/HuNanHongZhong.java index 0b39e48..924276d 100644 --- a/robots/majiang/robot_mj_hz/src/main/java/robot/mj/handler/HuNanHongZhong.java +++ b/robots/majiang/robot_mj_hz/src/main/java/robot/mj/handler/HuNanHongZhong.java @@ -23,8 +23,6 @@ import static robot.mj.thread.ThreadPoolConfig.getBusinessThreadPool; public class HuNanHongZhong { private static final Logger log = LoggerFactory.getLogger(HuNanHongZhong.class); - public int hongZhongCard = 0; - //红中麻将手牌 private final List hongZhongCardInhand = new ArrayList<>(); @@ -32,13 +30,16 @@ public class HuNanHongZhong { private final List hongZhongchuguopai = new ArrayList<>(); // 玩家座位号 - public int seat = 0; + private int seat = 0; - public int playerId = 0; + private int playerId = 0; - // 会话标识 + // 当前出的牌 + private int hongZhongCard = 0; + + // 会话标识 - 改为实例变量 public String session = ""; - // 访问令牌 + // 访问令牌 - 改为实例变量 public String token = ""; private static HongZhongSuanFaTest hongZhongSuanFaTest = new HongZhongSuanFaTest(); @@ -53,29 +54,41 @@ public class HuNanHongZhong { public List getChuGuoCardInhand() { return hongZhongchuguopai; } - + public int getSeat() { return seat; } - + public void setSeat(int seat) { this.seat = seat; } - + public int getPlayerId() { return playerId; } - + public void setPlayerId(int playerId) { this.playerId = playerId; } - - public int getHongZhongCard() { - return hongZhongCard; + + public String getSession() { + return session; + } + + public void setSession(String session) { + this.session = session; } - public void setHongZhongCard(int hongZhongCard) { - this.hongZhongCard = hongZhongCard; + public String getToken() { + return token; + } + + public void setToken(String token) { + this.token = token; + } + + public HongZhongSuanFaTest getHongZhongSuanFaTest() { + return hongZhongSuanFaTest; } @@ -199,9 +212,8 @@ public class HuNanHongZhong { if (param == null) { return null; } - //使用实例变量 - setHongZhongCard(param.getInt("card")); - log.info("出牌广播:{}", getHongZhongCard()); + hongZhongCard = param.getInt("card"); + log.info("出牌广播: {}", hongZhongCard); log.info("座位号:{}的用户出牌:{}", param.getInt("seat"), param.getInt("card")); } return null; @@ -291,16 +303,11 @@ public class HuNanHongZhong { for (int i = 0; i < cardList.size(); i++) { hongZhongCardInhand.add(cardList.getInt(i)); } - //设置座位号 - setSeat(param.getInt("seat")); - setPlayerId(param.getInt("player")); - if (hongZhongCardInhand.size() > 13) { outCard(client); - log.info("机器人:{}为庄家,需要出牌, 牌为:{}", param.getInt("seat"), hongZhongCardInhand.get(0)); + log.info("机器人:{}为庄家,需要出牌,牌为:{}", param.getInt("seat"), hongZhongCardInhand.get(0)); } - log.info("机器人:{}初始化手牌, 牌为:{}", param.getInt("seat"), hongZhongCardInhand.toString()); - + log.info("机器人:{}初始化手牌,牌为:{}", param.getInt("seat"), hongZhongCardInhand.toString()); } return null; } @@ -419,7 +426,7 @@ public class HuNanHongZhong { hongZhongSuanFaTest.separateAndAnalyzeHand(hongZhongCardInhand); // 红中麻将出牌 - String hongzhongOutCard = hongZhongSuanFaTest.outCardSuanFa(hongZhongCardInhand, getHongZhongCard()); + String hongzhongOutCard = hongZhongSuanFaTest.outCardSuanFa(hongZhongCardInhand, hongZhongCard); // String hongzhongOutCard = hongZhongSuanFaTest.outCardSuanFa(list, hongZhongCard); ITObject params = TObject.newInstance(); int cardToOut; @@ -484,7 +491,6 @@ public class HuNanHongZhong { log.debug("删除出过的牌组 card: {}", card); log.debug("删除出过的牌组 type: {}", type); log.debug("删除出过的牌组 from_seat: {}", from_seat); - log.debug("机器人 seat: {}", getSeat()); if (type == 2 || type == 3 || type == 5) { // 碰,杠 getChuGuoCardInhand().remove(Integer.valueOf(card));