parent
accdf5e4d6
commit
84bb216bb9
|
|
@ -55,6 +55,9 @@ public class RobotManager {
|
||||||
|
|
||||||
//跟踪已经恢复leftover_robot的机器人
|
//跟踪已经恢复leftover_robot的机器人
|
||||||
private final Set<Integer> leftoverRobotRecovered = ConcurrentHashMap.newKeySet();
|
private final Set<Integer> leftoverRobotRecovered = ConcurrentHashMap.newKeySet();
|
||||||
|
|
||||||
|
//房间级别的锁,用于细粒度的同步控制
|
||||||
|
private final Map<String, Object> roomLocks = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
|
||||||
public RobotManager() {
|
public RobotManager() {
|
||||||
|
|
@ -164,9 +167,6 @@ public class RobotManager {
|
||||||
gRobotMap.put("pid", String.valueOf(gameId));
|
gRobotMap.put("pid", String.valueOf(gameId));
|
||||||
jedis2.hmset("{grobot}:" + robot.getRobotId(), gRobotMap);
|
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());
|
String sql = String.format("UPDATE `account` SET start = %d WHERE id = %d", 1, robot.getRobotId());
|
||||||
DataBase.use().executeUpdate(sql);
|
DataBase.use().executeUpdate(sql);
|
||||||
|
|
@ -175,6 +175,8 @@ public class RobotManager {
|
||||||
//连接对应游戏服务器
|
//连接对应游戏服务器
|
||||||
RobotManagerInterface handler = getGameHandler(gameId);
|
RobotManagerInterface handler = getGameHandler(gameId);
|
||||||
handler.connectRobot(robot);
|
handler.connectRobot(robot);
|
||||||
|
//将登录后的机器人添加到已连接列表中 等待连接服务器
|
||||||
|
connectedRobots.put(robot.getRobotId(), robot);
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("机器人登录时发生错误", e);
|
log.error("机器人登录时发生错误", e);
|
||||||
|
|
@ -253,7 +255,7 @@ public class RobotManager {
|
||||||
/**
|
/**
|
||||||
* 断开多余的机器人连接
|
* 断开多余的机器人连接
|
||||||
*/
|
*/
|
||||||
public void disconnectExcessRobots(int wanfaId, int requiredCount) {
|
public void disconnectExcessRobots(int wanfaId) {
|
||||||
List<RobotInfo> allWanfaRobots = new ArrayList<>();
|
List<RobotInfo> allWanfaRobots = new ArrayList<>();
|
||||||
for (RobotInfo robot : connectedRobots.values()) {
|
for (RobotInfo robot : connectedRobots.values()) {
|
||||||
if (robot.getWanfaId() == wanfaId) {
|
if (robot.getWanfaId() == wanfaId) {
|
||||||
|
|
@ -261,38 +263,23 @@ public class RobotManager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//该玩法已连接的机器人
|
//断开该玩法下未使用的机器人
|
||||||
int currentlyConnected = 0;
|
int disconnectedCount = 0;
|
||||||
for (RobotInfo robot : allWanfaRobots) {
|
for (RobotInfo robot : allWanfaRobots) {
|
||||||
if (robot.isConnected()) {
|
synchronized(robot) {
|
||||||
currentlyConnected++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//需要断开的机器人
|
|
||||||
int toDisconnect = Math.max(0, currentlyConnected - requiredCount);
|
|
||||||
|
|
||||||
if (toDisconnect > 0) {
|
|
||||||
int disconnectedCount = 0;
|
|
||||||
for (int i = 0; i < allWanfaRobots.size() && disconnectedCount < toDisconnect; i++) {
|
|
||||||
RobotInfo robot = allWanfaRobots.get(i);
|
|
||||||
//不在使用断开连接
|
|
||||||
if (!robot.isUsing() && robot.isConnected()) {
|
if (!robot.isUsing() && robot.isConnected()) {
|
||||||
synchronized(robot) {
|
RobotManagerInterface handler = getGameHandler(robot.getWanfaId());
|
||||||
if (!robot.isUsing() && robot.isConnected()) {
|
if (handler != null) {
|
||||||
RobotManagerInterface handler = getGameHandler(robot.getWanfaId());
|
handler.disconnectRobot(robot);
|
||||||
if (handler != null) {
|
log.debug("断开未使用机器人 {} TCP连接,玩法ID: {}", robot.getRobotId(), wanfaId);
|
||||||
handler.disconnectRobot(robot);
|
|
||||||
log.debug("断开机器人 {} TCP连接,玩法ID: {}", robot.getRobotId(), wanfaId);
|
|
||||||
}
|
|
||||||
disconnectedCount++;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
disconnectedCount++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (disconnectedCount > 0) {
|
}
|
||||||
log.debug("玩法 {} 成功断开 {} 个机器人的TCP连接,目标连接数: {}", wanfaId, disconnectedCount, requiredCount);
|
|
||||||
}
|
if (disconnectedCount > 0) {
|
||||||
|
log.debug("玩法 {} 成功断开 {} 个未使用机器人的TCP连接", wanfaId, disconnectedCount);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -307,38 +294,48 @@ public class RobotManager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//该玩法已连接的机器人
|
//空闲机器人
|
||||||
int currentConnected = 0;
|
int availableCount = 0;
|
||||||
for (RobotInfo robot : allWanfaRobots) {
|
for (RobotInfo robot : allWanfaRobots) {
|
||||||
if (robot.isConnected()) {
|
if (robot.isConnected() && !robot.isUsing()) {
|
||||||
currentConnected++;
|
availableCount++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//当前连接数小于所需数量 则连接更多机器人
|
//可用机器人数量少于需求 连接更多机器人
|
||||||
if (currentConnected < requiredCount) {
|
if (availableCount < requiredCount) {
|
||||||
int reconnectedCount = 0;
|
int needToConnect = requiredCount - availableCount;
|
||||||
|
int connectedCount = 0;
|
||||||
|
|
||||||
for (RobotInfo robot : allWanfaRobots) {
|
for (RobotInfo robot : allWanfaRobots) {
|
||||||
if (!robot.isConnected() && !robot.isUsing() && reconnectedCount < (requiredCount - currentConnected)) {
|
if (connectedCount >= needToConnect) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!robot.isConnected() && !robot.isUsing()) {
|
||||||
RobotManagerInterface handler = getGameHandler(robot.getWanfaId());
|
RobotManagerInterface handler = getGameHandler(robot.getWanfaId());
|
||||||
if (handler != null) {
|
if (handler != null) {
|
||||||
if (shouldConnectRobot(robot)) {
|
if (shouldConnectRobot(robot)) {
|
||||||
synchronized(robot) {
|
synchronized(robot) {
|
||||||
if (!robot.isConnected() && !robot.isUsing()) {
|
if (!robot.isConnected() && !robot.isUsing()) {
|
||||||
handler.connectRobot(robot);
|
handler.connectRobot(robot);
|
||||||
log.debug("重新连接玩法 {} 的机器人: {}", wanfaId, robot.getRobotId());
|
log.debug("连接玩法 {} 的空闲机器人: {}", wanfaId, robot.getRobotId());
|
||||||
|
connectedCount++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
log.debug("玩法 {} 的leftover_robot为0,跳过连接机器人: {}", wanfaId, robot.getRobotId());
|
log.debug("玩法 {} 当前不允许连接机器人: {}", wanfaId, robot.getRobotId());
|
||||||
}
|
}
|
||||||
reconnectedCount++;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (connectedCount > 0) {
|
||||||
|
log.debug("玩法 {} 新连接了 {} 个机器人以满足需求", wanfaId, connectedCount);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取玩法房间轮询器
|
* 获取玩法房间轮询器
|
||||||
*/
|
*/
|
||||||
|
|
@ -386,7 +383,7 @@ public class RobotManager {
|
||||||
//获取指定玩法的所有可用机器人
|
//获取指定玩法的所有可用机器人
|
||||||
List<RobotInfo> availableRobots = new ArrayList<>();
|
List<RobotInfo> availableRobots = new ArrayList<>();
|
||||||
for (RobotInfo robot : connectedRobots.values()) {
|
for (RobotInfo robot : connectedRobots.values()) {
|
||||||
if (robot.getWanfaId() == wanfaId && robot.isOnline() && robot.isConnected() && !robot.isUsing()) {
|
if (robot.getWanfaId() == wanfaId && robot.isOnline() && !robot.isUsing()) {
|
||||||
availableRobots.add(robot);
|
availableRobots.add(robot);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -399,17 +396,20 @@ public class RobotManager {
|
||||||
|
|
||||||
RobotInfo selectedRobot = availableRobots.get(currentIndex);
|
RobotInfo selectedRobot = availableRobots.get(currentIndex);
|
||||||
|
|
||||||
selectedRobot.setLastActiveTime(System.currentTimeMillis());
|
synchronized (selectedRobot) {
|
||||||
|
if (!selectedRobot.isUsing()) {
|
||||||
selectedRobot.setUsing(true);
|
selectedRobot.setLastActiveTime(System.currentTimeMillis());
|
||||||
int nextIndex = (currentIndex + 1) % availableRobots.size();
|
int nextIndex = (currentIndex + 1) % availableRobots.size();
|
||||||
wanfaRobotIndex.put(wanfaId, nextIndex);
|
wanfaRobotIndex.put(wanfaId, nextIndex);
|
||||||
return selectedRobot;
|
return selectedRobot;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//如果没有连接的可用机器人,检查是否有未连接的机器人并尝试连接
|
||||||
List<RobotInfo> allWanfaRobots = new ArrayList<>();
|
List<RobotInfo> allWanfaRobots = new ArrayList<>();
|
||||||
for (RobotInfo robot : connectedRobots.values()) {
|
for (RobotInfo robot : connectedRobots.values()) {
|
||||||
if (robot.getWanfaId() == wanfaId && robot.isOnline() && robot.isConnected()) {
|
if (robot.getWanfaId() == wanfaId && robot.isOnline()) {
|
||||||
allWanfaRobots.add(robot);
|
allWanfaRobots.add(robot);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -422,12 +422,26 @@ public class RobotManager {
|
||||||
|
|
||||||
RobotInfo selectedRobot = allWanfaRobots.get(currentIndex);
|
RobotInfo selectedRobot = allWanfaRobots.get(currentIndex);
|
||||||
|
|
||||||
selectedRobot.setLastActiveTime(System.currentTimeMillis());
|
//机器人未连接 尝试重新连接
|
||||||
|
if (!selectedRobot.isConnected()) {
|
||||||
selectedRobot.setUsing(true);
|
selectedRobot.setUsing(false);
|
||||||
int nextIndex = (currentIndex + 1) % allWanfaRobots.size();
|
RobotManagerInterface handler = getGameHandler(selectedRobot.getWanfaId());
|
||||||
wanfaRobotIndex.put(wanfaId, nextIndex);
|
if (handler != null) {
|
||||||
return selectedRobot;
|
handler.connectRobot(selectedRobot);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!selectedRobot.isUsing()) {
|
||||||
|
//使用同步块确保原子操作
|
||||||
|
synchronized (selectedRobot) {
|
||||||
|
if (!selectedRobot.isUsing()) {
|
||||||
|
selectedRobot.setLastActiveTime(System.currentTimeMillis());
|
||||||
|
int nextIndex = (currentIndex + 1) % allWanfaRobots.size();
|
||||||
|
wanfaRobotIndex.put(wanfaId, nextIndex);
|
||||||
|
return selectedRobot;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
|
@ -538,4 +552,11 @@ public class RobotManager {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取房间级别的锁
|
||||||
|
*/
|
||||||
|
public Object getRoomLock(String roomId) {
|
||||||
|
return roomLocks.computeIfAbsent(roomId, k -> new Object());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
package com.group.robot;
|
package com.group.robot;
|
||||||
|
|
||||||
import com.group.robot.info.RobotInfo;
|
import com.group.robot.info.RobotInfo;
|
||||||
import com.group.robot.info.RoomInfo;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 机器人处理器接口 - 只负责连接管理和协议转发
|
* 机器人处理器接口 - 只负责连接管理和协议转发
|
||||||
|
|
|
||||||
|
|
@ -24,9 +24,6 @@ public class MaJiangRobotHandler implements RobotManagerInterface {
|
||||||
try {
|
try {
|
||||||
//连接处理器进行连接
|
//连接处理器进行连接
|
||||||
robotConnectionHandler.connectRobot(robot);
|
robotConnectionHandler.connectRobot(robot);
|
||||||
|
|
||||||
//设置机器人连接状态
|
|
||||||
robot.setConnected(true);
|
|
||||||
}catch (Exception e) {
|
}catch (Exception e) {
|
||||||
log.error("麻将机器人 {} 连接游戏服务器时发生异常", robot.getRobotId(), e);
|
log.error("麻将机器人 {} 连接游戏服务器时发生异常", robot.getRobotId(), e);
|
||||||
robot.setConnected(false);
|
robot.setConnected(false);
|
||||||
|
|
|
||||||
|
|
@ -2,11 +2,10 @@ package com.group.robot.handler;
|
||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
import java.util.Timer;
|
||||||
|
import java.util.TimerTask;
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import java.util.concurrent.Executors;
|
|
||||||
import java.util.concurrent.ScheduledExecutorService;
|
|
||||||
import java.util.concurrent.ScheduledFuture;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
|
|
@ -34,59 +33,16 @@ public class RobotConnectionHandler {
|
||||||
|
|
||||||
//机器人ID到客户端连接的映射
|
//机器人ID到客户端连接的映射
|
||||||
private final Map<Integer, TaurusClient> robotClients = new ConcurrentHashMap<>();
|
private final Map<Integer, TaurusClient> robotClients = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
//机器人ID到账户信息的映射
|
//机器人ID到连接ID的映射 用于标识每个机器人连接的唯一性
|
||||||
private final Map<Integer, RobotAccountInfo> robotAccounts = new ConcurrentHashMap<>();
|
|
||||||
|
|
||||||
//机器人ID到连接ID的映射,用于标识每个机器人连接的唯一性
|
|
||||||
private final Map<Integer, String> robotConnectionIds = new ConcurrentHashMap<>();
|
private final Map<Integer, String> robotConnectionIds = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
//机器人连接锁,防止重复连接
|
||||||
|
private final Map<Integer, Object> robotConnectionLocks = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
//机器人管理器引用
|
//机器人管理器引用
|
||||||
private final RobotManager robotManager;
|
private final RobotManager robotManager;
|
||||||
|
|
||||||
//心跳和重连
|
|
||||||
private final Map<Integer, ScheduledFuture<?>> heartbeatTasks = new ConcurrentHashMap<>();
|
|
||||||
private final Map<Integer, String> robotServerAddresses = new ConcurrentHashMap<>();
|
|
||||||
private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(10);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 机器人账户信息
|
|
||||||
*/
|
|
||||||
public static class RobotAccountInfo {
|
|
||||||
private int robotId;
|
|
||||||
private String account;
|
|
||||||
private String password;
|
|
||||||
private String session;
|
|
||||||
private String token;
|
|
||||||
private int groupId;
|
|
||||||
private String roomId;
|
|
||||||
private int gameId;
|
|
||||||
|
|
||||||
public RobotAccountInfo(int robotId, String account, String password, int groupId) {
|
|
||||||
this.robotId = robotId;
|
|
||||||
this.account = account;
|
|
||||||
this.password = password;
|
|
||||||
this.groupId = groupId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getRobotId() { return robotId; }
|
|
||||||
public void setRobotId(int robotId) { this.robotId = robotId; }
|
|
||||||
public String getAccount() { return account; }
|
|
||||||
public void setAccount(String account) { this.account = account; }
|
|
||||||
public String getPassword() { return password; }
|
|
||||||
public void setPassword(String password) { this.password = password; }
|
|
||||||
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; }
|
|
||||||
public int getGroupId() { return groupId; }
|
|
||||||
public void setGroupId(int groupId) { this.groupId = groupId; }
|
|
||||||
public String getRoomId() { return roomId; }
|
|
||||||
public void setRoomId(String roomId) { this.roomId = roomId; }
|
|
||||||
public int getGameId() { return gameId; }
|
|
||||||
public void setGameId(int gameId) { this.gameId = gameId; }
|
|
||||||
}
|
|
||||||
|
|
||||||
private RobotConnectionHandler() {
|
private RobotConnectionHandler() {
|
||||||
this.robotManager = RobotManager.getRobotManager();
|
this.robotManager = RobotManager.getRobotManager();
|
||||||
}
|
}
|
||||||
|
|
@ -111,53 +67,68 @@ public class RobotConnectionHandler {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//异步执行连接逻辑
|
//机器人锁 防止重复连接
|
||||||
CompletableFuture.runAsync(() -> {
|
Object lock = robotConnectionLocks.computeIfAbsent(robot.getRobotId(), k -> new Object());
|
||||||
try {
|
synchronized (lock) {
|
||||||
//连接前再次检查leftover_robot数量 防止并发
|
//再次检查是否已经存在有效连接
|
||||||
if (!robotManager.shouldConnectRobot(robot)) {
|
TaurusClient existingClient = robotClients.get(robot.getRobotId());
|
||||||
return;
|
if (existingClient != null && existingClient.isConnected()) {
|
||||||
}
|
log.debug("机器人 {} 已存在有效连接,跳过重复连接", robot.getRobotId());
|
||||||
|
|
||||||
log.info("开始连接机器人 {} 到游戏服务器,玩法ID: {}", robot.getRobotId(), robot.getWanfaId());
|
|
||||||
//TCP客户端连接
|
|
||||||
String serverAddress = getGameServerAddress(robot.getWanfaId());
|
|
||||||
TaurusClient client = new TaurusClient(serverAddress, "game", TaurusClient.ConnectionProtocol.Tcp);
|
|
||||||
client.connect();
|
|
||||||
|
|
||||||
//生成唯一的connecId
|
|
||||||
String connecId = generateConnectionId(robot.getRobotId());
|
|
||||||
|
|
||||||
//先清理可能存在的旧连接
|
|
||||||
TaurusClient oldClient = robotClients.remove(robot.getRobotId());
|
|
||||||
if (oldClient != null && oldClient.isConnected()) {
|
|
||||||
oldClient.killConnection();
|
|
||||||
}
|
|
||||||
|
|
||||||
//保存客户端连接
|
|
||||||
robotClients.put(robot.getRobotId(), client);
|
|
||||||
robotServerAddresses.put(robot.getRobotId(), serverAddress);
|
|
||||||
//保存connecId
|
|
||||||
robotConnectionIds.put(robot.getRobotId(), connecId);
|
|
||||||
|
|
||||||
//设置事件监听器
|
|
||||||
setupInitializationEventListeners(client, robot);
|
|
||||||
|
|
||||||
//连接成功后发送初始化协议
|
|
||||||
sendInitializationProtocol(client, robot);
|
|
||||||
|
|
||||||
//设置机器人连接状态
|
|
||||||
robot.setConnected(true);
|
robot.setConnected(true);
|
||||||
log.info("机器人 {} 成功连接到游戏服务器, ConnectionId: {}", robot.getRobotId(), connecId);
|
return;
|
||||||
|
|
||||||
//启动心跳
|
|
||||||
startHeartTask(robot.getRobotId(), client, robot.getWanfaId());
|
|
||||||
} catch (Exception e) {
|
|
||||||
log.error("连接机器人到游戏服务器时发生异常: " + robot.getRobotId(), e);
|
|
||||||
robot.setConnected(false);
|
|
||||||
disconnectRobot(robot.getRobotId());
|
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
//异步执行连接逻辑
|
||||||
|
CompletableFuture.runAsync(() -> {
|
||||||
|
try {
|
||||||
|
//连接前再次检查leftover_robot数量 防止并发
|
||||||
|
if (!robotManager.shouldConnectRobot(robot)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
log.info("开始连接机器人 {} 到游戏服务器,玩法ID: {}", robot.getRobotId(), robot.getWanfaId());
|
||||||
|
//TCP客户端连接
|
||||||
|
String serverAddress = getGameServerAddress(robot.getWanfaId());
|
||||||
|
TaurusClient client = new TaurusClient(serverAddress, "game", TaurusClient.ConnectionProtocol.Tcp);
|
||||||
|
client.connect();
|
||||||
|
|
||||||
|
//连接成功后发送初始化协议
|
||||||
|
sendInitializationProtocol(client, robot);
|
||||||
|
|
||||||
|
//设置事件监听器
|
||||||
|
setupInitializationEventListeners(client, robot);
|
||||||
|
|
||||||
|
//生成唯一的connecId
|
||||||
|
String connecId = generateConnectionId(robot.getRobotId());
|
||||||
|
|
||||||
|
//先清理可能存在的旧连接
|
||||||
|
TaurusClient oldClient = robotClients.remove(robot.getRobotId());
|
||||||
|
if (oldClient != null && oldClient.isConnected()) {
|
||||||
|
oldClient.killConnection();
|
||||||
|
}
|
||||||
|
|
||||||
|
//保存客户端连接
|
||||||
|
robotClients.put(robot.getRobotId(), client);
|
||||||
|
//保存connecId
|
||||||
|
robotConnectionIds.put(robot.getRobotId(), connecId);
|
||||||
|
|
||||||
|
//设置机器人连接状态
|
||||||
|
robot.setConnected(true);
|
||||||
|
System.out.println("connectRobot机器人尝试连接游戏服务器, client状态 :" + client.isConnected() + "机器人状态 :" + robot.isConnected());
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
System.out.println("连接机器人到游戏服务器时发生异常: " + robot.getRobotId());
|
||||||
|
robotClients.remove(robot.getRobotId());
|
||||||
|
robotConnectionIds.remove(robot.getRobotId());
|
||||||
|
robot.setConnected(false);
|
||||||
|
disconnectRobot(robot.getRobotId());
|
||||||
|
} finally {
|
||||||
|
if (!robotClients.containsKey(robot.getRobotId())) {
|
||||||
|
robotConnectionLocks.remove(robot.getRobotId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -210,77 +181,6 @@ public class RobotConnectionHandler {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 启动心跳任务
|
|
||||||
*/
|
|
||||||
private void startHeartTask(int robotId, TaurusClient client, int wanfaId) {
|
|
||||||
stopHeartTask(robotId);
|
|
||||||
|
|
||||||
ScheduledFuture<?> heartbeatTask = scheduler.scheduleWithFixedDelay(() -> {
|
|
||||||
try {
|
|
||||||
if (client != null && client.isConnected()) {
|
|
||||||
//发送心跳包
|
|
||||||
ITObject heartbeatParam = new TObject();
|
|
||||||
heartbeatParam.putString("type", "heartbeat");
|
|
||||||
heartbeatParam.putInt("robot_id", robotId);
|
|
||||||
heartbeatParam.putInt("wanfa_id", wanfaId);
|
|
||||||
heartbeatParam.putString("connecId", robotConnectionIds.get(robotId));
|
|
||||||
heartbeatParam.putLong("timestamp", System.currentTimeMillis());
|
|
||||||
|
|
||||||
client.send("ping", heartbeatParam, response -> {
|
|
||||||
if (response != null) {
|
|
||||||
log.debug("机器人 {} 心跳响应成功", robotId);
|
|
||||||
} else {
|
|
||||||
log.warn("机器人 {} 心跳响应失败", robotId);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
log.warn("机器人 {} 连接已断开,无法发送心跳", robotId);
|
|
||||||
//连接断开 尝试重连
|
|
||||||
RobotInfo robot = robotManager.getConnectedRobot(robotId);
|
|
||||||
if (robot != null) {
|
|
||||||
scheduleReconnection(robot);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
log.error("发送心跳时发生异常,机器人: " + robotId, e);
|
|
||||||
}
|
|
||||||
}, 30, 30, TimeUnit.SECONDS);//30秒发送一次心跳
|
|
||||||
|
|
||||||
heartbeatTasks.put(robotId, heartbeatTask);
|
|
||||||
log.info("已启动机器人 {} 的心跳任务", robotId);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 停止心跳任务
|
|
||||||
*/
|
|
||||||
private void stopHeartTask(int robotId) {
|
|
||||||
ScheduledFuture<?> task = heartbeatTasks.remove(robotId);
|
|
||||||
if (task != null && !task.isCancelled()) {
|
|
||||||
robotConnectionIds.remove(robotId);
|
|
||||||
task.cancel(false);
|
|
||||||
log.info("已停止机器人 {} 的心跳任务", robotId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 计划重连任务
|
|
||||||
*/
|
|
||||||
private void scheduleReconnection(RobotInfo robot) {
|
|
||||||
scheduler.schedule(() -> {
|
|
||||||
try {
|
|
||||||
log.info("开始重连机器人: {}", robot.getRobotId());
|
|
||||||
//清理可能存在的旧连接
|
|
||||||
robot.setConnected(false);
|
|
||||||
disconnectRobot(robot.getRobotId());
|
|
||||||
//重新连接
|
|
||||||
connectRobot(robot);
|
|
||||||
} catch (Exception e) {
|
|
||||||
log.error("重连机器人失败: {}", robot.getRobotId(), e);
|
|
||||||
}
|
|
||||||
}, 2, TimeUnit.SECONDS);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 根据游戏ID获取服务器地址
|
* 根据游戏ID获取服务器地址
|
||||||
*/
|
*/
|
||||||
|
|
@ -295,7 +195,7 @@ public class RobotConnectionHandler {
|
||||||
return "8.138.242.190:6841";
|
return "8.138.242.190:6841";
|
||||||
default:
|
default:
|
||||||
log.warn("未知的玩法ID: {}, 使用默认服务器地址", wanfaId);
|
log.warn("未知的玩法ID: {}, 使用默认服务器地址", wanfaId);
|
||||||
return "192.168.0.32:6311"; //默认地址
|
return "127.0.0.1:6311"; //默认地址
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -305,21 +205,25 @@ public class RobotConnectionHandler {
|
||||||
public void disconnectRobot(int robotId) {
|
public void disconnectRobot(int robotId) {
|
||||||
try {
|
try {
|
||||||
log.info("清理机器人 {} 的连接资源", robotId);
|
log.info("清理机器人 {} 的连接资源", robotId);
|
||||||
stopHeartTask(robotId);
|
Object lock = robotConnectionLocks.computeIfAbsent(robotId, k -> new Object());
|
||||||
//移除机器人TCP客户端连接
|
synchronized (lock) {
|
||||||
TaurusClient client = robotClients.remove(robotId);
|
//移除机器人TCP客户端连接
|
||||||
if (client != null) {
|
TaurusClient client = robotClients.remove(robotId);
|
||||||
client.killConnection();
|
if (client != null) {
|
||||||
log.debug("已清理机器人 {} 的客户端连接", robotId);
|
client.killConnection();
|
||||||
|
log.debug("已清理机器人 {} 的客户端连接", robotId);
|
||||||
|
}
|
||||||
|
//移除连接ID
|
||||||
|
robotConnectionIds.remove(robotId);
|
||||||
|
|
||||||
|
//清理锁对象
|
||||||
|
robotConnectionLocks.remove(robotId);
|
||||||
}
|
}
|
||||||
//移除机器人信息
|
|
||||||
RobotAccountInfo robotAccountInfo = robotAccounts.remove(robotId);
|
//从RobotManager中获取机器人信息并断开连接
|
||||||
if (robotAccountInfo != null && robotManager != null) {
|
RobotInfo robot = robotManager.getConnectedRobot(robotId);
|
||||||
//调用RobotManager的统一断开服务
|
if (robot != null) {
|
||||||
robotManager.safeDisconnectRobot(robotId,
|
robotManager.safeDisconnectRobot(robotId, robot.getGroupId(), robot.getWanfaId(), robot.getRoomId());
|
||||||
robotAccountInfo.getGroupId(),
|
|
||||||
robotAccountInfo.getGameId(),
|
|
||||||
robotAccountInfo.getRoomId());
|
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("断开机器人连接时发生异常: " + robotId, e);
|
log.error("断开机器人连接时发生异常: " + robotId, e);
|
||||||
|
|
@ -342,7 +246,8 @@ public class RobotConnectionHandler {
|
||||||
//发送离开房间协议
|
//发送离开房间协议
|
||||||
ITObject param = new TObject();
|
ITObject param = new TObject();
|
||||||
param.putString("robotId", String.valueOf(robot.getRobotId()));
|
param.putString("robotId", String.valueOf(robot.getRobotId()));
|
||||||
param.putString("connecId", robotConnectionIds.get(robot.getRobotId())); // 添加connecId
|
param.putString("connecId", robotConnectionIds.get(robot.getRobotId()));
|
||||||
|
System.out.println("readyTimeRobotExit 2005 client: "+ robotConnectionIds.get(robot.getRobotId()));
|
||||||
client.send("2005", param, response -> {
|
client.send("2005", param, response -> {
|
||||||
log.debug("机器人 {} 发送离开房间请求", robot.getRobotId());
|
log.debug("机器人 {} 发送离开房间请求", robot.getRobotId());
|
||||||
});
|
});
|
||||||
|
|
@ -407,20 +312,24 @@ public class RobotConnectionHandler {
|
||||||
/**
|
/**
|
||||||
* 发送加入房间消息给指定机器人
|
* 发送加入房间消息给指定机器人
|
||||||
*/
|
*/
|
||||||
public void sendJoinRoomMessage(RobotInfo robot) {
|
public void sendJoinRoomMessageAsync(RobotInfo robot, Consumer<Boolean> callback) {
|
||||||
TaurusClient client = robotClients.get(robot.getRobotId());
|
TaurusClient client = robotClients.get(robot.getRobotId());
|
||||||
|
|
||||||
if (client == null) {
|
if (client == null) {
|
||||||
log.warn("机器人 {} 没有有效的TCP连接,无法发送加入房间消息", robot.getRobotId());
|
callback.accept(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ITObject readyParam = new TObject();
|
ITObject readyParam = new TObject();
|
||||||
|
readyParam.putInt("groupId", robot.getGroupId());
|
||||||
|
readyParam.putString("roomId", robot.getRoomId());
|
||||||
|
|
||||||
readyParam.putString("session", robot.getSession() + "," + robot.getToken());
|
readyParam.putString("session", robot.getSession() + "," + robot.getToken());
|
||||||
readyParam.putString("robotId", String.valueOf(robot.getRobotId()));
|
readyParam.putString("robotId", String.valueOf(robot.getRobotId()));
|
||||||
readyParam.putString("connecId", robotConnectionIds.get(robot.getRobotId()));
|
readyParam.putString("connecId", robotConnectionIds.get(robot.getRobotId()));
|
||||||
|
System.out.println("sendJoinRoomMessageAsync 2002 client: "+ robotConnectionIds.get(robot.getRobotId()));
|
||||||
client.send("2002", readyParam, response -> {
|
client.send("2002", readyParam, response -> {
|
||||||
log.debug("机器人 {} 发送加入房间请求响应: {}", robot.getRobotId(), response);
|
boolean success = response != null && response.returnCode == 0;
|
||||||
|
callback.accept(success);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -486,13 +395,95 @@ public class RobotConnectionHandler {
|
||||||
readyParam.putString("session", robot.getSession() + "," + robot.getToken());
|
readyParam.putString("session", robot.getSession() + "," + robot.getToken());
|
||||||
readyParam.putString("robotId", String.valueOf(robot.getRobotId()));
|
readyParam.putString("robotId", String.valueOf(robot.getRobotId()));
|
||||||
readyParam.putString("connecId", robotConnectionIds.get(robot.getRobotId()));
|
readyParam.putString("connecId", robotConnectionIds.get(robot.getRobotId()));
|
||||||
|
System.out.println("sendReadyMessage 2003 client: "+ robotConnectionIds.get(robot.getRobotId()));
|
||||||
client.send("2003", readyParam, response -> {
|
client.send("2003", readyParam, response -> {
|
||||||
boolean success = response != null && response.returnCode == 0;
|
boolean success = response != null && response.returnCode == 0;
|
||||||
callback.accept(success);
|
callback.accept(success);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 异步发送加入房间消息给指定机器人,返回CompletableFuture
|
||||||
|
*/
|
||||||
|
public CompletableFuture<Boolean> sendJoinRoomMessageAsyncCompletable(RobotInfo robot) {
|
||||||
|
CompletableFuture<Boolean> future = new CompletableFuture<>();
|
||||||
|
|
||||||
|
TaurusClient client = robotClients.get(robot.getRobotId());
|
||||||
|
if (client == null) {
|
||||||
|
future.complete(false);
|
||||||
|
return future;
|
||||||
|
}
|
||||||
|
|
||||||
|
ITObject readyParam = new TObject();
|
||||||
|
readyParam.putInt("groupId", robot.getGroupId());
|
||||||
|
readyParam.putString("roomId", robot.getRoomId());
|
||||||
|
|
||||||
|
readyParam.putString("session", robot.getSession() + "," + robot.getToken());
|
||||||
|
readyParam.putString("robotId", String.valueOf(robot.getRobotId()));
|
||||||
|
readyParam.putString("connecId", robotConnectionIds.get(robot.getRobotId()));
|
||||||
|
System.out.println("sendJoinRoomMessageAsync 2002 client: " + robotConnectionIds.get(robot.getRobotId()));
|
||||||
|
|
||||||
|
// 设置超时机制
|
||||||
|
Timer timer = new Timer();
|
||||||
|
timer.schedule(new TimerTask() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
if (!future.isDone()) {
|
||||||
|
future.completeExceptionally(new RuntimeException("Join room timeout"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, 10000); // 10秒超时
|
||||||
|
|
||||||
|
client.send("2002", readyParam, response -> {
|
||||||
|
boolean success = response != null && response.returnCode == 0;
|
||||||
|
if (!future.isDone()) {
|
||||||
|
future.complete(success);
|
||||||
|
}
|
||||||
|
timer.cancel();
|
||||||
|
});
|
||||||
|
|
||||||
|
return future;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 异步发送准备消息给指定机器人,返回CompletableFuture
|
||||||
|
*/
|
||||||
|
public CompletableFuture<Boolean> sendReadyMessageAsyncCompletable(RobotInfo robot) {
|
||||||
|
CompletableFuture<Boolean> future = new CompletableFuture<>();
|
||||||
|
|
||||||
|
TaurusClient client = robotClients.get(robot.getRobotId());
|
||||||
|
if (client == null) {
|
||||||
|
future.complete(false);
|
||||||
|
return future;
|
||||||
|
}
|
||||||
|
|
||||||
|
ITObject readyParam = new TObject();
|
||||||
|
readyParam.putString("session", robot.getSession() + "," + robot.getToken());
|
||||||
|
readyParam.putString("robotId", String.valueOf(robot.getRobotId()));
|
||||||
|
readyParam.putString("connecId", robotConnectionIds.get(robot.getRobotId()));
|
||||||
|
|
||||||
|
// 设置超时机制
|
||||||
|
Timer timer = new Timer();
|
||||||
|
timer.schedule(new TimerTask() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
if (!future.isDone()) {
|
||||||
|
future.completeExceptionally(new RuntimeException("Ready message timeout"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, 10000); // 10秒超时
|
||||||
|
|
||||||
|
client.send("2003", readyParam, response -> {
|
||||||
|
boolean success = response != null && response.returnCode == 0;
|
||||||
|
if (!future.isDone()) {
|
||||||
|
future.complete(success);
|
||||||
|
}
|
||||||
|
timer.cancel();
|
||||||
|
});
|
||||||
|
|
||||||
|
return future;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 回调接口
|
* 回调接口
|
||||||
*/
|
*/
|
||||||
|
|
@ -511,7 +502,8 @@ public class RobotConnectionHandler {
|
||||||
*/
|
*/
|
||||||
public void sendCreateRoom(RobotInfo robot, int groupId, int wanfaId) {
|
public void sendCreateRoom(RobotInfo robot, int groupId, int wanfaId) {
|
||||||
TaurusClient client = robotClients.get(robot.getRobotId());
|
TaurusClient client = robotClients.get(robot.getRobotId());
|
||||||
if (client == null ) {
|
//todo !client.isConnected()
|
||||||
|
if (client == null || !client.isConnected()) {
|
||||||
connectRobot(robot);
|
connectRobot(robot);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,10 +4,7 @@ import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.*;
|
||||||
import java.util.concurrent.Executors;
|
|
||||||
import java.util.concurrent.ScheduledExecutorService;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
|
|
||||||
import com.group.robot.RobotManager;
|
import com.group.robot.RobotManager;
|
||||||
import com.group.robot.handler.RobotConnectionHandler;
|
import com.group.robot.handler.RobotConnectionHandler;
|
||||||
|
|
@ -79,7 +76,7 @@ public class RoomWanfaMatcher {
|
||||||
log.info("开始为群组 {} 玩法ID {} 启动房间轮询", groupId, wanfaId);
|
log.info("开始为群组 {} 玩法ID {} 启动房间轮询", groupId, wanfaId);
|
||||||
|
|
||||||
//10秒轮询一次
|
//10秒轮询一次
|
||||||
scheduler.scheduleWithFixedDelay(this::pollRooms, 0, 10, TimeUnit.SECONDS);
|
scheduler.scheduleWithFixedDelay(this::pollRooms, 0, 20, TimeUnit.SECONDS);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -163,18 +160,23 @@ public class RoomWanfaMatcher {
|
||||||
|
|
||||||
//房间没人 加入房间
|
//房间没人 加入房间
|
||||||
if (playersStr.equals("[]")) {
|
if (playersStr.equals("[]")) {
|
||||||
//房间是否正在被加入
|
Object roomSpecificLock = robotManager.getRoomLock(roomId);
|
||||||
if (!processingRooms.contains(roomId)) {
|
synchronized (roomSpecificLock) {
|
||||||
processingRooms.add(roomId);
|
if (!processingRooms.contains(roomId)) {
|
||||||
robotJoinRoom(robot, true);
|
processingRooms.add(roomId);
|
||||||
|
robotJoinRoomInternal(robot, true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
//房间有人 不是机器人则加入房间
|
//房间有人 不是机器人则加入房间
|
||||||
Integer robotInRoom = playerIsRobotRedis(playersStr);
|
Integer robotInRoom = playerIsRobotRedis(playersStr);
|
||||||
if (robotInRoom == null) {
|
if (robotInRoom == null) {
|
||||||
if (!processingRooms.contains(roomId)) {
|
Object roomSpecificLock = robotManager.getRoomLock(roomId);
|
||||||
processingRooms.add(roomId);
|
synchronized (roomSpecificLock) {
|
||||||
robotJoinRoom(robot, false);
|
if (!processingRooms.contains(roomId)) {
|
||||||
|
processingRooms.add(roomId);
|
||||||
|
robotJoinRoomInternal(robot, false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -188,70 +190,92 @@ public class RoomWanfaMatcher {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 机器人加入房间
|
* 内部机器人加入房间方法,不包含同步逻辑
|
||||||
|
* @param isRobot 是否是机器人创建房间
|
||||||
|
* @param robot 机器人实例
|
||||||
|
* */
|
||||||
|
private void robotJoinRoomInternal(RobotInfo robot, boolean isRobot) {
|
||||||
|
String roomId = robot != null ? robot.getRoomId() : null;
|
||||||
|
RobotInfo robotInfo = robot;
|
||||||
|
int groupId = robot.getGroupId();
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (robotInfo.getRobotId() == -1) {
|
||||||
|
robotInfo = robotManager.getLoggedInRobotForWanfa(wanfaId);
|
||||||
|
System.out.println("robotJoinRoom机器人加入房间 机器人状态 :" + robot.isConnecting());
|
||||||
|
if (robotInfo == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
robotInfo.setGroupId(groupId);
|
||||||
|
robotInfo.setRoomId(roomId);
|
||||||
|
|
||||||
|
//验证机器人连接状态
|
||||||
|
if (robotInfo.isUsing()) {
|
||||||
|
robotManager.releaseRobot(robotInfo.getRobotId());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 使用CompletableFuture替代嵌套回调,提高可读性和可控性
|
||||||
|
RobotInfo finalRobotInfo = robotInfo;
|
||||||
|
|
||||||
|
// 创建一个完整的加入房间流程
|
||||||
|
CompletableFuture<Boolean> joinFuture = robotConnectionHandler.sendJoinRoomMessageAsyncCompletable(finalRobotInfo);
|
||||||
|
|
||||||
|
joinFuture.thenCompose(joinSuccess -> {
|
||||||
|
if (joinSuccess) {
|
||||||
|
System.out.println("robotJoinRoomInternal机器人加入了房间 机器人状态 :" + robot.isConnecting());
|
||||||
|
// 准备阶段
|
||||||
|
return robotConnectionHandler.sendReadyMessageAsyncCompletable(finalRobotInfo);
|
||||||
|
} else {
|
||||||
|
System.out.println("robotJoinRoomInternal机器人加入了房间 失败 :" + robot.isConnecting());
|
||||||
|
// 加入失败,释放机器人
|
||||||
|
robotManager.releaseRobot(finalRobotInfo.getRobotId());
|
||||||
|
return CompletableFuture.completedFuture(false);
|
||||||
|
}
|
||||||
|
}).thenAccept(readySuccess -> {
|
||||||
|
if (readySuccess) {
|
||||||
|
System.out.println("robotJoinRoomInternal机器人准备 房间 机器人状态 :" + robot.isConnecting());
|
||||||
|
roomToRobotMap.put(roomId, finalRobotInfo.getRobotId());
|
||||||
|
updateRobotStatusRedis(finalRobotInfo);
|
||||||
|
if (isRobot) {
|
||||||
|
//6秒没有玩家加入 则退出房间
|
||||||
|
robotConnectionHandler.readyTimeRobotExit(finalRobotInfo, robotManager.getRoomLock(roomId));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
System.out.println("robotJoinRoomInternal机器人准备 房间 失败 :" + robot.isConnecting());
|
||||||
|
// 准备失败时释放机器人
|
||||||
|
robotManager.releaseRobot(finalRobotInfo.getRobotId());
|
||||||
|
}
|
||||||
|
}).exceptionally(throwable -> {
|
||||||
|
log.error("机器人加入房间流程异常", throwable);
|
||||||
|
robotManager.releaseRobot(finalRobotInfo.getRobotId());
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
if (robotInfo != null) {
|
||||||
|
//释放机器人
|
||||||
|
robotManager.releaseRobot(robotInfo.getRobotId());
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
// 从处理队列中移除房间 - 这个操作是必要的,无论是在哪种情况下
|
||||||
|
processingRooms.remove(roomId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 机器人加入房间 - 保持原有的公共接口
|
||||||
* @param isRobot 是否是机器人创建房间
|
* @param isRobot 是否是机器人创建房间
|
||||||
* @param robot 机器人实例
|
* @param robot 机器人实例
|
||||||
* */
|
* */
|
||||||
private void robotJoinRoom(RobotInfo robot, boolean isRobot) {
|
private void robotJoinRoom(RobotInfo robot, boolean isRobot) {
|
||||||
synchronized (joinRoomLock) {
|
String roomId = robot != null ? robot.getRoomId() : null;
|
||||||
RobotInfo robotInfo = robot;
|
// 使用房间级别的细粒度锁,而不是全局锁
|
||||||
String roomId = robot != null ? robot.getRoomId() : null;
|
Object roomSpecificLock = robotManager.getRoomLock(roomId);
|
||||||
int groupId = robot.getGroupId();
|
|
||||||
try {
|
synchronized (roomSpecificLock) {
|
||||||
if (robotInfo.getRobotId() == -1) {
|
robotJoinRoomInternal(robot, isRobot);
|
||||||
robotInfo = robotManager.getLoggedInRobotForWanfa(wanfaId);
|
|
||||||
robotInfo.setGroupId(groupId);
|
|
||||||
robotInfo.setRoomId(roomId);
|
|
||||||
}
|
|
||||||
|
|
||||||
//加入房间
|
|
||||||
try {
|
|
||||||
GroupRoomBusiness.joinRoom(robotInfo.getGroupId(), robotInfo.getRoomId(), robotInfo.getSession(), null);
|
|
||||||
Thread.sleep(5000);
|
|
||||||
robotConnectionHandler.sendJoinRoomMessage(robotInfo);
|
|
||||||
Thread.sleep(1000);
|
|
||||||
}catch (Exception e) {
|
|
||||||
log.error("加入房间失败", e);
|
|
||||||
processingRooms.remove(roomId);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
//准备
|
|
||||||
RobotInfo finalRobotInfo = robotInfo;
|
|
||||||
robotConnectionHandler.sendReadyMessageAsync(robotInfo, readySuccess -> {
|
|
||||||
if (readySuccess) {
|
|
||||||
roomToRobotMap.put(roomId, finalRobotInfo.getRobotId());
|
|
||||||
updateRobotStatusRedis(finalRobotInfo);
|
|
||||||
if (isRobot) {
|
|
||||||
//6秒没有玩家加入 则退出房间
|
|
||||||
robotConnectionHandler.readyTimeRobotExit(finalRobotInfo, joinRoomLock);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
System.out.println("机器人准备失败");
|
|
||||||
}
|
|
||||||
if (roomId != null) {
|
|
||||||
processingRooms.remove(roomId);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
/*boolean readySuccess = robotConnectionHandler.sendReadyMessageSync(robotInfo);
|
|
||||||
if (readySuccess) {
|
|
||||||
//记录机器人和房间的关联
|
|
||||||
roomToRobotMap.put(roomId, robotInfo.getRobotId());
|
|
||||||
|
|
||||||
updateRobotStatusRedis(robotInfo);
|
|
||||||
|
|
||||||
if (isRobot) {
|
|
||||||
//6秒没有玩家加入 则退出房间
|
|
||||||
robotConnectionHandler.readyTimeRobotExit(robotInfo, joinRoomLock);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
//robotConnectionHandler.disconnectRobot(robotInfo.getRobotId());
|
|
||||||
}*/
|
|
||||||
} catch (Exception e) {
|
|
||||||
if (robotInfo != null) {
|
|
||||||
//robotConnectionHandler.disconnectRobot(robotInfo.getRobotId());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -321,13 +345,14 @@ public class RoomWanfaMatcher {
|
||||||
private void manageRobotConnections(int currentLeftoverRobot) {
|
private void manageRobotConnections(int currentLeftoverRobot) {
|
||||||
if (lastLeftoverRobot != currentLeftoverRobot) {
|
if (lastLeftoverRobot != currentLeftoverRobot) {
|
||||||
if (currentLeftoverRobot <= 0 && lastLeftoverRobot > 0) {
|
if (currentLeftoverRobot <= 0 && lastLeftoverRobot > 0) {
|
||||||
//leftover_robot变为0 断开该玩法与robot_mj_cs的连接
|
//leftover_robot变为0 断开该玩法下未使用的机器人连接
|
||||||
robotManager.disconnectExcessRobots(wanfaId, 0);
|
robotManager.disconnectExcessRobots(wanfaId);
|
||||||
|
lastLeftoverRobot = 0;
|
||||||
} else if (currentLeftoverRobot > 0 && lastLeftoverRobot <= 0) {
|
} else if (currentLeftoverRobot > 0 && lastLeftoverRobot <= 0) {
|
||||||
//leftover_robot变为正数 重新连接机器人到robot_mj_cs
|
//leftover_robot变为正数 检查是否有可用的空闲机器人 没有则连接新的
|
||||||
robotManager.connectRequiredRobots(wanfaId, currentLeftoverRobot);
|
robotManager.connectRequiredRobots(wanfaId, currentLeftoverRobot);
|
||||||
|
lastLeftoverRobot = currentLeftoverRobot;
|
||||||
}
|
}
|
||||||
lastLeftoverRobot = currentLeftoverRobot;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
|
||||||
<gameSetting>
|
<gameSetting>
|
||||||
<host>127.0.0.1</host>
|
<host>192.168.0.32</host>
|
||||||
<intranet>127.0.0.1</intranet>
|
<intranet>192.168.0.32</intranet>
|
||||||
<port>8701</port>
|
<port>8701</port>
|
||||||
<serverId>7701</serverId>
|
<serverId>7701</serverId>
|
||||||
<gameId>10</gameId>
|
<gameId>10</gameId>
|
||||||
|
|
|
||||||
|
|
@ -38,15 +38,15 @@
|
||||||
</poolConfig>
|
</poolConfig>
|
||||||
|
|
||||||
<infos>
|
<infos>
|
||||||
<info name="group1_db0" host="8.148.219.235" password="cssq@2020" port="6379" database="0" timeout="5000"/>
|
<info name="group1_db0" host="8.134.76.43" password="cssq@2020" port="6379" database="0" timeout="5000"/>
|
||||||
<info name="group1_db1" host="8.148.219.235" password="cssq@2020" port="6379" database="1" timeout="5000"/>
|
<info name="group1_db1" host="8.134.76.43" password="cssq@2020" port="6379" database="1" timeout="5000"/>
|
||||||
<info name="group1_db2" host="8.148.219.235" password="cssq@2020" port="6379" database="2" timeout="5000"/>
|
<info name="group1_db2" host="8.134.76.43" password="cssq@2020" port="6379" database="2" timeout="5000"/>
|
||||||
<info name="group1_db5" host="8.148.219.235" password="cssq@2020" port="6379" database="5" timeout="5000"/>
|
<info name="group1_db5" host="8.134.76.43" password="cssq@2020" port="6379" database="5" timeout="5000"/>
|
||||||
<info name="group1_db8" host="8.148.219.235" password="cssq@2020" port="6379" database="8" timeout="5000"/>
|
<info name="group1_db8" host="8.134.76.43" password="cssq@2020" port="6379" database="8" timeout="5000"/>
|
||||||
<info name="group1_db9" host="8.148.219.235" password="cssq@2020" port="6379" database="9" timeout="5000"/>
|
<info name="group1_db9" host="8.134.76.43" password="cssq@2020" port="6379" database="9" timeout="5000"/>
|
||||||
<info name="group1_db10" host="8.148.219.235" password="cssq@2020" port="6379" database="10" timeout="5000"/>
|
<info name="group1_db10" host="8.134.76.43" password="cssq@2020" port="6379" database="10" timeout="5000"/>
|
||||||
<info name="group1_db11" host="8.148.219.235" password="cssq@2020" port="6379" database="11" timeout="5000"/>
|
<info name="group1_db11" host="8.134.76.43" password="cssq@2020" port="6379" database="11" timeout="5000"/>
|
||||||
<info name="tmp_group1_db9" host="8.148.219.235" password="654sads" port="6479" database="9" timeout="5000"/>
|
<info name="tmp_group1_db9" host="8.134.76.43" password="654sads" port="6479" database="9" timeout="5000"/>
|
||||||
</infos>
|
</infos>
|
||||||
<!--<infos>
|
<!--<infos>
|
||||||
<info name="group1_db0" host="127.0.0.1" port="6379" database="0" timeout="5000"/>
|
<info name="group1_db0" host="127.0.0.1" port="6379" database="0" timeout="5000"/>
|
||||||
|
|
|
||||||
|
|
@ -98,33 +98,36 @@ public class Config {
|
||||||
|
|
||||||
public static final String GAME_EVT_TING = "836";
|
public static final String GAME_EVT_TING = "836";
|
||||||
|
|
||||||
// 初始化连接协议
|
public static final String CREATE_ROOM_ROBOT = "create_room_for_robot";
|
||||||
public static final String INIT_CONNECTION = "init_connection";
|
public static final String INIT_CONNECTION = "init_connection";
|
||||||
|
|
||||||
// 创建房间机器人协议
|
/**
|
||||||
public static final String CREATE_ROOM_ROBOT = "create_room_for_robot";
|
* 加入房间 - robot_mgr to robot_mj_cs 的内部协议号
|
||||||
|
*/
|
||||||
|
public static final String JOIN_ROOM = "2002";
|
||||||
|
|
||||||
// 加入房间协议
|
/**
|
||||||
public static final String JOIN_ROOM = "2002";
|
* 发送准备 - robot_mgr to robot_mj_cs 的内部协议号
|
||||||
|
*/
|
||||||
|
public static final String GAME_READY = "2003";
|
||||||
|
|
||||||
// 加入房间CS协议
|
/**
|
||||||
public static final String JOIN_ROOM_CS = "1002";
|
* 退出房间 - robot_mgr to robot_mj_cs 的内部协议号
|
||||||
|
*/
|
||||||
|
public static final String EXIT_ROOM = "2005";
|
||||||
|
|
||||||
// 游戏准备协议
|
/**
|
||||||
public static final String GAME_READY = "2003";
|
* 发送准备 - robot_mj_cs to game_mj_cs 的协议号
|
||||||
|
*/
|
||||||
|
public static final String GAME_READY_CS = "1003";
|
||||||
|
|
||||||
// 游戏准备CS协议
|
/**
|
||||||
public static final String GAME_READY_CS = "1003";
|
* 加入房间 - robot_mgr to game_mj_cs 的内部协议号
|
||||||
|
*/
|
||||||
|
public static final String JOIN_ROOM_CS = "1002";
|
||||||
|
|
||||||
// 退出房间协议
|
/**
|
||||||
public static final String EXIT_ROOM = "2004";
|
* 退出房间 - robot_mgr to game_mj_cs 的内部协议号
|
||||||
|
*/
|
||||||
// 退出房间CS协议
|
public static final String EXIT_ROOM_CS = "1005";
|
||||||
public static final String EXIT_ROOM_CS = "1004";
|
|
||||||
|
|
||||||
// 其他可能的游戏相关协议
|
|
||||||
public static final String GAME_CHAT = "1006";
|
|
||||||
|
|
||||||
// 心跳协议
|
|
||||||
public static final String HEARTBEAT = "9000";
|
|
||||||
}
|
}
|
||||||
|
|
@ -5,18 +5,19 @@ import com.robot.GameInterceptor;
|
||||||
import com.robot.MainServer;
|
import com.robot.MainServer;
|
||||||
import com.taurus.core.entity.ITObject;
|
import com.taurus.core.entity.ITObject;
|
||||||
import com.taurus.core.entity.TObject;
|
import com.taurus.core.entity.TObject;
|
||||||
import com.taurus.core.events.Event;
|
|
||||||
import com.taurus.core.events.IEventListener;
|
|
||||||
import com.taurus.core.routes.ActionKey;
|
import com.taurus.core.routes.ActionKey;
|
||||||
import com.taurus.core.util.ICallback;
|
import com.taurus.core.util.ICallback;
|
||||||
import com.taurus.core.util.StringUtil;
|
|
||||||
import com.taurus.permanent.data.Session;
|
import com.taurus.permanent.data.Session;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import robot.mj.handler.HuNanChangSha;
|
import robot.mj.handler.HuNanChangSha;
|
||||||
import taurus.client.Message;
|
|
||||||
import taurus.client.MessageResponse;
|
import taurus.client.MessageResponse;
|
||||||
import taurus.client.TaurusClient;
|
import taurus.client.TaurusClient;
|
||||||
|
import taurus.client.business.GroupRoomBusiness;
|
||||||
|
|
||||||
|
import java.util.Timer;
|
||||||
|
import java.util.TimerTask;
|
||||||
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 长沙麻将游戏控制器 - 处理游戏协议
|
* 长沙麻将游戏控制器 - 处理游戏协议
|
||||||
|
|
@ -113,40 +114,56 @@ public class EXGameController extends GameController {
|
||||||
@ActionKey(value = Config.JOIN_ROOM, validate = GameInterceptor.NOT_PLAYER)
|
@ActionKey(value = Config.JOIN_ROOM, validate = GameInterceptor.NOT_PLAYER)
|
||||||
public void joinRoom(Session session, ITObject params, int gid) {
|
public void joinRoom(Session session, ITObject params, int gid) {
|
||||||
try {
|
try {
|
||||||
System.out.println("收到加入房间请求,Session: {}, GID: {}, 参数: {}");
|
|
||||||
|
|
||||||
String connecId = params.getString("connecId");
|
String connecId = params.getString("connecId");
|
||||||
TaurusClient client = null;// getCsMjGameServerConnection(connecId);
|
TaurusClient client = getCsMjGameServerConnection(connecId);
|
||||||
client = new TaurusClient("8.134.76.43" + ":" + "6311", "game", TaurusClient.ConnectionProtocol.Tcp);
|
System.out.println("接收来自robot_mgr的加入房间协议 connecId: = "+connecId);
|
||||||
client.connect();
|
System.out.println("接收来自robot_mgr的加入房间协议 client: = "+client);
|
||||||
if (client == null) {
|
if (client == null) {
|
||||||
|
// 返回失败响应而不是直接返回
|
||||||
|
ITObject errorResponse = TObject.newInstance();
|
||||||
|
errorResponse.putString("status", "failed");
|
||||||
|
errorResponse.putString("message", "无法获取游戏服务器连接");
|
||||||
|
MainServer.instance.sendResponse(gid, 1, errorResponse, session);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//设置session和token
|
//设置session和token
|
||||||
String sessionToken = params.getString("session");
|
String sessionToken = params.getString("session");
|
||||||
|
String robotSession = null;
|
||||||
if (sessionToken != null && sessionToken.contains(",")) {
|
if (sessionToken != null && sessionToken.contains(",")) {
|
||||||
String[] sessionParts = sessionToken.split(",");
|
String[] sessionParts = sessionToken.split(",");
|
||||||
if (sessionParts.length >= 2) {
|
if (sessionParts.length >= 2) {
|
||||||
String actualSessionFromParams = sessionParts[0];
|
robotSession = sessionParts[0];
|
||||||
String token = sessionParts[1];
|
String token = sessionParts[1];
|
||||||
connectionManager.setSessionAndToken(actualSessionFromParams, token);
|
connectionManager.setSessionAndToken(robotSession, token);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Integer groupId = params.getInt("groupId");
|
||||||
|
String roomId = params.getString("roomId");
|
||||||
|
|
||||||
//发送加入房间请求
|
// 在当前线程中同步执行阻塞操作
|
||||||
|
GroupRoomBusiness.joinRoom(groupId, roomId, robotSession, null);
|
||||||
|
|
||||||
|
Thread.sleep(5000); // 等待100毫秒后再次检查
|
||||||
|
|
||||||
|
|
||||||
|
// 发送加入房间请求到game_mj_cs
|
||||||
client.send(Config.JOIN_ROOM_CS, params, response -> {
|
client.send(Config.JOIN_ROOM_CS, params, response -> {
|
||||||
System.out.println("csmj OnEvent " + response.returnCode);
|
System.out.println("joinRoom: " + response);
|
||||||
log.info("加入房间请求发送结果: returnCode={}", response.returnCode);
|
|
||||||
});
|
|
||||||
client.addEventListener(TaurusClient.NetClientEvent.OnEvent, new IEventListener() {
|
|
||||||
@Override
|
|
||||||
public void handleEvent(Event event) {
|
|
||||||
System.out.println("csmj OnEvent 能监听:jefe " );
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 发送成功响应
|
||||||
|
ITObject paramsReq = TObject.newInstance();
|
||||||
|
paramsReq.putString("status", "success");
|
||||||
|
MainServer.instance.sendResponse(gid, 0, paramsReq, session);
|
||||||
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("处理加入房间请求时发生错误", e);
|
log.error("处理加入房间请求时发生错误", e);
|
||||||
|
ITObject errorResponse = TObject.newInstance();
|
||||||
|
errorResponse.putString("status", "error");
|
||||||
|
errorResponse.putString("message", "处理加入房间请求时发生错误: " + e.getMessage());
|
||||||
|
MainServer.instance.sendResponse(gid, 1, errorResponse, session);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -158,20 +175,34 @@ public class EXGameController extends GameController {
|
||||||
try {
|
try {
|
||||||
String connecId = params.getString("connecId");
|
String connecId = params.getString("connecId");
|
||||||
TaurusClient client = getCsMjGameServerConnection(connecId);
|
TaurusClient client = getCsMjGameServerConnection(connecId);
|
||||||
System.out.println("session: " + session);
|
System.out.println("接收来自robot_mgr的机器人准备协议 connecId: = "+connecId);
|
||||||
System.out.println("client: " + client);
|
System.out.println("接收来自robot_mgr的机器人准备协议 client: = "+client);
|
||||||
if (client == null) {
|
if (client == null) {
|
||||||
|
ITObject errorResponse = TObject.newInstance();
|
||||||
|
errorResponse.putString("status", "failed");
|
||||||
|
errorResponse.putString("message", "无法获取游戏服务器连接");
|
||||||
|
MainServer.instance.sendResponse(gid, 1, errorResponse, session);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
params.del("connecId");
|
params.del("connecId");
|
||||||
client.send(Config.GAME_READY_CS, params, null);
|
Thread.sleep(1000); // 等待100毫秒后再次检查
|
||||||
|
// 发送准备请求到game_mj_cs
|
||||||
|
client.send(Config.GAME_READY_CS, params, response -> {
|
||||||
|
System.out.println("robotReadyRoom: " + response);
|
||||||
|
});
|
||||||
|
|
||||||
|
// 发送成功响应
|
||||||
ITObject paramsReq = TObject.newInstance();
|
ITObject paramsReq = TObject.newInstance();
|
||||||
paramsReq.putString("status", "success");
|
paramsReq.putString("status", "success");
|
||||||
MainServer.instance.sendResponse(gid, 0, paramsReq, session);
|
MainServer.instance.sendResponse(gid, 0, paramsReq, session);
|
||||||
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("处理机器人准备请求时发生错误", e);
|
log.error("处理机器人准备请求时发生错误", e);
|
||||||
|
ITObject errorResponse = TObject.newInstance();
|
||||||
|
errorResponse.putString("status", "error");
|
||||||
|
errorResponse.putString("message", "服务器内部错误: " + e.getMessage());
|
||||||
|
MainServer.instance.sendResponse(gid, 1, errorResponse, session);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -183,18 +214,21 @@ public class EXGameController extends GameController {
|
||||||
public void exitRoom(Session session, ITObject params, int gid) {
|
public void exitRoom(Session session, ITObject params, int gid) {
|
||||||
try {
|
try {
|
||||||
String connecId = params.getString("connecId");
|
String connecId = params.getString("connecId");
|
||||||
TaurusClient client = getCsMjGameServerConnection(connecId);
|
log.info("处理退出房间请求,connecId: {}", connecId);
|
||||||
|
|
||||||
|
TaurusClient client = getCsMjGameServerConnection(connecId);
|
||||||
if (client == null) {
|
if (client == null) {
|
||||||
|
log.error("无法获取到游戏服务器连接,connecId: {}", connecId);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//发送退出房间请求
|
//发送退出房间请求
|
||||||
client.send(Config.EXIT_ROOM_CS, params, response -> {
|
client.send(Config.EXIT_ROOM_CS, params, response -> {
|
||||||
|
log.info("退出房间请求发送结果: returnCode={} for connecId={}", response.returnCode, connecId);
|
||||||
});
|
});
|
||||||
|
|
||||||
//断开与游戏服务器的连接
|
//断开与游戏服务器的连接
|
||||||
//connectionManager.disconnectFromGameServer(connecId);
|
connectionManager.disconnectFromGameServer(connecId);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("处理退出房间请求时发生错误", e);
|
log.error("处理退出房间请求时发生错误", e);
|
||||||
String connecId = params.getString("connecId");
|
String connecId = params.getString("connecId");
|
||||||
|
|
@ -204,21 +238,17 @@ public class EXGameController extends GameController {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 根据机器人ID和连接ID获取长沙麻将游戏服务器连接
|
* 根据机器人ID和连接ID获取长沙麻将游戏服务器连接
|
||||||
|
* 基于robotId和connectionId的组合复用连接
|
||||||
*/
|
*/
|
||||||
public static TaurusClient getCsMjGameServerConnection(String connecId) {
|
public static TaurusClient getCsMjGameServerConnection(String connecId) {
|
||||||
TaurusClient taurusClient = connectionManager.getGameServerConnection(connecId);
|
TaurusClient taurusClient = connectionManager.getGameClient(connecId);
|
||||||
|
System.out.println("根据机器人ID和连接ID获取长沙麻将游戏服务器连接 client: = "+taurusClient);
|
||||||
if (taurusClient != null) {
|
if (taurusClient != null) {
|
||||||
|
log.debug("成功获取游戏服务器连接,connecId: {}", connecId);
|
||||||
return taurusClient;
|
return taurusClient;
|
||||||
}
|
}
|
||||||
|
taurusClient = connectionManager.connectToGameServer(connecId);
|
||||||
boolean connected = connectionManager.connectToGameServer(connecId);
|
return taurusClient;
|
||||||
if (connected) {
|
|
||||||
taurusClient = connectionManager.getGameServerConnection(connecId);
|
|
||||||
if (taurusClient != null) {
|
|
||||||
return taurusClient;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -28,16 +28,6 @@ import robot.mj.handler.HuNanChangSha;
|
||||||
public class EXMainServer extends MainServer{
|
public class EXMainServer extends MainServer{
|
||||||
private static final Logger log = LoggerFactory.getLogger(EXMainServer.class);
|
private static final Logger log = LoggerFactory.getLogger(EXMainServer.class);
|
||||||
|
|
||||||
//机器人连接管理器
|
|
||||||
private static RobotConnectionManager robotConnectionManager;
|
|
||||||
|
|
||||||
//长沙麻将AI处理器
|
|
||||||
private static HuNanChangSha huNanChangSha;
|
|
||||||
|
|
||||||
//心跳和重连
|
|
||||||
private final Map<String, ScheduledFuture<?>> serverHeartbeatTasks = new ConcurrentHashMap<>();
|
|
||||||
private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(10);
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onStart() {
|
public void onStart() {
|
||||||
super.onStart();
|
super.onStart();
|
||||||
|
|
@ -67,10 +57,7 @@ public class EXMainServer extends MainServer{
|
||||||
* 初始化组件
|
* 初始化组件
|
||||||
*/
|
*/
|
||||||
private void initializeComponents() {
|
private void initializeComponents() {
|
||||||
robotConnectionManager = new RobotConnectionManager();
|
|
||||||
//长沙麻将AI处理器
|
|
||||||
huNanChangSha = new HuNanChangSha();
|
|
||||||
|
|
||||||
log.info("长沙麻将机器人服务器组件初始化完成");
|
log.info("长沙麻将机器人服务器组件初始化完成");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,6 @@ import taurus.client.Message;
|
||||||
import taurus.client.TaurusClient;
|
import taurus.client.TaurusClient;
|
||||||
import redis.clients.jedis.Jedis;
|
import redis.clients.jedis.Jedis;
|
||||||
import robot.mj.handler.HuNanChangSha;
|
import robot.mj.handler.HuNanChangSha;
|
||||||
import taurus.client.business.GroupRoomBusiness;
|
|
||||||
import taurus.util.ChangShaSuanFaTest;
|
import taurus.util.ChangShaSuanFaTest;
|
||||||
import taurus.util.TinHuChi;
|
import taurus.util.TinHuChi;
|
||||||
|
|
||||||
|
|
@ -21,8 +20,6 @@ import java.sql.SQLException;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.concurrent.*;
|
import java.util.concurrent.*;
|
||||||
|
|
||||||
import static java.lang.Thread.sleep;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 机器人连接管理器 - 管理与游戏服务器的连接
|
* 机器人连接管理器 - 管理与游戏服务器的连接
|
||||||
*/
|
*/
|
||||||
|
|
@ -33,10 +30,12 @@ public class RobotConnectionManager {
|
||||||
//存储全局的长沙麻将AI处理器
|
//存储全局的长沙麻将AI处理器
|
||||||
private HuNanChangSha huNanChangSha;
|
private HuNanChangSha huNanChangSha;
|
||||||
|
|
||||||
private final String host="8.134.76.43";
|
private final String host="192.168.0.32";
|
||||||
private final int port=6311;
|
private final int port=6311;
|
||||||
|
|
||||||
private TaurusClient client = null;
|
// 连接状态管理
|
||||||
|
private Map<String, Long> lastActivityTime = new ConcurrentHashMap<>();
|
||||||
|
private Map<String, Boolean> connectionRegistered = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
private Map<Integer, List<Integer>> playerOutcardsMap = new HashMap<>();
|
private Map<Integer, List<Integer>> playerOutcardsMap = new HashMap<>();
|
||||||
|
|
||||||
|
|
@ -59,8 +58,12 @@ public class RobotConnectionManager {
|
||||||
public RobotConnectionManager() {
|
public RobotConnectionManager() {
|
||||||
gameClients = new HashMap<>();
|
gameClients = new HashMap<>();
|
||||||
huNanChangSha = new HuNanChangSha();
|
huNanChangSha = new HuNanChangSha();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取所有session列表
|
* 获取所有session列表
|
||||||
*/
|
*/
|
||||||
|
|
@ -79,13 +82,18 @@ public class RobotConnectionManager {
|
||||||
/**
|
/**
|
||||||
* 连接到长沙麻将游戏服务器
|
* 连接到长沙麻将游戏服务器
|
||||||
*/
|
*/
|
||||||
public boolean connectToGameServer(String connecId) {
|
public TaurusClient connectToGameServer(String connecId) {
|
||||||
try {
|
try {
|
||||||
//检查是否已经连接
|
//检查是否已经连接
|
||||||
if (gameClients.containsKey(connecId)) {
|
if (gameClients.containsKey(connecId)) {
|
||||||
TaurusClient existingClient = gameClients.get(connecId);
|
TaurusClient existingClient = gameClients.get(connecId);
|
||||||
if (existingClient.isConnected()) {
|
if (existingClient.isConnected()) {
|
||||||
return true;
|
//检查是否已注册
|
||||||
|
if (!connectionRegistered.getOrDefault(connecId, false)) {
|
||||||
|
//如果连接存在但未注册 尝试重新注册
|
||||||
|
reRegisterConnection(connecId, existingClient);
|
||||||
|
}
|
||||||
|
return existingClient;
|
||||||
} else {
|
} else {
|
||||||
//连接断开 移除旧的客户端
|
//连接断开 移除旧的客户端
|
||||||
disconnectFromGameServer(connecId);
|
disconnectFromGameServer(connecId);
|
||||||
|
|
@ -93,22 +101,9 @@ public class RobotConnectionManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
//创建Taurus客户端
|
//创建Taurus客户端
|
||||||
client = new TaurusClient(host + ":" + port, "game", TaurusClient.ConnectionProtocol.Tcp);
|
TaurusClient client = new TaurusClient(host + ":" + port, "game", TaurusClient.ConnectionProtocol.Tcp);
|
||||||
client.connect();
|
|
||||||
|
//添加事件监听器处理网络消息和连接断开 - 必须在连接之前添加监听器
|
||||||
|
|
||||||
|
|
||||||
System.out.println("csmj OnEvent " + client.getSession());
|
|
||||||
/// GroupRoomBusiness.joinRoom(383709, "room:592473", "{user}:101555", null);
|
|
||||||
//Thread.sleep(5000);
|
|
||||||
System.out.println("csmj OnEvent2 " + client.getSession());
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
System.out.println("client.getSession()1111" +client.getSession());
|
|
||||||
System.out.println("client.getId()1111" +client.getId());
|
|
||||||
//添加事件监听器处理网络消息和连接断开
|
|
||||||
client.addEventListener(TaurusClient.NetClientEvent.OnEvent, new IEventListener() {
|
client.addEventListener(TaurusClient.NetClientEvent.OnEvent, new IEventListener() {
|
||||||
@Override
|
@Override
|
||||||
public void handleEvent(Event event) {
|
public void handleEvent(Event event) {
|
||||||
|
|
@ -117,7 +112,6 @@ public class RobotConnectionManager {
|
||||||
//获取 msg
|
//获取 msg
|
||||||
Message message = (Message) event.getParameter("msg");
|
Message message = (Message) event.getParameter("msg");
|
||||||
if (message == null) {
|
if (message == null) {
|
||||||
System.out.println("在OnEvent中收到空消息");
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -126,9 +120,9 @@ public class RobotConnectionManager {
|
||||||
String command = message.command;
|
String command = message.command;
|
||||||
System.out.println("csmj OnEvent msg: " + command);
|
System.out.println("csmj OnEvent msg: " + command);
|
||||||
|
|
||||||
// 添加更详细的日志
|
//更新最后活动时间
|
||||||
System.out.println("收到协议命令: " + command + " params: " + param);
|
lastActivityTime.put(connecId, System.currentTimeMillis());
|
||||||
|
|
||||||
//根据玩法ID处理不同的回调
|
//根据玩法ID处理不同的回调
|
||||||
if (StringUtil.isNotEmpty(command)) {
|
if (StringUtil.isNotEmpty(command)) {
|
||||||
//直接处理协议
|
//直接处理协议
|
||||||
|
|
@ -136,50 +130,79 @@ public class RobotConnectionManager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
//添加连接状态监听器
|
//添加连接状态监听器
|
||||||
client.addEventListener(TaurusClient.NetClientEvent.Connect, new IEventListener() {
|
client.addEventListener(TaurusClient.NetClientEvent.Connect, new IEventListener() {
|
||||||
@Override
|
@Override
|
||||||
public void handleEvent(Event event) {
|
public void handleEvent(Event event) {
|
||||||
System.out.println("Connect");
|
System.out.println("Connect");
|
||||||
System.out.println("csmj Connect connecId: " + connecId);
|
System.out.println("csmj Connect connecId: " + connecId);
|
||||||
|
|
||||||
|
//连接成功后立即尝试注册连接
|
||||||
|
registerConnection(connecId, client);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 添加连接断开监听器
|
||||||
|
/* client.addEventListener(TaurusClient.NetClientEvent.Disconnect, new IEventListener() {
|
||||||
|
@Override
|
||||||
|
public void handleEvent(Event event) {
|
||||||
|
System.out.println("Connection disconnected for connecId: " + connecId);
|
||||||
|
connectionRegistered.put(connecId, false);
|
||||||
|
}
|
||||||
|
});*/
|
||||||
|
|
||||||
|
client.connect();
|
||||||
|
//连接成功后立即尝试注册连接
|
||||||
|
//registerConnection(connecId, client);
|
||||||
|
|
||||||
ITObject readyParam = new TObject();
|
|
||||||
readyParam.putString("session","{user}:101555,c739ec6c3e93e9655e507397f78d857f");
|
|
||||||
readyParam.putString("pos", "10,10");
|
|
||||||
//readyParam.putString("connecId", "1");
|
|
||||||
//pos
|
|
||||||
client.send(Config.JOIN_ROOM_CS, readyParam, response -> {
|
|
||||||
System.out.println("csmj OnEvent " + response.returnCode);
|
|
||||||
log.info("加入房间请求发送结果: returnCode={}", response.returnCode);
|
|
||||||
});
|
|
||||||
|
|
||||||
readyParam.del("connecId");
|
|
||||||
sleep(5000);
|
|
||||||
client.send(Config.GAME_READY_CS, readyParam, null);
|
|
||||||
|
|
||||||
|
|
||||||
System.out.println(client);
|
|
||||||
System.out.println("client.getSession()2222" +client.getSession());
|
|
||||||
System.out.println("client.getId()2222" +client.getId());
|
|
||||||
gameClients.put(connecId, client);
|
gameClients.put(connecId, client);
|
||||||
System.out.println("gameClients" + gameClients.get(connecId));
|
|
||||||
|
|
||||||
return true;
|
return client;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("连接到游戏服务器时发生异常", e);
|
log.error("连接到游戏服务器时发生异常", e);
|
||||||
return false;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 注册连接到游戏服务器
|
||||||
|
*/
|
||||||
|
private void registerConnection(String connecId, TaurusClient client) {
|
||||||
|
ITObject authParam = new TObject();
|
||||||
|
authParam.putString("type", "robot_auth");
|
||||||
|
authParam.putString("connecId", connecId);
|
||||||
|
authParam.putInt("playerId", 0); // 机器人ID占位符
|
||||||
|
|
||||||
|
client.send("1000", authParam, response -> {
|
||||||
|
System.out.println("Robot authentication sent for connecId: " + connecId + ", response: " + response.returnCode);
|
||||||
|
|
||||||
|
if (response.returnCode == 0) {
|
||||||
|
connectionRegistered.put(connecId, true);
|
||||||
|
System.out.println("Successfully registered connection for connecId: " + connecId);
|
||||||
|
} else {
|
||||||
|
System.out.println("Failed to register connection for connecId: " + connecId);
|
||||||
|
connectionRegistered.put(connecId, false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 重新注册连接
|
||||||
|
*/
|
||||||
|
private void reRegisterConnection(String connecId, TaurusClient client) {
|
||||||
|
System.out.println("Re-registering connection for connecId: " + connecId);
|
||||||
|
registerConnection(connecId, client);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 断开与游戏服务器的连接
|
* 断开与游戏服务器的连接
|
||||||
*/
|
*/
|
||||||
public void disconnectFromGameServer(String compositeKey) {
|
public void disconnectFromGameServer(String compositeKey) {
|
||||||
TaurusClient client = gameClients.remove(compositeKey);
|
TaurusClient client = gameClients.remove(compositeKey);
|
||||||
|
connectionRegistered.remove(compositeKey);
|
||||||
|
lastActivityTime.remove(compositeKey);
|
||||||
|
|
||||||
if (client != null && client.isConnected()) {
|
if (client != null && client.isConnected()) {
|
||||||
try {
|
try {
|
||||||
client.killConnection();
|
client.killConnection();
|
||||||
|
|
@ -189,26 +212,11 @@ public class RobotConnectionManager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void main(String[] args) {
|
|
||||||
RobotConnectionManager rb=new RobotConnectionManager();
|
|
||||||
boolean i = rb.connectToGameServer("1");
|
|
||||||
System.out.println(i);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 根据connecId获取游戏服务器连接
|
* 根据connecId获取游戏服务器连接
|
||||||
*/
|
*/
|
||||||
public TaurusClient getGameServerConnection(String connecId) {
|
public TaurusClient getGameClient(String connecId) {
|
||||||
TaurusClient client = gameClients.get(connecId);
|
return gameClients.get(connecId);
|
||||||
|
|
||||||
if (client == null) {
|
|
||||||
System.out.println("Attempting to reconnect: " + connecId);
|
|
||||||
// 尝试重新连接
|
|
||||||
connectToGameServer(connecId);
|
|
||||||
client = gameClients.get(connecId);
|
|
||||||
}
|
|
||||||
|
|
||||||
return client;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -315,24 +323,20 @@ public class RobotConnectionManager {
|
||||||
HuNanChangSha.drawCard(command, message);
|
HuNanChangSha.drawCard(command, message);
|
||||||
break;
|
break;
|
||||||
case "819": //摸牌
|
case "819": //摸牌
|
||||||
System.out.println("Handling 819 - Draw card");
|
|
||||||
huNanChangSha.getCard(command, message);
|
huNanChangSha.getCard(command, message);
|
||||||
break;
|
break;
|
||||||
case "813": //出牌提示
|
case "813": //出牌提示
|
||||||
System.out.println("Handling 813 - Discard card tip received!");
|
|
||||||
huNanChangSha.outCard(client,playerOutcardsMap,playerchisMap,playerpengsMap,playermingsMap,playerzisMap);
|
huNanChangSha.outCard(client,playerOutcardsMap,playerchisMap,playerpengsMap,playermingsMap,playerzisMap);
|
||||||
break;
|
break;
|
||||||
case "814": //操作提示(吃碰杠胡)
|
case "814": //操作提示(吃碰杠胡)
|
||||||
System.out.println("Handling 814 - Action tips (Chi, Peng, Gang, Hu)");
|
|
||||||
huNanChangSha.actionCard(param, client);
|
huNanChangSha.actionCard(param, client);
|
||||||
break;
|
break;
|
||||||
case "2009": //其他操作 - 房间检查和踢人逻辑
|
case "2009": //其他操作 - 房间检查和踢人逻辑
|
||||||
System.out.println("Handling 2009 - Other operations");
|
|
||||||
try {
|
try {
|
||||||
Jedis jedis22 = Redis.use().getJedis();
|
Jedis jedis22 = Redis.use().getJedis();
|
||||||
// 使用JiQiRens的sleepTime方法
|
// 使用JiQiRens的sleepTime方法
|
||||||
try {
|
try {
|
||||||
sleep(3000);
|
Thread.sleep(3000);
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
|
|
@ -479,16 +483,13 @@ public class RobotConnectionManager {
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
case "815": //服务器通知客户端有玩家执行了操作
|
case "815": //服务器通知客户端有玩家执行了操作
|
||||||
System.out.println("Handling 815 - Server notifies client of player action");
|
|
||||||
//[TCP->815] data:{"playerid":101555,"card":104,"opcard":[105,103],"from_seat":2,"type":1,"opengang":false}
|
//[TCP->815] data:{"playerid":101555,"card":104,"opcard":[105,103],"from_seat":2,"type":1,"opengang":false}
|
||||||
huNanChangSha.shanchuchuguopai(param);
|
huNanChangSha.shanchuchuguopai(param);
|
||||||
break;
|
break;
|
||||||
case "820": //换牌提示
|
case "820": //换牌提示
|
||||||
System.out.println("Handling 820 - Change card tips");
|
|
||||||
HuNanChangSha.changePlayer(command, message);
|
HuNanChangSha.changePlayer(command, message);
|
||||||
break;
|
break;
|
||||||
case "825":
|
case "825":
|
||||||
System.out.println("Handling 825");
|
|
||||||
ITObject params25 = TObject.newInstance();
|
ITObject params25 = TObject.newInstance();
|
||||||
params25.putInt("qi", 0);
|
params25.putInt("qi", 0);
|
||||||
params25.putInt("id", 1);
|
params25.putInt("id", 1);
|
||||||
|
|
@ -498,7 +499,6 @@ public class RobotConnectionManager {
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
case "822":
|
case "822":
|
||||||
System.out.println("Handling 822");
|
|
||||||
ITObject params22 = TObject.newInstance();
|
ITObject params22 = TObject.newInstance();
|
||||||
//params.putInt("qi", 0);
|
//params.putInt("qi", 0);
|
||||||
params22.putInt("id", 1);
|
params22.putInt("id", 1);
|
||||||
|
|
@ -510,7 +510,6 @@ public class RobotConnectionManager {
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
case "2008": //解散房间时候恢复机器人账号可以使用
|
case "2008": //解散房间时候恢复机器人账号可以使用
|
||||||
System.out.println("Handling 2008 - Restore robot accounts when room is dismissed");
|
|
||||||
// Jedis jedis11s = Redis.use("group1_db11").getJedis();
|
// Jedis jedis11s = Redis.use("group1_db11").getJedis();
|
||||||
// String key = "g{" + groupId + "}:play:" + pid;
|
// String key = "g{" + groupId + "}:play:" + pid;
|
||||||
//
|
//
|
||||||
|
|
@ -542,7 +541,6 @@ public class RobotConnectionManager {
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case "838": //补杠事件
|
case "838": //补杠事件
|
||||||
System.out.println("Handling 838 - Bu Gang event");
|
|
||||||
int card838 = param.getInt("card");
|
int card838 = param.getInt("card");
|
||||||
ITObject params838 = new TObject();
|
ITObject params838 = new TObject();
|
||||||
params838.putInt("card", card838);
|
params838.putInt("card", card838);
|
||||||
|
|
@ -552,7 +550,6 @@ public class RobotConnectionManager {
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
case "816": //抢杠胡
|
case "816": //抢杠胡
|
||||||
System.out.println("Handling 816 - Qiang Gang Hu");
|
|
||||||
int card816 = param.getInt("card");
|
int card816 = param.getInt("card");
|
||||||
ITObject params816 = new TObject();
|
ITObject params816 = new TObject();
|
||||||
params816.putInt("type", 21); //胡牌类型
|
params816.putInt("type", 21); //胡牌类型
|
||||||
|
|
@ -563,7 +560,6 @@ public class RobotConnectionManager {
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
case "821": //吃牌
|
case "821": //吃牌
|
||||||
System.out.println("Handling 821 - Chi Pai");
|
|
||||||
int card821 = param.getInt("card");
|
int card821 = param.getInt("card");
|
||||||
ITObject params821 = new TObject();
|
ITObject params821 = new TObject();
|
||||||
params821.putInt("type", 21); //吃牌类型
|
params821.putInt("type", 21); //吃牌类型
|
||||||
|
|
@ -574,14 +570,12 @@ public class RobotConnectionManager {
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
case "823": //杠后补牌
|
case "823": //杠后补牌
|
||||||
System.out.println("Handling 823 - Gang after draw card");
|
|
||||||
//处理杠后补牌逻辑
|
//处理杠后补牌逻辑
|
||||||
int card823 = param.getInt("card");
|
int card823 = param.getInt("card");
|
||||||
huNanChangSha.getChangShaCardInhand().add(card823);
|
huNanChangSha.getChangShaCardInhand().add(card823);
|
||||||
log.info("杠后补牌: " + card823 + ", 当前手牌: " + huNanChangSha.getChangShaCardInhand());
|
log.info("杠后补牌: " + card823 + ", 当前手牌: " + huNanChangSha.getChangShaCardInhand());
|
||||||
break;
|
break;
|
||||||
case "835": //听牌相关
|
case "835": //听牌相关
|
||||||
System.out.println("Handling 835 - Ting Pai related");
|
|
||||||
ITObject params835 = new TObject();
|
ITObject params835 = new TObject();
|
||||||
params835.putInt("qi", 0);
|
params835.putInt("qi", 0);
|
||||||
params835.putInt("id", 1);
|
params835.putInt("id", 1);
|
||||||
|
|
@ -591,9 +585,11 @@ public class RobotConnectionManager {
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
System.out.println("Received unknown protocol command: " + command + ", params: " + param);
|
System.out.println("收到未知协议命令: " + command + ", 参数: " + param);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
Loading…
Reference in New Issue