From 1c5d453fb63464f0b057137b93798ad604cfe515 Mon Sep 17 00:00:00 2001 From: zhouwei <849588297@qq.com> Date: Thu, 5 Feb 2026 06:23:44 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=8C=E5=96=84TCP=E5=A4=9A=E8=BF=9E?= =?UTF-8?q?=E6=8E=A5=E7=9A=84=E5=90=8C=E6=AD=A5=E6=89=93=E7=89=8C=E5=8A=9F?= =?UTF-8?q?=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/robot/mj/EXGameController.java | 80 +++- .../src/main/java/robot/mj/EXMainServer.java | 14 +- .../java/robot/mj/RobotConnectionManager.java | 438 +++++++++++------- .../java/robot/mj/handler/HuNanChangSha.java | 169 ++++++- .../src/main/java/taurus/util/TinHuChi.java | 2 +- 5 files changed, 502 insertions(+), 201 deletions(-) diff --git a/robots/majiang/robot_mj_cs/src/main/java/robot/mj/EXGameController.java b/robots/majiang/robot_mj_cs/src/main/java/robot/mj/EXGameController.java index e8b2e16..88ad717 100644 --- a/robots/majiang/robot_mj_cs/src/main/java/robot/mj/EXGameController.java +++ b/robots/majiang/robot_mj_cs/src/main/java/robot/mj/EXGameController.java @@ -26,7 +26,7 @@ import java.util.concurrent.ConcurrentHashMap; public class EXGameController extends GameController { private static final Logger log = LoggerFactory.getLogger(EXGameController.class); - private static RobotConnectionManager robotConnectionManager = new RobotConnectionManager(); + private static final RobotConnectionManager robotConnectionManager = new RobotConnectionManager(); //机器人房间 protected static final Map robotRoomMapping = new ConcurrentHashMap<>(); @@ -131,12 +131,13 @@ public class EXGameController extends GameController { //设置session和token String sessionToken = params.getString("session"); String robotSession = null; + String token = null; if (sessionToken != null && sessionToken.contains(",")) { String[] sessionParts = sessionToken.split(","); if (sessionParts.length >= 2) { robotSession = sessionParts[0]; - String token = sessionParts[1]; - robotConnectionManager.setSessionAndToken(robotSession, token); + token = sessionParts[1]; + robotConnectionManager.setSessionAndToken(robotSession, token, connecId); } } @@ -218,7 +219,7 @@ public class EXGameController extends GameController { int robotId = params.getInt("robotid"); String roomId = params.getString("roomid"); int groupId = params.getInt("groupid"); - try (Jedis jedis0 = Redis.use("group1_db0").getJedis()){ + try (Jedis jedis0 = Redis.use("group1_db0").getJedis();Jedis jedis2 = Redis.use("group1_db2").getJedis()){ Set robotTokens = jedis0.smembers("{user}:"+robotId+"_token"); String robotSession = null; @@ -239,10 +240,13 @@ public class EXGameController extends GameController { //机器人房间映射关系 RobotUser robotUser = getRobotRoomInfo(String.valueOf(robotId)); - if (robotUser.getRoomId() == null) { + if (robotUser.getCurrentRoomId() == 0) { robotUser.setCurrentRoomId(Integer.parseInt(roomId)); robotUser.setClient(client); + robotUser.setConnecId(roomId+ "_"+ robotId); } + robotRoomMapping.put(robotUser.getConnecId(), robotUser); + robotRoomMapping.remove(robotUser.getRobotId()); System.out.println(roomId); System.out.println(Integer.parseInt(roomId)); System.out.println(robotUser.getCurrentRoomId()); @@ -259,6 +263,66 @@ public class EXGameController extends GameController { client.send(Config.GAME_READY_CS, params, response -> { System.out.println("1003:"+response); }); + jedis2.hset("gallrobot", String.valueOf(robotUser.getRobotId()), "1"); + + robotUser.setStatus(ROBOTEventType.ROBOT_INTOROOM_READY); + robotConnectionManager.setSessionAndToken("{user}:"+robotId, robotSession, robotUser.getConnecId()); + } + robotUser.setIntoRoomTime(robotConnectionManager.getTime()); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + public void webGroupJoinRoom(RobotUser robotUser) { + String connecId = robotUser.getConnecId(); + TaurusClient client = getCsMjGameServerConnection(connecId); + try (Jedis jedis0 = Redis.use("group1_db0").getJedis();Jedis jedis2 = Redis.use("group1_db2").getJedis()){ + Set robotTokens = jedis0.smembers("{user}:"+robotUser.getRobotId()+"_token"); + String robotSession = null; + + for (String token : robotTokens) { + if (jedis0.exists(token)) { + robotSession = token; + break; + } + } + String gallrobot = jedis2.hget("gallrobot", robotUser.getRobotId()); + if (gallrobot.equals("0")) { + robotRoomMapping.remove(connecId); + return; + } + System.out.println("重连进房间: "+robotUser.getRobotId()); + System.out.println("重连进房间: "+robotUser.getCurrentRoomId()); + System.out.println("重连进房间: "+"room:"+ robotUser.getCurrentRoomId()); + System.out.println("重连进房间: "+"{user}:"+robotUser.getRobotId()); + GroupRoomBusiness.joinRoom(Integer.parseInt(robotUser.getRobotGroupid()), "room:"+ robotUser.getCurrentRoomId(), "{user}:"+robotUser.getRobotId(), null); + + //机器人房间映射关系 + if (robotUser.getRoomId() == null) { + robotUser.setCurrentRoomId(robotUser.getCurrentRoomId()); + robotUser.setClient(client); + } + robotRoomMapping.put(robotUser.getConnecId(), robotUser); + robotRoomMapping.remove(robotUser.getRobotId()); + + Thread.sleep(2000); + ITObject params = new TObject(); + params.putString("session","{user}:"+robotUser.getRobotId()+ "," + robotSession); + //发送加入房间请求到game_mj_cs + client.send(Config.JOIN_ROOM_CS, params, response -> { + System.out.println("joinRoomController: " + response); + robotConnectionManager.reconnectToGameServer(response, robotUser, client); + }); + + Thread.sleep(1000); + if(client.isConnected()){ + client.send(Config.GAME_READY_CS, params, response -> { + System.out.println("1003:"+response); + }); + + jedis2.hset("gallrobot", String.valueOf(robotUser.getRobotId()), "1"); + robotUser.setStatus(ROBOTEventType.ROBOT_INTOROOM_READY); } robotUser.setIntoRoomTime(robotConnectionManager.getTime()); @@ -272,11 +336,11 @@ public class EXGameController extends GameController { */ public static RobotUser getRobotRoomInfo(String robotId) { RobotUser robotUser = robotRoomMapping.get(robotId); - if (robotUser ==null && robotUser.getRoomId() == null) { + if (robotUser ==null) { RobotUser robotUserCopy = new RobotUser(); robotUserCopy.setRobotId(robotId); robotUserCopy.setPassword("123456"); - robotUserCopy.setGameHost("8.138.242.190"); + robotUserCopy.setGameHost("8.134.76.43"); robotUserCopy.setGamePort("6311"); robotUserCopy.setRobotGroupid("330800"); robotUserCopy.setRobotPid("10"); @@ -299,7 +363,7 @@ public class EXGameController extends GameController { public static TaurusClient getCsMjGameServerConnection(String connecId) { TaurusClient taurusClient = robotConnectionManager.getGameClient(connecId); System.out.println("根据机器人ID和连接ID获取长沙麻将游戏服务器连接 client: = "+taurusClient); - if (taurusClient != null && taurusClient.isConnected()) { + if (taurusClient != null) { log.debug("成功获取游戏服务器连接,connecId: {}", connecId); return taurusClient; } diff --git a/robots/majiang/robot_mj_cs/src/main/java/robot/mj/EXMainServer.java b/robots/majiang/robot_mj_cs/src/main/java/robot/mj/EXMainServer.java index 1c832e1..d3a2ed2 100644 --- a/robots/majiang/robot_mj_cs/src/main/java/robot/mj/EXMainServer.java +++ b/robots/majiang/robot_mj_cs/src/main/java/robot/mj/EXMainServer.java @@ -42,8 +42,8 @@ public class EXMainServer extends MainServer{ // 2. 启动连接检查定时任务 //startConnectionCheckScheduler(); //测试 - /*Jedis jedis2 = Redis.use("group1_db2").getJedis(); - String robotskey = "g{"+330800+"}:play:"+10; + Jedis jedis2 = Redis.use("group1_db2").getJedis(); + String robotskey = "g{"+762479+"}:play:"+10; Map maprobot = jedis2.hgetAll(robotskey); for(Map.Entry entry : maprobot.entrySet()) { System.out.println(entry.getKey() + ":" + entry.getValue()); @@ -51,9 +51,9 @@ public class EXMainServer extends MainServer{ RobotUser robotUser = new RobotUser(); robotUser.setRobotId(entry.getKey()); robotUser.setPassword("123456"); - robotUser.setGameHost("8.138.242.190"); + robotUser.setGameHost("8.134.76.43"); robotUser.setGamePort("6311"); - robotUser.setRobotGroupid("330800"); + robotUser.setRobotGroupid("762479"); robotUser.setRobotPid("10"); robotRoomMapping.put(entry.getKey(), robotUser); @@ -70,7 +70,7 @@ public class EXMainServer extends MainServer{ if(!robotUser.isLogin){ robotConnectionManager.login(robotUser); } - //2、链接 + /*//2、链接 //判断是否链接 System.out.println("robotUser.isconnect"+robotUser.getIsconnect()); if(!robotUser.getIsconnect()){ @@ -95,11 +95,11 @@ public class EXMainServer extends MainServer{ if(robotUser.getIntoRoomTime()+6<=robotConnectionManager.getTime()){ //5、退出房间 robotConnectionManager.outoRoom(robotUser); - } + }*/ } } - }, 0, 5 ,TimeUnit.SECONDS);*/ + }, 0, 5 ,TimeUnit.SECONDS); //5、干活 log.info("长沙麻将机器人服务器已启动"); log.info("服务器将监听端口 {} 用于接收robot_mgr管理协议", gameSetting.port); diff --git a/robots/majiang/robot_mj_cs/src/main/java/robot/mj/RobotConnectionManager.java b/robots/majiang/robot_mj_cs/src/main/java/robot/mj/RobotConnectionManager.java index 019a2d7..ad5632b 100644 --- a/robots/majiang/robot_mj_cs/src/main/java/robot/mj/RobotConnectionManager.java +++ b/robots/majiang/robot_mj_cs/src/main/java/robot/mj/RobotConnectionManager.java @@ -18,33 +18,51 @@ import taurus.client.TaurusClient; import taurus.client.SocketCode; import redis.clients.jedis.Jedis; import robot.mj.handler.HuNanChangSha; -import taurus.util.ChangShaSuanFaTest; import taurus.util.ROBOTEventType; -import taurus.util.TinHuChi; import java.util.*; import java.util.concurrent.*; +import static robot.mj.EXGameController.robotRoomMapping; + /** * 机器人连接管理器 - 管理与游戏服务器的连接 */ public class RobotConnectionManager { private Logger log = Logger.getLogger(RobotConnectionManager.class); - private Map gameClients; - //存储全局的长沙麻将AI处理器 - private HuNanChangSha huNanChangSha; - private EXGameController exGameController; + private static final Map huNanChangShaInstances = new ConcurrentHashMap<>(); + private final EXGameController exGameController; - private final String host="8.138.242.190"; + private final String host="8.134.76.43"; private final int port=6311; /*长沙麻将游戏算法相关 start*/ - private Map> playerOutcardsMap = new HashMap<>(); - private Map> playerchisMap = new HashMap<>(); - private Map> playerpengsMap = new HashMap<>(); - private Map> playermingsMap = new HashMap<>(); - private Map> playerzisMap = new HashMap<>(); + private final Map>> playerOutcardsMapByConn = new ConcurrentHashMap<>(); + private final Map>> playerchisMapByConn = new ConcurrentHashMap<>(); + private final Map>> playerpengsMapByConn = new ConcurrentHashMap<>(); + private final Map>> playermingsMapByConn = new ConcurrentHashMap<>(); + private final Map>> playerzisMapByConn = new ConcurrentHashMap<>(); + + private Map> getPlayerOutcardsMap(String connecId) { + return playerOutcardsMapByConn.computeIfAbsent(connecId, k -> new ConcurrentHashMap<>()); + } + + private Map> getPlayerchisMap(String connecId) { + return playerchisMapByConn.computeIfAbsent(connecId, k -> new ConcurrentHashMap<>()); + } + + private Map> getPlayerpengsMap(String connecId) { + return playerpengsMapByConn.computeIfAbsent(connecId, k -> new ConcurrentHashMap<>()); + } + + private Map> getPlayermingsMap(String connecId) { + return playermingsMapByConn.computeIfAbsent(connecId, k -> new ConcurrentHashMap<>()); + } + + private Map> getPlayerzisMap(String connecId) { + return playerzisMapByConn.computeIfAbsent(connecId, k -> new ConcurrentHashMap<>()); + } private int groupId = 0; private int pid = 0; private int playerId = 0; @@ -56,17 +74,40 @@ public class RobotConnectionManager { public RobotConnectionManager() { - gameClients = new HashMap<>(); - huNanChangSha = new HuNanChangSha(); exGameController = new EXGameController(); } + /** + * 获取长沙麻将处理器实例 + */ + private HuNanChangSha getHuNanChangShaInstance(String connecId) { + HuNanChangSha existingInstance = huNanChangShaInstances.get(connecId); + if (existingInstance != null) { + return existingInstance; + } + + HuNanChangSha newInstance = new HuNanChangSha(); + + //从Redis恢复状态 + boolean restored = newInstance.restoreFromRedis(connecId); + if (restored) { + System.out.println("从Redis恢复HuNanChangSha实例: " + connecId); + } else { + System.out.println("创建新的HuNanChangSha实例: " + connecId); + } + + huNanChangShaInstances.put(connecId, newInstance); + System.out.println("当前HuNanChangSha实例总数: " + huNanChangShaInstances.size()); + return newInstance; + } + /** * 设置会话和令牌 */ - public void setSessionAndToken(String session, String token) { - huNanChangSha.session = session; - huNanChangSha.token = token; + public void setSessionAndToken(String session, String token, String connecId) { + HuNanChangSha instance = getHuNanChangShaInstance(connecId); + instance.session = session; + instance.token = token; } /** @@ -74,15 +115,6 @@ public class RobotConnectionManager { */ public TaurusClient connectToGameServer(String connecId) { try { - //检查是否已经连接 - if (gameClients.containsKey(connecId)) { - TaurusClient existingClient = gameClients.get(connecId); - if (existingClient.isConnected()) { - return existingClient; - } - //todo: 断线重连 - } - //创建Taurus客户端 TaurusClient client = new TaurusClient(host + ":" + port, "game", TaurusClient.ConnectionProtocol.Tcp); @@ -91,8 +123,6 @@ public class RobotConnectionManager { client.connect(); - gameClients.put(connecId, client); - return client; } catch (Exception e) { log.error("连接到游戏服务器时发生异常", e); @@ -105,33 +135,60 @@ public class RobotConnectionManager { */ public void disconnectFromGameServer(String connecId) { System.out.println("开始主动断开连接: {"+connecId+"}"); + RobotUser robotUser = robotRoomMapping.remove(connecId); - TaurusClient client = gameClients.remove(connecId); - if (client != null) { - try { - if (client.isConnected()) { - client.killConnection(); - } - System.out.println("客户端主动断开连接完成: {"+connecId+"}"); - } catch (Exception e) { - System.out.println("断开客户端连接时发生异常: " + connecId + ", 错误: " + e.getMessage()); + //清理连接数据 + if (connecId != null) { + HuNanChangSha.removeFromRedis(connecId); + + HuNanChangSha instance = huNanChangShaInstances.get(connecId); + if (instance != null) { + instance.getChangShaCardInhand().clear(); + instance.getChuGuoCardInhand().clear(); + instance.getgangdepai().clear(); + instance.getpongGroup().clear(); + instance.getchowGroup().clear(); + instance.getchangShaCardInhandgang().clear(); + instance.getChuGuoPainum().clear(); + System.out.println("清空HuNanChangSha集合数据: " + connecId); + } + + huNanChangShaInstances.remove(connecId); + playerOutcardsMapByConn.remove(connecId); + playerchisMapByConn.remove(connecId); + playerpengsMapByConn.remove(connecId); + playermingsMapByConn.remove(connecId); + playerzisMapByConn.remove(connecId); + } + + if (robotUser != null) { + TaurusClient client = robotUser.getClient(); + if (client != null) { + try { + if (client.isConnected()) { + client.killConnection(); + } + System.out.println("客户端主动断开连接完成: {"+connecId+"}"); + } catch (Exception e) { + System.out.println("断开客户端连接时发生异常: " + connecId + ", 错误: " + e.getMessage()); + } + } else { + System.out.println("客户端连接不存在: {"+connecId+"}"); } - } else { - System.out.println("客户端连接不存在: {"+connecId+"}"); } } /** - * 增加leftover_robot数量 机器人退出空房间的情况 + * 增加leftover_robot数量 机器人退出房间 */ - private void updateLeftoverRobot(String groupId, String wanfaId, int robotId) { - try (Jedis jedis11 = Redis.use("group1_db11").getJedis();Jedis jedis2 = Redis.use("group1_db2").getJedis()) { - String playKey = "g{" + groupId + "}:play:" + wanfaId; - jedis11.hincrBy(playKey, "leftover_robot", 1); + private void updateLeftoverRobot(int robotId) { + try (Jedis jedis2 = Redis.use("group1_db2").getJedis()) { + + jedis2.hset("gallrobot", String.valueOf(robotId), "0"); jedis2.hset("{grobot}:" + robotId, "start", "0"); - System.out.println("机器人 {"+robotId+"} 退出空房间,增加leftover_robot,群组={"+groupId+"}, 玩法={"+wanfaId+"}"); + System.out.println("机器人 {"+robotId+"} 退出房间,修改gallrobot为0"); } } @@ -180,6 +237,7 @@ public class RobotConnectionManager { * 机器人断线重连 */ public void reconnectToGameServer(MessageResponse response, RobotUser robotUser, TaurusClient client) { + String connecId = robotUser.getCurrentRoomId()+"_"+robotUser.getRobotId(); if(client.isConnected()){ ITObject obj = response.messageData.param.getTObject("tableInfo"); ITObject reloadInfo = response.messageData.param.getTObject("reloadInfo"); @@ -224,21 +282,41 @@ public class RobotConnectionManager { } } - + System.out.println("hcard>0"+hcard); if(hcard.size()>0){ //同步手牌 - huNanChangSha.updateHandCard(hcard); + HuNanChangSha currentInstance = getHuNanChangShaInstance(connecId); + + //检查Redis恢复的数据 避免覆盖 + if (currentInstance.getChangShaCardInhand().isEmpty()) { + //手牌集合为空 需要同步数据 + currentInstance.updateHandCard(hcard); + System.out.println("断线重连:同步手牌数据"); + } if(outcard_list.size()>0){ List outcards = new ArrayList<>(); for (int i = 0; i < outcard_list.size(); i++) { outcards.add(outcard_list.getInt(i)); } - huNanChangSha.updateOutCard(outcards); + + //检查出牌记录是否需要同步 + if (currentInstance.getChuGuoCardInhand().isEmpty()) { + currentInstance.updateOutCard(outcards); + System.out.println("断线重连:同步出牌数据"); + } } sleepTime(2000); - huNanChangSha.outCard(client,playerOutcardsMap, playerchisMap, playerpengsMap, playermingsMap, playerzisMap); + Map> currentPlayerOutcardsMap = getPlayerOutcardsMap(connecId); + Map> currentPlayerchisMap = getPlayerchisMap(connecId); + Map> currentPlayerpengsMap = getPlayerpengsMap(connecId); + Map> currentPlayermingsMap = getPlayermingsMap(connecId); + Map> currentPlayerzisMap = getPlayerzisMap(connecId); + + currentInstance.outCard(client, currentPlayerOutcardsMap, currentPlayerchisMap, currentPlayerpengsMap, currentPlayermingsMap, currentPlayerzisMap); + } else { + System.err.println("警告:重连时未获取到手牌数据"); } } } @@ -252,11 +330,10 @@ public class RobotConnectionManager { * 处理接收到的游戏协议 */ private void handleProtocol(String command, Message message, TaurusClient client, String connecId) { - String[] robotIds= connecId.split("_", 2); - int robotId = Integer.parseInt(robotIds[0]); - RobotUser robotUser = EXGameController.getRobotRoomInfo(String.valueOf(robotId)); - + RobotUser robotUser = robotRoomMapping.get(connecId); + int robotId = Integer.parseInt(robotUser.getRobotId()); ITObject param = message.param; + HuNanChangSha huNanChangSha = getHuNanChangShaInstance(connecId); try (Jedis jedis0 = Redis.use().getJedis();Jedis jedis2 = Redis.use("group1_db2").getJedis();){ //长沙麻将 机器人处理事件 @@ -281,6 +358,9 @@ public class RobotConnectionManager { } } huNanChangSha.cardInHead(command, message, client); + //处理完协议后保存到Redis + HuNanChangSha currentInstance = huNanChangShaInstances.get(connecId); + currentInstance.saveToRedis(connecId); } //出牌广播 else if ("812".equalsIgnoreCase(command)) { @@ -291,12 +371,19 @@ public class RobotConnectionManager { ITArray opmingcards = param.getTArray("opmingcards"); ITArray opzicards = param.getTArray("opzicards"); + // 获取当前连接专用的Maps + Map> currentPlayerOutcardsMap = getPlayerOutcardsMap(connecId); + Map> currentPlayerchisMap = getPlayerchisMap(connecId); + Map> currentPlayerpengsMap = getPlayerpengsMap(connecId); + Map> currentPlayermingsMap = getPlayermingsMap(connecId); + Map> currentPlayerzisMap = getPlayerzisMap(connecId); + // 清空旧数据,用新数据完全覆盖 - playerOutcardsMap.clear(); - playerchisMap.clear(); - playerpengsMap.clear(); - playermingsMap.clear(); - playerzisMap.clear(); + currentPlayerOutcardsMap.clear(); + currentPlayerchisMap.clear(); + currentPlayerpengsMap.clear(); + currentPlayermingsMap.clear(); + currentPlayerzisMap.clear(); //出过的牌 if (outcard_map != null) { for (int i = 0; i < outcard_map.size(); i++) { @@ -310,8 +397,8 @@ public class RobotConnectionManager { outcardsList.add(outcardsArray.getInt(j)); } - // 存储到Map中(覆盖旧数据) - playerOutcardsMap.put(playerId, outcardsList); + // 存储到当前连接的Map中(覆盖旧数据) + currentPlayerOutcardsMap.put(playerId, outcardsList); } } @@ -327,7 +414,7 @@ public class RobotConnectionManager { for (int j = 0; j < outchiArray.size(); j++) { outchiList.add(outchiArray.getInt(j)); } - playerchisMap.put(playerId, outchiList); + currentPlayerchisMap.put(playerId, outchiList); } } @@ -342,7 +429,7 @@ public class RobotConnectionManager { for (int j = 0; j < outpengArray.size(); j++) { outpengList.add(outpengArray.getInt(j)); } - playerpengsMap.put(playerId, outpengList); + currentPlayerpengsMap.put(playerId, outpengList); } } @@ -357,7 +444,7 @@ public class RobotConnectionManager { for (int j = 0; j < outmingArray.size(); j++) { outmingList.add(outmingArray.getInt(j)); } - playermingsMap.put(playerId, outmingList); + currentPlayermingsMap.put(playerId, outmingList); } } @@ -372,102 +459,107 @@ public class RobotConnectionManager { for (int j = 0; j < outziArray.size(); j++) { outziList.add(outziArray.getInt(j)); } - playerzisMap.put(playerId, outziList); + currentPlayerzisMap.put(playerId, outziList); } } - HuNanChangSha.drawCard(command, message); + huNanChangSha.drawCard(command, message); + //处理完协议后保存到Redis + HuNanChangSha currentInstance = huNanChangShaInstances.get(connecId); + currentInstance.saveToRedis(connecId); } //摸牌 else if ("819".equalsIgnoreCase(command)) { huNanChangSha.getCard(command, message, client); + //处理完协议后保存到Redis + HuNanChangSha currentInstance = huNanChangShaInstances.get(connecId); + currentInstance.saveToRedis(connecId); } //出牌提示 else if ("813".equalsIgnoreCase(command)) { - huNanChangSha.outCard(client,playerOutcardsMap,playerchisMap,playerpengsMap,playermingsMap,playerzisMap); + // 获取当前连接专用的Maps + Map> currentPlayerOutcardsMap = getPlayerOutcardsMap(connecId); + Map> currentPlayerchisMap = getPlayerchisMap(connecId); + Map> currentPlayerpengsMap = getPlayerpengsMap(connecId); + Map> currentPlayermingsMap = getPlayermingsMap(connecId); + Map> currentPlayerzisMap = getPlayerzisMap(connecId); + + huNanChangSha.outCard(client, currentPlayerOutcardsMap, currentPlayerchisMap, currentPlayerpengsMap, currentPlayermingsMap, currentPlayerzisMap); + //处理完协议后保存到Redis + HuNanChangSha currentInstance = huNanChangShaInstances.get(connecId); + currentInstance.saveToRedis(connecId); } //放招提示 else if ("814".equalsIgnoreCase(command)) { huNanChangSha.actionCard(param, client); + //处理完协议后保存到Redis + HuNanChangSha currentInstance = huNanChangShaInstances.get(connecId); + currentInstance.saveToRedis(connecId); } //2026.02.03修改 玩家加入房间 else if ("2001".equalsIgnoreCase(command)) { - Integer userId = param.getInt("aid"); - robotUser.setUserId(userId); - System.out.println("玩家{"+ robotUser.getRoomId()+"}加入房间:"+ param); - } - //2026.02.03修改 玩家退出房间也要检查 - /*else if ("2002".equalsIgnoreCase(command)) { CompletableFuture.runAsync(() -> { - Integer userId = param.getInt("aid"); sleepTime(6000); - if (userId.equals(robotUser.getUserId())) { - String roomKey = robotUser.getRoomId(); + String roomKey = String.valueOf(robotUser.getCurrentRoomId()); - //查询该房间的玩家信息 - String playersStr = jedis0.hget(roomKey, "players"); - if (!playersStr.equals("[]")) { - String players = playersStr.substring(1, playersStr.length() - 1); - String[] playerIds = players.split(","); + //查询该房间的玩家信息 + String playersStr = jedis0.hget("room:"+roomKey, "players"); + if (!playersStr.equals("[]")) { + String players = playersStr.substring(1, playersStr.length() - 1); + String[] playerIds = players.split(","); - //判断只有当前机器人一个玩家 - if (playerIds.length == 1) { - int playerId = Integer.parseInt(playerIds[0].trim()); - if (playerId == robotId) { - - String gpid = jedis0.hget(roomKey, "gpid"); - String gpId = jedis0.hget(roomKey, "group"); + //判断只有当前机器人一个玩家 + if (playerIds.length == 1) { + int playerId = Integer.parseInt(playerIds[0].trim()); + if (playerId == robotId) { + //发送退出房间协议 + ITObject params = TObject.newInstance(); + client.send("1005", params, response -> { + EXGameController.removeRobotRoomInfo(String.valueOf(robotId)); //更新机器人剩余数量 - if (count != null && count.containsKey(Integer.parseInt(gpid))) { - Integer currentValue = count.get(Integer.parseInt(gpid)); - if (currentValue > 0) { - count.put(Integer.parseInt(gpid), currentValue - 1); - } - } - - //发送退出房间协议 - ITObject params = TObject.newInstance(); - client.send("1005", params, response -> { - EXGameController.removeRobotRoomInfo(String.valueOf(robotId)); - //更新机器人剩余数量 - updateLeftoverRobot(gpId, gpid, robotId); - System.out.println("2002发送退出房间协议1005,robotId: {"+robotId+"}"); - }); - } + updateLeftoverRobot(robotId); + disconnectFromGameServer(connecId); + System.out.println("2002发送退出房间协议1005,robotId: {"+robotId+"}"); + }); } } } }); - }*/ - else if("2002".equalsIgnoreCase(command)) { - System.out.println("comds:2002"); + System.out.println("玩家{"+ robotUser.getCurrentRoomId()+"}加入房间:"+ param); + } + //2026.02.03修改 玩家退出房间也要检查 + else if ("2002".equalsIgnoreCase(command)) { + CompletableFuture.runAsync(() -> { + sleepTime(6000); - ITObject params = TObject.newInstance(); - String aid = client.getGameID(); + String roomKey = String.valueOf(robotUser.getCurrentRoomId()); - String getKey = "{robortInfo}:" + aid; - Jedis jedis20 = Redis.use("group1_db2").getJedis(); + //查询该房间的玩家信息 + String playersStr = jedis0.hget("room:"+roomKey, "players"); + if (!playersStr.equals("[]")) { + String players = playersStr.substring(1, playersStr.length() - 1); + String[] playerIds = players.split(","); - String circleId1 = jedis20.hget(getKey, "circleId"); - String pid = jedis20.hget(getKey, "pid"); + //判断只有当前机器人一个玩家 + if (playerIds.length == 1) { + int playerId = Integer.parseInt(playerIds[0].trim()); + if (playerId == robotId) { - String key = "g{" + circleId1 + "}:play:" + pid; - - client.send("1005", params, response -> { - log.info("退出状态1---------"+response); - log.info("退出状态1getKey---------"+getKey); - log.info("退出状态1key---------"+key); - log.info("退出状态1aid---------"+aid); - jedis20.hset(getKey, "circleId", "0"); - jedis20.hset(getKey, "pid", "0"); - jedis20.hset(getKey, "room_id", "0"); - //退出修改机器人状态 - jedis20.hset(key,aid, "0"); + //发送退出房间协议 + ITObject params = TObject.newInstance(); + client.send("1005", params, response -> { + EXGameController.removeRobotRoomInfo(String.valueOf(robotId)); + //更新机器人剩余数量 + updateLeftoverRobot(robotId); + disconnectFromGameServer(connecId); + System.out.println("2002发送退出房间协议1005,robotId: {"+robotId+"}"); + }); + } + } + } }); - jedis20.close(); - } //2026.02.03修改 玩家解散房间 else if ("2005".equalsIgnoreCase(command)) { @@ -490,7 +582,7 @@ public class RobotConnectionManager { } EXGameController.removeRobotRoomInfo(String.valueOf(robotId)); //更新机器人剩余数量 - updateLeftoverRobot(gpId, gpid, robotId); + updateLeftoverRobot(robotId); disconnectFromGameServer(connecId); System.out.println("2005玩家发送解散房间协议,robotId: {"+robotId+"}"); } @@ -499,18 +591,9 @@ public class RobotConnectionManager { } //2026.02.03修改 解散房间时候恢复机器人账号可以使用 else if ("2008".equalsIgnoreCase(command)) { - String roomKey = robotUser.getRoomId(); - if (jedis0.exists(roomKey)) { - String gpid = jedis0.hget(roomKey, "gpid"); - String gpId = jedis0.hget(roomKey, "group"); - EXGameController.removeRobotRoomInfo(String.valueOf(robotId)); - //更新机器人剩余数量 - updateLeftoverRobot(gpId, gpid, robotId); - disconnectFromGameServer(connecId); - jedis0.del(roomKey); - System.out.println("2008结束房间,robotId: {"+robotId+"}"); - } + updateLeftoverRobot(Integer.parseInt(robotUser.getRobotId())); + disconnectFromGameServer(connecId); } //2026.02.03修改 通过机器人房间映射直接获取房间信息 else if ("2009".equalsIgnoreCase(command)) { @@ -550,7 +633,7 @@ public class RobotConnectionManager { //断开连接 disconnectFromGameServer(connecId); //更新机器人剩余数量 - updateLeftoverRobot(gpId, gpid, paramRobotId); + updateLeftoverRobot(paramRobotId); System.out.println("2009发送退出房间协议1005,robotId: {"+paramRobotId+"}"); }); } @@ -561,16 +644,14 @@ public class RobotConnectionManager { } //结算 else if ("817".equalsIgnoreCase(command)) { + //清空所有HuNanChangSha相关的集合数据 huNanChangSha.getChangShaCardInhand().clear(); huNanChangSha.getChuGuoCardInhand().clear(); + huNanChangSha.getgangdepai().clear(); huNanChangSha.getpongGroup().clear(); huNanChangSha.getchowGroup().clear(); - TinHuChi.lastTingCount = 0; - TinHuChi.isMoreThanLast = false; - ChangShaSuanFaTest.isTin=false; - ChangShaSuanFaTest.isChi=false; - ChangShaSuanFaTest.isPeng=false; - ChangShaSuanFaTest.tinCards.clear(); + huNanChangSha.getchangShaCardInhandgang().clear(); + huNanChangSha.getChuGuoPainum().clear(); Integer type = param.getInt("type"); if (type == 1 || type == 2) { //为1为大结算 为2为解散 Jedis jedis11s = Redis.use("group1_db11").getJedis(); @@ -640,10 +721,16 @@ public class RobotConnectionManager { else if ("815".equalsIgnoreCase(command)) { //[TCP->815] data:{"playerid":101555,"card":104,"opcard":[105,103],"from_seat":2,"type":1,"opengang":false} huNanChangSha.shanchuchuguopai(param); + //处理完协议后保存到Redis + HuNanChangSha currentInstance = huNanChangShaInstances.get(connecId); + currentInstance.saveToRedis(connecId); } //换牌提示 else if ("820".equalsIgnoreCase(command)) { huNanChangSha.changePlayer(command, message); + //处理完协议后保存到Redis + HuNanChangSha currentInstance = huNanChangShaInstances.get(connecId); + currentInstance.saveToRedis(connecId); } else if ("825".equalsIgnoreCase(command)) { ITObject params = TObject.newInstance(); @@ -703,31 +790,29 @@ public class RobotConnectionManager { if(object==null){ object = accountBusiness.idPasswordLogin(Integer.parseInt(robotUser.getRobotId()), robotUser.getPassword()); } - if (object != null) { - //判断是否有房间 - if(object.getTObject("account")!=null){ - ITObject validate = TObject.newInstance(); - validate.putString("token", object.getString("token")); - robotUser.setToken(object.getString("token"));; - robotUser.setLoginsession("{user}:"+robotUser.getRobotId()); - if (robotUser.getLoginsession() != null) { - robotUser.setIsLogin(true); - } - if(object.getTObject("account").get("roomid")!=null){ - String roomid = object.getTObject("account").get("roomid").toString(); - robotUser.setCurrentRoomId(Integer.parseInt(roomid)); - connectGame(robotUser); + ITObject finalObject = object; + CompletableFuture.runAsync(() -> { + if (finalObject != null) { + //判断是否有房间 + if(finalObject.getTObject("account")!=null){ + ITObject validate = TObject.newInstance(); + validate.putString("token", finalObject.getString("token")); + robotUser.setToken(finalObject.getString("token"));; + robotUser.setLoginsession("{user}:"+robotUser.getRobotId()); + if (robotUser.getLoginsession() != null) { + robotUser.setIsLogin(true); + } + if(finalObject.getTObject("account").get("roomid")!=null){ + String roomid = finalObject.getTObject("account").get("roomid").toString(); + robotUser.setCurrentRoomId(Integer.parseInt(roomid)); + connectGame(robotUser); - ITObject params = new TObject(); - params.putString("connecId", robotUser.getRoomId()+"_"+robotUser.getRobotId()); - params.putString("roomId", robotUser.getRoomId()); - params.putString("groupId", robotUser.getRobotGroupid()); - params.putString("session", "{user}:"+robotUser.getRobotId()); - exGameController.joinRoom(null, params, robotUser.getClient().getId()); + robotUser.setConnecId(robotUser.getCurrentRoomId()+"_"+robotUser.getRobotId()); + exGameController.webGroupJoinRoom(robotUser); + } } } - } - + }); } catch (Exception e) { throw new RuntimeException(e); } @@ -736,12 +821,18 @@ public class RobotConnectionManager { public void connectGame(RobotUser robotUser){ if(robotUser.isLogin){ if(robotUser.getClient()==null){ - TaurusClient client = new TaurusClient (robotUser.getGameHost()+":"+robotUser.getGamePort(), String.valueOf(robotUser.getRobotId()), TaurusClient.ConnectionProtocol.Tcp); + TaurusClient client = new TaurusClient(robotUser.getGameHost()+":"+robotUser.getGamePort(), "game", TaurusClient.ConnectionProtocol.Tcp); client.setSession(robotUser.getLoginsession()); client.connect(); setupEventListeners(client, robotUser.getCurrentRoomId()+"_"+robotUser.getRobotId()); robotUser.setIsconnect(client.isConnected()); + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } robotUser.setClient(client); + EXGameController.robotRoomMapping.put(robotUser.getCurrentRoomId()+"_"+robotUser.getRobotId(), robotUser); }else{ System.out.println("reconnect"); System.out.println("client.isConnected()"+robotUser.getClient().isConnected()); @@ -749,10 +840,17 @@ public class RobotConnectionManager { robotUser.setIsconnect(true); }else{ System.out.println("reconnect"+robotUser.getClient().getGameID()); - TaurusClient client = new TaurusClient (robotUser.getGameHost()+":"+robotUser.getGamePort(), String.valueOf(robotUser.getRobotId()), TaurusClient.ConnectionProtocol.Tcp); + TaurusClient client = new TaurusClient(robotUser.getGameHost()+":"+robotUser.getGamePort(), "game", TaurusClient.ConnectionProtocol.Tcp); client.setSession(robotUser.getLoginsession()); client.connect(); robotUser.setIsconnect(client.isConnected()); + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + robotUser.setClient(client); + EXGameController.robotRoomMapping.put(robotUser.getCurrentRoomId()+"_"+robotUser.getRobotId(), robotUser); } } } @@ -842,7 +940,7 @@ public class RobotConnectionManager { * 根据connecId获取游戏服务器连接 */ public TaurusClient getGameClient(String connecId) { - return gameClients.get(connecId); + return robotRoomMapping.get(connecId) != null ? robotRoomMapping.get(connecId).getClient() : null; } } \ No newline at end of file diff --git a/robots/majiang/robot_mj_cs/src/main/java/robot/mj/handler/HuNanChangSha.java b/robots/majiang/robot_mj_cs/src/main/java/robot/mj/handler/HuNanChangSha.java index 07d2b71..a001a04 100644 --- a/robots/majiang/robot_mj_cs/src/main/java/robot/mj/handler/HuNanChangSha.java +++ b/robots/majiang/robot_mj_cs/src/main/java/robot/mj/handler/HuNanChangSha.java @@ -18,11 +18,14 @@ import java.sql.SQLException; import java.util.*; import java.util.stream.Collectors; +import com.google.gson.Gson; +import com.google.gson.reflect.TypeToken; + public class HuNanChangSha { - public static int changShaCard = 0; - public static boolean isTinChi = false; + public int changShaCard = 0; + public boolean isTinChi = false; public static boolean isTinPeng = false; private int robotid=0; @@ -36,44 +39,45 @@ public class HuNanChangSha { // private static final Logger log = Logger.getLogger(DoTest.class); - private List changShaCardInhandgang = new ArrayList<>(); + private final List changShaCardInhandgang = new ArrayList<>(); //长沙麻将出过的牌 - private List changShachuguopai = new ArrayList<>(); + private final List changShachuguopai = new ArrayList<>(); - private List changShaCardInhand = new ArrayList<>(); + private final List changShaCardInhand = new ArrayList<>(); public List getChangShaCardInhand() { return changShaCardInhand; } - private Map chuGuoPainum = new HashMap<>(); + private final Map chuGuoPainum = new HashMap<>(); //杠的牌 - private List gangdepai = new ArrayList<>(); + private final List gangdepai = new ArrayList<>(); //碰牌 - private List pongGroup = new ArrayList<>(); + private final List pongGroup = new ArrayList<>(); //吃牌 - private List chowGroup = new ArrayList<>(); + private final List chowGroup = new ArrayList<>(); // 玩家座位号 - public static int seat = 0; + public int seat = 0; // 会话标识 - public static String session = ""; + public String session = ""; // 访问令牌 - public static String token = ""; + public String token = ""; private static ChangShaSuanFaTest changShaSuanFaTest = new ChangShaSuanFaTest(); - + + private static final Gson gson = new Gson(); // 公共的getter和setter方法 @@ -102,6 +106,132 @@ public class HuNanChangSha { public Map getChuGuoPainum() { return chuGuoPainum; } + + /** + * 将当前实例状态序列化为JSON字符串并保存到Redis + * @param connecId 连接ID + */ + public void saveToRedis(String connecId) { + try (Jedis jedis = Redis.use("group1_db2").getJedis()) { + Map stateMap = new HashMap<>(); + + stateMap.put("changShaCardInhand", gson.toJson(changShaCardInhand)); + stateMap.put("changShachuguopai", gson.toJson(changShachuguopai)); + stateMap.put("chuGuoPainum", gson.toJson(chuGuoPainum)); + stateMap.put("gangdepai", gson.toJson(gangdepai)); + stateMap.put("pongGroup", gson.toJson(pongGroup)); + stateMap.put("chowGroup", gson.toJson(chowGroup)); + stateMap.put("changShaCardInhandgang", gson.toJson(changShaCardInhandgang)); + + stateMap.put("changShaCard", String.valueOf(changShaCard)); + stateMap.put("session", session); + stateMap.put("token", token); + + String redisKey = "{csmj}:" + connecId; + jedis.hmset(redisKey, stateMap); + //1小时过期时间 + jedis.expire(redisKey, 3600); + + System.out.println("保存HuNanChangSha状态到Redis: " + connecId); + } catch (Exception e) { + System.err.println("保存HuNanChangSha状态到Redis失败: " + e.getMessage()); + } + } + + /** + * 从Redis恢复实例状态 + * @param connecId 连接ID + * @return 是否成功恢复 + */ + public boolean restoreFromRedis(String connecId) { + try (Jedis jedis = Redis.use("group1_db2").getJedis()) { + String redisKey = "{csmj}:" + connecId; + Map stateMap = jedis.hgetAll(redisKey); + + if (stateMap == null || stateMap.isEmpty()) { + System.out.println("Redis中没有找到HuNanChangSha状态数据: " + connecId); + return false; + } + + //反序列化集合 + if (stateMap.containsKey("changShaCardInhand")) { + changShaCardInhand.clear(); + List handCards = gson.fromJson(stateMap.get("changShaCardInhand"), + new TypeToken>(){}.getType()); + if (handCards != null) changShaCardInhand.addAll(handCards); + } + + if (stateMap.containsKey("changShachuguopai")) { + changShachuguopai.clear(); + List outCards = gson.fromJson(stateMap.get("changShachuguopai"), + new TypeToken>(){}.getType()); + if (outCards != null) changShachuguopai.addAll(outCards); + } + + if (stateMap.containsKey("chuGuoPainum")) { + chuGuoPainum.clear(); + Map painum = gson.fromJson(stateMap.get("chuGuoPainum"), + new TypeToken>(){}.getType()); + if (painum != null) chuGuoPainum.putAll(painum); + } + + if (stateMap.containsKey("gangdepai")) { + gangdepai.clear(); + List gangCards = gson.fromJson(stateMap.get("gangdepai"), + new TypeToken>(){}.getType()); + if (gangCards != null) gangdepai.addAll(gangCards); + } + + if (stateMap.containsKey("pongGroup")) { + pongGroup.clear(); + List pongCards = gson.fromJson(stateMap.get("pongGroup"), + new TypeToken>(){}.getType()); + if (pongCards != null) pongGroup.addAll(pongCards); + } + + if (stateMap.containsKey("chowGroup")) { + chowGroup.clear(); + List chowCards = gson.fromJson(stateMap.get("chowGroup"), + new TypeToken>(){}.getType()); + if (chowCards != null) chowGroup.addAll(chowCards); + } + + if (stateMap.containsKey("changShaCardInhandgang")) { + changShaCardInhandgang.clear(); + List gangHandCards = gson.fromJson(stateMap.get("changShaCardInhandgang"), + new TypeToken>(){}.getType()); + if (gangHandCards != null) changShaCardInhandgang.addAll(gangHandCards); + } + + // 恢复基本属性 + if (stateMap.containsKey("changShaCard")) { + changShaCard = Integer.parseInt(stateMap.get("changShaCard")); + } + + session = stateMap.getOrDefault("session", ""); + token = stateMap.getOrDefault("token", ""); + + System.out.println("从Redis恢复HuNanChangSha状态成功: " + connecId + ", 手牌数量: " + changShaCardInhand.size()); + return true; + } catch (Exception e) { + System.err.println("从Redis恢复HuNanChangSha状态失败: " + e.getMessage()); + return false; + } + } + + /** + * 从Redis清除实例状态 + * @param connecId 连接ID + */ + public static void removeFromRedis(String connecId) { + try (Jedis jedis = Redis.use("group1_db2").getJedis()) { + String redisKey = "{csmj}:" + connecId; + jedis.del(redisKey); + System.out.println("从Redis删除HuNanChangSha状态: " + connecId); + } catch (Exception e) { + System.err.println("从Redis删除HuNanChangSha状态失败: " + e.getMessage()); + } + } /** * 出牌广播协议 812 @@ -110,7 +240,7 @@ public class HuNanChangSha { * @param message 消息对象 * @return */ - public static String drawCard(String command, Message message) { + public String drawCard(String command, Message message) { if (command.equalsIgnoreCase("812")) { ITObject param = message.param; if (param == null) { @@ -144,7 +274,9 @@ public class HuNanChangSha { Integer player = param.getInt("player"); int drawnCard = param.getInt("card"); changShaSuanFaTest.drawnCards = drawnCard;//存储摸到的牌 + System.out.println("changShaCardInhand"+changShaCardInhand); changShaCardInhand.add(drawnCard); + System.out.println("changShaCardInhandAdd"+changShaCardInhand); System.out.println("param.getInt(player)" + param.getInt("player") ); System.out.println("摸到的牌 +++++++++ " + drawnCard); if (jedis222.hget("{robortInfo}:" + player, "circleId") != null && jedis222.hget("{robortInfo}:" + player, "pid") != null) { @@ -220,8 +352,11 @@ public class HuNanChangSha { * @param handCard */ public void updateHandCard(List handCard) { + System.out.println("updateHandCard同步手牌:"+ handCard); changShaCardInhand.clear(); + System.out.println("updateHandCard同步手牌changShaCardInhand:"+ changShaCardInhand); changShaCardInhand.addAll(handCard); + System.out.println("updateHandCard同步手牌add:"+ changShaCardInhand); } public void updateOutCard(List outCard) { @@ -322,7 +457,7 @@ public class HuNanChangSha { // log.info("tipList" +tipList); ITObject params = TObject.newInstance(); int card = 0; - getChangShaCardInhand(); + // getChangShaCardInhand(); //循环 List yupanhandcard = new ArrayList<>(); yupanhandcard.addAll(changShaCardInhand); @@ -786,6 +921,7 @@ public class HuNanChangSha { } } } + System.out.println("actchangShaCardInhand"+changShaCardInhand); params.putString("session", session + "," + token); params.putInt("qi", 0); params.putInt("id", 0); @@ -1788,8 +1924,11 @@ public class HuNanChangSha { resultList.addAll(zigang); } + System.out.println("长沙麻将出牌"+changShaCardInhand); // 长沙麻将出牌 String changShaOutCard = changShaSuanFaTest.outCardSuanFa(changShaCardInhand, pongGroup, chowGroup, gangdepai, resultList); + System.out.println("长沙麻将出牌"+changShaCardInhand); + // String changShaOutCard = changShaSuanFaTest.outCardSuanFa(list, changShaCard,pongGroup); ITObject params = TObject.newInstance(); int cardToOut; diff --git a/robots/majiang/robot_mj_cs/src/main/java/taurus/util/TinHuChi.java b/robots/majiang/robot_mj_cs/src/main/java/taurus/util/TinHuChi.java index ff64360..ba6e166 100644 --- a/robots/majiang/robot_mj_cs/src/main/java/taurus/util/TinHuChi.java +++ b/robots/majiang/robot_mj_cs/src/main/java/taurus/util/TinHuChi.java @@ -627,7 +627,7 @@ public class TinHuChi { // 5. 检查打牌后是否能听牌 boolean canTing = checkCanTing(afterDiscard, needs258, targetSizeAfterDiscard); if (canTing) { - HuNanChangSha.isTinChi = true; + //HuNanChangSha.isTinChi = true; ChangShaSuanFaTest.isChi=true; System.out.println(" ✓ 听牌!"); foundTing = true;