From 552620e486ffdc5fe0d4b250873f09493556450b Mon Sep 17 00:00:00 2001 From: zhouwei <849588297@qq.com> Date: Mon, 26 Jan 2026 16:49:01 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E6=9C=BA=E5=99=A8=E4=BA=BA?= =?UTF-8?q?=E7=99=BB=E5=BD=95=E8=BF=9E=E6=8E=A5=E9=9C=80=E6=B1=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/com/group/MainServer.java | 134 +- .../java/com/group/robot/RobotManager.java | 374 ++---- .../group/robot/RobotManagerInterface.java | 4 +- .../robot/connect/RedisRoomListener.java | 451 ------- .../group/robot/connect/RobotDisconnect.java | 2 +- .../robot/connect/RobotMgrTcpClient.java | 240 ---- .../robot/handler/MaJiangRobotHandler.java | 17 +- .../robot/handler/PokerRobotHandler.java | 18 +- .../robot/handler/RobotConnectionHandler.java | 351 ++--- .../java/com/group/robot/info/RobotInfo.java | 58 +- .../group/robot/matcher/RoomWanfaMatcher.java | 271 ++++ .../test/java/com/group/robot/TcpTest.java | 1124 ----------------- .../src/main/java/robot/mj/RoomCreator.java | 60 +- 13 files changed, 702 insertions(+), 2402 deletions(-) delete mode 100644 game_web/robot_mgr/src/main/java/com/group/robot/connect/RedisRoomListener.java delete mode 100644 game_web/robot_mgr/src/main/java/com/group/robot/connect/RobotMgrTcpClient.java create mode 100644 game_web/robot_mgr/src/main/java/com/group/robot/matcher/RoomWanfaMatcher.java delete mode 100644 game_web/robot_mgr/src/test/java/com/group/robot/TcpTest.java diff --git a/game_web/robot_mgr/src/main/java/com/group/MainServer.java b/game_web/robot_mgr/src/main/java/com/group/MainServer.java index 42c76ab..b0f478d 100644 --- a/game_web/robot_mgr/src/main/java/com/group/MainServer.java +++ b/game_web/robot_mgr/src/main/java/com/group/MainServer.java @@ -2,14 +2,14 @@ package com.group; import java.sql.SQLException; -import java.util.HashMap; -import java.util.Map; +import java.util.*; import java.util.concurrent.ScheduledThreadPoolExecutor; import java.util.concurrent.TimeUnit; import com.data.cache.AccountCache; import com.data.cache.GroupCache; import com.group.robot.RobotManager; +import com.group.robot.info.RobotInfo; import com.taurus.core.entity.ITArray; import com.taurus.core.entity.ITObject; import com.taurus.core.plugin.database.DataBase; @@ -19,11 +19,9 @@ import com.taurus.core.routes.Routes; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import redis.clients.jedis.Jedis; import taurus.client.NetManager; - public class MainServer extends Extension { private static final Logger log = LoggerFactory.getLogger(MainServer.class); private ScheduledThreadPoolExecutor timeScheduler; @@ -32,8 +30,8 @@ public class MainServer extends Extension { private static final String FORCE_VER_KEY = "force_ver"; //机器人管理器 - private RobotManager robotManager; - + private RobotManager robotManager = new RobotManager(); + public static Map lua_map = new HashMap<>(); public MainServer() { super(); @@ -65,17 +63,26 @@ public class MainServer extends Extension { public void onStart() { System.out.println("开始创建机器人连接..."); - - - //初始化机器人管理器 - robotManager = new RobotManager(); - - //0 加载机器人到redis 2 - loadGroupRobot(); - - // 1. 先启动独立的事件处理线程(只启动一次) + //1.先启动独立的事件处理线程(只启动一次) startNetEventThread(); + //2.加载机器人到redis 2 + loadGroupRobot(); + + //关闭时重置机器人状态 + Runtime.getRuntime().addShutdownHook(new Thread(this::resetRobotStatus)); + } + + /** + * 重置机器人状态为未使用 + */ + private void resetRobotStatus() { + try { + String sql = "UPDATE account SET start = 0 WHERE jiqiren = 9998"; + DataBase.use().executeUpdate(sql); + } catch (Exception e) { + e.printStackTrace(); + } } // 独立的事件处理线程 @@ -100,67 +107,60 @@ public class MainServer extends Extension { * 把机器人加载到redis2 */ private void loadGroupRobot(){ - Jedis jedis2 = Redis.use("group1_db2").getJedis(); + String sql = "SELECT id,acc,nick,portrait,password FROM `account` WHERE jiqiren=9998 and start = 0"; + ITArray robotIds = null; try { - String sql = String.format("SELECT id,acc,nick,portrait,password FROM `account` WHERE jiqiren=9998 and start = 0"); - ITArray robotIds = DataBase.use().executeQueryByTArray(sql); - HashMap robotMap = new HashMap<>(); - - //遍历机器人, - for(int i = 0; i < robotIds.size(); ++i) { -// //把机器人按group 分类好 存放到redis2 - - ITObject robot = robotIds.getTObject(i); - Integer robotId = robot.getInt("id"); - String robotAcc = robot.getString("acc"); - String robotNick = robot.getString("nick"); - String robotPortrait = robot.getString("portrait"); - String robotPassword = robot.getString("password"); - - robotMap.put("acc", robotAcc); - robotMap.put("nick", robotNick); - robotMap.put("portrait", robotPortrait); - robotMap.put("password", robotPassword); - jedis2.hmset("{robot}:" + robotId , robotMap); - -// String sqls = String.format("UPDATE `account` SET start = %d WHERE id = %d", 1, robotId); -// DataBase.use().executeUpdate(sqls); - } - - - Map gRobotMap = new HashMap<>(); - gRobotMap.put("start", "0"); - gRobotMap.put("pid", "66"); - jedis2.hmset("{grobot}:"+101666, gRobotMap); - - - - } catch (SQLException e) { + robotIds = DataBase.use().executeQueryByTArray(sql); + } catch (SQLException e) { throw new RuntimeException(e); - }finally { - jedis2.close(); + } + + Map gameRobotConfig = new HashMap<>(); + gameRobotConfig.put(10, 5); + gameRobotConfig.put(22, 3); + int robotIndex = 0; + + //长沙麻将机器人 + List csRobots = new ArrayList<>(); + for (int i = 0; i < gameRobotConfig.get(10) && robotIndex < robotIds.size(); i++, robotIndex++) { + ITObject robot = robotIds.getTObject(robotIndex); + RobotInfo robotInfo = createRobotInfo(robot, 10); + csRobots.add(robotInfo); } + //红中麻将机器人 + List hzRobots = new ArrayList<>(); + for (int i = 0; i < gameRobotConfig.get(22) && robotIndex < robotIds.size(); i++, robotIndex++) { + ITObject robot = robotIds.getTObject(robotIndex); + RobotInfo robotInfo = createRobotInfo(robot, 22); + hzRobots.add(robotInfo); + } + + log.info("机器人分配完成:长沙麻将{}个,红中麻将{}个", csRobots.size(), hzRobots.size()); + + //登录分配的机器人 + //初始化机器人管理器 + robotManager.loginRobots(csRobots, 10); + robotManager.loginRobots(hzRobots, 22); } + /** + * 创建机器人信息对象 + */ + private RobotInfo createRobotInfo(ITObject robotObj, int wanfaId) { + RobotInfo robot = new RobotInfo(); + robot.setRobotId(robotObj.getInt("id")); + robot.setAccount(robotObj.getString("acc")); + robot.setNickName(robotObj.getString("nick")); + robot.setPortrait(robotObj.getString("portrait")); + robot.setPassword(robotObj.getString("password")); + robot.setWanfaId(wanfaId); + return robot; + } + @Override public void configRoute(Routes me) { } - - @Override - public void onStop() { - if(timeScheduler!=null) { - timeScheduler.shutdownNow(); - - //关闭机器人管理器 - if (robotManager != null) { - robotManager.shutdown(); - } - - } - } - - } \ No newline at end of file diff --git a/game_web/robot_mgr/src/main/java/com/group/robot/RobotManager.java b/game_web/robot_mgr/src/main/java/com/group/robot/RobotManager.java index 78decb7..903d185 100644 --- a/game_web/robot_mgr/src/main/java/com/group/robot/RobotManager.java +++ b/game_web/robot_mgr/src/main/java/com/group/robot/RobotManager.java @@ -3,26 +3,22 @@ package com.group.robot; import java.util.*; import java.util.concurrent.*; -import com.group.robot.connect.RedisRoomListener; import com.group.robot.connect.RobotDisconnect; +import com.group.robot.handler.*; import com.group.robot.info.RobotInfo; -import com.group.robot.info.RoomInfo; +import com.group.robot.matcher.RoomWanfaMatcher; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import redis.clients.jedis.Jedis; import com.taurus.core.plugin.redis.Redis; import com.taurus.core.plugin.database.DataBase; -import com.taurus.core.entity.ITArray; import com.taurus.core.entity.ITObject; -import com.group.robot.handler.CSMJRobotHandler; -import com.group.robot.handler.HZMJRobotHandler; -import com.group.robot.handler.PokerRobotHandler; -import com.group.robot.handler.ZZMJRobotHandler; import com.group.robot.matcher.majiang.CSMJRoomMatcher; import com.group.robot.matcher.majiang.HZMJRoomMatcher; import com.group.robot.matcher.poker.PokerRoomMatcher; import com.group.robot.matcher.majiang.ZZMJRoomMatcher; import com.group.robot.matcher.GameRoomMatcherInterface; +import taurus.client.business.AccountBusiness; /** * 机器人管理器 - 管理游戏机器人、游戏房间、监听 @@ -42,12 +38,12 @@ public class RobotManager { //游戏特定的房间匹配器 private final Map gameRoomMatchers = new ConcurrentHashMap<>(); - //Redis房间监听器 - private RedisRoomListener redisRoomListener; - //使用数量计数器 跟踪每种玩法的机器人使用数量 private final Map count = new ConcurrentHashMap<>(); + //玩法房间轮询器 + private final Map wanfaRoomPollers = new ConcurrentHashMap<>(); + //定时任务调度器 private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(2); @@ -61,9 +57,6 @@ public class RobotManager { //1、启动 ==》2、登录,3、是否快捷登录 4、分配做什么工作(a:长麻,b:红中,c:跑得快)5、干活,6、销毁回收 - - - //初始化游戏处理器 initializeGameHandlers(); //1、设定每个玩法多少机器人 @@ -72,10 +65,7 @@ public class RobotManager { //初始化游戏房间匹配器 initializeGameRoomMatchers(); - //初始化Redis房间监听器 - initializeRedisListener(); - - //定时清理任务 + //定时任务 startCleanupTask(); } @@ -94,32 +84,6 @@ public class RobotManager { log.info("已初始化 {} 个游戏处理器", gameHandlers.size()); } - /** - * 添加游戏处理器 - */ - public void addGameHandler(int gameId, RobotManagerInterface handler) { - gameHandlers.put(gameId, handler); - log.info("添加游戏处理器: gameId={}, handler={}", gameId, handler.getClass().getSimpleName()); - } - - /** - * 获取游戏处理器 - */ - public RobotManagerInterface getGameHandler(int gameId) { - return gameHandlers.get(gameId); - } - - /** - * 初始化Redis房间监听器 - */ - private void initializeRedisListener() { - redisRoomListener = new RedisRoomListener(this); - //启动Redis实时监听 - redisRoomListener.startListening(); - - log.info("房间监控已启动 - 实时监听模式,支持 {} 种游戏类型", gameHandlers.size()); - } - /** * 初始化游戏房间匹配器 */ @@ -145,115 +109,146 @@ public class RobotManager { } /** - * 定时清理任务 + * 登录单个机器人 */ - private void startCleanupTask() { - //每30秒检查一次不活跃的机器人连接 - scheduler.scheduleAtFixedRate(this::cleanupInactiveRobots, 30, 30, java.util.concurrent.TimeUnit.SECONDS); + public void loginRobots(List robots, int gameId) { + try (Jedis jedis0 = Redis.use().getJedis(); Jedis jedis2 = Redis.use("group1_db2").getJedis()){ + for (RobotInfo robot : robots) { + AccountBusiness accountBusiness = new AccountBusiness(); + //检查Redis中是否存在已有token + Set tokenKeys = jedis0.keys("{user}:" + robot.getRobotId() + "_token"); + ITObject loginResult; - log.info("定时清理任务已启动"); + if (tokenKeys != null && !tokenKeys.isEmpty()) { + log.debug("机器人 {} 存在已有token,直接使用", robot.getRobotId()); + Set tokenSet = jedis0.smembers("{user}:" + robot.getRobotId() + "_token"); + List tokenList = new ArrayList<>(tokenSet); + + robot.setSession("{user}:" + robot.getRobotId()); + if (!tokenList.isEmpty()) { + robot.setToken(tokenList.get(0)); + } else { + //如果没有token 则执行正常登录 + loginResult = accountBusiness.idPasswordLogin(robot.getRobotId(), robot.getPassword()); + robot.setToken(loginResult.getString("token")); + robot.setSession(accountBusiness.getSession()); + } + } else { + log.debug("机器人 {} 执行常规登录", robot.getRobotId()); + //执行正常登录流程 + loginResult = accountBusiness.idPasswordLogin(robot.getRobotId(), robot.getPassword()); + robot.setToken(loginResult.getString("token")); + robot.setSession(accountBusiness.getSession()); + } + robot.setOnline(true); + robot.setWanfaId(gameId); + robot.setLastActiveTime(System.currentTimeMillis()); + + HashMap robotMap = new HashMap<>(); + robotMap.put("acc", robot.getAccount()); + robotMap.put("nick", robot.getNickName()); + robotMap.put("portrait", robot.getPortrait()); + robotMap.put("password", robot.getPassword()); + jedis2.hmset("{robot}:" + robot.getRobotId(), robotMap); + + //todo 将机器人信息存储到grobot键中,用于按group分类 + Map gRobotMap = new HashMap<>(); + gRobotMap.put("start", "0"); + gRobotMap.put("pid", String.valueOf(gameId)); + jedis2.hmset("{grobot}:" + robot.getRobotId(), gRobotMap); + + //将登录后的机器人添加到已连接列表中 等待连接服务器 + connectedRobots.put(robot.getRobotId(), robot); + + //更新数据库状态为已使用 + String sql = String.format("UPDATE `account` SET start = %d WHERE id = %d", 1, robot.getRobotId()); + DataBase.use().executeUpdate(sql); + log.info("机器人{}登录成功,分配到玩法{}", robot.getRobotId(), gameId); + + //连接对应游戏服务器 + RobotManagerInterface handler = getGameHandler(gameId); + handler.connectRobot(robot); + } + } catch (Exception e) { + log.error("机器人登录时发生错误", e); + } } /** - * 清理不活跃的机器人连接 + * 添加游戏处理器 */ - private void cleanupInactiveRobots() { - log.debug("开始清理不活跃的机器人连接..."); + public void addGameHandler(int gameId, RobotManagerInterface handler) { + gameHandlers.put(gameId, handler); + log.info("添加游戏处理器: gameId={}, handler={}", gameId, handler.getClass().getSimpleName()); + } - //已连接的机器人 - for (RobotInfo robot : new ArrayList<>(connectedRobots.values())) { - //检查机器人是否仍然连接到房间 - try { - //检查房间状态 - try (Jedis jedis0 = Redis.use().getJedis()){ - String roomKey = robot.getCurrentRoomId(); - if (roomKey != null) { - //检查房间是否存在或是否已结束 - String status = jedis0.hget(roomKey, "status"); - if (status != null) { - int roomStatus = Integer.parseInt(status); - //如果房间已结束或已删除 断开机器人连接 - if (roomStatus == 2 || roomStatus == 3) { - log.info("房间 {} 已结束,断开机器人 {} 连接", roomKey, robot.getRobotId()); - disconnectRobot(robot); - } - } + /** + * 获取游戏处理器 + */ + public RobotManagerInterface getGameHandler(int gameId) { + return gameHandlers.get(gameId); + } - //检查房间玩家列表 确认机器人是否仍在房间中 - String players = jedis0.hget(roomKey, "players"); - if (players != null && !players.equals("[]")) { - String playersStr = players.substring(1, players.length() - 1); - String[] playerIds = playersStr.split(","); - boolean robotInRoom = false; + /** + * 定时任务 + */ + private void startCleanupTask() { + //每15秒检查一次玩法配置 + scheduler.scheduleAtFixedRate(this::manageWanfaPollers, 15, 15, TimeUnit.SECONDS); + } - for (String playerIdStr : playerIds) { - int playerId = Integer.parseInt(playerIdStr.trim()); - if (playerId == robot.getRobotId()) { - robotInRoom = true; - break; - } - } - //如果机器人不在房间玩家列表中 断开连接 - if (!robotInRoom) { - log.info("机器人 {} 不在房间 {} 断开连接", robot.getRobotId(), roomKey); - disconnectRobot(robot); + /** + * 管理玩法轮询器 + */ + private void manageWanfaPollers() { + try (Jedis jedis11 = Redis.use("group1_db11").getJedis()) { + Set playKeys = jedis11.keys("g{*}:play:*"); + + for (String playKey : playKeys) { + try { + String[] parts = playKey.split(":"); + if (parts.length >= 3) { + String groupStr = parts[0]; + int groupId = Integer.parseInt(groupStr.substring(2, groupStr.length() - 1)); + int wanfaId = Integer.parseInt(parts[parts.length - 1]); + + //检查是否配置了机器人 + int shangxianRobot = Integer.parseInt(jedis11.hget(playKey, "shangxian_robot")); + int leftoverRobot = Integer.parseInt(jedis11.hget(playKey, "leftover_robot")); + + if (shangxianRobot != 0 && leftoverRobot > 0) { + RoomWanfaMatcher poller = getWanfaRoomPoller(groupId, wanfaId); + if (!poller.isRunning()) { + poller.startPolling(); + log.info("为玩法ID {} 启动房间轮询器", wanfaId); } } else { - //如果房间玩家列表为空 但机器人连接到此房间 断开连接 - if (roomKey.equals(robot.getCurrentRoomId())) { - log.info("房间 {} 玩家列表为空,断开机器人 {} 连接", roomKey, robot.getRobotId()); - disconnectRobot(robot); + //如果没有配置机器人 停止轮询器 + RoomWanfaMatcher poller = wanfaRoomPollers.get(wanfaId); + if (poller != null) { + poller.stopPolling(); + log.info("为玩法ID {} 停止房间轮询器", wanfaId); } } } + } catch (NumberFormatException e) { + log.debug("无法解析玩法ID: {}", playKey); } - } catch (Exception e) { - log.error("检查机器人 {} 连接状态时发生错误", robot.getRobotId(), e); } - } - log.debug("清理不活跃的机器人连接完成,当前连接机器人数量: {}", connectedRobots.size()); - } - - /** - * 连接机器人到指定房间 - */ - public void connectRobotToRoom(RobotInfo robot, RoomInfo room) { - RobotManagerInterface handler = getGameHandler(room.getWanfaId()); - if (handler == null) { - log.warn("未找到处理玩法ID {} 的处理器", room.getWanfaId()); - return; - } - - //增加对应玩法的机器人使用计数 - increaseRobotUsageCount(room.getGroupId(), room.getWanfaId()); - log.info("机器人 {} 加入房间前,减少leftover_robot数量,群组={}, 玩法ID={}", robot.getRobotId(), room.getGroupId(), room.getWanfaId()); - - try { - //通过处理器连接机器人 - handler.connectRobot(robot, room); - connectedRobots.put(robot.getRobotId(), robot); } catch (Exception e) { - log.error("连接机器人到房间时发生异常", e); - robot.setConnected(false); - //异常时回滚计数 - rollbackRobotCounts(room.getGroupId(), room.getWanfaId()); + log.error("管理玩法轮询器时发生错误", e); } } - + /** - * 回滚机器人相关计数 + * 获取玩法房间轮询器 */ - private void rollbackRobotCounts(int groupId, int wanfaId) { - //减少的机器人使用计数回滚 - decreaseRobotCount(wanfaId); - //增加leftover_robot数量 - try (Jedis jedis11 = Redis.use("group1_db11").getJedis()) { - String playKey = "g{" + groupId + "}:play:" + wanfaId; - jedis11.hincrBy(playKey, "leftover_robot", 1); - log.info("回滚机器人计数,群组={}, 玩法ID={}", groupId, wanfaId); - } catch (Exception e) { - log.error("回滚leftover_robot计数时发生异常", e); - } + public RoomWanfaMatcher getWanfaRoomPoller(int groupId, int wanfaId) { + return wanfaRoomPollers.computeIfAbsent(wanfaId, k -> { + RoomWanfaMatcher poller = new RoomWanfaMatcher(this, groupId, wanfaId); + log.info("创建玩法ID {} 的房间轮询器", wanfaId); + return poller; + }); } /** @@ -261,9 +256,9 @@ public class RobotManager { */ public void disconnectRobot(RobotInfo robot) { int robotId = robot.getRobotId(); - int groupId = getGroupIdFromRoomId(robot.getCurrentRoomId()); - int gameId = robot.getCurrentWanfaId(); - String roomId = robot.getCurrentRoomId(); + int groupId = getGroupIdFromRoomId(robot.getRoomId()); + int gameId = robot.getWanfaId(); + String roomId = robot.getRoomId(); //断开机器人服务 safeDisconnectRobot(robotId, groupId, gameId, roomId); @@ -285,92 +280,17 @@ public class RobotManager { } /** - * 获取可用机器人列表 + * 获取已登录的指定玩法的机器人 */ - public List getAvailableRobots(int count) { - List availableRobots = new ArrayList<>(); - - try { - //获取可用机器人信息 - String sql = String.format("SELECT id,acc,nick,portrait,password FROM `account` WHERE jiqiren=9998 and start = 0 LIMIT %d", count); - ITArray robotArray = DataBase.use().executeQueryByTArray(sql); - - for (int i = 0; i < robotArray.size() && i < count; i++) { - ITObject robotObj = robotArray.getTObject(i); - - RobotInfo robot = new RobotInfo(); - robot.setRobotId(robotObj.getInt("id")); - robot.setAccount(robotObj.getString("acc")); - robot.setNickName(robotObj.getString("nick")); - robot.setPortrait(robotObj.getString("portrait")); - robot.setPassword(robotObj.getString("password")); - robot.setOnline(false); - robot.setConnected(false); - - availableRobots.add(robot); - } - } catch (Exception e) { - log.error("获取可用机器人列表时发生错误", e); - } finally { - //更新机器人状态为已使用 - if (!availableRobots.isEmpty()) { - for (RobotInfo robot : availableRobots) { - try { - String sql = String.format("UPDATE `account` SET start = %d WHERE id = %d", 1, robot.getRobotId()); - DataBase.use().executeUpdate(sql); - log.debug("机器人 {} 状态已更新为已使用", robot.getRobotId()); - } catch (Exception e) { - log.error("更新机器人 {} 状态失败", robot.getRobotId(), e); - } - } - } - } - - return availableRobots; - } - - /** - * 获取指定玩法类型的房间匹配器 - */ - public GameRoomMatcherInterface getGameRoomMatcher(int wanfaId) { - return gameRoomMatchers.get(wanfaId); - } - - /** - * 关闭机器人管理器 - */ - public void shutdown() { - //停止Redis监听 - if (redisRoomListener != null) { - redisRoomListener.stopListening(); - } - - //断开所有机器人连接 + public RobotInfo getLoggedInRobotForWanfa(int wanfaId) { for (RobotInfo robot : connectedRobots.values()) { - disconnectRobot(robot); - } - - //恢复所有机器人状态为可用 - try { - String sql = "UPDATE `account` SET start = 0 WHERE jiqiren = 9998"; - DataBase.use().executeUpdate(sql); - log.info("所有机器人状态已重置为可用"); - } catch (Exception e) { - log.error("重置机器人状态时发生错误", e); - } - - //关闭定时任务调度器 - try { - scheduler.shutdown(); - if (!scheduler.awaitTermination(5, TimeUnit.SECONDS)) { - scheduler.shutdownNow(); + if (robot.getWanfaId() == wanfaId && robot.isOnline() && robot.isConnected()) { + //更新最后活跃时间 + robot.setLastActiveTime(System.currentTimeMillis()); + return robot; } - } catch (InterruptedException e) { - scheduler.shutdownNow(); - Thread.currentThread().interrupt(); } - - log.info("机器人管理器已关闭,断开了 {} 个机器人连接", connectedRobots.size()); + return null; } /** @@ -380,21 +300,6 @@ public class RobotManager { return robotManager; } - /** - * 增加指定玩法ID的机器人使用计数 - */ - public void increaseRobotUsageCount(int groupId, int wanfaId) { - count.put(wanfaId, count.getOrDefault(wanfaId, 0) + 1); - - try (Jedis jedis11 = Redis.use("group1_db11").getJedis()) { - String playKey = "g{" + groupId + "}:play:" + wanfaId; - jedis11.hincrBy(playKey, "leftover_robot", -1); - } catch (Exception e) { - decreaseRobotCount(wanfaId); - } - log.debug("玩法ID {} 的机器人使用计数增加到: {}", wanfaId, count.get(wanfaId)); - } - /** * 减少指定玩法ID的机器人使用计数 */ @@ -406,13 +311,6 @@ public class RobotManager { } } - /** - * 获取指定玩法ID的机器人使用计数 - */ - public int getRobotUsageCount(int wanfaId) { - return count.getOrDefault(wanfaId, 0); - } - /** * 获取已连接的机器人 */ diff --git a/game_web/robot_mgr/src/main/java/com/group/robot/RobotManagerInterface.java b/game_web/robot_mgr/src/main/java/com/group/robot/RobotManagerInterface.java index c5c9478..bf48da1 100644 --- a/game_web/robot_mgr/src/main/java/com/group/robot/RobotManagerInterface.java +++ b/game_web/robot_mgr/src/main/java/com/group/robot/RobotManagerInterface.java @@ -8,9 +8,9 @@ import com.group.robot.info.RoomInfo; */ public interface RobotManagerInterface { /** - * 连接机器人到房间 + * 连接机器人到游戏服务器 */ - void connectRobot(RobotInfo robot, RoomInfo room); + void connectRobot(RobotInfo robot); /** * 断开机器人连接 diff --git a/game_web/robot_mgr/src/main/java/com/group/robot/connect/RedisRoomListener.java b/game_web/robot_mgr/src/main/java/com/group/robot/connect/RedisRoomListener.java deleted file mode 100644 index c5e8f0a..0000000 --- a/game_web/robot_mgr/src/main/java/com/group/robot/connect/RedisRoomListener.java +++ /dev/null @@ -1,451 +0,0 @@ -package com.group.robot.connect; - -import java.util.List; -import java.util.Set; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.TimeUnit; - -import com.group.robot.RobotManager; -import com.group.robot.info.RobotInfo; -import com.group.robot.info.RoomInfo; -import com.taurus.core.entity.ITArray; -import com.taurus.core.entity.ITObject; -import com.taurus.core.plugin.database.DataBase; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import redis.clients.jedis.Jedis; -import redis.clients.jedis.JedisPubSub; -import com.taurus.core.plugin.redis.Redis; -import com.group.robot.matcher.GameRoomMatcherInterface; - -/** - * Redis房间监听器 - 实时监听房间的游戏类型 触发对应游戏类型匹配器 - */ -public class RedisRoomListener extends JedisPubSub { - - private static final Logger log = LoggerFactory.getLogger(RedisRoomListener.class); - private final ExecutorService executorService = Executors.newFixedThreadPool(4); - //机器人管理器 - private final RobotManager robotManager; - - public RedisRoomListener(RobotManager robotManager) { - this.robotManager = robotManager; - } - - /** - * 开始监听房间变化 - */ - public void startListening() { - // 启动db0监听线程(房间变化) - Thread db0ListenerThread = new Thread(() -> { - Jedis jedis0 = Redis.use().getJedis(); // 默认db0 - try { - log.info("开始监听db0的房间键空间变化..."); - - //订阅键空间通知 - db0中的房间变化 - //注意:Redis需要开启键空间通知:config set notify-keyspace-events Ex - jedis0.psubscribe(this, "__keyspace@0__:room:*"); - - } catch (Exception e) { - log.error("监听db0房间变化时发生错误", e); - } finally { - if (jedis0 != null) { - jedis0.close(); - } - } - }); - db0ListenerThread.setDaemon(true); - db0ListenerThread.setName("RedisRoomListener-db0"); - db0ListenerThread.start(); - - //启动db11监听线程(玩法配置变化) - Thread db11ListenerThread = new Thread(() -> { - Jedis jedis11 = Redis.use("group1_db11").getJedis(); - try { - log.info("开始监听db11的玩法配置变化..."); - - //订阅键空间通知 - db11中的玩法配置变化 - //注意:需要订阅正确的模式 - jedis11.psubscribe(this, "__keyspace@11__:g{*}:play:*"); - - } catch (Exception e) { - log.error("监听db11玩法配置变化时发生错误", e); - } finally { - if (jedis11 != null) { - jedis11.close(); - } - } - }); - db11ListenerThread.setDaemon(true); - db11ListenerThread.setName("RedisRoomListener-db11"); - db11ListenerThread.start(); - - log.info("Redis房间监听器已启动,正在监听db0的房间变化和db11的玩法配置变化"); - - //等待监听线程启动 - try { - Thread.sleep(1000); - if (db0ListenerThread.isAlive() && db11ListenerThread.isAlive()) { - log.info("两个监听线程都已成功启动"); - System.out.println("Redis房间监听器已启动,正在监听db0的房间变化和db11的玩法配置变化"); - } - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - } - } - - @Override - public void onMessage(String channel, String message) { - log.debug("收到Redis频道消息: channel={}, message={}", channel, message); - System.out.println("收到Redis频道消息: channel=" + channel + ", message=" + message); - //根据订阅类型处理 - if (channel.startsWith("__keyspace@0__:room:")) { - //处理房间人员进出或状态变化 - handleRoomEvent(channel, message); - } else if (channel.startsWith("g{") && channel.contains("}:play:")) { - //群组玩法配置变化事件 - handleGroupPlayChange(channel, message); - } - } - - /** - * 处理房间变化事件 - */ - private void handleRoomEvent(String channel, String message) { - executorService.submit(() -> { - try (Jedis jedis0 = Redis.use().getJedis(); Jedis jedis11 = Redis.use("group1_db11").getJedis()) { - //获取房间ID - String roomId = getRedisChannelRoomId(channel); - - int wanfaId = Integer.parseInt(jedis0.hget(roomId, "game")); - int groupId = Integer.parseInt(jedis0.hget(roomId, "group")); - int status = Integer.parseInt(jedis0.hget(roomId, "status")); - int maxPlayers = Integer.parseInt(jedis0.hget(roomId, "maxPlayers")); - - if (maxPlayers != 2) { - return; - } - - //房间已结束或已删除 - if (status == 2 || status == 3) { - String playersStr = jedis0.hget(roomId, "players"); - if (playersStr != null && !playersStr.equals("[]")) { - //房间结束后 如果房间中有机器人 恢复剩余机器人数量 - restoreLeftoverRobotOnRoomEnd(roomId, groupId, wanfaId, playersStr, jedis11); - - //房间结束后 立即检查是否需要创建新房间 - checkCreateRobotRoomTCP(wanfaId, groupId, jedis0, jedis11); - return; - } - } - - /* 匹配机器人机制 */ - //检查玩法配置中的机器人设置 - String playKey = "g{" + groupId + "}:play:" + wanfaId; - int shangxianRobot = Integer.parseInt(jedis11.hget(playKey, "shangxian_robot")); - - //玩法配置了机器人上限 - if (shangxianRobot > 0) { - String playersStr = jedis0.hget(roomId, "players"); - - //房间中当前人数 - int currentPlayers = 0; - if (playersStr != null && !playersStr.equals("[]")) { - String playersClean = playersStr.substring(1, playersStr.length() - 1); - if (!playersClean.isEmpty()) { - String[] playerIds = playersClean.split(","); - currentPlayers = playerIds.length; - } - } - - //检查房间中是否已有机器人 - boolean hasRobot = hasRobotInRoom(roomId, jedis0); - - //触发对应游戏类型的房间匹配器 - GameRoomMatcherInterface matcher = robotManager.getGameRoomMatcher(wanfaId); - if (matcher != null && !hasRobot && currentPlayers < maxPlayers) { - log.info("触发玩法ID {} 的房间匹配", wanfaId); - - //获取玩法配置中的剩余机器人数量 - int leftoverRobot = Integer.parseInt(jedis11.hget(playKey, "leftover_robot")); - if (leftoverRobot > 0) { - int currentUsage = robotManager.getRobotUsageCount(wanfaId); - //当前机器人使用数量小于上限 - if (currentUsage < shangxianRobot) { - //获取可用机器人 - List availableRobots = robotManager.getAvailableRobots(1); - if (!availableRobots.isEmpty()) { - RobotInfo robot = availableRobots.get(0); - - //创建房间信息对象 - RoomInfo roomInfo = new RoomInfo(); - roomInfo.setRoomId(roomId); - roomInfo.setWanfaId(wanfaId); - roomInfo.setGroupId(groupId); - roomInfo.setCurrentPlayers(currentPlayers); - roomInfo.setMaxPlayers(maxPlayers); - roomInfo.setGame(String.valueOf(wanfaId)); - - //连接机器人到房间 - robotManager.connectRobotToRoom(robot, roomInfo); - } - } - } - } else { - log.debug("玩法ID {} 房间已有机器人或房间已满", wanfaId); - } - } else { - log.debug("玩法ID {} 没有配置机器人上限或上限为0 跳过处理", wanfaId); - } - - /* 对2人房间进行检查 当房间状态发生变化时 检查是否需要创建新房间 */ - checkCreateRobotRoomTCP(wanfaId, groupId, jedis0, jedis11); - } catch (Exception e) { - log.error("处理房间变化事件时发生错误", e); - } - }); - } - - /** - * 处理群组玩法配置变化 - */ - private void handleGroupPlayChange(String channel, String message) { - executorService.submit(() -> { - try (Jedis jedis0 = Redis.use().getJedis(); Jedis jedis11 = Redis.use("group1_db11").getJedis()){ - log.info("监听到群组玩法配置变化: {}", channel); - - int braceIndex = channel.indexOf('}'); - if (braceIndex > 1) { - String groupIdStr = channel.substring(2, braceIndex); - String remaining = channel.substring(braceIndex + 1); - - if (remaining.startsWith(":play:") && remaining.length() > 6) { - String wanfaIdStr = remaining.substring(6); - int groupId = Integer.parseInt(groupIdStr); - int wanfaId = Integer.parseInt(wanfaIdStr); - - //当玩法配置发生变化时 立即检查是否需要创建房间 - checkCreateRobotRoomTCP(wanfaId, groupId, jedis0, jedis11); - } - } - } catch (Exception e) { - log.error("处理群组玩法配置变化时发生错误", e); - } - }); - } - - /** - * 获取房间ID - */ - private String getRedisChannelRoomId(String channel) { - if (channel.startsWith("__keyspace@0__:room:")) { - return "room:" + channel.substring("__keyspace@0__:room:".length()); - } - return null; - } - - /** - * 停止监听 - */ - public void stopListening() { - try { - this.unsubscribe(); - executorService.shutdown(); - try { - //等待现有任务完成 - if (!executorService.awaitTermination(60, TimeUnit.SECONDS)) { - executorService.shutdownNow(); - //再次等待 - if (!executorService.awaitTermination(60, TimeUnit.SECONDS)) { - log.error("线程池未能正常关闭"); - } - } - } catch (InterruptedException e) { - // 重新中断当前线程 - executorService.shutdownNow(); - Thread.currentThread().interrupt(); - } - log.info("Redis房间监听器已停止"); - } catch (Exception e) { - log.error("停止Redis房间监听器时发生错误", e); - } - } - - /** - * 检查房间中是否已有机器人 - */ - private boolean hasRobotInRoom(String roomId, Jedis jedis0) { - String players = jedis0.hget(roomId, "players"); - Integer playerId = hasRobotInPlayerList(players); - return playerId != null; - } - - /** - * 检查玩家列表中是否包含机器人 - */ - public static Integer hasRobotInPlayerList(String playersStr) { - if (playersStr == null || playersStr.equals("[]")) { - return null; - } - - String playersClean = playersStr.substring(1, playersStr.length() - 1); - String[] playerIds = playersClean.split(","); - - for (String playerIdStr : playerIds) { - try { - int playerId = Integer.parseInt(playerIdStr.trim()); - //检查是否为机器人账户(jiqiren=9998) - String checkSql = String.format("SELECT jiqiren FROM `account` WHERE id = %d", playerId); - ITArray checkArray = DataBase.use().executeQueryByTArray(checkSql); - - if (checkArray.size() > 0) { - ITObject checkObj = checkArray.getTObject(0); - int jiqiren = checkObj.getInt("jiqiren"); - if (jiqiren == 9998) { //是机器人 - return playerId; - } - } - } catch (Exception e) { - log.warn("检查玩家是否为机器人时发生错误: {}", playerIdStr, e); - } - } - return null; - } - - /** - * 检查是否需要为指定玩法和群组创建新房间 通过TCP服务 - */ - private void checkCreateRobotRoomTCP(int wanfaId, int groupId, Jedis jedis0, Jedis jedis11) { - try { - //获取玩法配置中是否允许机器人创建房间 - String playKey = "g{" + groupId + "}:play:" + wanfaId; - String leftoverRobotValue = jedis11.hget(playKey, "leftover_robot"); - String shangxianRobotValue = jedis11.hget(playKey, "shangxian_robot"); - - if (leftoverRobotValue == null || shangxianRobotValue == null) { - return; - } - - int leftoverRobot = Integer.parseInt(leftoverRobotValue); - int shangxianRobot = Integer.parseInt(shangxianRobotValue); - - //检查当前玩法的机器人使用数量 - int currentUsage = robotManager.getRobotUsageCount(wanfaId); - if (leftoverRobot > 0 && currentUsage < shangxianRobot) { - Set roomIds = jedis0.keys("room:*"); - //有效房间数量 - int validRoomCount = 0; - - for (String roomId : roomIds) { - String groupValue = jedis0.hget(roomId, "group"); - String gameValue = jedis0.hget(roomId, "game"); - - if (groupValue == null || gameValue == null) { - continue; - } - - int roomGroup = Integer.parseInt(groupValue); - int roomWanfa = Integer.parseInt(gameValue); - - //检查玩法和群组是否匹配 - if (roomGroup == groupId && roomWanfa == wanfaId) { - int status = Integer.parseInt(jedis0.hget(roomId, "status")); - int maxPlayers = Integer.parseInt(jedis0.hget(roomId, "maxPlayers")); - - //只考虑2人房间 未开始或进行中 - if (maxPlayers == 2 && status < 2) { - String playersStr = jedis0.hget(roomId, "players"); - if (!playersStr.equals("[]")) { - String playersClean = playersStr.substring(1, playersStr.length() - 1); - int currentPlayers = 0; - if (!playersClean.isEmpty()) { - String[] playerIds = playersClean.split(","); - currentPlayers = playerIds.length; - } - if (currentPlayers < maxPlayers) { - validRoomCount++; //未满员的有效房间 - } - } - } - } - } - - //如果没有有效房间(空房间或未满员房间)则通过TCP创建新房间 - if (validRoomCount == 0) { - log.info("检测到群组 {} 和玩法ID {} 没有效房间,通过TCP创建房间: 剩余机器人={}, 当前使用={}, 上限={}",groupId, wanfaId, leftoverRobot, currentUsage, shangxianRobot); - //通过TCP创建新房间 - createRoomForWanfaTCP(groupId, wanfaId, jedis11); - } - } - } catch (Exception e) { - log.error("检查是否需要通过TCP创建房间时发生错误", e); - } - } - - /** - * 通过TCP服务为指定群组和玩法创建房间 - */ - private void createRoomForWanfaTCP(int groupId, int wanfaId, Jedis jedis11) { - //检查玩法配置中的机器人设置 - try { - String playKey = "g{" + groupId + "}:play:" + wanfaId; - String shangxianRobotValue = jedis11.hget(playKey, "shangxian_robot"); - - if (shangxianRobotValue == null) { - return; - } - - int shangxianRobot = Integer.parseInt(shangxianRobotValue); - - if (shangxianRobot != 0) { - int currentUsage = robotManager.getRobotUsageCount(wanfaId); - - if (currentUsage < shangxianRobot) { - RobotMgrTcpClient tcpClient = new RobotMgrTcpClient("127.0.0.1", 8701); - - //获取可用机器人 - List availableRobots = robotManager.getAvailableRobots(1); - if (!availableRobots.isEmpty()) { - RobotInfo robot = availableRobots.get(0); - - //TCP客户端连接到robot_mj_cs - int attempts = 0; - while (!tcpClient.isConnected() && attempts < 10) { - Thread.sleep(100); - attempts++; - } - - //发送创建房间请求 - CompletableFuture future = tcpClient.sendCreateRoomForRobot(groupId, wanfaId, robot.getRobotId()); - - RoomInfo roomInfo = future.get(); - if (roomInfo != null) { - log.info("收到创建房间{}响应:", roomInfo.getRoomId()); - robotManager.connectRobotToRoom(robot, roomInfo); - log.info("成功为玩法ID {} 的房间 {} 添加机器人 {}", wanfaId, roomInfo.getRoomId(), robot.getRobotId()); - } - } - } else { - log.warn("玩法ID {} 已达到机器人使用上限: 当前={}, 上限={}", wanfaId, currentUsage, shangxianRobot); - } - } - } catch (Exception e) { - log.error("通过TCP为群组 {} 和玩法ID {} 创建房间时发生错误", groupId, wanfaId, e); - } - } - - /** - * 房间结束时恢复leftover_robot数量 - */ - private void restoreLeftoverRobotOnRoomEnd(String roomId, int groupId, int wanfaId, String playersStr, Jedis jedis11) { - Integer robotId = hasRobotInPlayerList(playersStr); - if (robotId != null) { - log.info("房间 {} 结束,检测到机器人 {},调用统一断开服务", roomId, robotId); - //调用RobotManager的统一断开服务 - robotManager.safeDisconnectRobot(robotId, groupId, wanfaId, roomId); - } - } - -} \ No newline at end of file diff --git a/game_web/robot_mgr/src/main/java/com/group/robot/connect/RobotDisconnect.java b/game_web/robot_mgr/src/main/java/com/group/robot/connect/RobotDisconnect.java index f21105d..b1d545a 100644 --- a/game_web/robot_mgr/src/main/java/com/group/robot/connect/RobotDisconnect.java +++ b/game_web/robot_mgr/src/main/java/com/group/robot/connect/RobotDisconnect.java @@ -56,7 +56,7 @@ public class RobotDisconnect { //处理对应游戏处理器断开连接 if (robot != null) { - RobotManagerInterface handler = robotManager.getGameHandler(robot.getCurrentWanfaId()); + RobotManagerInterface handler = robotManager.getGameHandler(robot.getWanfaId()); if (handler != null) { handler.disconnectRobot(robot); log.debug("游戏处理器已断开机器人 {} 连接", robotId); diff --git a/game_web/robot_mgr/src/main/java/com/group/robot/connect/RobotMgrTcpClient.java b/game_web/robot_mgr/src/main/java/com/group/robot/connect/RobotMgrTcpClient.java deleted file mode 100644 index cb420fb..0000000 --- a/game_web/robot_mgr/src/main/java/com/group/robot/connect/RobotMgrTcpClient.java +++ /dev/null @@ -1,240 +0,0 @@ -package com.group.robot.connect; - -import java.util.concurrent.CompletableFuture; - -import com.group.Protocol; -import com.group.robot.info.RoomInfo; -import com.taurus.core.entity.ITObject; -import com.taurus.core.entity.TObject; -import com.taurus.core.util.ICallback; -import com.taurus.core.util.Logger; -import taurus.client.MessageResponse; -import taurus.client.NetManager; -import taurus.client.TaurusClient; - -/** - * TCP客户端 - 与robot_mj_cs服务端通信 - */ -public class RobotMgrTcpClient { - - private Logger log = Logger.getLogger(RobotMgrTcpClient.class); - private TaurusClient client; - private volatile boolean isConnected = false; - private volatile boolean isInitialized = false; - private volatile boolean isLoginCompleted = false; - private Thread eventThread; - - /** - * 构造函数 - * @param host 服务器主机地址 - * @param port 服务器端口 - */ - public RobotMgrTcpClient(String host, int port) { - try { - //创建TCP客户端 - this.client = new TaurusClient(host + ":" + port, "10", TaurusClient.ConnectionProtocol.Tcp); - - //启动网络事件处理线程 - startNetEventThread(); - - //连接到服务器 异步 - client.connect(); - - int attempts = 0; - while (!client.isConnected() && attempts < 100) { - try { - Thread.sleep(200); - attempts++; - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - System.err.println("等待连接建立时被中断: " + e.getMessage()); - break; - } - } - - //连接成功 发送握手协议 - if (client.isConnected()) { - log.info("TCP连接已建立 发送握手协议"); - isConnected = true; - isInitialized = true; - - try { - Thread.sleep(500); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - } - - //发送初始化协议 完成握手过程 防止服务端超时断开连接 - sendInitializationProtocol(); - - attempts = 0; - while (!isLoginCompleted && attempts < 50) { - try { - Thread.sleep(200); - attempts++; - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - log.error("等待握手完成被中断: " + e.getMessage()); - break; - } - } - } - } catch (Exception e) { - e.printStackTrace(); - } - } - - /** - * 启动网络事件处理线程 - */ - private void startNetEventThread() { - eventThread = new Thread(() -> { - while (!Thread.currentThread().isInterrupted()) { - NetManager.processEvents(); - try { - Thread.sleep(2); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - break; - } catch (Exception e) { - log.error("网络事件处理错误: " + e.getMessage()); - } - } - }, "RobotMgrTcpClient-NetEventThread"); - - eventThread.setDaemon(true); - eventThread.start(); - } - - /** - * 发送初始化协议到robot_mj_cs服务器 - */ - private void sendInitializationProtocol() { - try { - log.info("发送初始化协议到robot_mj_cs服务器"); - - //构建初始化参数 - ITObject params = TObject.newInstance(); - params.putString("type", "manager_connection"); - params.putString("client", "robot_mgr"); - - //发送初始化协议 - client.send("init_connection", params, new ICallback() { - @Override - public void action(MessageResponse response) { - if (response.returnCode == 0) { - isLoginCompleted = true; - } else { - isLoginCompleted = false; - } - } - }); - } catch (Exception e) { - e.printStackTrace(); - isLoginCompleted = false; - } - } - - /** - * 检查连接状态 - */ - public boolean isConnected() { - return isConnected && isInitialized && isLoginCompleted && client != null && client.isConnected(); - } - - /** - * 发送创建房间协议到robot_mj_cs - * @param groupId 群组ID - * @param wanfaId 玩法ID - * @return CompletableFuture 异步返回房间信息 - */ - public CompletableFuture sendCreateRoomForRobot(int groupId, int wanfaId, int robotId) { - CompletableFuture future = new CompletableFuture<>(); - - if (!isConnected()) { - future.completeExceptionally(new RuntimeException("未连接到robot_mj_cs服务器")); - return future; - } - - try { - //构建请求参数 - ITObject params = TObject.newInstance(); - params.putInt("groupId", groupId); - params.putInt("wanfaId", wanfaId); - params.putInt("robotId", robotId); - - //发送创建房间请求 - client.send(Protocol.CREATE_ROOM_FOR_ROBOT, params, new ICallback() { - @Override - public void action(MessageResponse response) { - if (response.returnCode == 0 && response.messageData != null && - response.messageData.param != null) { - //解析响应数据 - ITObject responseData = response.messageData.param; - RoomInfo roomInfo = new RoomInfo(); - - //设置房间信息 - roomInfo.setRoomId(responseData.getString("roomKey")); - roomInfo.setGroupId(responseData.getInt("groupId")); - roomInfo.setWanfaId(responseData.getInt("wanfaId")); - - //获取游戏服务器地址和端口 - if (responseData.containsKey("server_ip")) { - roomInfo.setGameServerHost(responseData.getString("server_ip")); - } - if (responseData.containsKey("server_port")) { - roomInfo.setGameServerPort(responseData.getInt("server_port")); - } - - future.complete(roomInfo); - log.info("robot_mj_cs创建房间成功: " + roomInfo.getRoomId()); - } else { - future.completeExceptionally(new RuntimeException("创建房间失败,错误码: " + response.returnCode)); - } - } - }); - } catch (Exception e) { - System.err.println("发送创建房间协议时发生错误: " + e.getMessage()); - future.completeExceptionally(e); - } - - return future; - } - - /** - * 关闭连接 - */ - public void close() { - try { - //停止网络事件处理线程 - if (eventThread != null) { - eventThread.interrupt(); - try { - eventThread.join(2000); - } catch (InterruptedException e) { - log.warn("等待事件线程结束时被中断", e); - Thread.currentThread().interrupt(); - } - eventThread = null; - } - //关闭客户端连接 - if (client != null) { - try { - client.killConnection(); - log.debug("已关闭TCP客户端连接"); - } catch (Exception e) { - log.warn("关闭TCP客户端连接时发生异常", e); - } finally { - client = null; - } - } - //重置状态 - isConnected = false; - isInitialized = false; - isLoginCompleted = false; - log.info("RobotMgrTcpClient连接已关闭"); - } catch (Exception e) { - log.error("关闭RobotMgrTcpClient时发生异常", e); - } - } -} \ No newline at end of file diff --git a/game_web/robot_mgr/src/main/java/com/group/robot/handler/MaJiangRobotHandler.java b/game_web/robot_mgr/src/main/java/com/group/robot/handler/MaJiangRobotHandler.java index 06d568b..fba72e4 100644 --- a/game_web/robot_mgr/src/main/java/com/group/robot/handler/MaJiangRobotHandler.java +++ b/game_web/robot_mgr/src/main/java/com/group/robot/handler/MaJiangRobotHandler.java @@ -5,7 +5,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.group.robot.info.RobotInfo; -import com.group.robot.info.RoomInfo; /** @@ -17,17 +16,19 @@ public class MaJiangRobotHandler implements RobotManagerInterface { private final RobotConnectionHandler robotConnectionHandler; public MaJiangRobotHandler() { - this.robotConnectionHandler = new RobotConnectionHandler(); + this.robotConnectionHandler = RobotConnectionHandler.getInstance(); } @Override - public void connectRobot(RobotInfo robot, RoomInfo room) { + public void connectRobot(RobotInfo robot) { try { - log.info("麻将机器人 {} 正在连接到房间 {}", robot.getRobotId(), room.getRoomId()); //连接处理器进行连接 - robotConnectionHandler.connectRobot(robot, room); + robotConnectionHandler.connectRobot(robot); + + //设置机器人连接状态 + robot.setConnected(true); }catch (Exception e) { - log.error("麻将机器人 {} 连接房间 {} 时发生异常", robot.getRobotId(), room.getRoomId(), e); + log.error("麻将机器人 {} 连接游戏服务器时发生异常", robot.getRobotId(), e); robot.setConnected(false); } } @@ -41,9 +42,7 @@ public class MaJiangRobotHandler implements RobotManagerInterface { robotConnectionHandler.disconnectRobot(robot.getRobotId()); robot.setConnected(false); - robot.setCurrentRoomId(null); - robot.setCurrentWanfaId(0); - + log.info("麻将机器人 {} 连接已断开", robot.getRobotId()); } catch (Exception e) { log.error("断开麻将机器人连接时发生错误: " + robot.getRobotId(), e); diff --git a/game_web/robot_mgr/src/main/java/com/group/robot/handler/PokerRobotHandler.java b/game_web/robot_mgr/src/main/java/com/group/robot/handler/PokerRobotHandler.java index 290222e..177da54 100644 --- a/game_web/robot_mgr/src/main/java/com/group/robot/handler/PokerRobotHandler.java +++ b/game_web/robot_mgr/src/main/java/com/group/robot/handler/PokerRobotHandler.java @@ -17,24 +17,21 @@ public class PokerRobotHandler implements RobotManagerInterface { private final RobotConnectionHandler connectionHandler; public PokerRobotHandler() { - this.connectionHandler = new RobotConnectionHandler(); + this.connectionHandler = RobotConnectionHandler.getInstance(); } @Override - public void connectRobot(RobotInfo robot, RoomInfo room) { + public void connectRobot(RobotInfo robot) { try { - log.info("扑克机器人 {} 正在连接到房间 {}", robot.getRobotId(), room.getRoomId()); + log.info("扑克机器人 {} 正在连接到房间 {}", robot.getRobotId(), robot.getRoomId()); //使用连接处理器进行连接 - connectionHandler.connectRobot(robot, room); + connectionHandler.connectRobot(robot); // 设置机器人连接状态和房间信息 robot.setConnected(true); - robot.setCurrentWanfaId(room.getWanfaId()); - robot.setCurrentRoomId(room.getRoomId()); - - log.info("扑克机器人 {} 开始连接到房间 {}, 玩法ID: {}", - robot.getRobotId(), room.getRoomId(), room.getWanfaId()); + + log.info("扑克机器人 {} 开始连接到房间 {}, 玩法ID: {}", robot.getRobotId(), robot.getRoomId(), robot.getWanfaId()); } catch (Exception e) { log.error("扑克机器人连接失败: " + robot.getRobotId(), e); } @@ -49,9 +46,6 @@ public class PokerRobotHandler implements RobotManagerInterface { connectionHandler.disconnectRobot(robot.getRobotId()); robot.setConnected(false); - robot.setCurrentRoomId(null); - robot.setCurrentWanfaId(0); - log.info("扑克机器人 {} 连接已断开", robot.getRobotId()); } catch (Exception e) { log.error("断开扑克机器人连接时发生错误: " + robot.getRobotId(), e); diff --git a/game_web/robot_mgr/src/main/java/com/group/robot/handler/RobotConnectionHandler.java b/game_web/robot_mgr/src/main/java/com/group/robot/handler/RobotConnectionHandler.java index d8bd704..b97c8d2 100644 --- a/game_web/robot_mgr/src/main/java/com/group/robot/handler/RobotConnectionHandler.java +++ b/game_web/robot_mgr/src/main/java/com/group/robot/handler/RobotConnectionHandler.java @@ -1,37 +1,31 @@ package com.group.robot.handler; import java.util.Map; -import java.util.Set; -import java.util.List; -import java.util.ArrayList; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ConcurrentHashMap; -import com.group.robot.connect.RedisRoomListener; +import com.group.Protocol; import com.group.robot.info.RobotInfo; import com.group.robot.RobotManager; import com.group.robot.info.RoomInfo; -import com.taurus.core.entity.ITArray; +import com.group.robot.matcher.RoomWanfaMatcher; import com.taurus.core.entity.TObject; -import com.taurus.core.plugin.database.DataBase; +import com.taurus.core.util.ICallback; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import taurus.client.MessageResponse; import taurus.client.SocketCode; import taurus.client.TaurusClient; import taurus.client.Message; -import taurus.client.business.AccountBusiness; -import taurus.client.business.GroupRoomBusiness; import com.taurus.core.entity.ITObject; import com.taurus.core.events.Event; import com.taurus.core.events.IEventListener; -import com.taurus.core.plugin.redis.Redis; -import com.taurus.core.util.StringUtil; -import redis.clients.jedis.Jedis; /** * 机器人连接处理器 - 将机器人连接到游戏服务器并准备 */ public class RobotConnectionHandler { + private static volatile RobotConnectionHandler instance; private static final Logger log = LoggerFactory.getLogger(RobotConnectionHandler.class); //机器人ID到客户端连接的映射 @@ -81,54 +75,44 @@ public class RobotConnectionHandler { public void setGameId(int gameId) { this.gameId = gameId; } } - public RobotConnectionHandler() { + private RobotConnectionHandler() { this.robotManager = RobotManager.getRobotManager(); } + public static RobotConnectionHandler getInstance() { + if (instance == null) { + synchronized (RobotConnectionHandler.class) { + if (instance == null) { + instance = new RobotConnectionHandler(); + } + } + } + return instance; + } + /** - * 连接机器人到指定房间并准备 + * 连接机器人到游戏服务器 */ - public void connectRobot(RobotInfo robot, RoomInfo room) { + public void connectRobot(RobotInfo robot) { //异步执行连接逻辑 CompletableFuture.runAsync(() -> { try { - log.info("开始连接机器人 {} 到房间 {}, 玩法ID: {}", robot.getRobotId(), room.getRoomId(), room.getWanfaId()); - - //获取机器人账户信息 - RobotAccountInfo accountInfo = getRobotAccountInfo(robot.getRobotId(), room.getGroupId()); - if (accountInfo == null) { - log.error("无法获取机器人 {} 的账户信息", robot.getRobotId()); - return; - } - - //根据玩法ID获取服务器地址 - String serverAddress = getGameServerAddress(room.getWanfaId()); - //创建TCP客户端连接 - TaurusClient client = new TaurusClient(serverAddress, "game", TaurusClient.ConnectionProtocol.Tcp); + log.info("开始连接机器人 {} 到游戏服务器,玩法ID: {}", robot.getRobotId(), robot.getWanfaId()); + //TCP客户端连接 + TaurusClient client = new TaurusClient(getGameServerAddress(robot.getWanfaId()), "game", TaurusClient.ConnectionProtocol.Tcp); client.connect(); //保存客户端连接 robotClients.put(robot.getRobotId(), client); //设置事件监听器 - setupInitializationEventListeners(client, robot, room); + setupInitializationEventListeners(client, robot); - //登录并加入房间 - Thread.sleep(5000); - loginAndJoinRoom(accountInfo, room); - - //登录成功后 - robotAccounts.put(robot.getRobotId(), accountInfo); - - //发送准备请求 - Thread.sleep(1000); - sendReadyRequest(client, accountInfo.getRobotId()); - log.info("机器人 {} 成功连接到房间 {}", robot.getRobotId(), room.getRoomId()); - - //6秒没有玩家加入 则退出房间 - readyTimeRobotExit(accountInfo.getRobotId(), room); + //连接成功后发送初始化协议 + sendInitializationProtocol(client, robot); + log.info("机器人 {} 成功连接到游戏服务器", robot.getRobotId()); } catch (Exception e) { - log.error("连接机器人时发生异常: " + robot.getRobotId(), e); + log.error("连接机器人到游戏服务器时发生异常: " + robot.getRobotId(), e); //清理已经建立的连接 disconnectRobot(robot.getRobotId()); } @@ -138,7 +122,7 @@ public class RobotConnectionHandler { /** * 设置初始化阶段的事件监听器 */ - private void setupInitializationEventListeners(TaurusClient client, RobotInfo robot, RoomInfo room) { + private void setupInitializationEventListeners(TaurusClient client, RobotInfo robot) { //添加连接状态监听器 client.addEventListener(TaurusClient.NetClientEvent.Connect, new IEventListener() { @Override @@ -175,74 +159,6 @@ public class RobotConnectionHandler { }); } - /** - * 登录并加入房间 - */ - private void loginAndJoinRoom(RobotAccountInfo accountInfo, RoomInfo room) { - try { - //登录获取session和token - AccountBusiness accountBusiness = new AccountBusiness(); - - try (Jedis jedis0 = Redis.use().getJedis()){ - //检查Redis中是否存在已有token - Set tokenKeys = jedis0.keys("{user}:" + accountInfo.getRobotId() + "_token"); - ITObject loginResult; - - if (tokenKeys != null && !tokenKeys.isEmpty()) { - log.debug("机器人 {} 存在已有token,直接使用", accountInfo.getRobotId()); - Set tokenSet = jedis0.smembers("{user}:" + accountInfo.getRobotId() + "_token"); - List tokenList = new ArrayList<>(tokenSet); - - accountInfo.setSession("{user}:" + accountInfo.getRobotId()); - if (!tokenList.isEmpty()) { - accountInfo.setToken(tokenList.get(0)); - } else { - //如果没有token 则执行正常登录 - loginResult = accountBusiness.idPasswordLogin(accountInfo.getRobotId(), accountInfo.getPassword()); - accountInfo.setToken(loginResult.getString("token")); - accountInfo.setSession(accountBusiness.getSession()); - } - } else { - log.debug("机器人 {} 执行常规登录", accountInfo.getRobotId()); - //执行正常登录流程 - loginResult = accountBusiness.idPasswordLogin(accountInfo.getRobotId(), accountInfo.getPassword()); - accountInfo.setToken(loginResult.getString("token")); - accountInfo.setSession(accountBusiness.getSession()); - } - } - //加入房间 - GroupRoomBusiness.joinRoom(accountInfo.getGroupId(), room.getRoomId(), accountInfo.getSession(), null); - log.info("机器人 {} 已成功加入房间 {}", accountInfo.getRobotId(), room.getRoomId()); - } catch (Exception e) { - log.error("登录并加入房间时发生异常", e); - } - } - - /** - * 发送准备请求 - */ - private void sendReadyRequest(TaurusClient client, int robotId) { - try { - //获取机器人的账户信息以获取session和token - RobotAccountInfo accountInfo = robotAccounts.get(robotId); - if (accountInfo == null) { - log.error("机器人 {} 的账户信息不存在,无法发送准备请求", robotId); - return; - } - if (StringUtil.isEmpty(accountInfo.getSession()) || StringUtil.isEmpty(accountInfo.getToken())) { - log.error("机器人 {} 的session或token为空,无法发送准备请求", robotId); - return; - } - ITObject readyParam = new TObject(); - readyParam.putString("session", accountInfo.getSession() + "," + accountInfo.getToken()); - client.send("1003", readyParam, response -> { - log.debug("机器人 {} 发送准备请求响应: {}", robotId, response); - }); - } catch (Exception e) { - log.error("发送准备请求时发生异常", e); - } - } - /** * 根据游戏ID获取服务器地址 */ @@ -250,11 +166,9 @@ public class RobotConnectionHandler { //根据玩法ID返回对应的服务器地址 switch (wanfaId) { case 10: //长沙麻将 - return "127.0.0.1:6311"; + return "127.0.0.1:8701"; case 22: //红中麻将 return "8.138.242.190:6421"; - case 108: //转转麻将 - return "8.138.242.190:6841"; case 66: //跑得快 return "8.138.242.190:6841"; default: @@ -263,53 +177,6 @@ public class RobotConnectionHandler { } } - /** - * 获取机器人信息 - */ - private RobotAccountInfo getRobotAccountInfo(int robotId, int groupId) { - try { - //获取机器人信息 - String sql = String.format("SELECT id,acc,nick,portrait,password FROM `account` WHERE id = %d", robotId); - ITArray robotArray = DataBase.use().executeQueryByTArray(sql); - - if (robotArray.size() == 0) { - //数据库中没有 从Redis获取信息 - Jedis jedis = Redis.use("group1_db2").getJedis(); - try { - Map robotData = jedis.hgetAll("{robot}:" + robotId); - if (robotData.isEmpty()) { - log.error("未找到机器人ID {} 的信息", robotId); - return null; - } - - String account = robotData.get("acc"); - String password = robotData.get("password"); - - if (StringUtil.isEmpty(account) || StringUtil.isEmpty(password)) { - log.error("机器人 {} 的信息不完整", robotId); - return null; - } - - return new RobotAccountInfo(robotId, account, password, groupId); - } finally { - jedis.close(); - } - } else { - //数据库获取信息 - ITObject robotObj = robotArray.getTObject(0); - - int id = robotObj.getInt("id"); - String account = robotObj.getString("acc"); - String password = robotObj.getString("password"); - - return new RobotAccountInfo(id, account, password, groupId); - } - } catch (Exception e) { - log.error("获取机器人账户时发生异常: " + robotId, e); - return null; - } - } - /** * 断开机器人连接 */ @@ -339,68 +206,128 @@ public class RobotConnectionHandler { /** * 超时检查 6秒没有玩家加入 则退出房间 */ - private void readyTimeRobotExit(int robotId, RoomInfo room) { + public void readyTimeRobotExit(RobotInfo robot) { CompletableFuture.runAsync(() -> { try { Thread.sleep(6000); - //检查房间内是否只有机器人 - if (ifExitRoom(room)) { - log.info("机器人 {} 准备时间超过6秒且房间人数不足,退出房间", robotId); - //获取客户端连接 - TaurusClient client = robotClients.remove(robotId); - if (client != null) { - //发送离开房间协议 - ITObject param = new TObject(); - client.send("1005", param, response -> { - log.debug("机器人 {} 发送离开房间请求", robotId); - }); - //关闭连接 - client.clearResponse(); - } - //延迟后断开连接 - Thread.sleep(1000); - disconnectRobot(robotId); + log.info("机器人 {} 准备时间超过6秒且房间人数不足,退出房间", robot.getRobotId()); + TaurusClient client = robotClients.get(robot.getRobotId()); + + if (client != null && client.isConnected()) { + //发送离开房间协议 + ITObject param = new TObject(); + client.send("1005", param, response -> { + log.debug("机器人 {} 发送离开房间请求", robot.getRobotId()); + }); + } else { + log.warn("机器人 {} 连接不存在或未激活,跳过离开房间操作", robot.getRobotId()); } + + //延迟后断开连接 + Thread.sleep(1000); + disconnectRobot(robot.getRobotId()); } catch (InterruptedException e) { - log.debug("超时检查线程被中断: {}", robotId); + log.debug("超时检查线程被中断: {}", robot.getRobotId()); Thread.currentThread().interrupt(); - } catch (Exception e) { - log.error("超时检查过程中发生异常", e); } }); } /** - * 检查是否退出房间 + * 发送初始化协议 */ - private boolean ifExitRoom(RoomInfo room) { - try { - Jedis jedis0 = Redis.use().getJedis(); - try { - String players = jedis0.hget(room.getRoomId(), "players"); - if (players != null && !players.equals("[]")) { - Integer robotInRoom = RedisRoomListener.hasRobotInPlayerList(players); - - //计算房间总人数 - String playersClean = players.substring(1, players.length() - 1); - String[] playerIds = playersClean.split(","); - int totalPlayers = 0; - for (String playerIdStr : playerIds) { - playerIdStr = playerIdStr.trim(); - if (!playerIdStr.isEmpty()) { - totalPlayers++; - } - } - - //如果机器人在房间中 且房间总人数小于2人 则退出房间 - return robotInRoom != null && totalPlayers < 2; - } - } finally { - jedis0.close(); - } - } catch (Exception e) { - log.error("检查房间玩家数量时发生异常", e); + private void sendInitializationProtocol(TaurusClient client, RobotInfo robot) { + if (client == null || !client.isConnected()) { + log.warn("机器人 {} 没有有效的TCP连接,无法发送初始化协议", robot.getRobotId()); + return; } - return true; + + ITObject param = new TObject(); + param.putString("type", "manager_connection"); + param.putString("client", "robot_mgr"); + param.putString("session", robot.getSession() + "," + robot.getToken()); + client.send("init_connection", param, response -> { + if (response != null && response.returnCode == 0) { + log.info("机器人 {} 初始化协议发送成功", robot.getRobotId()); + } + }); } + + /** + * 发送准备消息给指定机器人 + */ + public void sendReadyMessage(RobotInfo robot) { + TaurusClient client = robotClients.get(robot.getRobotId()); + + if (client == null || !client.isConnected()) { + log.warn("机器人 {} 没有有效的TCP连接,无法发送准备消息", robot.getRobotId()); + return; + } + + ITObject readyParam = new TObject(); + readyParam.putString("session", robot.getSession() + "," + robot.getToken()); + client.send("1003", readyParam, response -> { + log.debug("机器人 {} 发送准备请求响应: {}", robot.getRobotId(), response); + }); + } + + /** + * 回调接口 + */ + public interface RoomCreatedCallback { + void onRoomCreated(RobotInfo robot, int groupId, String roomId, int wanfaId); + } + + private RoomCreatedCallback roomCreatedCallback; + + public void setRoomCreatedCallback(RoomCreatedCallback callback) { + this.roomCreatedCallback = callback; + } + + /** + * 发送创建房间请求 + */ + public void sendCreateRoom(RobotInfo robot, int groupId, int wanfaId) { + CompletableFuture future = new CompletableFuture<>(); + TaurusClient client = robotClients.get(robot.getRobotId()); + if (!client.isConnected()) { + log.warn("机器人 {} 的TCP连接未激活,无法发送创建房间请求", robot.getRobotId()); + robotClients.remove(robot.getRobotId()); + return; + } + + ITObject param = new TObject(); + param.putInt("groupId", groupId); + param.putInt("wanfaId", wanfaId); + param.putInt("robotId", robot.getRobotId()); + param.putString("session", robot.getSession() + "," + robot.getToken()); + client.send(Protocol.CREATE_ROOM_FOR_ROBOT, param, response -> { + if (response != null && response.returnCode == 0) { + ITObject responseData = response.messageData.param; + String roomId = responseData.getString("roomKey"); + log.info("机器人 {} 成功创建房间 {}", robot.getRobotId(), roomId); + if (roomCreatedCallback != null) { + roomCreatedCallback.onRoomCreated(robot, groupId, roomId, wanfaId); + } + } + }); + /*client.send(Protocol.CREATE_ROOM_FOR_ROBOT, param, new ICallback() { + @Override + public void action(MessageResponse response) { + if (response.returnCode == 0) { + //解析响应数据 + ITObject responseData = response.messageData.param; + RoomInfo roomInfo = new RoomInfo(); + + //RoomWanfaMatcher.robotJoinRoom(groupId, responseData.getString("roomKey"), wanfaId, true); + + future.complete(roomInfo); + log.info("robot_mj_cs创建房间成功: " + roomInfo.getRoomId()); + } else { + future.completeExceptionally(new RuntimeException("创建房间失败,错误码: " + response.returnCode)); + } + } + });*/ + } + } \ No newline at end of file diff --git a/game_web/robot_mgr/src/main/java/com/group/robot/info/RobotInfo.java b/game_web/robot_mgr/src/main/java/com/group/robot/info/RobotInfo.java index 9c0a948..0c7deab 100644 --- a/game_web/robot_mgr/src/main/java/com/group/robot/info/RobotInfo.java +++ b/game_web/robot_mgr/src/main/java/com/group/robot/info/RobotInfo.java @@ -12,9 +12,11 @@ public class RobotInfo { private boolean isOnline; //是否在线 private boolean isConnected; //是否已连接到游戏服务器 private boolean isConnecting; //是否正在连接 - private String currentRoomId; //当前所在房间ID - private int currentWanfaId; //当前玩法ID + private String roomId; //当前所在房间ID + private int wanfaId; //当前玩法ID private long lastActiveTime; //最后活跃时间 + private String session; + private String token; public RobotInfo() { this.lastActiveTime = System.currentTimeMillis(); @@ -83,23 +85,23 @@ public class RobotInfo { public void setConnecting(boolean connecting) { isConnecting = connecting; } - - public String getCurrentRoomId() { - return currentRoomId; + + public String getRoomId() { + return roomId; } - - public void setCurrentRoomId(String currentRoomId) { - this.currentRoomId = currentRoomId; + + public void setRoomId(String roomId) { + this.roomId = roomId; } - - public int getCurrentWanfaId() { - return currentWanfaId; + + public int getWanfaId() { + return wanfaId; } - - public void setCurrentWanfaId(int currentWanfaId) { - this.currentWanfaId = currentWanfaId; + + public void setWanfaId(int wanfaId) { + this.wanfaId = wanfaId; } - + public long getLastActiveTime() { return lastActiveTime; } @@ -107,7 +109,24 @@ public class RobotInfo { public void setLastActiveTime(long lastActiveTime) { this.lastActiveTime = lastActiveTime; } - + + public String getSession() { + return session; + } + + public void setSession(String session) { + this.session = session; + } + + public String getToken() { + return token; + } + + public void setToken(String token) { + this.token = token; + } + + @Override public String toString() { return "RobotInfo{" + @@ -115,8 +134,11 @@ public class RobotInfo { ", account='" + account + '\'' + ", isOnline=" + isOnline + ", isConnected=" + isConnected + - ", currentRoomId='" + currentRoomId + '\'' + - ", currentWanfaId=" + currentWanfaId + + ", roomId='" + roomId + '\'' + + ", wanfaId=" + wanfaId + + ", lastActiveTime=" + lastActiveTime + + ", session='" + session + '\'' + + ", token='" + token + '\'' + '}'; } } \ No newline at end of file diff --git a/game_web/robot_mgr/src/main/java/com/group/robot/matcher/RoomWanfaMatcher.java b/game_web/robot_mgr/src/main/java/com/group/robot/matcher/RoomWanfaMatcher.java new file mode 100644 index 0000000..5649356 --- /dev/null +++ b/game_web/robot_mgr/src/main/java/com/group/robot/matcher/RoomWanfaMatcher.java @@ -0,0 +1,271 @@ +package com.group.robot.matcher; + +import java.util.ArrayList; +import java.util.List; +import java.util.Set; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; + +import com.group.robot.RobotManager; +import com.group.robot.handler.RobotConnectionHandler; +import com.group.robot.info.RobotInfo; +import com.taurus.core.entity.ITArray; +import com.taurus.core.entity.ITObject; +import com.taurus.core.plugin.database.DataBase; +import com.taurus.core.plugin.redis.Redis; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import redis.clients.jedis.Jedis; +import taurus.client.business.GroupRoomBusiness; + +/** + * 玩法房间轮询器 - 按玩法定期查询房间 + */ +public class RoomWanfaMatcher { + private static final Logger log = LoggerFactory.getLogger(RoomWanfaMatcher.class); + + private final RobotManager robotManager; + private final int groupId; + private final int wanfaId; + private final Object lock = new Object(); + private volatile ScheduledExecutorService scheduler; + private volatile boolean isRunning = false; + //机器人连接处理器 + private final RobotConnectionHandler robotConnectionHandler; + + public RoomWanfaMatcher(RobotManager robotManager, int groupId, int wanfaId) { + this.robotManager = robotManager; + this.groupId = groupId; + this.wanfaId = wanfaId; + this.scheduler = Executors.newSingleThreadScheduledExecutor(); + this.robotConnectionHandler = RobotConnectionHandler.getInstance(); + + //设置房间创建回调 + this.robotConnectionHandler.setRoomCreatedCallback(this::onRoomCreated); + } + + /** + * 启动轮询 + */ + public void startPolling() { + synchronized(lock) { + if (isRunning) { + return; + } + + if (scheduler == null || scheduler.isShutdown()) { + scheduler = Executors.newSingleThreadScheduledExecutor(); + } + + isRunning = true; + log.info("开始为玩法ID {} 启动房间轮询", wanfaId); + + //10秒轮询一次 + scheduler.scheduleWithFixedDelay(this::pollRooms, 0, 10, TimeUnit.SECONDS); + } + } + + /** + * 轮询房间 + */ + private void pollRooms() { + try { + if (!isRunning) { + return; + } + + try (Jedis jedis0 = Redis.use().getJedis(); Jedis jedis11 = Redis.use("group1_db11").getJedis()) { + Set roomIds = jedis0.keys("room:*"); + if (roomIds.isEmpty()) { + createRobotWanfaRoomTCP(groupId, this.wanfaId); + } + + int groupId = -1; + + for (String roomId : roomIds) { + int wanfaId = Integer.parseInt(jedis0.hget(roomId, "gpid")); + if (wanfaId == this.wanfaId) { + groupId = Integer.parseInt(jedis0.hget(roomId, "group")); + break; + } + } + + if (groupId != -1) { + //检查该玩法是否配置了机器人 + String playKey = "g{" + groupId + "}:play:" + this.wanfaId; + int leftoverRobot = Integer.parseInt(jedis11.hget(playKey, "leftover_robot")); + + if (leftoverRobot > 0) { + //满人房间 + int fullRooms = 0; + //所有房间 + int totalRooms = 0; + List roomsList = new ArrayList<>(); + + //统计所有2人房间 + for (String roomId : roomIds) { + int currentWanfaId = Integer.parseInt(jedis0.hget(roomId, "gpid")); + int status = Integer.parseInt(jedis0.hget(roomId, "status")); + int maxPlayers = Integer.parseInt(jedis0.hget(roomId, "maxPlayers")); + + //处理当前玩法maxPlayers为2的房间 + if (maxPlayers == 2 && currentWanfaId == this.wanfaId && status == 0) { + totalRooms++; + + String playersStr = jedis0.hget(roomId, "players"); + int currentPlayers = 0; + if (!playersStr.equals("[]")) { + String playersClean = playersStr.substring(1, playersStr.length() - 1); + if (!playersClean.isEmpty()) { + String[] playerIds = playersClean.split(","); + currentPlayers = playerIds.length; + } + } + if (currentPlayers == maxPlayers) { + fullRooms++; + } else { + roomsList.add(roomId); + } + } + } + + //该玩法机器人房间满了 创建新房间 + if (fullRooms == totalRooms && totalRooms > 0) { + createRobotWanfaRoomTCP(groupId, this.wanfaId); + } + + for (String roomId : roomsList) { + int group = Integer.parseInt(jedis0.hget(roomId, "group")); + int status = Integer.parseInt(jedis0.hget(roomId, "status")); + + //处理未开始的陪打房间 + if (status == 0) { + String playersStr = jedis0.hget(roomId, "players"); + + //房间没人 加入房间 + if (playersStr.equals("[]")) { + robotJoinRoom(group, roomId, this.wanfaId, true); + } else { + //房间有人 不是机器人则加入房间 + Integer robotInRoom = playerIsRobotRedis(playersStr); + if (robotInRoom == null) { + robotJoinRoom(group, roomId, this.wanfaId, false); + } + } + } + } + } + } + } + } catch (Throwable t) { // 捕获所有Throwable,包括Error + log.error("轮询玩法ID {} 的房间时发生严重错误", wanfaId, t); + } + } + + /** + * 机器人加入房间 + * */ + private void robotJoinRoom(int group, String roomId, int wanfaId, boolean isRobot) { + //检查调度器是否可用 + if (!scheduler.isShutdown()) { + CompletableFuture.runAsync(() -> { + try { + RobotInfo robot = robotManager.getLoggedInRobotForWanfa(wanfaId); + //加入房间 + GroupRoomBusiness.joinRoom(group, roomId, robot.getSession(), null); + + //准备 + Thread.sleep(1000); + robotConnectionHandler.sendReadyMessage(robot); + + if (isRobot) { + //6秒没有玩家加入 则退出房间 + robotConnectionHandler.readyTimeRobotExit(robot); + } + } catch (Exception e) { + log.error("机器人加入房间时发生错误: groupId={}, roomId={}, wanfaId={}, isRobot={}", group, roomId, wanfaId, isRobot, e); + } + }); + } + } + + /** + * 通过TCP服务为指定群组和玩法创建房间 + */ + private void createRobotWanfaRoomTCP(int groupId, int wanfaId) { + try { + RobotInfo robot = robotManager.getLoggedInRobotForWanfa(wanfaId); + if (robot == null) { + log.warn("未能获取到玩法ID {} 的已登录机器人", wanfaId); + return; + } + //使用机器人连接处理器发送创建房间请求 + robotConnectionHandler.sendCreateRoom(robot, groupId, wanfaId); + } catch (Exception e) { + log.error("创建玩法ID {} 的房间时发生错误", wanfaId, e); + } + } + + /** + * 房间创建成功后的回调方法 + */ + private void onRoomCreated(RobotInfo robot, int groupId, String roomId, int wanfaId) { + //加入新创建的房间 + robotJoinRoom(groupId, roomId, wanfaId, true); + } + + /** + * 检查玩家列表中是否包含机器人 + */ + public static Integer playerIsRobotRedis(String playersStr) { + String playersClean = playersStr.substring(1, playersStr.length() - 1); + String[] playerIds = playersClean.split(","); + + for (String playerIdStr : playerIds) { + try { + int playerId = Integer.parseInt(playerIdStr.trim()); + //检查是否为机器人账户(jiqiren=9998) + String checkSql = String.format("SELECT jiqiren FROM `account` WHERE id = %d", playerId); + ITArray checkArray = DataBase.use().executeQueryByTArray(checkSql); + + if (checkArray.size() > 0) { + ITObject checkObj = checkArray.getTObject(0); + int jiqiren = checkObj.getInt("jiqiren"); + if (jiqiren == 9998) { //是机器人 + return playerId; + } + } + } catch (Exception e) { + log.warn("检查玩家是否为机器人时发生错误: {}", playerIdStr, e); + } + } + return null; + } + + public boolean isRunning() { + return isRunning; + } + + /** + * 停止轮询 + */ + public void stopPolling() { + synchronized(lock) { + isRunning = false; + if (scheduler != null && !scheduler.isShutdown()) { + scheduler.shutdown(); + try { + if (!scheduler.awaitTermination(5, TimeUnit.SECONDS)) { + scheduler.shutdownNow(); + } + } catch (InterruptedException e) { + scheduler.shutdownNow(); + Thread.currentThread().interrupt(); + } + } + } + log.info("玩法ID {} 的房间轮询已停止", wanfaId); + } +} \ No newline at end of file diff --git a/game_web/robot_mgr/src/test/java/com/group/robot/TcpTest.java b/game_web/robot_mgr/src/test/java/com/group/robot/TcpTest.java deleted file mode 100644 index 52f8ee5..0000000 --- a/game_web/robot_mgr/src/test/java/com/group/robot/TcpTest.java +++ /dev/null @@ -1,1124 +0,0 @@ -package com.group.robot; - -import com.group.MainServer; -import com.group.robot.connect.RedisRoomListener; -import com.group.robot.info.RoomInfo; -import com.taurus.core.plugin.PluginService; -import com.taurus.core.plugin.redis.Redis; -import com.taurus.core.plugin.database.DataBase; -import com.taurus.core.entity.ITArray; -import com.taurus.core.entity.ITObject; -import com.taurus.web.JettyServer; -import redis.clients.jedis.Jedis; - -import java.io.File; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.Scanner; -import java.util.Random; -import java.util.concurrent.*; - -/** - * 机器人系统测试类 - 模拟客户端行为,触发Redis变化,验证RedisRoomListener响应 - * 只负责模拟用户操作,不直接处理机器人逻辑 - */ -public class TcpTest { - - private static MainServer mainServer; - private static volatile boolean keepRunning = true; - private static ScheduledExecutorService scheduler; - private static Scanner scanner; - private static RedisRoomListener redisRoomListener; - - // 测试配置 - private static final int[] TEST_GROUP_IDS = {100000}; - private static final int[] TEST_GAME_IDS = {10}; // , 22, 108, 66长沙麻将、红中麻将、转转麻将、跑得快 - private static final String[] GAME_NAMES = {"长沙麻将"};//, "红中麻将", "转转麻将", "跑得快" - - // 数据库常量 - private static final int ROBOT_TYPE = 9998; - - public static void main(String[] args) { - System.out.println("=== 机器人系统客户端模拟测试 ==="); - System.out.println("本测试模拟客户端行为,验证RedisRoomListener监听处理"); - System.out.println("请选择测试模式:"); - System.out.println("1. 完整系统测试(模拟真实用户场景)"); - System.out.println("2. 快速Redis操作测试(直接修改Redis)"); - - try { - int mode = getUserChoice(); - - switch (mode) { - case 1: - testFullSystem(); - break; - case 2: - testRedisDirect(); - break; - default: - System.out.println("无效的选择,使用默认模式1"); - testFullSystem(); - } - } catch (Exception e) { - System.err.println("测试过程中发生错误: " + e.getMessage()); - e.printStackTrace(); - } - } - - private static int getUserChoice() { - try { - scanner = new Scanner(System.in); - System.out.print("请输入选择 (1 或 2): "); - return scanner.nextInt(); - } catch (Exception e) { - return 1; - } - } - - /** - * 完整系统测试 - 模拟真实用户场景 - */ - public static void testFullSystem() { - JettyServer server = null; - - // 启动控制台监听线程 - startConsoleListener(); - - try { - System.out.println("=== 开始完整系统测试 ==="); - System.out.println("测试目标:模拟用户行为,验证RedisRoomListener响应"); - System.out.println("输入 'stop' 停止测试"); - - // 1. 初始化环境 - System.out.println(">>> 1. 初始化环境..."); - initializeEnvironment(); - - // 2. 启动Web服务器 - System.out.println(">>> 2. 启动Web服务器..."); - server = startWebServer(); - - // 3. 启动MainServer(这会初始化RobotManager和RedisRoomListener) - System.out.println(">>> 4. 启动MainServer..."); - startMainServer(); - - // 4. 获取RedisRoomListener(通过MainServer间接获取) - System.out.println(">>> 4. 初始化测试数据..."); - initTestData(); - - System.out.println("\n系统启动完成,开始模拟用户行为..."); - System.out.println("RedisRoomListener正在监听Redis变化"); - System.out.println("输入 'help' 查看可用命令\n"); - - // 5. 启动持续模拟任务 - System.out.println(">>> 5. 启动持续模拟任务..."); - startContinuousSimulation(); - - // 6. 保持程序运行 - while (keepRunning) { - Thread.sleep(1000); - } - - System.out.println("\n收到停止信号,正在停止测试..."); - - } catch (Exception e) { - System.err.println("完整系统测试过程中发生错误: " + e.getMessage()); - e.printStackTrace(); - } finally { - // 8. 关闭系统 - System.out.println("\n>>> 8. 关闭系统..."); - cleanupResources(server); - } - - System.out.println("\n=== 完整系统测试完成 ==="); - } - - - /** - * 启动持续模拟任务 - 模拟用户行为 - */ - private static void startContinuousSimulation() { - scheduler = Executors.newScheduledThreadPool(2); - - // 任务1:定期状态监控(每30秒) - scheduler.scheduleAtFixedRate(() -> { - try { - monitorSystemStatus(); - } catch (Exception e) { - System.err.println("状态监控任务失败: " + e.getMessage()); - } - }, 0, 30, TimeUnit.SECONDS); - - // 任务2:持续模拟用户行为(每60-120秒一次) - scheduler.scheduleAtFixedRate(() -> { - try { - simulateUserBehavior(); - } catch (Exception e) { - System.err.println("用户行为模拟失败: " + e.getMessage()); - } - }, 10, getRandomInterval(60, 120), TimeUnit.SECONDS); - - System.out.println("持续模拟任务已启动"); - } - - /** - * 模拟用户行为 - 核心方法 - * 只操作Redis,不直接处理机器人逻辑 - */ - private static void simulateUserBehavior() { - Random random = new Random(); - - try (Jedis jedis0 = Redis.use().getJedis(); - Jedis jedis11 = Redis.use("group1_db11").getJedis()) { - - // 随机选择测试参数 - int groupId = TEST_GROUP_IDS[random.nextInt(TEST_GROUP_IDS.length)]; - int gameId = TEST_GAME_IDS[random.nextInt(TEST_GAME_IDS.length)]; - String gameName = GAME_NAMES[getGameIndex(gameId)]; - - System.out.println("\n>>> 模拟用户行为 [" + new java.util.Date() + "]"); - System.out.println(" 群组ID: " + groupId); - System.out.println(" 玩法ID: " + gameId + " (" + gameName + ")"); - - // 1. 随机决定操作类型 - int actionType = random.nextInt(3); // 0:创建房间, 1:玩家加入, 2:修改配置 - - switch (actionType) { - case 0: - // 创建房间 - simulateCreateRoom(jedis0, groupId, gameId, gameName); - break; - case 1: - // 玩家加入现有房间 - simulatePlayerJoin(jedis0, jedis11, groupId, gameId); - break; - case 2: - // 修改玩法配置 - simulateModifyConfig(jedis11, groupId, gameId); - break; - } - - System.out.println(" 用户行为模拟完成\n"); - - } catch (Exception e) { - System.err.println(" 模拟用户行为失败: " + e.getMessage()); - } - } - - /** - * 模拟创建房间 - */ - private static void simulateCreateRoom(Jedis jedis0, int groupId, int gameId, String gameName) { - Random random = new Random(); - - try { - // 生成房间ID - String roomId = "room:0_" + random.nextInt(1000); - - // 模拟真实玩家ID(大数字,避免与机器人ID冲突) - long creatorId = 10000000L + random.nextInt(90000000); - - // 创建房间数据 - Map roomData = new HashMap<>(); - roomData.put("game", String.valueOf(gameId)); - roomData.put("group", String.valueOf(groupId)); - roomData.put("status", "0"); // 未开始 - roomData.put("maxPlayers", "2"); - roomData.put("players", "[]"); - roomData.put("creator", String.valueOf(creatorId)); - roomData.put("createTime", String.valueOf(System.currentTimeMillis())); - roomData.put("roomKey", roomId); - - // 写入Redis - RedisRoomListener会监听到这个变化 - jedis0.hmset(roomId, roomData); - - System.out.println(" 创建房间: " + roomId); - System.out.println(" 玩法: " + gameName + " (" + gameId + ")"); - System.out.println(" 创建者: " + creatorId + " (真实玩家)"); - System.out.println(" 状态: 未开始,等待玩家加入"); - - // 等待5-10秒,观察RedisRoomListener是否触发机器人匹配 - int waitTime = random.nextInt(6) + 5; - System.out.println(" 等待 " + waitTime + " 秒观察系统响应..."); - Thread.sleep(waitTime * 1000L); - - // 检查房间状态 - Map updatedRoom = jedis0.hgetAll(roomId); - if (updatedRoom != null) { - String players = updatedRoom.get("players"); - System.out.println(" 当前玩家: " + players); - - // 检查是否有机器人加入 - if (players != null && !players.equals("[]")) { - String[] playerIds = players.substring(1, players.length() - 1).split(","); - for (String playerIdStr : playerIds) { - try { - int playerId = Integer.parseInt(playerIdStr.trim()); - // 检查是否为机器人 - if (isRobot(playerId)) { - System.out.println(" ✓ 机器人 " + playerId + " 已自动加入房间"); - } else if (playerId != creatorId) { - System.out.println(" ✓ 真实玩家 " + playerId + " 加入房间"); - } - } catch (Exception e) { - // 忽略解析错误 - } - } - } - } - - } catch (Exception e) { - System.err.println("模拟创建房间失败: " + e.getMessage()); - } - } - - /** - * 模拟玩家加入房间 - */ - private static void simulatePlayerJoin(Jedis jedis0, Jedis jedis11, int groupId, int gameId) { - Random random = new Random(); - - try { - // 查找现有房间 - Set roomKeys = jedis0.keys("room:*"); - String targetRoomId = null; - Map targetRoom = null; - - for (String roomKey : roomKeys) { - Map roomData = jedis0.hgetAll(roomKey); - if (roomData != null) { - String roomGroup = roomData.get("group"); - String roomGame = roomData.get("game"); - String status = roomData.get("status"); - - if (roomGroup != null && roomGame != null && "0".equals(status)) { - int roomGroupId = Integer.parseInt(roomGroup); - int roomGameId = Integer.parseInt(roomGame); - - if (roomGroupId == groupId && roomGameId == gameId) { - targetRoomId = roomKey; - targetRoom = roomData; - break; - } - } - } - } - - if (targetRoomId == null) { - System.out.println(" 没有找到合适的房间,先创建一个新房间"); - simulateCreateRoom(jedis0, groupId, gameId, GAME_NAMES[getGameIndex(gameId)]); - return; - } - - // 检查房间是否已满 - String playersStr = targetRoom.get("players"); - int currentPlayers = 0; - if (playersStr != null && !playersStr.equals("[]")) { - String cleanPlayers = playersStr.substring(1, playersStr.length() - 1); - if (!cleanPlayers.isEmpty()) { - String[] playerIds = cleanPlayers.split(","); - currentPlayers = playerIds.length; - } - } - - int maxPlayers = Integer.parseInt(targetRoom.get("maxPlayers")); - - if (currentPlayers >= maxPlayers) { - System.out.println(" 房间 " + targetRoomId + " 已满,无法加入"); - return; - } - - // 模拟真实玩家加入 - long newPlayerId = 10000000L + random.nextInt(90000000); - - // 更新玩家列表 - if (playersStr.equals("[]")) { - playersStr = "[" + newPlayerId + "]"; - } else { - String cleanPlayers = playersStr.substring(1, playersStr.length() - 1); - playersStr = "[" + cleanPlayers + "," + newPlayerId + "]"; - } - - jedis0.hset(targetRoomId, "players", playersStr); - - System.out.println(" 玩家 " + newPlayerId + " 加入房间: " + targetRoomId); - System.out.println(" 当前玩家: " + playersStr); - - // 等待观察 - int waitTime = random.nextInt(5) + 3; - System.out.println(" 等待 " + waitTime + " 秒观察系统响应..."); - Thread.sleep(waitTime * 1000L); - - // 检查更新后的房间状态 - Map updatedRoom = jedis0.hgetAll(targetRoomId); - if (updatedRoom != null) { - String updatedPlayers = updatedRoom.get("players"); - System.out.println(" 更新后玩家: " + updatedPlayers); - } - - } catch (Exception e) { - System.err.println("模拟玩家加入失败: " + e.getMessage()); - } - } - - /** - * 模拟修改配置 - */ - private static void simulateModifyConfig(Jedis jedis11, int groupId, int gameId) { - Random random = new Random(); - - try { - String playKey = "g{" + groupId + "}:play:" + gameId; - Map config = jedis11.hgetAll(playKey); - - if (config.isEmpty()) { - // 创建新配置 - Map newConfig = new HashMap<>(); - newConfig.put("shangxian_robot", String.valueOf(random.nextInt(5) + 1)); - newConfig.put("leftover_robot", String.valueOf(random.nextInt(5) + 1)); - newConfig.put("name", GAME_NAMES[getGameIndex(gameId)]); - newConfig.put("gameId", String.valueOf(gameId)); - newConfig.put("groupId", String.valueOf(groupId)); - newConfig.put("robot_room", "1"); - - jedis11.hmset(playKey, newConfig); - - System.out.println(" 创建玩法配置: " + playKey); - System.out.println(" 机器人上限: " + newConfig.get("shangxian_robot")); - System.out.println(" 剩余机器人: " + newConfig.get("leftover_robot")); - } else { - // 修改现有配置 - int currentLeftover = Integer.parseInt(config.getOrDefault("leftover_robot", "0")); - int newLeftover = Math.max(0, currentLeftover + (random.nextInt(3) - 1)); - - jedis11.hset(playKey, "leftover_robot", String.valueOf(newLeftover)); - - System.out.println(" 修改玩法配置: " + playKey); - System.out.println(" 剩余机器人: " + currentLeftover + " → " + newLeftover); - - // 随机修改其他配置 - if (random.nextBoolean()) { - int currentShangxian = Integer.parseInt(config.getOrDefault("shangxian_robot", "0")); - int newShangxian = Math.max(1, currentShangxian + (random.nextInt(3) - 1)); - jedis11.hset(playKey, "shangxian_robot", String.valueOf(newShangxian)); - System.out.println(" 机器人上限: " + currentShangxian + " → " + newShangxian); - } - } - - System.out.println(" RedisRoomListener将监听到配置变化,可能触发房间创建"); - - } catch (Exception e) { - System.err.println("模拟修改配置失败: " + e.getMessage()); - } - } - - /** - * 检查是否为机器人 - */ - private static boolean isRobot(int playerId) { - try { - String sql = "SELECT jiqiren FROM `account` WHERE id = " + playerId; - ITArray result = DataBase.use().executeQueryByTArray(sql); - if (result != null && result.size() > 0) { - ITObject obj = result.getTObject(0); - return obj.getInt("jiqiren") == ROBOT_TYPE; - } - } catch (Exception e) { - // 忽略查询错误 - } - return false; - } - - /** - * 启动控制台监听 - */ - private static void startConsoleListener() { - Thread consoleThread = new Thread(() -> { - scanner = new Scanner(System.in); - - System.out.println("\n=== 测试控制台命令列表 ==="); - System.out.println(" status - 显示系统状态"); - System.out.println(" create - 手动创建房间"); - System.out.println(" join - 手动加入房间"); - System.out.println(" config - 手动修改配置"); - System.out.println(" rooms - 查看房间列表"); - System.out.println(" robots - 查看机器人信息"); - System.out.println(" stop - 停止测试程序"); - System.out.println(" help - 显示此帮助信息"); - - while (keepRunning) { - try { - System.out.print("\n测试> "); - String input = scanner.nextLine().trim(); - - if (input.isEmpty()) continue; - - String command = input.toLowerCase(); - - switch (command) { - case "status": - showSystemStatus(); - break; - - case "create": - manualCreateRoom(); - break; - - case "join": - manualJoinRoom(); - break; - - case "config": - manualModifyConfig(); - break; - - case "rooms": - showRoomList(); - break; - - case "robots": - showRobotInfo(); - break; - - case "stop": - keepRunning = false; - System.out.println("正在停止测试..."); - break; - - case "help": - System.out.println("命令列表:"); - System.out.println(" status - 显示系统状态"); - System.out.println(" create - 手动创建房间"); - System.out.println(" join - 手动加入房间"); - System.out.println(" config - 手动修改配置"); - System.out.println(" rooms - 查看房间列表"); - System.out.println(" robots - 查看机器人信息"); - System.out.println(" stop - 停止测试程序"); - System.out.println(" help - 显示此帮助信息"); - break; - - default: - System.out.println("未知命令,输入 'help' 查看可用命令"); - } - } catch (Exception e) { - System.out.println("命令执行错误: " + e.getMessage()); - } - } - - scanner.close(); - }); - - consoleThread.setDaemon(true); - consoleThread.start(); - } - - /** - * 快速Redis操作测试 - */ - public static void testRedisDirect() { - try { - System.out.println("\n=== 快速Redis操作测试 ==="); - System.out.println("直接操作Redis,验证RedisRoomListener响应"); - - // 初始化环境 - initializeEnvironment(); - - System.out.println(">>> 1. 检查Redis连接..."); - try (Jedis jedis = Redis.use().getJedis()) { - String result = jedis.ping(); - System.out.println(" Redis连接: " + ("PONG".equals(result) ? "正常" : "异常")); - } - - System.out.println(">>> 2. 创建测试房间..."); - try (Jedis jedis0 = Redis.use().getJedis()) { - Random random = new Random(); - String roomId = "room:test_direct_" + System.currentTimeMillis(); - - Map roomData = new HashMap<>(); - roomData.put("game", "10"); - roomData.put("group", "100000"); - roomData.put("status", "0"); - roomData.put("maxPlayers", "2"); - roomData.put("players", "[]"); - roomData.put("creator", "1000001"); - roomData.put("createTime", String.valueOf(System.currentTimeMillis())); - - jedis0.hmset(roomId, roomData); - System.out.println(" 已创建房间: " + roomId); - System.out.println(" RedisRoomListener将监听到此变化"); - } - - System.out.println(">>> 3. 等待10秒观察系统响应..."); - Thread.sleep(10000); - - System.out.println(">>> 4. 检查房间状态..."); - try (Jedis jedis0 = Redis.use().getJedis()) { - String roomId = "room:test_direct_*"; - Set rooms = jedis0.keys(roomId); - for (String room : rooms) { - Map roomData = jedis0.hgetAll(room); - System.out.println(" 房间: " + room); - System.out.println(" 玩家: " + roomData.get("players")); - } - } - - System.out.println("快速Redis操作测试完成"); - - } catch (Exception e) { - System.err.println("快速Redis操作测试失败: " + e.getMessage()); - e.printStackTrace(); - } - } - - /** - * 初始化环境 - */ - private static void initializeEnvironment() { - try { - // 设置配置路径 - String configPath = new File("game_web/robot_mgr/src/main/webapp").getAbsolutePath(); - System.setProperty("taurus.config.path", configPath); - System.setProperty("WORKDIR", configPath); - - // 初始化Taurus插件 - PluginService.me().loadConfig(); - - System.out.println("环境初始化完成"); - } catch (Exception e) { - System.err.println("初始化环境失败: " + e.getMessage()); - throw new RuntimeException("环境初始化失败", e); - } - } - - /** - * 启动Web服务器 - */ - private static JettyServer startWebServer() { - try { - // 创建Jetty服务器实例 - JettyServer server = new JettyServer("game_web/robot_mgr/src/main/webapp", 6669, "/"); - - // 启动Jetty服务器 - Thread serverThread = new Thread(() -> { - try { - server.start(); - System.out.println("Web服务器启动完成"); - } catch (Exception e) { - System.err.println("启动服务器时发生错误: " + e.getMessage()); - e.printStackTrace(); - } - }); - - serverThread.setDaemon(true); - serverThread.start(); - - // 等待服务器启动 - Thread.sleep(2000); - - return server; - } catch (Exception e) { - System.err.println("启动Web服务器失败: " + e.getMessage()); - throw new RuntimeException("Web服务器启动失败", e); - } - } - - /** - * 启动MainServer - */ - private static void startMainServer() { - try { - mainServer = new MainServer(); - mainServer.onStart(); - - System.out.println("MainServer启动完成"); - System.out.println(" RobotManager已初始化"); - System.out.println(" RedisRoomListener已启动监听"); - - } catch (Exception e) { - System.err.println("启动MainServer失败: " + e.getMessage()); - throw new RuntimeException("MainServer启动失败", e); - } - } - - /** - * 初始化测试数据 - */ - private static void initTestData() { - try (Jedis jedis11 = Redis.use("group1_db11").getJedis()) { - System.out.println("初始化测试数据..."); - - // 为每个群组和玩法初始化默认配置 - for (int groupId : TEST_GROUP_IDS) { - for (int i = 0; i < TEST_GAME_IDS.length; i++) { - int gameId = TEST_GAME_IDS[i]; - String gameName = GAME_NAMES[i]; - - String playKey = "g{" + groupId + "}:play:" + gameId; - - Map playMap = new HashMap<>(); - playMap.put("shangxian_robot", "3"); - playMap.put("leftover_robot", "3"); - playMap.put("name", gameName); - playMap.put("gameId", String.valueOf(gameId)); - playMap.put("groupId", String.valueOf(groupId)); - playMap.put("robot_room", "1"); - - jedis11.hmset(playKey, playMap); - } - } - System.out.println("默认玩法配置已初始化"); - - } catch (Exception e) { - System.err.println("初始化测试数据失败: " + e.getMessage()); - } - } - - /** - * 监控系统状态 - */ - private static void monitorSystemStatus() { - try { - System.out.println("\n=== 系统状态监控 [" + new java.util.Date() + "] ==="); - - // Redis房间统计 - try (Jedis jedis0 = Redis.use().getJedis()) { - Set roomKeys = jedis0.keys("room:*"); - int totalRooms = roomKeys.size(); - int testRooms = 0; - int activeRooms = 0; - - for (String roomKey : roomKeys) { - if (roomKey.contains("0_")) { - testRooms++; - } - Map roomData = jedis0.hgetAll(roomKey); - if (roomData != null && "0".equals(roomData.get("status"))) { - activeRooms++; - } - } - - System.out.println("房间统计:"); - System.out.println(" 总房间数: " + totalRooms); - System.out.println(" 测试房间数: " + testRooms); - System.out.println(" 活跃房间数: " + activeRooms); - } - - // 玩法配置状态 - try (Jedis jedis11 = Redis.use("group1_db11").getJedis()) { - System.out.println("玩法配置状态:"); - for (int i = 0; i < Math.min(3, TEST_GAME_IDS.length); i++) { - String playKey = "g{" + TEST_GROUP_IDS[0] + "}:play:" + TEST_GAME_IDS[i]; - Map config = jedis11.hgetAll(playKey); - if (!config.isEmpty()) { - System.out.println(" " + TEST_GAME_IDS[i] + " (" + config.get("name") + "):"); - System.out.println(" 剩余机器人: " + config.get("leftover_robot")); - System.out.println(" 机器人上限: " + config.get("shangxian_robot")); - } - } - } - - System.out.println("=== 监控结束 ===\n"); - - } catch (Exception e) { - System.err.println("监控系统状态失败: " + e.getMessage()); - } - } - - /** - * 显示系统状态 - */ - private static void showSystemStatus() { - try { - System.out.println("\n=== 系统状态信息 ==="); - - // Redis连接 - try (Jedis jedis = Redis.use().getJedis()) { - String result = jedis.ping(); - System.out.println("Redis连接: " + ("PONG".equals(result) ? "正常" : "异常")); - } - - // 数据库连接 - try { - String sql = "SELECT 1 as test"; - ITArray result = DataBase.use().executeQueryByTArray(sql); - System.out.println("数据库连接: " + (result != null ? "正常" : "异常")); - } catch (Exception e) { - System.out.println("数据库连接: 异常 - " + e.getMessage()); - } - - // 房间统计 - try (Jedis jedis0 = Redis.use().getJedis()) { - Set roomKeys = jedis0.keys("room:*"); - System.out.println("当前房间数量: " + roomKeys.size()); - } - - // 机器人统计 - try { - String sql = "SELECT COUNT(*) as total FROM `account` WHERE jiqiren = " + ROBOT_TYPE; - ITArray result = DataBase.use().executeQueryByTArray(sql); - if (result != null && result.size() > 0) { - int total = result.getTObject(0).getInt("total"); - System.out.println("机器人总数: " + total); - } - } catch (Exception e) { - System.out.println("机器人统计: 获取失败"); - } - - System.out.println("=== 状态显示结束 ==="); - - } catch (Exception e) { - System.out.println("获取系统状态失败: " + e.getMessage()); - } - } - - /** - * 手动创建房间 - */ - private static void manualCreateRoom() { - try (Jedis jedis0 = Redis.use().getJedis()) { - Random random = new Random(); - - System.out.println("\n手动创建测试房间"); - System.out.print("请输入群组ID (默认" + TEST_GROUP_IDS[0] + "): "); - String groupInput = scanner.nextLine().trim(); - int groupId = groupInput.isEmpty() ? TEST_GROUP_IDS[0] : Integer.parseInt(groupInput); - - System.out.print("请输入玩法ID (10=长沙麻将, 22=红中麻将, 108=转转麻将, 66=跑得快): "); - String gameInput = scanner.nextLine().trim(); - int gameId = gameInput.isEmpty() ? TEST_GAME_IDS[0] : Integer.parseInt(gameInput); - - String roomId = "room:manual_" + System.currentTimeMillis(); - - // 模拟真实玩家ID - long creatorId = 10000000L + random.nextInt(90000000); - - Map roomData = new HashMap<>(); - roomData.put("game", String.valueOf(gameId)); - roomData.put("group", String.valueOf(groupId)); - roomData.put("status", "0"); - roomData.put("maxPlayers", "2"); - roomData.put("players", "[]"); - roomData.put("creator", String.valueOf(creatorId)); - roomData.put("createTime", String.valueOf(System.currentTimeMillis())); - - jedis0.hmset(roomId, roomData); - - System.out.println("已创建房间: " + roomId); - System.out.println("玩法: " + gameId + ", 群组: " + groupId); - System.out.println("创建者: " + creatorId + " (模拟真实玩家)"); - System.out.println("RedisRoomListener将监听到此房间创建"); - - } catch (Exception e) { - System.out.println("手动创建房间失败: " + e.getMessage()); - } - } - - /** - * 手动加入房间 - */ - private static void manualJoinRoom() { - try (Jedis jedis0 = Redis.use().getJedis()) { - Random random = new Random(); - - System.out.println("\n手动加入房间"); - - // 显示现有房间 - Set roomKeys = jedis0.keys("room:*"); - if (roomKeys.isEmpty()) { - System.out.println("没有可用房间,请先创建房间"); - return; - } - - int roomIndex = Integer.parseInt(scanner.nextLine().trim()); - - if (roomIndex < 1 || roomIndex > roomKeys.size()) { - System.out.println("无效的房间序号"); - return; - } - - String roomId = roomKeys.toArray(new String[0])[roomIndex - 1]; - Map roomData = jedis0.hgetAll(roomId); - - if (roomData == null) { - System.out.println("房间不存在"); - return; - } - - // 检查房间状态 - if (!"0".equals(roomData.get("status"))) { - System.out.println("房间已开始或已结束,无法加入"); - return; - } - - // 检查房间人数 - String players = roomData.get("players"); - int maxPlayers = Integer.parseInt(roomData.get("maxPlayers")); - int currentPlayers = 0; - - if (players != null && !players.equals("[]")) { - String cleanPlayers = players.substring(1, players.length() - 1); - if (!cleanPlayers.isEmpty()) { - currentPlayers = cleanPlayers.split(",").length; - } - } - - if (currentPlayers >= maxPlayers) { - System.out.println("房间已满,无法加入"); - return; - } - - // 模拟玩家加入 - long playerId = 10000000L + random.nextInt(90000000); - - if (players.equals("[]")) { - players = "[" + playerId + "]"; - } else { - String cleanPlayers = players.substring(1, players.length() - 1); - players = "[" + cleanPlayers + "," + playerId + "]"; - } - - jedis0.hset(roomId, "players", players); - - System.out.println("玩家 " + playerId + " 加入房间: " + roomId); - System.out.println("当前玩家: " + players); - System.out.println("RedisRoomListener将监听到玩家加入"); - - } catch (Exception e) { - System.out.println("手动加入房间失败: " + e.getMessage()); - } - } - - /** - * 手动修改配置 - */ - private static void manualModifyConfig() { - try (Jedis jedis11 = Redis.use("group1_db11").getJedis()) { - System.out.println("\n手动修改玩法配置"); - System.out.print("请输入群组ID (默认" + TEST_GROUP_IDS[0] + "): "); - String groupInput = scanner.nextLine().trim(); - int groupId = groupInput.isEmpty() ? TEST_GROUP_IDS[0] : Integer.parseInt(groupInput); - - System.out.print("请输入玩法ID (10=长沙麻将, 22=红中麻将, 108=转转麻将, 66=跑得快): "); - String gameInput = scanner.nextLine().trim(); - int gameId = gameInput.isEmpty() ? TEST_GAME_IDS[0] : Integer.parseInt(gameInput); - - String playKey = "g{" + groupId + "}:play:" + gameId; - Map config = jedis11.hgetAll(playKey); - - if (config.isEmpty()) { - System.out.println("配置不存在,将创建新配置"); - config = new HashMap<>(); - } - - System.out.print("请输入剩余机器人数量 (当前: " + config.getOrDefault("leftover_robot", "未设置") + "): "); - String leftoverInput = scanner.nextLine().trim(); - if (!leftoverInput.isEmpty()) { - jedis11.hset(playKey, "leftover_robot", leftoverInput); - } - - System.out.print("请输入机器人上限 (当前: " + config.getOrDefault("shangxian_robot", "未设置") + "): "); - String shangxianInput = scanner.nextLine().trim(); - if (!shangxianInput.isEmpty()) { - jedis11.hset(playKey, "shangxian_robot", shangxianInput); - } - - System.out.println("配置已更新: " + playKey); - System.out.println("RedisRoomListener将监听到配置变化"); - - } catch (Exception e) { - System.out.println("手动修改配置失败: " + e.getMessage()); - } - } - - /** - * 显示房间列表 - */ - private static void showRoomList() { - try (Jedis jedis0 = Redis.use().getJedis()) { - System.out.println("\n房间列表:"); - - Set roomKeys = jedis0.keys("room:*"); - if (roomKeys.isEmpty()) { - System.out.println("没有房间"); - return; - } - - for (String roomKey : roomKeys) { - Map roomData = jedis0.hgetAll(roomKey); - if (roomData != null) { - System.out.println(" " + roomKey + ":"); - System.out.println(" 玩法: " + roomData.get("game")); - System.out.println(" 群组: " + roomData.get("group")); - System.out.println(" 状态: " + getStatusText(roomData.get("status"))); - System.out.println(" 玩家: " + roomData.get("players")); - System.out.println(" 最大人数: " + roomData.get("maxPlayers")); - } - } - - } catch (Exception e) { - System.out.println("显示房间列表失败: " + e.getMessage()); - } - } - - /** - * 获取状态文本 - */ - private static String getStatusText(String status) { - if (status == null) return "未知"; - switch (status) { - case "0": return "未开始"; - case "1": return "进行中"; - case "2": return "已结束"; - case "3": return "已删除"; - default: return status; - } - } - - /** - * 显示机器人信息 - */ - private static void showRobotInfo() { - try { - System.out.println("\n机器人信息:"); - - // 从数据库获取机器人信息 - String sql = "SELECT id, acc, nick, start FROM `account` WHERE jiqiren = " + ROBOT_TYPE + " LIMIT 10"; - ITArray result = DataBase.use().executeQueryByTArray(sql); - - if (result == null || result.size() == 0) { - System.out.println("没有机器人数据"); - return; - } - - int available = 0; - int used = 0; - - System.out.println("机器人列表 (最多显示10个):"); - for (int i = 0; i < result.size(); i++) { - ITObject robot = result.getTObject(i); - int robotId = robot.getInt("id"); - String account = robot.getString("acc"); - String nick = robot.getString("nick"); - int status = robot.getInt("start"); - String statusText = status == 0 ? "可用" : "使用中"; - - if (status == 0) available++; - else used++; - - System.out.println(" ID: " + robotId + - ", 账号: " + account + - ", 昵称: " + nick + - ", 状态: " + statusText); - } - - System.out.println("统计: 可用=" + available + ", 使用中=" + used); - - } catch (Exception e) { - System.out.println("显示机器人信息失败: " + e.getMessage()); - } - } - - /** - * 清理测试数据 - */ - private static void cleanupTestData() { - try (Jedis jedis0 = Redis.use().getJedis(); - Jedis jedis11 = Redis.use("group1_db11").getJedis()) { - - System.out.println("清理测试数据..."); - - // 1. 删除测试房间 - Set roomKeys = jedis0.keys("room:*"); - int deletedRooms = 0; - for (String roomKey : roomKeys) { - if (roomKey.contains("test_") || roomKey.contains("manual_")) { - jedis0.del(roomKey); - deletedRooms++; - } - } - System.out.println(" 删除测试房间: " + deletedRooms + " 个"); - - // 2. 重置机器人状态 - try { - String resetSql = "UPDATE `account` SET start = 0 WHERE jiqiren = " + ROBOT_TYPE; - int updated = DataBase.use().executeUpdate(resetSql); - System.out.println(" 重置机器人状态: " + updated + " 个"); - } catch (Exception e) { - System.err.println(" 重置机器人状态失败: " + e.getMessage()); - } - - System.out.println("测试数据清理完成"); - - } catch (Exception e) { - System.err.println("清理测试数据失败: " + e.getMessage()); - } - } - - /** - * 清理资源 - */ - private static void cleanupResources(JettyServer server) { - try { - System.out.println("清理系统资源..."); - - // 停止模拟任务 - if (scheduler != null) { - scheduler.shutdown(); - try { - if (!scheduler.awaitTermination(5, TimeUnit.SECONDS)) { - scheduler.shutdownNow(); - } - } catch (InterruptedException e) { - scheduler.shutdownNow(); - } - System.out.println(" 模拟任务已停止"); - } - - // 清理测试数据 - cleanupTestData(); - - // 关闭MainServer - if (mainServer != null) { - try { - mainServer.onStop(); - System.out.println(" MainServer已停止"); - } catch (Exception e) { - System.out.println(" MainServer停止异常: " + e.getMessage()); - } - } - - // 停止Web服务器 - if (server != null) { - server.stop(); - System.out.println(" Web服务器已停止"); - } - - System.out.println("系统资源清理完成"); - - } catch (Exception e) { - System.err.println("清理资源失败: " + e.getMessage()); - e.printStackTrace(); - } - } - - /** - * 获取随机间隔时间 - */ - private static int getRandomInterval(int min, int max) { - Random random = new Random(); - return min + random.nextInt(max - min + 1); - } - - /** - * 获取游戏索引 - */ - private static int getGameIndex(int gameId) { - for (int i = 0; i < TEST_GAME_IDS.length; i++) { - if (TEST_GAME_IDS[i] == gameId) { - return i; - } - } - return 0; - } -} \ No newline at end of file diff --git a/robots/majiang/robot_mj_cs/src/main/java/robot/mj/RoomCreator.java b/robots/majiang/robot_mj_cs/src/main/java/robot/mj/RoomCreator.java index 823f388..95878f1 100644 --- a/robots/majiang/robot_mj_cs/src/main/java/robot/mj/RoomCreator.java +++ b/robots/majiang/robot_mj_cs/src/main/java/robot/mj/RoomCreator.java @@ -75,27 +75,27 @@ public class RoomCreator { Map roomMap = new HashMap<>(); //基础房间信息 - roomMap.put("id", newRoomId); //房间ID - roomMap.put("owner", "{user}:" + robotId); //房间所有者 roomMap.put("AA", "0"); //AA支付标志 - roomMap.put("pay", gameInfo.getOrDefault("pay", "0")); //支付金额 roomMap.put("agent", "1"); //代理标志 - roomMap.put("group", String.valueOf(groupId)); //群组ID - roomMap.put("gpid", String.valueOf(wanfaId)); //玩法ID - roomMap.put("payer", String.valueOf(robotId)); //支付者ID - roomMap.put("maxPlayers", gameInfo.getOrDefault("maxPlayers", "4")); //最大玩家数 - roomMap.put("times", gameInfo.getOrDefault("times", "8")); //局数 - roomMap.put("opt", playConfig.getOrDefault("opt", "1")); //选项 - roomMap.put("status", "0"); //房间状态 - roomMap.put("hpOnOff", playConfig.getOrDefault("hpOnOff", "0")); //体力开关 - roomMap.put("rewardType", playConfig.getOrDefault("rewardType", "0")); //奖励类型 - roomMap.put("rewardValueType", playConfig.getOrDefault("rewardValueType", "0")); //奖励值类型 - roomMap.put("xipai_rewardType", playConfig.getOrDefault("xipai_rewardType", "0")); //洗牌奖励类型 - roomMap.put("xipai_rewardValueType", playConfig.getOrDefault("xipai_rewardValueType", "0")); //洗牌奖励值类型 roomMap.put("dismiss_time", "30"); //解散时间 - roomMap.put("kick_time", "60"); //踢出时间 - roomMap.put("hp_times", playConfig.getOrDefault("hp_times", "1")); //体力次数 - + roomMap.put("gpid", String.valueOf(wanfaId)); //玩法ID + roomMap.put("group", String.valueOf(groupId)); //群组ID + roomMap.put("hpOnOff", "1"); //体力开关 + roomMap.put("hp_times", "1000"); //体力次数 + roomMap.put("id", newRoomId); //房间ID + roomMap.put("kick_time", "30"); //踢出时间 + roomMap.put("owner", "{user}:" + robotId); //房间所有者 + roomMap.put("maxPlayers", "2"); //最大玩家数 + roomMap.put("opt", "2"); //选项 + roomMap.put("pay", "0"); //支付金额 + roomMap.put("payer", String.valueOf(robotId)); //支付者ID + roomMap.put("rewardType", "0"); //奖励类型 + roomMap.put("rewardValueType", "0"); //奖励值类型 + roomMap.put("status", "0"); //房间状态 + roomMap.put("times", "4"); //局数 + roomMap.put("xipai_rewardType", "3"); //洗牌奖励类型 + roomMap.put("xipai_rewardValueType", "1"); //洗牌奖励值类型 + //如果有体力配置 String hpConfig = playConfig.get("hpConfig"); if (hpConfig != null) { @@ -236,20 +236,24 @@ public class RoomCreator { String groupKey = "group:" + groupId; Map defaultGroupInfo = new HashMap<>(); - defaultGroupInfo.put("id", String.valueOf(groupId)); - defaultGroupInfo.put("name", "机器人专用群组-" + groupId); - defaultGroupInfo.put("owner", "999999"); //使用机器人系统账户ID - defaultGroupInfo.put("type", "1"); //普通群组类型 - defaultGroupInfo.put("pay_type", "1"); //房主支付 - defaultGroupInfo.put("opt", "1"); //开启状态 defaultGroupInfo.put("ban", "0"); //未禁用 - defaultGroupInfo.put("dissolve_opt", "1"); //解散选项 - defaultGroupInfo.put("kick_opt", "1"); //踢人选项 defaultGroupInfo.put("ban_apply", "0"); //不禁止申请 + defaultGroupInfo.put("ban_chat1", "false"); + defaultGroupInfo.put("ban_chat2", "false"); defaultGroupInfo.put("create_time", String.valueOf(System.currentTimeMillis() / 1000)); - defaultGroupInfo.put("gms", "1"); //成员数 + defaultGroupInfo.put("dissolve_opt", "1"); //解散选项 + defaultGroupInfo.put("exit_opt", "0"); + defaultGroupInfo.put("gms", "19"); + defaultGroupInfo.put("id", String.valueOf(groupId)); + defaultGroupInfo.put("kick_opt", "1"); //踢人选项 + defaultGroupInfo.put("name", "机器人专用群组-" + groupId); + defaultGroupInfo.put("notice", ""); + defaultGroupInfo.put("opt", "1"); //开启状态 defaultGroupInfo.put("option", "0"); //选项 - + defaultGroupInfo.put("owner", "999999"); //使用机器人系统账户ID + defaultGroupInfo.put("pay_type", "1"); //房主支付 + defaultGroupInfo.put("type", "2"); //普通群组类型 + jedis11.hmset(groupKey, defaultGroupInfo); log.info("成功创建默认群组信息,键名: {}", groupKey);