完善TCP多连接的同步打牌功能

master
zhouwei 2026-02-05 06:23:44 +08:00
parent 74d0d4c989
commit 1c5d453fb6
5 changed files with 502 additions and 201 deletions

View File

@ -26,7 +26,7 @@ import java.util.concurrent.ConcurrentHashMap;
public class EXGameController extends GameController {
private static final Logger log = LoggerFactory.getLogger(EXGameController.class);
private static RobotConnectionManager robotConnectionManager = new RobotConnectionManager();
private static final RobotConnectionManager robotConnectionManager = new RobotConnectionManager();
//机器人房间
protected static final Map<String, RobotUser> robotRoomMapping = new ConcurrentHashMap<>();
@ -131,12 +131,13 @@ public class EXGameController extends GameController {
//设置session和token
String sessionToken = params.getString("session");
String robotSession = null;
String token = null;
if (sessionToken != null && sessionToken.contains(",")) {
String[] sessionParts = sessionToken.split(",");
if (sessionParts.length >= 2) {
robotSession = sessionParts[0];
String token = sessionParts[1];
robotConnectionManager.setSessionAndToken(robotSession, token);
token = sessionParts[1];
robotConnectionManager.setSessionAndToken(robotSession, token, connecId);
}
}
@ -218,7 +219,7 @@ public class EXGameController extends GameController {
int robotId = params.getInt("robotid");
String roomId = params.getString("roomid");
int groupId = params.getInt("groupid");
try (Jedis jedis0 = Redis.use("group1_db0").getJedis()){
try (Jedis jedis0 = Redis.use("group1_db0").getJedis();Jedis jedis2 = Redis.use("group1_db2").getJedis()){
Set<String> robotTokens = jedis0.smembers("{user}:"+robotId+"_token");
String robotSession = null;
@ -239,10 +240,13 @@ public class EXGameController extends GameController {
//机器人房间映射关系
RobotUser robotUser = getRobotRoomInfo(String.valueOf(robotId));
if (robotUser.getRoomId() == null) {
if (robotUser.getCurrentRoomId() == 0) {
robotUser.setCurrentRoomId(Integer.parseInt(roomId));
robotUser.setClient(client);
robotUser.setConnecId(roomId+ "_"+ robotId);
}
robotRoomMapping.put(robotUser.getConnecId(), robotUser);
robotRoomMapping.remove(robotUser.getRobotId());
System.out.println(roomId);
System.out.println(Integer.parseInt(roomId));
System.out.println(robotUser.getCurrentRoomId());
@ -259,6 +263,66 @@ public class EXGameController extends GameController {
client.send(Config.GAME_READY_CS, params, response -> {
System.out.println("1003:"+response);
});
jedis2.hset("gallrobot", String.valueOf(robotUser.getRobotId()), "1");
robotUser.setStatus(ROBOTEventType.ROBOT_INTOROOM_READY);
robotConnectionManager.setSessionAndToken("{user}:"+robotId, robotSession, robotUser.getConnecId());
}
robotUser.setIntoRoomTime(robotConnectionManager.getTime());
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public void webGroupJoinRoom(RobotUser robotUser) {
String connecId = robotUser.getConnecId();
TaurusClient client = getCsMjGameServerConnection(connecId);
try (Jedis jedis0 = Redis.use("group1_db0").getJedis();Jedis jedis2 = Redis.use("group1_db2").getJedis()){
Set<String> robotTokens = jedis0.smembers("{user}:"+robotUser.getRobotId()+"_token");
String robotSession = null;
for (String token : robotTokens) {
if (jedis0.exists(token)) {
robotSession = token;
break;
}
}
String gallrobot = jedis2.hget("gallrobot", robotUser.getRobotId());
if (gallrobot.equals("0")) {
robotRoomMapping.remove(connecId);
return;
}
System.out.println("重连进房间: "+robotUser.getRobotId());
System.out.println("重连进房间: "+robotUser.getCurrentRoomId());
System.out.println("重连进房间: "+"room:"+ robotUser.getCurrentRoomId());
System.out.println("重连进房间: "+"{user}:"+robotUser.getRobotId());
GroupRoomBusiness.joinRoom(Integer.parseInt(robotUser.getRobotGroupid()), "room:"+ robotUser.getCurrentRoomId(), "{user}:"+robotUser.getRobotId(), null);
//机器人房间映射关系
if (robotUser.getRoomId() == null) {
robotUser.setCurrentRoomId(robotUser.getCurrentRoomId());
robotUser.setClient(client);
}
robotRoomMapping.put(robotUser.getConnecId(), robotUser);
robotRoomMapping.remove(robotUser.getRobotId());
Thread.sleep(2000);
ITObject params = new TObject();
params.putString("session","{user}:"+robotUser.getRobotId()+ "," + robotSession);
//发送加入房间请求到game_mj_cs
client.send(Config.JOIN_ROOM_CS, params, response -> {
System.out.println("joinRoomController: " + response);
robotConnectionManager.reconnectToGameServer(response, robotUser, client);
});
Thread.sleep(1000);
if(client.isConnected()){
client.send(Config.GAME_READY_CS, params, response -> {
System.out.println("1003:"+response);
});
jedis2.hset("gallrobot", String.valueOf(robotUser.getRobotId()), "1");
robotUser.setStatus(ROBOTEventType.ROBOT_INTOROOM_READY);
}
robotUser.setIntoRoomTime(robotConnectionManager.getTime());
@ -272,11 +336,11 @@ public class EXGameController extends GameController {
*/
public static RobotUser getRobotRoomInfo(String robotId) {
RobotUser robotUser = robotRoomMapping.get(robotId);
if (robotUser ==null && robotUser.getRoomId() == null) {
if (robotUser ==null) {
RobotUser robotUserCopy = new RobotUser();
robotUserCopy.setRobotId(robotId);
robotUserCopy.setPassword("123456");
robotUserCopy.setGameHost("8.138.242.190");
robotUserCopy.setGameHost("8.134.76.43");
robotUserCopy.setGamePort("6311");
robotUserCopy.setRobotGroupid("330800");
robotUserCopy.setRobotPid("10");
@ -299,7 +363,7 @@ public class EXGameController extends GameController {
public static TaurusClient getCsMjGameServerConnection(String connecId) {
TaurusClient taurusClient = robotConnectionManager.getGameClient(connecId);
System.out.println("根据机器人ID和连接ID获取长沙麻将游戏服务器连接 client: = "+taurusClient);
if (taurusClient != null && taurusClient.isConnected()) {
if (taurusClient != null) {
log.debug("成功获取游戏服务器连接connecId: {}", connecId);
return taurusClient;
}

View File

@ -42,8 +42,8 @@ public class EXMainServer extends MainServer{
// 2. 启动连接检查定时任务
//startConnectionCheckScheduler();
//测试
/*Jedis jedis2 = Redis.use("group1_db2").getJedis();
String robotskey = "g{"+330800+"}:play:"+10;
Jedis jedis2 = Redis.use("group1_db2").getJedis();
String robotskey = "g{"+762479+"}:play:"+10;
Map<String, String> maprobot = jedis2.hgetAll(robotskey);
for(Map.Entry<String, String> entry : maprobot.entrySet()) {
System.out.println(entry.getKey() + ":" + entry.getValue());
@ -51,9 +51,9 @@ public class EXMainServer extends MainServer{
RobotUser robotUser = new RobotUser();
robotUser.setRobotId(entry.getKey());
robotUser.setPassword("123456");
robotUser.setGameHost("8.138.242.190");
robotUser.setGameHost("8.134.76.43");
robotUser.setGamePort("6311");
robotUser.setRobotGroupid("330800");
robotUser.setRobotGroupid("762479");
robotUser.setRobotPid("10");
robotRoomMapping.put(entry.getKey(), robotUser);
@ -70,7 +70,7 @@ public class EXMainServer extends MainServer{
if(!robotUser.isLogin){
robotConnectionManager.login(robotUser);
}
//2、链接
/*//2、链接
//判断是否链接
System.out.println("robotUser.isconnect"+robotUser.getIsconnect());
if(!robotUser.getIsconnect()){
@ -95,11 +95,11 @@ public class EXMainServer extends MainServer{
if(robotUser.getIntoRoomTime()+6<=robotConnectionManager.getTime()){
//5、退出房间
robotConnectionManager.outoRoom(robotUser);
}
}*/
}
}
}, 0, 5 ,TimeUnit.SECONDS);*/
}, 0, 5 ,TimeUnit.SECONDS);
//5、干活
log.info("长沙麻将机器人服务器已启动");
log.info("服务器将监听端口 {} 用于接收robot_mgr管理协议", gameSetting.port);

View File

@ -18,33 +18,51 @@ import taurus.client.TaurusClient;
import taurus.client.SocketCode;
import redis.clients.jedis.Jedis;
import robot.mj.handler.HuNanChangSha;
import taurus.util.ChangShaSuanFaTest;
import taurus.util.ROBOTEventType;
import taurus.util.TinHuChi;
import java.util.*;
import java.util.concurrent.*;
import static robot.mj.EXGameController.robotRoomMapping;
/**
* -
*/
public class RobotConnectionManager {
private Logger log = Logger.getLogger(RobotConnectionManager.class);
private Map<String, TaurusClient> gameClients;
//存储全局的长沙麻将AI处理器
private HuNanChangSha huNanChangSha;
private EXGameController exGameController;
private static final Map<String, HuNanChangSha> huNanChangShaInstances = new ConcurrentHashMap<>();
private final EXGameController exGameController;
private final String host="8.138.242.190";
private final String host="8.134.76.43";
private final int port=6311;
/*长沙麻将游戏算法相关 start*/
private Map<Integer, List<Integer>> playerOutcardsMap = new HashMap<>();
private Map<Integer, List<Integer>> playerchisMap = new HashMap<>();
private Map<Integer, List<Integer>> playerpengsMap = new HashMap<>();
private Map<Integer, List<Integer>> playermingsMap = new HashMap<>();
private Map<Integer, List<Integer>> playerzisMap = new HashMap<>();
private final Map<String, Map<Integer, List<Integer>>> playerOutcardsMapByConn = new ConcurrentHashMap<>();
private final Map<String, Map<Integer, List<Integer>>> playerchisMapByConn = new ConcurrentHashMap<>();
private final Map<String, Map<Integer, List<Integer>>> playerpengsMapByConn = new ConcurrentHashMap<>();
private final Map<String, Map<Integer, List<Integer>>> playermingsMapByConn = new ConcurrentHashMap<>();
private final Map<String, Map<Integer, List<Integer>>> playerzisMapByConn = new ConcurrentHashMap<>();
private Map<Integer, List<Integer>> getPlayerOutcardsMap(String connecId) {
return playerOutcardsMapByConn.computeIfAbsent(connecId, k -> new ConcurrentHashMap<>());
}
private Map<Integer, List<Integer>> getPlayerchisMap(String connecId) {
return playerchisMapByConn.computeIfAbsent(connecId, k -> new ConcurrentHashMap<>());
}
private Map<Integer, List<Integer>> getPlayerpengsMap(String connecId) {
return playerpengsMapByConn.computeIfAbsent(connecId, k -> new ConcurrentHashMap<>());
}
private Map<Integer, List<Integer>> getPlayermingsMap(String connecId) {
return playermingsMapByConn.computeIfAbsent(connecId, k -> new ConcurrentHashMap<>());
}
private Map<Integer, List<Integer>> getPlayerzisMap(String connecId) {
return playerzisMapByConn.computeIfAbsent(connecId, k -> new ConcurrentHashMap<>());
}
private int groupId = 0;
private int pid = 0;
private int playerId = 0;
@ -56,17 +74,40 @@ public class RobotConnectionManager {
public RobotConnectionManager() {
gameClients = new HashMap<>();
huNanChangSha = new HuNanChangSha();
exGameController = new EXGameController();
}
/**
*
*/
private HuNanChangSha getHuNanChangShaInstance(String connecId) {
HuNanChangSha existingInstance = huNanChangShaInstances.get(connecId);
if (existingInstance != null) {
return existingInstance;
}
HuNanChangSha newInstance = new HuNanChangSha();
//从Redis恢复状态
boolean restored = newInstance.restoreFromRedis(connecId);
if (restored) {
System.out.println("从Redis恢复HuNanChangSha实例: " + connecId);
} else {
System.out.println("创建新的HuNanChangSha实例: " + connecId);
}
huNanChangShaInstances.put(connecId, newInstance);
System.out.println("当前HuNanChangSha实例总数: " + huNanChangShaInstances.size());
return newInstance;
}
/**
*
*/
public void setSessionAndToken(String session, String token) {
huNanChangSha.session = session;
huNanChangSha.token = token;
public void setSessionAndToken(String session, String token, String connecId) {
HuNanChangSha instance = getHuNanChangShaInstance(connecId);
instance.session = session;
instance.token = token;
}
/**
@ -74,15 +115,6 @@ public class RobotConnectionManager {
*/
public TaurusClient connectToGameServer(String connecId) {
try {
//检查是否已经连接
if (gameClients.containsKey(connecId)) {
TaurusClient existingClient = gameClients.get(connecId);
if (existingClient.isConnected()) {
return existingClient;
}
//todo: 断线重连
}
//创建Taurus客户端
TaurusClient client = new TaurusClient(host + ":" + port, "game", TaurusClient.ConnectionProtocol.Tcp);
@ -91,8 +123,6 @@ public class RobotConnectionManager {
client.connect();
gameClients.put(connecId, client);
return client;
} catch (Exception e) {
log.error("连接到游戏服务器时发生异常", e);
@ -105,8 +135,34 @@ public class RobotConnectionManager {
*/
public void disconnectFromGameServer(String connecId) {
System.out.println("开始主动断开连接: {"+connecId+"}");
RobotUser robotUser = robotRoomMapping.remove(connecId);
TaurusClient client = gameClients.remove(connecId);
//清理连接数据
if (connecId != null) {
HuNanChangSha.removeFromRedis(connecId);
HuNanChangSha instance = huNanChangShaInstances.get(connecId);
if (instance != null) {
instance.getChangShaCardInhand().clear();
instance.getChuGuoCardInhand().clear();
instance.getgangdepai().clear();
instance.getpongGroup().clear();
instance.getchowGroup().clear();
instance.getchangShaCardInhandgang().clear();
instance.getChuGuoPainum().clear();
System.out.println("清空HuNanChangSha集合数据: " + connecId);
}
huNanChangShaInstances.remove(connecId);
playerOutcardsMapByConn.remove(connecId);
playerchisMapByConn.remove(connecId);
playerpengsMapByConn.remove(connecId);
playermingsMapByConn.remove(connecId);
playerzisMapByConn.remove(connecId);
}
if (robotUser != null) {
TaurusClient client = robotUser.getClient();
if (client != null) {
try {
if (client.isConnected()) {
@ -120,18 +176,19 @@ public class RobotConnectionManager {
System.out.println("客户端连接不存在: {"+connecId+"}");
}
}
}
/**
* leftover_robot 退
* leftover_robot 退
*/
private void updateLeftoverRobot(String groupId, String wanfaId, int robotId) {
try (Jedis jedis11 = Redis.use("group1_db11").getJedis();Jedis jedis2 = Redis.use("group1_db2").getJedis()) {
String playKey = "g{" + groupId + "}:play:" + wanfaId;
jedis11.hincrBy(playKey, "leftover_robot", 1);
private void updateLeftoverRobot(int robotId) {
try (Jedis jedis2 = Redis.use("group1_db2").getJedis()) {
jedis2.hset("gallrobot", String.valueOf(robotId), "0");
jedis2.hset("{grobot}:" + robotId, "start", "0");
System.out.println("机器人 {"+robotId+"} 退出空房间增加leftover_robot群组={"+groupId+"}, 玩法={"+wanfaId+"}");
System.out.println("机器人 {"+robotId+"} 退出房间修改gallrobot为0");
}
}
@ -180,6 +237,7 @@ public class RobotConnectionManager {
* 线
*/
public void reconnectToGameServer(MessageResponse response, RobotUser robotUser, TaurusClient client) {
String connecId = robotUser.getCurrentRoomId()+"_"+robotUser.getRobotId();
if(client.isConnected()){
ITObject obj = response.messageData.param.getTObject("tableInfo");
ITObject reloadInfo = response.messageData.param.getTObject("reloadInfo");
@ -224,21 +282,41 @@ public class RobotConnectionManager {
}
}
System.out.println("hcard>0"+hcard);
if(hcard.size()>0){
//同步手牌
huNanChangSha.updateHandCard(hcard);
HuNanChangSha currentInstance = getHuNanChangShaInstance(connecId);
//检查Redis恢复的数据 避免覆盖
if (currentInstance.getChangShaCardInhand().isEmpty()) {
//手牌集合为空 需要同步数据
currentInstance.updateHandCard(hcard);
System.out.println("断线重连:同步手牌数据");
}
if(outcard_list.size()>0){
List<Integer> outcards = new ArrayList<>();
for (int i = 0; i < outcard_list.size(); i++) {
outcards.add(outcard_list.getInt(i));
}
huNanChangSha.updateOutCard(outcards);
//检查出牌记录是否需要同步
if (currentInstance.getChuGuoCardInhand().isEmpty()) {
currentInstance.updateOutCard(outcards);
System.out.println("断线重连:同步出牌数据");
}
}
sleepTime(2000);
huNanChangSha.outCard(client,playerOutcardsMap, playerchisMap, playerpengsMap, playermingsMap, playerzisMap);
Map<Integer, List<Integer>> currentPlayerOutcardsMap = getPlayerOutcardsMap(connecId);
Map<Integer, List<Integer>> currentPlayerchisMap = getPlayerchisMap(connecId);
Map<Integer, List<Integer>> currentPlayerpengsMap = getPlayerpengsMap(connecId);
Map<Integer, List<Integer>> currentPlayermingsMap = getPlayermingsMap(connecId);
Map<Integer, List<Integer>> currentPlayerzisMap = getPlayerzisMap(connecId);
currentInstance.outCard(client, currentPlayerOutcardsMap, currentPlayerchisMap, currentPlayerpengsMap, currentPlayermingsMap, currentPlayerzisMap);
} else {
System.err.println("警告:重连时未获取到手牌数据");
}
}
}
@ -252,11 +330,10 @@ public class RobotConnectionManager {
*
*/
private void handleProtocol(String command, Message message, TaurusClient client, String connecId) {
String[] robotIds= connecId.split("_", 2);
int robotId = Integer.parseInt(robotIds[0]);
RobotUser robotUser = EXGameController.getRobotRoomInfo(String.valueOf(robotId));
RobotUser robotUser = robotRoomMapping.get(connecId);
int robotId = Integer.parseInt(robotUser.getRobotId());
ITObject param = message.param;
HuNanChangSha huNanChangSha = getHuNanChangShaInstance(connecId);
try (Jedis jedis0 = Redis.use().getJedis();Jedis jedis2 = Redis.use("group1_db2").getJedis();){
//长沙麻将 机器人处理事件
@ -281,6 +358,9 @@ public class RobotConnectionManager {
}
}
huNanChangSha.cardInHead(command, message, client);
//处理完协议后保存到Redis
HuNanChangSha currentInstance = huNanChangShaInstances.get(connecId);
currentInstance.saveToRedis(connecId);
}
//出牌广播
else if ("812".equalsIgnoreCase(command)) {
@ -291,12 +371,19 @@ public class RobotConnectionManager {
ITArray opmingcards = param.getTArray("opmingcards");
ITArray opzicards = param.getTArray("opzicards");
// 获取当前连接专用的Maps
Map<Integer, List<Integer>> currentPlayerOutcardsMap = getPlayerOutcardsMap(connecId);
Map<Integer, List<Integer>> currentPlayerchisMap = getPlayerchisMap(connecId);
Map<Integer, List<Integer>> currentPlayerpengsMap = getPlayerpengsMap(connecId);
Map<Integer, List<Integer>> currentPlayermingsMap = getPlayermingsMap(connecId);
Map<Integer, List<Integer>> currentPlayerzisMap = getPlayerzisMap(connecId);
// 清空旧数据,用新数据完全覆盖
playerOutcardsMap.clear();
playerchisMap.clear();
playerpengsMap.clear();
playermingsMap.clear();
playerzisMap.clear();
currentPlayerOutcardsMap.clear();
currentPlayerchisMap.clear();
currentPlayerpengsMap.clear();
currentPlayermingsMap.clear();
currentPlayerzisMap.clear();
//出过的牌
if (outcard_map != null) {
for (int i = 0; i < outcard_map.size(); i++) {
@ -310,8 +397,8 @@ public class RobotConnectionManager {
outcardsList.add(outcardsArray.getInt(j));
}
// 存储到Map中覆盖旧数据
playerOutcardsMap.put(playerId, outcardsList);
// 存储到当前连接的Map中覆盖旧数据
currentPlayerOutcardsMap.put(playerId, outcardsList);
}
}
@ -327,7 +414,7 @@ public class RobotConnectionManager {
for (int j = 0; j < outchiArray.size(); j++) {
outchiList.add(outchiArray.getInt(j));
}
playerchisMap.put(playerId, outchiList);
currentPlayerchisMap.put(playerId, outchiList);
}
}
@ -342,7 +429,7 @@ public class RobotConnectionManager {
for (int j = 0; j < outpengArray.size(); j++) {
outpengList.add(outpengArray.getInt(j));
}
playerpengsMap.put(playerId, outpengList);
currentPlayerpengsMap.put(playerId, outpengList);
}
}
@ -357,7 +444,7 @@ public class RobotConnectionManager {
for (int j = 0; j < outmingArray.size(); j++) {
outmingList.add(outmingArray.getInt(j));
}
playermingsMap.put(playerId, outmingList);
currentPlayermingsMap.put(playerId, outmingList);
}
}
@ -372,41 +459,52 @@ public class RobotConnectionManager {
for (int j = 0; j < outziArray.size(); j++) {
outziList.add(outziArray.getInt(j));
}
playerzisMap.put(playerId, outziList);
currentPlayerzisMap.put(playerId, outziList);
}
}
HuNanChangSha.drawCard(command, message);
huNanChangSha.drawCard(command, message);
//处理完协议后保存到Redis
HuNanChangSha currentInstance = huNanChangShaInstances.get(connecId);
currentInstance.saveToRedis(connecId);
}
//摸牌
else if ("819".equalsIgnoreCase(command)) {
huNanChangSha.getCard(command, message, client);
//处理完协议后保存到Redis
HuNanChangSha currentInstance = huNanChangShaInstances.get(connecId);
currentInstance.saveToRedis(connecId);
}
//出牌提示
else if ("813".equalsIgnoreCase(command)) {
huNanChangSha.outCard(client,playerOutcardsMap,playerchisMap,playerpengsMap,playermingsMap,playerzisMap);
// 获取当前连接专用的Maps
Map<Integer, List<Integer>> currentPlayerOutcardsMap = getPlayerOutcardsMap(connecId);
Map<Integer, List<Integer>> currentPlayerchisMap = getPlayerchisMap(connecId);
Map<Integer, List<Integer>> currentPlayerpengsMap = getPlayerpengsMap(connecId);
Map<Integer, List<Integer>> currentPlayermingsMap = getPlayermingsMap(connecId);
Map<Integer, List<Integer>> currentPlayerzisMap = getPlayerzisMap(connecId);
huNanChangSha.outCard(client, currentPlayerOutcardsMap, currentPlayerchisMap, currentPlayerpengsMap, currentPlayermingsMap, currentPlayerzisMap);
//处理完协议后保存到Redis
HuNanChangSha currentInstance = huNanChangShaInstances.get(connecId);
currentInstance.saveToRedis(connecId);
}
//放招提示
else if ("814".equalsIgnoreCase(command)) {
huNanChangSha.actionCard(param, client);
//处理完协议后保存到Redis
HuNanChangSha currentInstance = huNanChangShaInstances.get(connecId);
currentInstance.saveToRedis(connecId);
}
//2026.02.03修改 玩家加入房间
else if ("2001".equalsIgnoreCase(command)) {
Integer userId = param.getInt("aid");
robotUser.setUserId(userId);
System.out.println("玩家{"+ robotUser.getRoomId()+"}加入房间:"+ param);
}
//2026.02.03修改 玩家退出房间也要检查
/*else if ("2002".equalsIgnoreCase(command)) {
CompletableFuture.runAsync(() -> {
Integer userId = param.getInt("aid");
sleepTime(6000);
if (userId.equals(robotUser.getUserId())) {
String roomKey = robotUser.getRoomId();
String roomKey = String.valueOf(robotUser.getCurrentRoomId());
//查询该房间的玩家信息
String playersStr = jedis0.hget(roomKey, "players");
String playersStr = jedis0.hget("room:"+roomKey, "players");
if (!playersStr.equals("[]")) {
String players = playersStr.substring(1, playersStr.length() - 1);
String[] playerIds = players.split(",");
@ -416,58 +514,52 @@ public class RobotConnectionManager {
int playerId = Integer.parseInt(playerIds[0].trim());
if (playerId == robotId) {
String gpid = jedis0.hget(roomKey, "gpid");
String gpId = jedis0.hget(roomKey, "group");
//发送退出房间协议
ITObject params = TObject.newInstance();
client.send("1005", params, response -> {
EXGameController.removeRobotRoomInfo(String.valueOf(robotId));
//更新机器人剩余数量
if (count != null && count.containsKey(Integer.parseInt(gpid))) {
Integer currentValue = count.get(Integer.parseInt(gpid));
if (currentValue > 0) {
count.put(Integer.parseInt(gpid), currentValue - 1);
updateLeftoverRobot(robotId);
disconnectFromGameServer(connecId);
System.out.println("2002发送退出房间协议1005robotId: {"+robotId+"}");
});
}
}
}
});
System.out.println("玩家{"+ robotUser.getCurrentRoomId()+"}加入房间:"+ param);
}
//2026.02.03修改 玩家退出房间也要检查
else if ("2002".equalsIgnoreCase(command)) {
CompletableFuture.runAsync(() -> {
sleepTime(6000);
String roomKey = String.valueOf(robotUser.getCurrentRoomId());
//查询该房间的玩家信息
String playersStr = jedis0.hget("room:"+roomKey, "players");
if (!playersStr.equals("[]")) {
String players = playersStr.substring(1, playersStr.length() - 1);
String[] playerIds = players.split(",");
//判断只有当前机器人一个玩家
if (playerIds.length == 1) {
int playerId = Integer.parseInt(playerIds[0].trim());
if (playerId == robotId) {
//发送退出房间协议
ITObject params = TObject.newInstance();
client.send("1005", params, response -> {
EXGameController.removeRobotRoomInfo(String.valueOf(robotId));
//更新机器人剩余数量
updateLeftoverRobot(gpId, gpid, robotId);
updateLeftoverRobot(robotId);
disconnectFromGameServer(connecId);
System.out.println("2002发送退出房间协议1005robotId: {"+robotId+"}");
});
}
}
}
}
});
}*/
else if("2002".equalsIgnoreCase(command)) {
System.out.println("comds:2002");
ITObject params = TObject.newInstance();
String aid = client.getGameID();
String getKey = "{robortInfo}:" + aid;
Jedis jedis20 = Redis.use("group1_db2").getJedis();
String circleId1 = jedis20.hget(getKey, "circleId");
String pid = jedis20.hget(getKey, "pid");
String key = "g{" + circleId1 + "}:play:" + pid;
client.send("1005", params, response -> {
log.info("退出状态1---------"+response);
log.info("退出状态1getKey---------"+getKey);
log.info("退出状态1key---------"+key);
log.info("退出状态1aid---------"+aid);
jedis20.hset(getKey, "circleId", "0");
jedis20.hset(getKey, "pid", "0");
jedis20.hset(getKey, "room_id", "0");
//退出修改机器人状态
jedis20.hset(key,aid, "0");
});
jedis20.close();
}
//2026.02.03修改 玩家解散房间
else if ("2005".equalsIgnoreCase(command)) {
@ -490,7 +582,7 @@ public class RobotConnectionManager {
}
EXGameController.removeRobotRoomInfo(String.valueOf(robotId));
//更新机器人剩余数量
updateLeftoverRobot(gpId, gpid, robotId);
updateLeftoverRobot(robotId);
disconnectFromGameServer(connecId);
System.out.println("2005玩家发送解散房间协议robotId: {"+robotId+"}");
}
@ -499,18 +591,9 @@ public class RobotConnectionManager {
}
//2026.02.03修改 解散房间时候恢复机器人账号可以使用
else if ("2008".equalsIgnoreCase(command)) {
String roomKey = robotUser.getRoomId();
if (jedis0.exists(roomKey)) {
String gpid = jedis0.hget(roomKey, "gpid");
String gpId = jedis0.hget(roomKey, "group");
EXGameController.removeRobotRoomInfo(String.valueOf(robotId));
//更新机器人剩余数量
updateLeftoverRobot(gpId, gpid, robotId);
updateLeftoverRobot(Integer.parseInt(robotUser.getRobotId()));
disconnectFromGameServer(connecId);
jedis0.del(roomKey);
System.out.println("2008结束房间robotId: {"+robotId+"}");
}
}
//2026.02.03修改 通过机器人房间映射直接获取房间信息
else if ("2009".equalsIgnoreCase(command)) {
@ -550,7 +633,7 @@ public class RobotConnectionManager {
//断开连接
disconnectFromGameServer(connecId);
//更新机器人剩余数量
updateLeftoverRobot(gpId, gpid, paramRobotId);
updateLeftoverRobot(paramRobotId);
System.out.println("2009发送退出房间协议1005robotId: {"+paramRobotId+"}");
});
}
@ -561,16 +644,14 @@ public class RobotConnectionManager {
}
//结算
else if ("817".equalsIgnoreCase(command)) {
//清空所有HuNanChangSha相关的集合数据
huNanChangSha.getChangShaCardInhand().clear();
huNanChangSha.getChuGuoCardInhand().clear();
huNanChangSha.getgangdepai().clear();
huNanChangSha.getpongGroup().clear();
huNanChangSha.getchowGroup().clear();
TinHuChi.lastTingCount = 0;
TinHuChi.isMoreThanLast = false;
ChangShaSuanFaTest.isTin=false;
ChangShaSuanFaTest.isChi=false;
ChangShaSuanFaTest.isPeng=false;
ChangShaSuanFaTest.tinCards.clear();
huNanChangSha.getchangShaCardInhandgang().clear();
huNanChangSha.getChuGuoPainum().clear();
Integer type = param.getInt("type");
if (type == 1 || type == 2) { //为1为大结算 为2为解散
Jedis jedis11s = Redis.use("group1_db11").getJedis();
@ -640,10 +721,16 @@ public class RobotConnectionManager {
else if ("815".equalsIgnoreCase(command)) {
//[TCP->815] data:{"playerid":101555,"card":104,"opcard":[105,103],"from_seat":2,"type":1,"opengang":false}
huNanChangSha.shanchuchuguopai(param);
//处理完协议后保存到Redis
HuNanChangSha currentInstance = huNanChangShaInstances.get(connecId);
currentInstance.saveToRedis(connecId);
}
//换牌提示
else if ("820".equalsIgnoreCase(command)) {
huNanChangSha.changePlayer(command, message);
//处理完协议后保存到Redis
HuNanChangSha currentInstance = huNanChangShaInstances.get(connecId);
currentInstance.saveToRedis(connecId);
}
else if ("825".equalsIgnoreCase(command)) {
ITObject params = TObject.newInstance();
@ -703,31 +790,29 @@ public class RobotConnectionManager {
if(object==null){
object = accountBusiness.idPasswordLogin(Integer.parseInt(robotUser.getRobotId()), robotUser.getPassword());
}
if (object != null) {
ITObject finalObject = object;
CompletableFuture.runAsync(() -> {
if (finalObject != null) {
//判断是否有房间
if(object.getTObject("account")!=null){
if(finalObject.getTObject("account")!=null){
ITObject validate = TObject.newInstance();
validate.putString("token", object.getString("token"));
robotUser.setToken(object.getString("token"));;
validate.putString("token", finalObject.getString("token"));
robotUser.setToken(finalObject.getString("token"));;
robotUser.setLoginsession("{user}:"+robotUser.getRobotId());
if (robotUser.getLoginsession() != null) {
robotUser.setIsLogin(true);
}
if(object.getTObject("account").get("roomid")!=null){
String roomid = object.getTObject("account").get("roomid").toString();
if(finalObject.getTObject("account").get("roomid")!=null){
String roomid = finalObject.getTObject("account").get("roomid").toString();
robotUser.setCurrentRoomId(Integer.parseInt(roomid));
connectGame(robotUser);
ITObject params = new TObject();
params.putString("connecId", robotUser.getRoomId()+"_"+robotUser.getRobotId());
params.putString("roomId", robotUser.getRoomId());
params.putString("groupId", robotUser.getRobotGroupid());
params.putString("session", "{user}:"+robotUser.getRobotId());
exGameController.joinRoom(null, params, robotUser.getClient().getId());
robotUser.setConnecId(robotUser.getCurrentRoomId()+"_"+robotUser.getRobotId());
exGameController.webGroupJoinRoom(robotUser);
}
}
}
});
} catch (Exception e) {
throw new RuntimeException(e);
}
@ -736,12 +821,18 @@ public class RobotConnectionManager {
public void connectGame(RobotUser robotUser){
if(robotUser.isLogin){
if(robotUser.getClient()==null){
TaurusClient client = new TaurusClient (robotUser.getGameHost()+":"+robotUser.getGamePort(), String.valueOf(robotUser.getRobotId()), TaurusClient.ConnectionProtocol.Tcp);
TaurusClient client = new TaurusClient(robotUser.getGameHost()+":"+robotUser.getGamePort(), "game", TaurusClient.ConnectionProtocol.Tcp);
client.setSession(robotUser.getLoginsession());
client.connect();
setupEventListeners(client, robotUser.getCurrentRoomId()+"_"+robotUser.getRobotId());
robotUser.setIsconnect(client.isConnected());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
robotUser.setClient(client);
EXGameController.robotRoomMapping.put(robotUser.getCurrentRoomId()+"_"+robotUser.getRobotId(), robotUser);
}else{
System.out.println("reconnect");
System.out.println("client.isConnected()"+robotUser.getClient().isConnected());
@ -749,10 +840,17 @@ public class RobotConnectionManager {
robotUser.setIsconnect(true);
}else{
System.out.println("reconnect"+robotUser.getClient().getGameID());
TaurusClient client = new TaurusClient (robotUser.getGameHost()+":"+robotUser.getGamePort(), String.valueOf(robotUser.getRobotId()), TaurusClient.ConnectionProtocol.Tcp);
TaurusClient client = new TaurusClient(robotUser.getGameHost()+":"+robotUser.getGamePort(), "game", TaurusClient.ConnectionProtocol.Tcp);
client.setSession(robotUser.getLoginsession());
client.connect();
robotUser.setIsconnect(client.isConnected());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
robotUser.setClient(client);
EXGameController.robotRoomMapping.put(robotUser.getCurrentRoomId()+"_"+robotUser.getRobotId(), robotUser);
}
}
}
@ -842,7 +940,7 @@ public class RobotConnectionManager {
* connecId
*/
public TaurusClient getGameClient(String connecId) {
return gameClients.get(connecId);
return robotRoomMapping.get(connecId) != null ? robotRoomMapping.get(connecId).getClient() : null;
}
}

View File

@ -18,11 +18,14 @@ import java.sql.SQLException;
import java.util.*;
import java.util.stream.Collectors;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
public class HuNanChangSha {
public static int changShaCard = 0;
public static boolean isTinChi = false;
public int changShaCard = 0;
public boolean isTinChi = false;
public static boolean isTinPeng = false;
private int robotid=0;
@ -36,44 +39,45 @@ public class HuNanChangSha {
// private static final Logger log = Logger.getLogger(DoTest.class);
private List<Integer> changShaCardInhandgang = new ArrayList<>();
private final List<Integer> changShaCardInhandgang = new ArrayList<>();
//长沙麻将出过的牌
private List<Integer> changShachuguopai = new ArrayList<>();
private final List<Integer> changShachuguopai = new ArrayList<>();
private List<Integer> changShaCardInhand = new ArrayList<>();
private final List<Integer> changShaCardInhand = new ArrayList<>();
public List<Integer> getChangShaCardInhand() {
return changShaCardInhand;
}
private Map<Integer, Integer> chuGuoPainum = new HashMap<>();
private final Map<Integer, Integer> chuGuoPainum = new HashMap<>();
//杠的牌
private List<Integer> gangdepai = new ArrayList<>();
private final List<Integer> gangdepai = new ArrayList<>();
//碰牌
private List<Integer> pongGroup = new ArrayList<>();
private final List<Integer> pongGroup = new ArrayList<>();
//吃牌
private List<Integer> chowGroup = new ArrayList<>();
private final List<Integer> chowGroup = new ArrayList<>();
// 玩家座位号
public static int seat = 0;
public int seat = 0;
// 会话标识
public static String session = "";
public String session = "";
// 访问令牌
public static String token = "";
public String token = "";
private static ChangShaSuanFaTest changShaSuanFaTest = new ChangShaSuanFaTest();
private static final Gson gson = new Gson();
// 公共的getter和setter方法
@ -103,6 +107,132 @@ public class HuNanChangSha {
return chuGuoPainum;
}
/**
* JSONRedis
* @param connecId ID
*/
public void saveToRedis(String connecId) {
try (Jedis jedis = Redis.use("group1_db2").getJedis()) {
Map<String, String> stateMap = new HashMap<>();
stateMap.put("changShaCardInhand", gson.toJson(changShaCardInhand));
stateMap.put("changShachuguopai", gson.toJson(changShachuguopai));
stateMap.put("chuGuoPainum", gson.toJson(chuGuoPainum));
stateMap.put("gangdepai", gson.toJson(gangdepai));
stateMap.put("pongGroup", gson.toJson(pongGroup));
stateMap.put("chowGroup", gson.toJson(chowGroup));
stateMap.put("changShaCardInhandgang", gson.toJson(changShaCardInhandgang));
stateMap.put("changShaCard", String.valueOf(changShaCard));
stateMap.put("session", session);
stateMap.put("token", token);
String redisKey = "{csmj}:" + connecId;
jedis.hmset(redisKey, stateMap);
//1小时过期时间
jedis.expire(redisKey, 3600);
System.out.println("保存HuNanChangSha状态到Redis: " + connecId);
} catch (Exception e) {
System.err.println("保存HuNanChangSha状态到Redis失败: " + e.getMessage());
}
}
/**
* Redis
* @param connecId ID
* @return
*/
public boolean restoreFromRedis(String connecId) {
try (Jedis jedis = Redis.use("group1_db2").getJedis()) {
String redisKey = "{csmj}:" + connecId;
Map<String, String> stateMap = jedis.hgetAll(redisKey);
if (stateMap == null || stateMap.isEmpty()) {
System.out.println("Redis中没有找到HuNanChangSha状态数据: " + connecId);
return false;
}
//反序列化集合
if (stateMap.containsKey("changShaCardInhand")) {
changShaCardInhand.clear();
List<Integer> handCards = gson.fromJson(stateMap.get("changShaCardInhand"),
new TypeToken<List<Integer>>(){}.getType());
if (handCards != null) changShaCardInhand.addAll(handCards);
}
if (stateMap.containsKey("changShachuguopai")) {
changShachuguopai.clear();
List<Integer> outCards = gson.fromJson(stateMap.get("changShachuguopai"),
new TypeToken<List<Integer>>(){}.getType());
if (outCards != null) changShachuguopai.addAll(outCards);
}
if (stateMap.containsKey("chuGuoPainum")) {
chuGuoPainum.clear();
Map<Integer, Integer> painum = gson.fromJson(stateMap.get("chuGuoPainum"),
new TypeToken<Map<Integer, Integer>>(){}.getType());
if (painum != null) chuGuoPainum.putAll(painum);
}
if (stateMap.containsKey("gangdepai")) {
gangdepai.clear();
List<Integer> gangCards = gson.fromJson(stateMap.get("gangdepai"),
new TypeToken<List<Integer>>(){}.getType());
if (gangCards != null) gangdepai.addAll(gangCards);
}
if (stateMap.containsKey("pongGroup")) {
pongGroup.clear();
List<Integer> pongCards = gson.fromJson(stateMap.get("pongGroup"),
new TypeToken<List<Integer>>(){}.getType());
if (pongCards != null) pongGroup.addAll(pongCards);
}
if (stateMap.containsKey("chowGroup")) {
chowGroup.clear();
List<Integer> chowCards = gson.fromJson(stateMap.get("chowGroup"),
new TypeToken<List<Integer>>(){}.getType());
if (chowCards != null) chowGroup.addAll(chowCards);
}
if (stateMap.containsKey("changShaCardInhandgang")) {
changShaCardInhandgang.clear();
List<Integer> gangHandCards = gson.fromJson(stateMap.get("changShaCardInhandgang"),
new TypeToken<List<Integer>>(){}.getType());
if (gangHandCards != null) changShaCardInhandgang.addAll(gangHandCards);
}
// 恢复基本属性
if (stateMap.containsKey("changShaCard")) {
changShaCard = Integer.parseInt(stateMap.get("changShaCard"));
}
session = stateMap.getOrDefault("session", "");
token = stateMap.getOrDefault("token", "");
System.out.println("从Redis恢复HuNanChangSha状态成功: " + connecId + ", 手牌数量: " + changShaCardInhand.size());
return true;
} catch (Exception e) {
System.err.println("从Redis恢复HuNanChangSha状态失败: " + e.getMessage());
return false;
}
}
/**
* Redis
* @param connecId ID
*/
public static void removeFromRedis(String connecId) {
try (Jedis jedis = Redis.use("group1_db2").getJedis()) {
String redisKey = "{csmj}:" + connecId;
jedis.del(redisKey);
System.out.println("从Redis删除HuNanChangSha状态: " + connecId);
} catch (Exception e) {
System.err.println("从Redis删除HuNanChangSha状态失败: " + e.getMessage());
}
}
/**
* 广 812
*
@ -110,7 +240,7 @@ public class HuNanChangSha {
* @param message
* @return
*/
public static String drawCard(String command, Message message) {
public String drawCard(String command, Message message) {
if (command.equalsIgnoreCase("812")) {
ITObject param = message.param;
if (param == null) {
@ -144,7 +274,9 @@ public class HuNanChangSha {
Integer player = param.getInt("player");
int drawnCard = param.getInt("card");
changShaSuanFaTest.drawnCards = drawnCard;//存储摸到的牌
System.out.println("changShaCardInhand"+changShaCardInhand);
changShaCardInhand.add(drawnCard);
System.out.println("changShaCardInhandAdd"+changShaCardInhand);
System.out.println("param.getInt(player)" + param.getInt("player") );
System.out.println("摸到的牌 +++++++++ " + drawnCard);
if (jedis222.hget("{robortInfo}:" + player, "circleId") != null && jedis222.hget("{robortInfo}:" + player, "pid") != null) {
@ -220,8 +352,11 @@ public class HuNanChangSha {
* @param handCard
*/
public void updateHandCard(List<Integer> handCard) {
System.out.println("updateHandCard同步手牌:"+ handCard);
changShaCardInhand.clear();
System.out.println("updateHandCard同步手牌changShaCardInhand:"+ changShaCardInhand);
changShaCardInhand.addAll(handCard);
System.out.println("updateHandCard同步手牌add:"+ changShaCardInhand);
}
public void updateOutCard(List<Integer> outCard) {
@ -322,7 +457,7 @@ public class HuNanChangSha {
// log.info("tipList" +tipList);
ITObject params = TObject.newInstance();
int card = 0;
getChangShaCardInhand();
// getChangShaCardInhand();
//循环
List<Integer> yupanhandcard = new ArrayList<>();
yupanhandcard.addAll(changShaCardInhand);
@ -786,6 +921,7 @@ public class HuNanChangSha {
}
}
}
System.out.println("actchangShaCardInhand"+changShaCardInhand);
params.putString("session", session + "," + token);
params.putInt("qi", 0);
params.putInt("id", 0);
@ -1788,8 +1924,11 @@ public class HuNanChangSha {
resultList.addAll(zigang);
}
System.out.println("长沙麻将出牌"+changShaCardInhand);
// 长沙麻将出牌
String changShaOutCard = changShaSuanFaTest.outCardSuanFa(changShaCardInhand, pongGroup, chowGroup, gangdepai, resultList);
System.out.println("长沙麻将出牌"+changShaCardInhand);
// String changShaOutCard = changShaSuanFaTest.outCardSuanFa(list, changShaCard,pongGroup);
ITObject params = TObject.newInstance();
int cardToOut;

View File

@ -627,7 +627,7 @@ public class TinHuChi {
// 5. 检查打牌后是否能听牌
boolean canTing = checkCanTing(afterDiscard, needs258, targetSizeAfterDiscard);
if (canTing) {
HuNanChangSha.isTinChi = true;
//HuNanChangSha.isTinChi = true;
ChangShaSuanFaTest.isChi=true;
System.out.println(" ✓ 听牌!");
foundTing = true;