修改机器人登录连接需求

master
zhouwei 2026-01-26 16:49:01 +08:00
parent 9717f80bfb
commit 552620e486
13 changed files with 702 additions and 2402 deletions

View File

@ -2,14 +2,14 @@ package com.group;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.HashMap; import java.util.*;
import java.util.Map;
import java.util.concurrent.ScheduledThreadPoolExecutor; import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import com.data.cache.AccountCache; import com.data.cache.AccountCache;
import com.data.cache.GroupCache; import com.data.cache.GroupCache;
import com.group.robot.RobotManager; import com.group.robot.RobotManager;
import com.group.robot.info.RobotInfo;
import com.taurus.core.entity.ITArray; import com.taurus.core.entity.ITArray;
import com.taurus.core.entity.ITObject; import com.taurus.core.entity.ITObject;
import com.taurus.core.plugin.database.DataBase; import com.taurus.core.plugin.database.DataBase;
@ -19,11 +19,9 @@ import com.taurus.core.routes.Routes;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import redis.clients.jedis.Jedis;
import taurus.client.NetManager; import taurus.client.NetManager;
public class MainServer extends Extension { public class MainServer extends Extension {
private static final Logger log = LoggerFactory.getLogger(MainServer.class); private static final Logger log = LoggerFactory.getLogger(MainServer.class);
private ScheduledThreadPoolExecutor timeScheduler; private ScheduledThreadPoolExecutor timeScheduler;
@ -32,8 +30,8 @@ public class MainServer extends Extension {
private static final String FORCE_VER_KEY = "force_ver"; private static final String FORCE_VER_KEY = "force_ver";
//机器人管理器 //机器人管理器
private RobotManager robotManager; private RobotManager robotManager = new RobotManager();
public static Map<String,String> lua_map = new HashMap<>(); public static Map<String,String> lua_map = new HashMap<>();
public MainServer() { public MainServer() {
super(); super();
@ -65,17 +63,26 @@ public class MainServer extends Extension {
public void onStart() { public void onStart() {
System.out.println("开始创建机器人连接..."); System.out.println("开始创建机器人连接...");
//1.先启动独立的事件处理线程(只启动一次)
//初始化机器人管理器
robotManager = new RobotManager();
//0 加载机器人到redis 2
loadGroupRobot();
// 1. 先启动独立的事件处理线程(只启动一次)
startNetEventThread(); 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 * redis2
*/ */
private void loadGroupRobot(){ 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 { try {
String sql = String.format("SELECT id,acc,nick,portrait,password FROM `account` WHERE jiqiren=9998 and start = 0"); robotIds = DataBase.use().executeQueryByTArray(sql);
ITArray robotIds = DataBase.use().executeQueryByTArray(sql); } catch (SQLException e) {
HashMap<String, String> 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<String,String> gRobotMap = new HashMap<>();
gRobotMap.put("start", "0");
gRobotMap.put("pid", "66");
jedis2.hmset("{grobot}:"+101666, gRobotMap);
} catch (SQLException e) {
throw new RuntimeException(e); throw new RuntimeException(e);
}finally { }
jedis2.close();
Map<Integer, Integer> gameRobotConfig = new HashMap<>();
gameRobotConfig.put(10, 5);
gameRobotConfig.put(22, 3);
int robotIndex = 0;
//长沙麻将机器人
List<RobotInfo> 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<RobotInfo> 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 @Override
public void configRoute(Routes me) { public void configRoute(Routes me) {
} }
@Override
public void onStop() {
if(timeScheduler!=null) {
timeScheduler.shutdownNow();
//关闭机器人管理器
if (robotManager != null) {
robotManager.shutdown();
}
}
}
} }

View File

@ -3,26 +3,22 @@ package com.group.robot;
import java.util.*; import java.util.*;
import java.util.concurrent.*; import java.util.concurrent.*;
import com.group.robot.connect.RedisRoomListener;
import com.group.robot.connect.RobotDisconnect; import com.group.robot.connect.RobotDisconnect;
import com.group.robot.handler.*;
import com.group.robot.info.RobotInfo; 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.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import redis.clients.jedis.Jedis; import redis.clients.jedis.Jedis;
import com.taurus.core.plugin.redis.Redis; import com.taurus.core.plugin.redis.Redis;
import com.taurus.core.plugin.database.DataBase; import com.taurus.core.plugin.database.DataBase;
import com.taurus.core.entity.ITArray;
import com.taurus.core.entity.ITObject; 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.CSMJRoomMatcher;
import com.group.robot.matcher.majiang.HZMJRoomMatcher; import com.group.robot.matcher.majiang.HZMJRoomMatcher;
import com.group.robot.matcher.poker.PokerRoomMatcher; import com.group.robot.matcher.poker.PokerRoomMatcher;
import com.group.robot.matcher.majiang.ZZMJRoomMatcher; import com.group.robot.matcher.majiang.ZZMJRoomMatcher;
import com.group.robot.matcher.GameRoomMatcherInterface; import com.group.robot.matcher.GameRoomMatcherInterface;
import taurus.client.business.AccountBusiness;
/** /**
* - * -
@ -42,12 +38,12 @@ public class RobotManager {
//游戏特定的房间匹配器 //游戏特定的房间匹配器
private final Map<Integer, GameRoomMatcherInterface> gameRoomMatchers = new ConcurrentHashMap<>(); private final Map<Integer, GameRoomMatcherInterface> gameRoomMatchers = new ConcurrentHashMap<>();
//Redis房间监听器
private RedisRoomListener redisRoomListener;
//使用数量计数器 跟踪每种玩法的机器人使用数量 //使用数量计数器 跟踪每种玩法的机器人使用数量
private final Map<Integer, Integer> count = new ConcurrentHashMap<>(); private final Map<Integer, Integer> count = new ConcurrentHashMap<>();
//玩法房间轮询器
private final Map<Integer, RoomWanfaMatcher> wanfaRoomPollers = new ConcurrentHashMap<>();
//定时任务调度器 //定时任务调度器
private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(2); private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(2);
@ -61,9 +57,6 @@ public class RobotManager {
//1、启动 ==》2、登录3、是否快捷登录 4、分配做什么工作a:长麻b:红中c:跑得快5、干活6、销毁回收 //1、启动 ==》2、登录3、是否快捷登录 4、分配做什么工作a:长麻b:红中c:跑得快5、干活6、销毁回收
//初始化游戏处理器 //初始化游戏处理器
initializeGameHandlers(); initializeGameHandlers();
//1、设定每个玩法多少机器人 //1、设定每个玩法多少机器人
@ -72,10 +65,7 @@ public class RobotManager {
//初始化游戏房间匹配器 //初始化游戏房间匹配器
initializeGameRoomMatchers(); initializeGameRoomMatchers();
//初始化Redis房间监听器 //定时任务
initializeRedisListener();
//定时清理任务
startCleanupTask(); startCleanupTask();
} }
@ -94,32 +84,6 @@ public class RobotManager {
log.info("已初始化 {} 个游戏处理器", gameHandlers.size()); 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() { public void loginRobots(List<RobotInfo> robots, int gameId) {
//每30秒检查一次不活跃的机器人连接 try (Jedis jedis0 = Redis.use().getJedis(); Jedis jedis2 = Redis.use("group1_db2").getJedis()){
scheduler.scheduleAtFixedRate(this::cleanupInactiveRobots, 30, 30, java.util.concurrent.TimeUnit.SECONDS); for (RobotInfo robot : robots) {
AccountBusiness accountBusiness = new AccountBusiness();
//检查Redis中是否存在已有token
Set<String> tokenKeys = jedis0.keys("{user}:" + robot.getRobotId() + "_token");
ITObject loginResult;
log.info("定时清理任务已启动"); if (tokenKeys != null && !tokenKeys.isEmpty()) {
log.debug("机器人 {} 存在已有token直接使用", robot.getRobotId());
Set<String> tokenSet = jedis0.smembers("{user}:" + robot.getRobotId() + "_token");
List<String> 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<String, String> 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<String, String> 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() { public void addGameHandler(int gameId, RobotManagerInterface handler) {
log.debug("开始清理不活跃的机器人连接..."); gameHandlers.put(gameId, handler);
log.info("添加游戏处理器: gameId={}, handler={}", gameId, handler.getClass().getSimpleName());
}
//已连接的机器人 /**
for (RobotInfo robot : new ArrayList<>(connectedRobots.values())) { *
//检查机器人是否仍然连接到房间 */
try { public RobotManagerInterface getGameHandler(int gameId) {
//检查房间状态 return gameHandlers.get(gameId);
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);
}
}
//检查房间玩家列表 确认机器人是否仍在房间中 /**
String players = jedis0.hget(roomKey, "players"); *
if (players != null && !players.equals("[]")) { */
String playersStr = players.substring(1, players.length() - 1); private void startCleanupTask() {
String[] playerIds = playersStr.split(","); //每15秒检查一次玩法配置
boolean robotInRoom = false; scheduler.scheduleAtFixedRate(this::manageWanfaPollers, 15, 15, TimeUnit.SECONDS);
}
for (String playerIdStr : playerIds) { /**
int playerId = Integer.parseInt(playerIdStr.trim()); *
if (playerId == robot.getRobotId()) { */
robotInRoom = true; private void manageWanfaPollers() {
break; try (Jedis jedis11 = Redis.use("group1_db11").getJedis()) {
} Set<String> playKeys = jedis11.keys("g{*}:play:*");
}
//如果机器人不在房间玩家列表中 断开连接 for (String playKey : playKeys) {
if (!robotInRoom) { try {
log.info("机器人 {} 不在房间 {} 断开连接", robot.getRobotId(), roomKey); String[] parts = playKey.split(":");
disconnectRobot(robot); 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 { } else {
//如果房间玩家列表为空 但机器人连接到此房间 断开连接 //如果没有配置机器人 停止轮询器
if (roomKey.equals(robot.getCurrentRoomId())) { RoomWanfaMatcher poller = wanfaRoomPollers.get(wanfaId);
log.info("房间 {} 玩家列表为空,断开机器人 {} 连接", roomKey, robot.getRobotId()); if (poller != null) {
disconnectRobot(robot); 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) { } catch (Exception e) {
log.error("连接机器人到房间时发生异常", e); log.error("管理玩法轮询器时发生错误", e);
robot.setConnected(false);
//异常时回滚计数
rollbackRobotCounts(room.getGroupId(), room.getWanfaId());
} }
} }
/** /**
* *
*/ */
private void rollbackRobotCounts(int groupId, int wanfaId) { public RoomWanfaMatcher getWanfaRoomPoller(int groupId, int wanfaId) {
//减少的机器人使用计数回滚 return wanfaRoomPollers.computeIfAbsent(wanfaId, k -> {
decreaseRobotCount(wanfaId); RoomWanfaMatcher poller = new RoomWanfaMatcher(this, groupId, wanfaId);
//增加leftover_robot数量 log.info("创建玩法ID {} 的房间轮询器", wanfaId);
try (Jedis jedis11 = Redis.use("group1_db11").getJedis()) { return poller;
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);
}
} }
/** /**
@ -261,9 +256,9 @@ public class RobotManager {
*/ */
public void disconnectRobot(RobotInfo robot) { public void disconnectRobot(RobotInfo robot) {
int robotId = robot.getRobotId(); int robotId = robot.getRobotId();
int groupId = getGroupIdFromRoomId(robot.getCurrentRoomId()); int groupId = getGroupIdFromRoomId(robot.getRoomId());
int gameId = robot.getCurrentWanfaId(); int gameId = robot.getWanfaId();
String roomId = robot.getCurrentRoomId(); String roomId = robot.getRoomId();
//断开机器人服务 //断开机器人服务
safeDisconnectRobot(robotId, groupId, gameId, roomId); safeDisconnectRobot(robotId, groupId, gameId, roomId);
@ -285,92 +280,17 @@ public class RobotManager {
} }
/** /**
* *
*/ */
public List<RobotInfo> getAvailableRobots(int count) { public RobotInfo getLoggedInRobotForWanfa(int wanfaId) {
List<RobotInfo> 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();
}
//断开所有机器人连接
for (RobotInfo robot : connectedRobots.values()) { for (RobotInfo robot : connectedRobots.values()) {
disconnectRobot(robot); if (robot.getWanfaId() == wanfaId && robot.isOnline() && robot.isConnected()) {
} //更新最后活跃时间
robot.setLastActiveTime(System.currentTimeMillis());
//恢复所有机器人状态为可用 return 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();
} }
} catch (InterruptedException e) {
scheduler.shutdownNow();
Thread.currentThread().interrupt();
} }
return null;
log.info("机器人管理器已关闭,断开了 {} 个机器人连接", connectedRobots.size());
} }
/** /**
@ -380,21 +300,6 @@ public class RobotManager {
return 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使 * ID使
*/ */
@ -406,13 +311,6 @@ public class RobotManager {
} }
} }
/**
* ID使
*/
public int getRobotUsageCount(int wanfaId) {
return count.getOrDefault(wanfaId, 0);
}
/** /**
* *
*/ */

View File

@ -8,9 +8,9 @@ import com.group.robot.info.RoomInfo;
*/ */
public interface RobotManagerInterface { public interface RobotManagerInterface {
/** /**
* *
*/ */
void connectRobot(RobotInfo robot, RoomInfo room); void connectRobot(RobotInfo robot);
/** /**
* *

View File

@ -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<RobotInfo> 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<String> 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<RobotInfo> 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<RoomInfo> 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);
}
}
}

View File

@ -56,7 +56,7 @@ public class RobotDisconnect {
//处理对应游戏处理器断开连接 //处理对应游戏处理器断开连接
if (robot != null) { if (robot != null) {
RobotManagerInterface handler = robotManager.getGameHandler(robot.getCurrentWanfaId()); RobotManagerInterface handler = robotManager.getGameHandler(robot.getWanfaId());
if (handler != null) { if (handler != null) {
handler.disconnectRobot(robot); handler.disconnectRobot(robot);
log.debug("游戏处理器已断开机器人 {} 连接", robotId); log.debug("游戏处理器已断开机器人 {} 连接", robotId);

View File

@ -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<MessageResponse>() {
@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<RoomInfo>
*/
public CompletableFuture<RoomInfo> sendCreateRoomForRobot(int groupId, int wanfaId, int robotId) {
CompletableFuture<RoomInfo> 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<MessageResponse>() {
@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);
}
}
}

View File

@ -5,7 +5,6 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import com.group.robot.info.RobotInfo; 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; private final RobotConnectionHandler robotConnectionHandler;
public MaJiangRobotHandler() { public MaJiangRobotHandler() {
this.robotConnectionHandler = new RobotConnectionHandler(); this.robotConnectionHandler = RobotConnectionHandler.getInstance();
} }
@Override @Override
public void connectRobot(RobotInfo robot, RoomInfo room) { public void connectRobot(RobotInfo robot) {
try { try {
log.info("麻将机器人 {} 正在连接到房间 {}", robot.getRobotId(), room.getRoomId());
//连接处理器进行连接 //连接处理器进行连接
robotConnectionHandler.connectRobot(robot, room); robotConnectionHandler.connectRobot(robot);
//设置机器人连接状态
robot.setConnected(true);
}catch (Exception e) { }catch (Exception e) {
log.error("麻将机器人 {} 连接房间 {} 时发生异常", robot.getRobotId(), room.getRoomId(), e); log.error("麻将机器人 {} 连接游戏服务器时发生异常", robot.getRobotId(), e);
robot.setConnected(false); robot.setConnected(false);
} }
} }
@ -41,9 +42,7 @@ public class MaJiangRobotHandler implements RobotManagerInterface {
robotConnectionHandler.disconnectRobot(robot.getRobotId()); robotConnectionHandler.disconnectRobot(robot.getRobotId());
robot.setConnected(false); robot.setConnected(false);
robot.setCurrentRoomId(null);
robot.setCurrentWanfaId(0);
log.info("麻将机器人 {} 连接已断开", robot.getRobotId()); log.info("麻将机器人 {} 连接已断开", robot.getRobotId());
} catch (Exception e) { } catch (Exception e) {
log.error("断开麻将机器人连接时发生错误: " + robot.getRobotId(), e); log.error("断开麻将机器人连接时发生错误: " + robot.getRobotId(), e);

View File

@ -17,24 +17,21 @@ public class PokerRobotHandler implements RobotManagerInterface {
private final RobotConnectionHandler connectionHandler; private final RobotConnectionHandler connectionHandler;
public PokerRobotHandler() { public PokerRobotHandler() {
this.connectionHandler = new RobotConnectionHandler(); this.connectionHandler = RobotConnectionHandler.getInstance();
} }
@Override @Override
public void connectRobot(RobotInfo robot, RoomInfo room) { public void connectRobot(RobotInfo robot) {
try { try {
log.info("扑克机器人 {} 正在连接到房间 {}", robot.getRobotId(), room.getRoomId()); log.info("扑克机器人 {} 正在连接到房间 {}", robot.getRobotId(), robot.getRoomId());
//使用连接处理器进行连接 //使用连接处理器进行连接
connectionHandler.connectRobot(robot, room); connectionHandler.connectRobot(robot);
// 设置机器人连接状态和房间信息 // 设置机器人连接状态和房间信息
robot.setConnected(true); robot.setConnected(true);
robot.setCurrentWanfaId(room.getWanfaId());
robot.setCurrentRoomId(room.getRoomId()); log.info("扑克机器人 {} 开始连接到房间 {}, 玩法ID: {}", robot.getRobotId(), robot.getRoomId(), robot.getWanfaId());
log.info("扑克机器人 {} 开始连接到房间 {}, 玩法ID: {}",
robot.getRobotId(), room.getRoomId(), room.getWanfaId());
} catch (Exception e) { } catch (Exception e) {
log.error("扑克机器人连接失败: " + robot.getRobotId(), e); log.error("扑克机器人连接失败: " + robot.getRobotId(), e);
} }
@ -49,9 +46,6 @@ public class PokerRobotHandler implements RobotManagerInterface {
connectionHandler.disconnectRobot(robot.getRobotId()); connectionHandler.disconnectRobot(robot.getRobotId());
robot.setConnected(false); robot.setConnected(false);
robot.setCurrentRoomId(null);
robot.setCurrentWanfaId(0);
log.info("扑克机器人 {} 连接已断开", robot.getRobotId()); log.info("扑克机器人 {} 连接已断开", robot.getRobotId());
} catch (Exception e) { } catch (Exception e) {
log.error("断开扑克机器人连接时发生错误: " + robot.getRobotId(), e); log.error("断开扑克机器人连接时发生错误: " + robot.getRobotId(), e);

View File

@ -1,37 +1,31 @@
package com.group.robot.handler; package com.group.robot.handler;
import java.util.Map; 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.CompletableFuture;
import java.util.concurrent.ConcurrentHashMap; 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.info.RobotInfo;
import com.group.robot.RobotManager; import com.group.robot.RobotManager;
import com.group.robot.info.RoomInfo; 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.entity.TObject;
import com.taurus.core.plugin.database.DataBase; import com.taurus.core.util.ICallback;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import taurus.client.MessageResponse;
import taurus.client.SocketCode; import taurus.client.SocketCode;
import taurus.client.TaurusClient; import taurus.client.TaurusClient;
import taurus.client.Message; import taurus.client.Message;
import taurus.client.business.AccountBusiness;
import taurus.client.business.GroupRoomBusiness;
import com.taurus.core.entity.ITObject; import com.taurus.core.entity.ITObject;
import com.taurus.core.events.Event; import com.taurus.core.events.Event;
import com.taurus.core.events.IEventListener; 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 { public class RobotConnectionHandler {
private static volatile RobotConnectionHandler instance;
private static final Logger log = LoggerFactory.getLogger(RobotConnectionHandler.class); private static final Logger log = LoggerFactory.getLogger(RobotConnectionHandler.class);
//机器人ID到客户端连接的映射 //机器人ID到客户端连接的映射
@ -81,54 +75,44 @@ public class RobotConnectionHandler {
public void setGameId(int gameId) { this.gameId = gameId; } public void setGameId(int gameId) { this.gameId = gameId; }
} }
public RobotConnectionHandler() { private RobotConnectionHandler() {
this.robotManager = RobotManager.getRobotManager(); 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(() -> { CompletableFuture.runAsync(() -> {
try { try {
log.info("开始连接机器人 {} 到房间 {}, 玩法ID: {}", robot.getRobotId(), room.getRoomId(), room.getWanfaId()); log.info("开始连接机器人 {} 到游戏服务器玩法ID: {}", robot.getRobotId(), robot.getWanfaId());
//TCP客户端连接
//获取机器人账户信息 TaurusClient client = new TaurusClient(getGameServerAddress(robot.getWanfaId()), "game", TaurusClient.ConnectionProtocol.Tcp);
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);
client.connect(); client.connect();
//保存客户端连接 //保存客户端连接
robotClients.put(robot.getRobotId(), client); robotClients.put(robot.getRobotId(), client);
//设置事件监听器 //设置事件监听器
setupInitializationEventListeners(client, robot, room); setupInitializationEventListeners(client, robot);
//登录并加入房间 //连接成功后发送初始化协议
Thread.sleep(5000); sendInitializationProtocol(client, robot);
loginAndJoinRoom(accountInfo, room); log.info("机器人 {} 成功连接到游戏服务器", robot.getRobotId());
//登录成功后
robotAccounts.put(robot.getRobotId(), accountInfo);
//发送准备请求
Thread.sleep(1000);
sendReadyRequest(client, accountInfo.getRobotId());
log.info("机器人 {} 成功连接到房间 {}", robot.getRobotId(), room.getRoomId());
//6秒没有玩家加入 则退出房间
readyTimeRobotExit(accountInfo.getRobotId(), room);
} catch (Exception e) { } catch (Exception e) {
log.error("连接机器人时发生异常: " + robot.getRobotId(), e); log.error("连接机器人到游戏服务器时发生异常: " + robot.getRobotId(), e);
//清理已经建立的连接 //清理已经建立的连接
disconnectRobot(robot.getRobotId()); 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() { client.addEventListener(TaurusClient.NetClientEvent.Connect, new IEventListener() {
@Override @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<String> tokenKeys = jedis0.keys("{user}:" + accountInfo.getRobotId() + "_token");
ITObject loginResult;
if (tokenKeys != null && !tokenKeys.isEmpty()) {
log.debug("机器人 {} 存在已有token直接使用", accountInfo.getRobotId());
Set<String> tokenSet = jedis0.smembers("{user}:" + accountInfo.getRobotId() + "_token");
List<String> 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 * ID
*/ */
@ -250,11 +166,9 @@ public class RobotConnectionHandler {
//根据玩法ID返回对应的服务器地址 //根据玩法ID返回对应的服务器地址
switch (wanfaId) { switch (wanfaId) {
case 10: //长沙麻将 case 10: //长沙麻将
return "127.0.0.1:6311"; return "127.0.0.1:8701";
case 22: //红中麻将 case 22: //红中麻将
return "8.138.242.190:6421"; return "8.138.242.190:6421";
case 108: //转转麻将
return "8.138.242.190:6841";
case 66: //跑得快 case 66: //跑得快
return "8.138.242.190:6841"; return "8.138.242.190:6841";
default: 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<String, String> 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 退 * 6 退
*/ */
private void readyTimeRobotExit(int robotId, RoomInfo room) { public void readyTimeRobotExit(RobotInfo robot) {
CompletableFuture.runAsync(() -> { CompletableFuture.runAsync(() -> {
try { try {
Thread.sleep(6000); Thread.sleep(6000);
//检查房间内是否只有机器人 log.info("机器人 {} 准备时间超过6秒且房间人数不足退出房间", robot.getRobotId());
if (ifExitRoom(room)) { TaurusClient client = robotClients.get(robot.getRobotId());
log.info("机器人 {} 准备时间超过6秒且房间人数不足退出房间", robotId);
//获取客户端连接 if (client != null && client.isConnected()) {
TaurusClient client = robotClients.remove(robotId); //发送离开房间协议
if (client != null) { ITObject param = new TObject();
//发送离开房间协议 client.send("1005", param, response -> {
ITObject param = new TObject(); log.debug("机器人 {} 发送离开房间请求", robot.getRobotId());
client.send("1005", param, response -> { });
log.debug("机器人 {} 发送离开房间请求", robotId); } else {
}); log.warn("机器人 {} 连接不存在或未激活,跳过离开房间操作", robot.getRobotId());
//关闭连接
client.clearResponse();
}
//延迟后断开连接
Thread.sleep(1000);
disconnectRobot(robotId);
} }
//延迟后断开连接
Thread.sleep(1000);
disconnectRobot(robot.getRobotId());
} catch (InterruptedException e) { } catch (InterruptedException e) {
log.debug("超时检查线程被中断: {}", robotId); log.debug("超时检查线程被中断: {}", robot.getRobotId());
Thread.currentThread().interrupt(); Thread.currentThread().interrupt();
} catch (Exception e) {
log.error("超时检查过程中发生异常", e);
} }
}); });
} }
/** /**
* 退 *
*/ */
private boolean ifExitRoom(RoomInfo room) { private void sendInitializationProtocol(TaurusClient client, RobotInfo robot) {
try { if (client == null || !client.isConnected()) {
Jedis jedis0 = Redis.use().getJedis(); log.warn("机器人 {} 没有有效的TCP连接无法发送初始化协议", robot.getRobotId());
try { return;
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);
} }
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<RoomInfo> 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<MessageResponse>() {
@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));
}
}
});*/
}
} }

View File

@ -12,9 +12,11 @@ public class RobotInfo {
private boolean isOnline; //是否在线 private boolean isOnline; //是否在线
private boolean isConnected; //是否已连接到游戏服务器 private boolean isConnected; //是否已连接到游戏服务器
private boolean isConnecting; //是否正在连接 private boolean isConnecting; //是否正在连接
private String currentRoomId; //当前所在房间ID private String roomId; //当前所在房间ID
private int currentWanfaId; //当前玩法ID private int wanfaId; //当前玩法ID
private long lastActiveTime; //最后活跃时间 private long lastActiveTime; //最后活跃时间
private String session;
private String token;
public RobotInfo() { public RobotInfo() {
this.lastActiveTime = System.currentTimeMillis(); this.lastActiveTime = System.currentTimeMillis();
@ -83,23 +85,23 @@ public class RobotInfo {
public void setConnecting(boolean connecting) { public void setConnecting(boolean connecting) {
isConnecting = connecting; isConnecting = connecting;
} }
public String getCurrentRoomId() { public String getRoomId() {
return currentRoomId; return roomId;
} }
public void setCurrentRoomId(String currentRoomId) { public void setRoomId(String roomId) {
this.currentRoomId = currentRoomId; this.roomId = roomId;
} }
public int getCurrentWanfaId() { public int getWanfaId() {
return currentWanfaId; return wanfaId;
} }
public void setCurrentWanfaId(int currentWanfaId) { public void setWanfaId(int wanfaId) {
this.currentWanfaId = currentWanfaId; this.wanfaId = wanfaId;
} }
public long getLastActiveTime() { public long getLastActiveTime() {
return lastActiveTime; return lastActiveTime;
} }
@ -107,7 +109,24 @@ public class RobotInfo {
public void setLastActiveTime(long lastActiveTime) { public void setLastActiveTime(long lastActiveTime) {
this.lastActiveTime = 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 @Override
public String toString() { public String toString() {
return "RobotInfo{" + return "RobotInfo{" +
@ -115,8 +134,11 @@ public class RobotInfo {
", account='" + account + '\'' + ", account='" + account + '\'' +
", isOnline=" + isOnline + ", isOnline=" + isOnline +
", isConnected=" + isConnected + ", isConnected=" + isConnected +
", currentRoomId='" + currentRoomId + '\'' + ", roomId='" + roomId + '\'' +
", currentWanfaId=" + currentWanfaId + ", wanfaId=" + wanfaId +
", lastActiveTime=" + lastActiveTime +
", session='" + session + '\'' +
", token='" + token + '\'' +
'}'; '}';
} }
} }

View File

@ -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<String> 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<String> 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);
}
}

File diff suppressed because it is too large Load Diff

View File

@ -75,27 +75,27 @@ public class RoomCreator {
Map<String, String> roomMap = new HashMap<>(); Map<String, String> roomMap = new HashMap<>();
//基础房间信息 //基础房间信息
roomMap.put("id", newRoomId); //房间ID
roomMap.put("owner", "{user}:" + robotId); //房间所有者
roomMap.put("AA", "0"); //AA支付标志 roomMap.put("AA", "0"); //AA支付标志
roomMap.put("pay", gameInfo.getOrDefault("pay", "0")); //支付金额
roomMap.put("agent", "1"); //代理标志 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("dismiss_time", "30"); //解散时间
roomMap.put("kick_time", "60"); //踢出时间 roomMap.put("gpid", String.valueOf(wanfaId)); //玩法ID
roomMap.put("hp_times", playConfig.getOrDefault("hp_times", "1")); //体力次数 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"); String hpConfig = playConfig.get("hpConfig");
if (hpConfig != null) { if (hpConfig != null) {
@ -236,20 +236,24 @@ public class RoomCreator {
String groupKey = "group:" + groupId; String groupKey = "group:" + groupId;
Map<String, String> defaultGroupInfo = new HashMap<>(); Map<String, String> 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("ban", "0"); //未禁用
defaultGroupInfo.put("dissolve_opt", "1"); //解散选项
defaultGroupInfo.put("kick_opt", "1"); //踢人选项
defaultGroupInfo.put("ban_apply", "0"); //不禁止申请 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("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("option", "0"); //选项
defaultGroupInfo.put("owner", "999999"); //使用机器人系统账户ID
defaultGroupInfo.put("pay_type", "1"); //房主支付
defaultGroupInfo.put("type", "2"); //普通群组类型
jedis11.hmset(groupKey, defaultGroupInfo); jedis11.hmset(groupKey, defaultGroupInfo);
log.info("成功创建默认群组信息,键名: {}", groupKey); log.info("成功创建默认群组信息,键名: {}", groupKey);