机器人连接0130
parent
18a90dd89d
commit
14e81d42ab
|
|
@ -116,8 +116,8 @@ public class MainServer extends Extension {
|
||||||
}
|
}
|
||||||
|
|
||||||
Map<Integer, Integer> gameRobotConfig = new HashMap<>();
|
Map<Integer, Integer> gameRobotConfig = new HashMap<>();
|
||||||
gameRobotConfig.put(10, 5);
|
gameRobotConfig.put(10, 1);
|
||||||
gameRobotConfig.put(22, 3);
|
gameRobotConfig.put(22, 0);
|
||||||
int robotIndex = 0;
|
int robotIndex = 0;
|
||||||
|
|
||||||
//长沙麻将机器人
|
//长沙麻将机器人
|
||||||
|
|
|
||||||
|
|
@ -45,7 +45,7 @@ public class RobotManager {
|
||||||
private final Map<Integer, Integer> wanfaRobotIndex = new ConcurrentHashMap<>();
|
private final Map<Integer, Integer> wanfaRobotIndex = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
//玩法房间轮询器
|
//玩法房间轮询器
|
||||||
private final Map<Integer, RoomWanfaMatcher> wanfaRoomPollers = new ConcurrentHashMap<>();
|
private final Map<String, RoomWanfaMatcher> wanfaRoomPollers = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
//定时任务调度器
|
//定时任务调度器
|
||||||
private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(2);
|
private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(2);
|
||||||
|
|
@ -135,19 +135,20 @@ public class RobotManager {
|
||||||
robot.setToken(tokenList.get(0));
|
robot.setToken(tokenList.get(0));
|
||||||
} else {
|
} else {
|
||||||
//如果没有token 则执行正常登录
|
//如果没有token 则执行正常登录
|
||||||
loginResult = accountBusiness.idPasswordLogin(robot.getRobotId(), robot.getPassword());
|
loginResult = accountBusiness.idPasswordLogin(robot.getRobotId(), "123456");
|
||||||
robot.setToken(loginResult.getString("token"));
|
robot.setToken(loginResult.getString("token"));
|
||||||
robot.setSession(accountBusiness.getSession());
|
robot.setSession(accountBusiness.getSession());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
log.debug("机器人 {} 执行常规登录", robot.getRobotId());
|
log.debug("机器人 {} 执行常规登录", robot.getRobotId());
|
||||||
//执行正常登录流程
|
//执行正常登录流程
|
||||||
loginResult = accountBusiness.idPasswordLogin(robot.getRobotId(), robot.getPassword());
|
loginResult = accountBusiness.idPasswordLogin(robot.getRobotId(), "123456");
|
||||||
robot.setToken(loginResult.getString("token"));
|
robot.setToken(loginResult.getString("token"));
|
||||||
robot.setSession(accountBusiness.getSession());
|
robot.setSession(accountBusiness.getSession());
|
||||||
}
|
}
|
||||||
robot.setOnline(true);
|
robot.setOnline(true);
|
||||||
robot.setWanfaId(gameId);
|
robot.setWanfaId(gameId);
|
||||||
|
robot.setGroupId(-1);
|
||||||
robot.setLastActiveTime(System.currentTimeMillis());
|
robot.setLastActiveTime(System.currentTimeMillis());
|
||||||
|
|
||||||
HashMap<String, String> robotMap = new HashMap<>();
|
HashMap<String, String> robotMap = new HashMap<>();
|
||||||
|
|
@ -226,14 +227,15 @@ public class RobotManager {
|
||||||
RoomWanfaMatcher poller = getWanfaRoomPoller(groupId, wanfaId);
|
RoomWanfaMatcher poller = getWanfaRoomPoller(groupId, wanfaId);
|
||||||
if (!poller.isRunning()) {
|
if (!poller.isRunning()) {
|
||||||
poller.startPolling();
|
poller.startPolling();
|
||||||
log.info("为玩法ID {} 启动房间轮询器", wanfaId);
|
log.info("为群组 {} 玩法ID {} 启动房间轮询器", groupId, wanfaId);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
//如果没有配置机器人 停止轮询器
|
//如果没有配置机器人 停止轮询器
|
||||||
RoomWanfaMatcher poller = wanfaRoomPollers.get(wanfaId);
|
String key = groupId + ":" + wanfaId;
|
||||||
|
RoomWanfaMatcher poller = wanfaRoomPollers.get(key);
|
||||||
if (poller != null) {
|
if (poller != null) {
|
||||||
poller.stopPolling();
|
poller.stopPolling();
|
||||||
log.info("为玩法ID {} 停止房间轮询器", wanfaId);
|
log.info("为群组 {} 玩法ID {} 停止房间轮询器", groupId, wanfaId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -274,16 +276,20 @@ public class RobotManager {
|
||||||
int disconnectedCount = 0;
|
int disconnectedCount = 0;
|
||||||
for (int i = 0; i < allWanfaRobots.size() && disconnectedCount < toDisconnect; i++) {
|
for (int i = 0; i < allWanfaRobots.size() && disconnectedCount < toDisconnect; i++) {
|
||||||
RobotInfo robot = allWanfaRobots.get(i);
|
RobotInfo robot = allWanfaRobots.get(i);
|
||||||
//不在使用中且已连接则断开连接
|
//不在使用断开连接
|
||||||
|
if (!robot.isUsing() && robot.isConnected()) {
|
||||||
|
synchronized(robot) {
|
||||||
if (!robot.isUsing() && robot.isConnected()) {
|
if (!robot.isUsing() && robot.isConnected()) {
|
||||||
RobotManagerInterface handler = getGameHandler(robot.getWanfaId());
|
RobotManagerInterface handler = getGameHandler(robot.getWanfaId());
|
||||||
if (handler != null) {
|
if (handler != null) {
|
||||||
handler.disconnectRobot(robot);
|
handler.disconnectRobot(robot);
|
||||||
log.debug("仅断开机器人 {} TCP连接,保持注册状态", robot.getRobotId());
|
log.debug("断开机器人 {} TCP连接,玩法ID: {}", robot.getRobotId(), wanfaId);
|
||||||
}
|
}
|
||||||
disconnectedCount++;
|
disconnectedCount++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
if (disconnectedCount > 0) {
|
if (disconnectedCount > 0) {
|
||||||
log.debug("玩法 {} 成功断开 {} 个机器人的TCP连接,目标连接数: {}", wanfaId, disconnectedCount, requiredCount);
|
log.debug("玩法 {} 成功断开 {} 个机器人的TCP连接,目标连接数: {}", wanfaId, disconnectedCount, requiredCount);
|
||||||
}
|
}
|
||||||
|
|
@ -316,8 +322,16 @@ public class RobotManager {
|
||||||
if (!robot.isConnected() && !robot.isUsing() && reconnectedCount < (requiredCount - currentConnected)) {
|
if (!robot.isConnected() && !robot.isUsing() && reconnectedCount < (requiredCount - currentConnected)) {
|
||||||
RobotManagerInterface handler = getGameHandler(robot.getWanfaId());
|
RobotManagerInterface handler = getGameHandler(robot.getWanfaId());
|
||||||
if (handler != null) {
|
if (handler != null) {
|
||||||
|
if (shouldConnectRobot(robot)) {
|
||||||
|
synchronized(robot) {
|
||||||
|
if (!robot.isConnected() && !robot.isUsing()) {
|
||||||
handler.connectRobot(robot);
|
handler.connectRobot(robot);
|
||||||
log.debug("重新连接玩法 {} 的机器人: {}", wanfaId, robot.getRobotId());
|
log.debug("重新连接玩法 {} 的机器人: {}", wanfaId, robot.getRobotId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
log.debug("玩法 {} 的leftover_robot为0,跳过连接机器人: {}", wanfaId, robot.getRobotId());
|
||||||
|
}
|
||||||
reconnectedCount++;
|
reconnectedCount++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -329,9 +343,10 @@ public class RobotManager {
|
||||||
* 获取玩法房间轮询器
|
* 获取玩法房间轮询器
|
||||||
*/
|
*/
|
||||||
public RoomWanfaMatcher getWanfaRoomPoller(int groupId, int wanfaId) {
|
public RoomWanfaMatcher getWanfaRoomPoller(int groupId, int wanfaId) {
|
||||||
return wanfaRoomPollers.computeIfAbsent(wanfaId, k -> {
|
String key = groupId + ":" + wanfaId;
|
||||||
|
return wanfaRoomPollers.computeIfAbsent(key, k -> {
|
||||||
RoomWanfaMatcher poller = new RoomWanfaMatcher(this, groupId, wanfaId);
|
RoomWanfaMatcher poller = new RoomWanfaMatcher(this, groupId, wanfaId);
|
||||||
log.info("创建玩法ID {} 的房间轮询器", wanfaId);
|
log.info("创建群组 {} 玩法ID {} 的房间轮询器", groupId, wanfaId);
|
||||||
return poller;
|
return poller;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
@ -495,7 +510,32 @@ public class RobotManager {
|
||||||
public void releaseRobot(int robotId) {
|
public void releaseRobot(int robotId) {
|
||||||
RobotInfo robot = connectedRobots.get(robotId);
|
RobotInfo robot = connectedRobots.get(robotId);
|
||||||
if (robot != null) {
|
if (robot != null) {
|
||||||
|
synchronized(robot) {
|
||||||
robot.setUsing(false);
|
robot.setUsing(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据玩法的leftover_robot数量检查是否连接机器人
|
||||||
|
*/
|
||||||
|
public boolean shouldConnectRobot(RobotInfo robot) {
|
||||||
|
if (robot.getGroupId() == -1) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
try (Jedis jedis11 = Redis.use("group1_db11").getJedis()) {
|
||||||
|
String playKey = "g{" + robot.getGroupId() + "}:play:" + robot.getWanfaId();
|
||||||
|
String leftoverRobotStr = jedis11.hget(playKey, "leftover_robot");
|
||||||
|
|
||||||
|
if (leftoverRobotStr != null) {
|
||||||
|
int leftoverRobot = Integer.parseInt(leftoverRobotStr);
|
||||||
|
return leftoverRobot > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
} catch (Exception e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1,20 +1,22 @@
|
||||||
package com.group.robot.handler;
|
package com.group.robot.handler;
|
||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.UUID;
|
||||||
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.function.Consumer;
|
||||||
|
|
||||||
import com.group.Protocol;
|
import com.group.Protocol;
|
||||||
import com.group.robot.info.RobotInfo;
|
import com.group.robot.info.RobotInfo;
|
||||||
import com.group.robot.RobotManager;
|
import com.group.robot.RobotManager;
|
||||||
import com.group.robot.info.RoomInfo;
|
|
||||||
import com.group.robot.matcher.RoomWanfaMatcher;
|
|
||||||
import com.taurus.core.entity.TObject;
|
import com.taurus.core.entity.TObject;
|
||||||
import com.taurus.core.plugin.redis.Redis;
|
import com.taurus.core.plugin.redis.Redis;
|
||||||
import com.taurus.core.util.ICallback;
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import taurus.client.MessageResponse;
|
|
||||||
import taurus.client.SocketCode;
|
import taurus.client.SocketCode;
|
||||||
import taurus.client.TaurusClient;
|
import taurus.client.TaurusClient;
|
||||||
import taurus.client.Message;
|
import taurus.client.Message;
|
||||||
|
|
@ -36,9 +38,17 @@ public class RobotConnectionHandler {
|
||||||
//机器人ID到账户信息的映射
|
//机器人ID到账户信息的映射
|
||||||
private final Map<Integer, RobotAccountInfo> robotAccounts = new ConcurrentHashMap<>();
|
private final Map<Integer, RobotAccountInfo> robotAccounts = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
//机器人ID到连接ID的映射,用于标识每个机器人连接的唯一性
|
||||||
|
private final Map<Integer, String> robotConnectionIds = 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);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 机器人账户信息
|
* 机器人账户信息
|
||||||
*/
|
*/
|
||||||
|
|
@ -96,31 +106,68 @@ public class RobotConnectionHandler {
|
||||||
* 连接机器人到游戏服务器
|
* 连接机器人到游戏服务器
|
||||||
*/
|
*/
|
||||||
public void connectRobot(RobotInfo robot) {
|
public void connectRobot(RobotInfo robot) {
|
||||||
|
//玩法leftover_robot大于0连接机器人
|
||||||
|
if (!robotManager.shouldConnectRobot(robot)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
//异步执行连接逻辑
|
//异步执行连接逻辑
|
||||||
CompletableFuture.runAsync(() -> {
|
CompletableFuture.runAsync(() -> {
|
||||||
try {
|
try {
|
||||||
|
//连接前再次检查leftover_robot数量 防止并发
|
||||||
|
if (!robotManager.shouldConnectRobot(robot)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
log.info("开始连接机器人 {} 到游戏服务器,玩法ID: {}", robot.getRobotId(), robot.getWanfaId());
|
log.info("开始连接机器人 {} 到游戏服务器,玩法ID: {}", robot.getRobotId(), robot.getWanfaId());
|
||||||
//TCP客户端连接
|
//TCP客户端连接
|
||||||
TaurusClient client = new TaurusClient(getGameServerAddress(robot.getWanfaId()), "game", TaurusClient.ConnectionProtocol.Tcp);
|
String serverAddress = getGameServerAddress(robot.getWanfaId());
|
||||||
|
TaurusClient client = new TaurusClient(serverAddress, "game", TaurusClient.ConnectionProtocol.Tcp);
|
||||||
client.connect();
|
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);
|
robotClients.put(robot.getRobotId(), client);
|
||||||
|
robotServerAddresses.put(robot.getRobotId(), serverAddress);
|
||||||
|
//保存connecId
|
||||||
|
robotConnectionIds.put(robot.getRobotId(), connecId);
|
||||||
|
|
||||||
//设置事件监听器
|
//设置事件监听器
|
||||||
setupInitializationEventListeners(client, robot);
|
setupInitializationEventListeners(client, robot);
|
||||||
|
|
||||||
//连接成功后发送初始化协议
|
//连接成功后发送初始化协议
|
||||||
sendInitializationProtocol(client, robot);
|
sendInitializationProtocol(client, robot);
|
||||||
log.info("机器人 {} 成功连接到游戏服务器", robot.getRobotId());
|
|
||||||
|
//设置机器人连接状态
|
||||||
|
robot.setConnected(true);
|
||||||
|
log.info("机器人 {} 成功连接到游戏服务器, ConnectionId: {}", robot.getRobotId(), connecId);
|
||||||
|
|
||||||
|
//启动心跳
|
||||||
|
startHeartTask(robot.getRobotId(), client, robot.getWanfaId());
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("连接机器人到游戏服务器时发生异常: " + robot.getRobotId(), e);
|
log.error("连接机器人到游戏服务器时发生异常: " + robot.getRobotId(), e);
|
||||||
//清理已经建立的连接
|
robot.setConnected(false);
|
||||||
disconnectRobot(robot.getRobotId());
|
disconnectRobot(robot.getRobotId());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生成唯一的连接ID
|
||||||
|
*/
|
||||||
|
private String generateConnectionId(int robotId) {
|
||||||
|
String uuid = UUID.randomUUID().toString().replace("-", "").substring(0, 16);
|
||||||
|
return robotId + "_" + uuid;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 设置初始化阶段的事件监听器
|
* 设置初始化阶段的事件监听器
|
||||||
*/
|
*/
|
||||||
|
|
@ -132,8 +179,10 @@ public class RobotConnectionHandler {
|
||||||
SocketCode code = (SocketCode) event.getParameter("code");
|
SocketCode code = (SocketCode) event.getParameter("code");
|
||||||
if (code == SocketCode.Connect) {
|
if (code == SocketCode.Connect) {
|
||||||
log.info("机器人 {} 连接游戏服务器成功", robot.getRobotId());
|
log.info("机器人 {} 连接游戏服务器成功", robot.getRobotId());
|
||||||
|
robot.setConnected(true);
|
||||||
} else {
|
} else {
|
||||||
log.warn("机器人 {} 连接游戏服务器失败: {}", robot.getRobotId(), code);
|
log.warn("机器人 {} 连接游戏服务器失败: {}", robot.getRobotId(), code);
|
||||||
|
robot.setConnected(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
@ -161,6 +210,77 @@ 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获取服务器地址
|
||||||
*/
|
*/
|
||||||
|
|
@ -168,14 +288,14 @@ public class RobotConnectionHandler {
|
||||||
//根据玩法ID返回对应的服务器地址
|
//根据玩法ID返回对应的服务器地址
|
||||||
switch (wanfaId) {
|
switch (wanfaId) {
|
||||||
case 10: //长沙麻将
|
case 10: //长沙麻将
|
||||||
return "127.0.0.1:8701";
|
return "192.168.0.32:8701";
|
||||||
case 22: //红中麻将
|
case 22: //红中麻将
|
||||||
return "8.138.242.190:6421";
|
return "8.138.242.190:6421";
|
||||||
case 66: //跑得快
|
case 66: //跑得快
|
||||||
return "8.138.242.190:6841";
|
return "8.138.242.190:6841";
|
||||||
default:
|
default:
|
||||||
log.warn("未知的玩法ID: {}, 使用默认服务器地址", wanfaId);
|
log.warn("未知的玩法ID: {}, 使用默认服务器地址", wanfaId);
|
||||||
return "127.0.0.1:6311"; //默认地址
|
return "192.168.0.32:6311"; //默认地址
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -185,10 +305,11 @@ public class RobotConnectionHandler {
|
||||||
public void disconnectRobot(int robotId) {
|
public void disconnectRobot(int robotId) {
|
||||||
try {
|
try {
|
||||||
log.info("清理机器人 {} 的连接资源", robotId);
|
log.info("清理机器人 {} 的连接资源", robotId);
|
||||||
|
stopHeartTask(robotId);
|
||||||
//移除机器人TCP客户端连接
|
//移除机器人TCP客户端连接
|
||||||
TaurusClient client = robotClients.remove(robotId);
|
TaurusClient client = robotClients.remove(robotId);
|
||||||
if (client != null) {
|
if (client != null) {
|
||||||
client.clearResponse();
|
client.killConnection();
|
||||||
log.debug("已清理机器人 {} 的客户端连接", robotId);
|
log.debug("已清理机器人 {} 的客户端连接", robotId);
|
||||||
}
|
}
|
||||||
//移除机器人信息
|
//移除机器人信息
|
||||||
|
|
@ -220,6 +341,8 @@ public class RobotConnectionHandler {
|
||||||
if (client != null) {
|
if (client != null) {
|
||||||
//发送离开房间协议
|
//发送离开房间协议
|
||||||
ITObject param = new TObject();
|
ITObject param = new TObject();
|
||||||
|
param.putString("robotId", String.valueOf(robot.getRobotId()));
|
||||||
|
param.putString("connecId", robotConnectionIds.get(robot.getRobotId())); // 添加connecId
|
||||||
client.send("2005", param, response -> {
|
client.send("2005", param, response -> {
|
||||||
log.debug("机器人 {} 发送离开房间请求", robot.getRobotId());
|
log.debug("机器人 {} 发送离开房间请求", robot.getRobotId());
|
||||||
});
|
});
|
||||||
|
|
@ -281,6 +404,9 @@ public class RobotConnectionHandler {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 发送加入房间消息给指定机器人
|
||||||
|
*/
|
||||||
public void sendJoinRoomMessage(RobotInfo robot) {
|
public void sendJoinRoomMessage(RobotInfo robot) {
|
||||||
TaurusClient client = robotClients.get(robot.getRobotId());
|
TaurusClient client = robotClients.get(robot.getRobotId());
|
||||||
|
|
||||||
|
|
@ -291,6 +417,8 @@ public class RobotConnectionHandler {
|
||||||
|
|
||||||
ITObject readyParam = new TObject();
|
ITObject readyParam = new TObject();
|
||||||
readyParam.putString("session", robot.getSession() + "," + robot.getToken());
|
readyParam.putString("session", robot.getSession() + "," + robot.getToken());
|
||||||
|
readyParam.putString("robotId", String.valueOf(robot.getRobotId()));
|
||||||
|
readyParam.putString("connecId", robotConnectionIds.get(robot.getRobotId()));
|
||||||
client.send("2002", readyParam, response -> {
|
client.send("2002", readyParam, response -> {
|
||||||
log.debug("机器人 {} 发送加入房间请求响应: {}", robot.getRobotId(), response);
|
log.debug("机器人 {} 发送加入房间请求响应: {}", robot.getRobotId(), response);
|
||||||
});
|
});
|
||||||
|
|
@ -309,11 +437,62 @@ public class RobotConnectionHandler {
|
||||||
|
|
||||||
ITObject readyParam = new TObject();
|
ITObject readyParam = new TObject();
|
||||||
readyParam.putString("session", robot.getSession() + "," + robot.getToken());
|
readyParam.putString("session", robot.getSession() + "," + robot.getToken());
|
||||||
|
readyParam.putString("robotId", String.valueOf(robot.getRobotId()));
|
||||||
|
readyParam.putString("connecId", robotConnectionIds.get(robot.getRobotId()));
|
||||||
client.send("2003", readyParam, response -> {
|
client.send("2003", readyParam, response -> {
|
||||||
log.debug("机器人 {} 发送准备请求响应: {}", robot.getRobotId(), response);
|
log.debug("机器人 {} 发送准备请求响应: {}", robot.getRobotId(), response);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 同步发送准备消息并等待响应
|
||||||
|
*/
|
||||||
|
public boolean sendReadyMessageSync(RobotInfo robot) {
|
||||||
|
CompletableFuture<Boolean> future = new CompletableFuture<>();
|
||||||
|
TaurusClient client = robotClients.get(robot.getRobotId());
|
||||||
|
if (client == null) {
|
||||||
|
log.warn("机器人 {} 没有有效的TCP连接,无法发送准备消息", robot.getRobotId());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
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()));
|
||||||
|
|
||||||
|
client.send("2003", readyParam, response -> {
|
||||||
|
if (response != null && response.returnCode == 0) {
|
||||||
|
future.complete(true);
|
||||||
|
} else {
|
||||||
|
future.complete(false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
try {
|
||||||
|
return future.get(15, TimeUnit.SECONDS);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("发送准备消息时发生异常", e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void sendReadyMessageAsync(RobotInfo robot, Consumer<Boolean> callback) {
|
||||||
|
TaurusClient client = robotClients.get(robot.getRobotId());
|
||||||
|
if (client == null) {
|
||||||
|
callback.accept(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
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()));
|
||||||
|
|
||||||
|
client.send("2003", readyParam, response -> {
|
||||||
|
boolean success = response != null && response.returnCode == 0;
|
||||||
|
callback.accept(success);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 回调接口
|
* 回调接口
|
||||||
*/
|
*/
|
||||||
|
|
@ -332,9 +511,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.isConnected()) {
|
if (client == null ) {
|
||||||
log.warn("机器人 {} 的TCP连接未激活,无法发送创建房间请求", robot.getRobotId());
|
connectRobot(robot);
|
||||||
robotClients.remove(robot.getRobotId());
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -357,5 +535,4 @@ public class RobotConnectionHandler {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -76,7 +76,7 @@ public class RoomWanfaMatcher {
|
||||||
}
|
}
|
||||||
|
|
||||||
isRunning = true;
|
isRunning = true;
|
||||||
log.info("开始为玩法ID {} 启动房间轮询", wanfaId);
|
log.info("开始为群组 {} 玩法ID {} 启动房间轮询", groupId, wanfaId);
|
||||||
|
|
||||||
//10秒轮询一次
|
//10秒轮询一次
|
||||||
scheduler.scheduleWithFixedDelay(this::pollRooms, 0, 10, TimeUnit.SECONDS);
|
scheduler.scheduleWithFixedDelay(this::pollRooms, 0, 10, TimeUnit.SECONDS);
|
||||||
|
|
@ -93,44 +93,37 @@ public class RoomWanfaMatcher {
|
||||||
}
|
}
|
||||||
|
|
||||||
try (Jedis jedis0 = Redis.use().getJedis(); Jedis jedis11 = Redis.use("group1_db11").getJedis()) {
|
try (Jedis jedis0 = Redis.use().getJedis(); Jedis jedis11 = Redis.use("group1_db11").getJedis()) {
|
||||||
Set<String> roomIds = jedis0.keys("room:*");
|
String playKey = "g{" + groupId + "}:play:" + wanfaId;
|
||||||
if (roomIds.isEmpty()) {
|
String leftoverRobotStr = jedis11.hget(playKey, "leftover_robot");
|
||||||
createRobotWanfaRoomTCP(groupId, this.wanfaId);
|
|
||||||
}
|
|
||||||
|
|
||||||
int groupId = -1;
|
int leftoverRobot = Integer.parseInt(leftoverRobotStr);
|
||||||
|
|
||||||
for (String roomId : roomIds) {
|
|
||||||
int wanfaId = Integer.parseInt(jedis0.hget(roomId, "gpid"));
|
|
||||||
if (wanfaId == this.wanfaId) {
|
|
||||||
groupId = Integer.parseInt(jedis0.hget(roomId, "group"));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (groupId != -1) {
|
|
||||||
//检查该玩法是否配置了机器人
|
|
||||||
String playKey = "g{" + groupId + "}:play:" + this.wanfaId;
|
|
||||||
int leftoverRobot = Integer.parseInt(jedis11.hget(playKey, "leftover_robot"));
|
|
||||||
|
|
||||||
//根据leftover_robot数量管理机器人连接状态
|
//根据leftover_robot数量管理机器人连接状态
|
||||||
manageRobotConnections(leftoverRobot);
|
manageRobotConnections(leftoverRobot);
|
||||||
|
|
||||||
if (leftoverRobot > 0) {
|
if (leftoverRobot > 0) {
|
||||||
|
//查询当前群组和玩法的房间
|
||||||
|
Set<String> roomIds = jedis0.keys("room:*");
|
||||||
|
|
||||||
|
if (roomIds.isEmpty()) {
|
||||||
|
createRobotWanfaRoomTCP(groupId, this.wanfaId);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
//满人房间
|
//满人房间
|
||||||
int fullRooms = 0;
|
int fullRooms = 0;
|
||||||
//所有房间
|
//所有房间
|
||||||
int totalRooms = 0;
|
int totalRooms = 0;
|
||||||
List<String> roomsList = new ArrayList<>();
|
List<String> roomsList = new ArrayList<>();
|
||||||
|
|
||||||
//统计所有2人房间
|
//统计所有当前群组和玩法的2人房间
|
||||||
for (String roomId : roomIds) {
|
for (String roomId : roomIds) {
|
||||||
int currentWanfaId = Integer.parseInt(jedis0.hget(roomId, "gpid"));
|
int currentWanfaId = Integer.parseInt(jedis0.hget(roomId, "gpid"));
|
||||||
int status = Integer.parseInt(jedis0.hget(roomId, "status"));
|
int currentGroup = Integer.parseInt(jedis0.hget(roomId, "group"));
|
||||||
int maxPlayers = Integer.parseInt(jedis0.hget(roomId, "maxPlayers"));
|
int maxPlayers = Integer.parseInt(jedis0.hget(roomId, "maxPlayers"));
|
||||||
|
|
||||||
//处理当前玩法maxPlayers为2的房间
|
//处理当前群组和玩法maxPlayers为2的房间
|
||||||
if (maxPlayers == 2 && currentWanfaId == this.wanfaId && status == 0) {
|
if (maxPlayers == 2 && currentWanfaId == this.wanfaId && currentGroup == this.groupId) {
|
||||||
totalRooms++;
|
totalRooms++;
|
||||||
|
|
||||||
String playersStr = jedis0.hget(roomId, "players");
|
String playersStr = jedis0.hget(roomId, "players");
|
||||||
|
|
@ -150,13 +143,13 @@ public class RoomWanfaMatcher {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//该玩法机器人房间满了 创建新房间
|
//todo该玩法机器人房间满了 创建新房间
|
||||||
if (fullRooms == totalRooms && totalRooms > 0) {
|
/*if (fullRooms == totalRooms && totalRooms > 0) {
|
||||||
createRobotWanfaRoomTCP(groupId, this.wanfaId);
|
createRobotWanfaRoomTCP(groupId, this.wanfaId);
|
||||||
}
|
return;
|
||||||
|
}*/
|
||||||
|
|
||||||
for (String roomId : roomsList) {
|
for (String roomId : roomsList) {
|
||||||
int group = Integer.parseInt(jedis0.hget(roomId, "group"));
|
|
||||||
int status = Integer.parseInt(jedis0.hget(roomId, "status"));
|
int status = Integer.parseInt(jedis0.hget(roomId, "status"));
|
||||||
|
|
||||||
//处理未开始的陪打房间
|
//处理未开始的陪打房间
|
||||||
|
|
@ -164,7 +157,7 @@ public class RoomWanfaMatcher {
|
||||||
String playersStr = jedis0.hget(roomId, "players");
|
String playersStr = jedis0.hget(roomId, "players");
|
||||||
RobotInfo robot = new RobotInfo();
|
RobotInfo robot = new RobotInfo();
|
||||||
robot.setWanfaId(this.wanfaId);
|
robot.setWanfaId(this.wanfaId);
|
||||||
robot.setGroupId(group);
|
robot.setGroupId(this.groupId);
|
||||||
robot.setRoomId(roomId);
|
robot.setRoomId(roomId);
|
||||||
robot.setRobotId(-1);
|
robot.setRobotId(-1);
|
||||||
|
|
||||||
|
|
@ -189,9 +182,8 @@ public class RoomWanfaMatcher {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
} catch (Throwable t) {
|
} catch (Throwable t) {
|
||||||
log.error("轮询玩法ID {} 的房间时发生严重错误", wanfaId, t);
|
log.error("轮询群组 {} 玩法ID {} 的房间时发生严重错误", groupId, wanfaId, t);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -213,31 +205,51 @@ public class RoomWanfaMatcher {
|
||||||
}
|
}
|
||||||
|
|
||||||
//加入房间
|
//加入房间
|
||||||
|
try {
|
||||||
GroupRoomBusiness.joinRoom(robotInfo.getGroupId(), robotInfo.getRoomId(), robotInfo.getSession(), null);
|
GroupRoomBusiness.joinRoom(robotInfo.getGroupId(), robotInfo.getRoomId(), robotInfo.getSession(), null);
|
||||||
Thread.sleep(5000);
|
Thread.sleep(5000);
|
||||||
robotConnectionHandler.sendJoinRoomMessage(robotInfo);
|
robotConnectionHandler.sendJoinRoomMessage(robotInfo);
|
||||||
|
Thread.sleep(1000);
|
||||||
|
}catch (Exception e) {
|
||||||
|
log.error("加入房间失败", e);
|
||||||
|
processingRooms.remove(roomId);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
//准备
|
//准备
|
||||||
Thread.sleep(1000);
|
RobotInfo finalRobotInfo = robotInfo;
|
||||||
robotConnectionHandler.sendReadyMessage(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());
|
roomToRobotMap.put(roomId, robotInfo.getRobotId());
|
||||||
|
|
||||||
|
updateRobotStatusRedis(robotInfo);
|
||||||
|
|
||||||
if (isRobot) {
|
if (isRobot) {
|
||||||
updateRobotStatusRedis(robotInfo, isRobot);
|
|
||||||
//6秒没有玩家加入 则退出房间
|
//6秒没有玩家加入 则退出房间
|
||||||
robotConnectionHandler.readyTimeRobotExit(robotInfo, joinRoomLock);
|
robotConnectionHandler.readyTimeRobotExit(robotInfo, joinRoomLock);
|
||||||
} else {
|
|
||||||
updateRobotStatusRedis(robotInfo, isRobot);
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
//robotConnectionHandler.disconnectRobot(robotInfo.getRobotId());
|
||||||
|
}*/
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
if (robotInfo != null) {
|
if (robotInfo != null) {
|
||||||
robotConnectionHandler.disconnectRobot(robotInfo.getRobotId());
|
//robotConnectionHandler.disconnectRobot(robotInfo.getRobotId());
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
if (roomId != null) {
|
|
||||||
processingRooms.remove(roomId);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -309,10 +321,10 @@ 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 断开该玩法未连接的机器人
|
//leftover_robot变为0 断开该玩法与robot_mj_cs的连接
|
||||||
robotManager.disconnectExcessRobots(wanfaId, 0);
|
robotManager.disconnectExcessRobots(wanfaId, 0);
|
||||||
} else if (currentLeftoverRobot > 0 && lastLeftoverRobot <= 0) {
|
} else if (currentLeftoverRobot > 0 && lastLeftoverRobot <= 0) {
|
||||||
//leftover_robot变为正数 重新连接机器人
|
//leftover_robot变为正数 重新连接机器人到robot_mj_cs
|
||||||
robotManager.connectRequiredRobots(wanfaId, currentLeftoverRobot);
|
robotManager.connectRequiredRobots(wanfaId, currentLeftoverRobot);
|
||||||
}
|
}
|
||||||
lastLeftoverRobot = currentLeftoverRobot;
|
lastLeftoverRobot = currentLeftoverRobot;
|
||||||
|
|
@ -341,28 +353,24 @@ public class RoomWanfaMatcher {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 机器人加入真人房间
|
* 更新机器人状态 - 减少leftover_robot计数并更新机器人start状态
|
||||||
*/
|
*/
|
||||||
private void updateRobotStatusRedis(RobotInfo robot, boolean isRobot) {
|
private void updateRobotStatusRedis(RobotInfo robot) {
|
||||||
try (Jedis jedis11 = Redis.use("group1_db11").getJedis(); Jedis jedis2 = Redis.use("group1_db2").getJedis()) {
|
try (Jedis jedis11 = Redis.use("group1_db11").getJedis(); Jedis jedis2 = Redis.use("group1_db2").getJedis()) {
|
||||||
|
|
||||||
String playKey = "g{" + robot.getGroupId() + "}:play:" + robot.getWanfaId();
|
String playKey = "g{" + robot.getGroupId() + "}:play:" + robot.getWanfaId();
|
||||||
|
|
||||||
if (!isRobot) {
|
|
||||||
jedis11.hincrBy(playKey, "leftover_robot", -1);
|
jedis11.hincrBy(playKey, "leftover_robot", -1);
|
||||||
|
|
||||||
String gRobotKey = "{grobot}:" + robot.getRobotId();
|
String gRobotKey = "{grobot}:" + robot.getRobotId();
|
||||||
jedis2.hset(gRobotKey, "start", "1");
|
jedis2.hset(gRobotKey, "start", "1");
|
||||||
|
|
||||||
log.debug("机器人 {} 加入非机器人房间,减少leftover_robot并更新redis2状态,群组={}, 玩法={}", robot.getRobotId(), robot.getGroupId(), robot.getWanfaId());
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("更新机器人状态时异常,机器人={}, 群组={}, 玩法={}", robot.getRobotId(), robot.getGroupId(), robot.getWanfaId(), e);
|
log.error("更新机器人状态时异常,机器人={}, 群组={}, 玩法={}", robot.getRobotId(), robot.getGroupId(), robot.getWanfaId(), e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 通知房间处理完成,从processingRooms集合中移除指定房间
|
* 通知房间处理完成 从processingRooms集合中移除指定房间
|
||||||
*/
|
*/
|
||||||
public void roomProcessingFinish(String roomId) {
|
public void roomProcessingFinish(String roomId) {
|
||||||
processingRooms.remove(roomId);
|
processingRooms.remove(roomId);
|
||||||
|
|
|
||||||
|
|
@ -257,6 +257,8 @@ public class GameController implements IController{
|
||||||
AccountBean acc = AccountCache.getAccount(session_key);
|
AccountBean acc = AccountCache.getAccount(session_key);
|
||||||
int playerid = acc.id;
|
int playerid = acc.id;
|
||||||
|
|
||||||
|
Global.logger.info("joinRoom - 正在处理加入请求-PlayerId: {}, Session: {}, Sender: {}", playerid, session_key, sender);
|
||||||
|
|
||||||
boolean full = owner.playerMapBySeat.size() >= owner.maxPlayers;
|
boolean full = owner.playerMapBySeat.size() >= owner.maxPlayers;
|
||||||
boolean reload = owner.status == Constant.ROOM_STATUS_PLAYING;
|
boolean reload = owner.status == Constant.ROOM_STATUS_PLAYING;
|
||||||
|
|
||||||
|
|
@ -269,6 +271,7 @@ public class GameController implements IController{
|
||||||
boolean new_player = false;
|
boolean new_player = false;
|
||||||
if (owner.playerMapById.containsKey(playerid)) {
|
if (owner.playerMapById.containsKey(playerid)) {
|
||||||
player = owner.playerMapById.get(playerid);
|
player = owner.playerMapById.get(playerid);
|
||||||
|
Global.logger.info("joinRoom - 已找到现有玩家-PlayerId: {}, Player: {}, isConnect: {}", playerid, player, player.isConnect);
|
||||||
if (player.isReload) {
|
if (player.isReload) {
|
||||||
player.isReload = false;
|
player.isReload = false;
|
||||||
player.stateMachine.changeState(Global.getState(PlayerInitState.class));
|
player.stateMachine.changeState(Global.getState(PlayerInitState.class));
|
||||||
|
|
@ -280,6 +283,7 @@ public class GameController implements IController{
|
||||||
if (full) {
|
if (full) {
|
||||||
sender.setHashId(null);
|
sender.setHashId(null);
|
||||||
delRoomSeat(session_key, owner.room_key);
|
delRoomSeat(session_key, owner.room_key);
|
||||||
|
Global.logger.warn("joinRoom - 房间已满,拒绝玩家: {}", playerid);
|
||||||
return ErrorCode.ROOM_CLOSE;
|
return ErrorCode.ROOM_CLOSE;
|
||||||
}
|
}
|
||||||
// 检测是否打开GPS 、IP检测
|
// 检测是否打开GPS 、IP检测
|
||||||
|
|
@ -318,6 +322,7 @@ public class GameController implements IController{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
player = MainServer.instance.newPlayer(playerid, owner, session_key);
|
player = MainServer.instance.newPlayer(playerid, owner, session_key);
|
||||||
|
Global.logger.info("joinRoom - 已创建新玩家-PlayerId: {}, Player: {}", playerid, player);
|
||||||
player.hp.cur_hp = cur_hp;
|
player.hp.cur_hp = cur_hp;
|
||||||
|
|
||||||
owner.addPlayer(player, false, onseat);
|
owner.addPlayer(player, false, onseat);
|
||||||
|
|
@ -333,6 +338,9 @@ public class GameController implements IController{
|
||||||
if (StringUtil.isNotEmpty(gps_pos))
|
if (StringUtil.isNotEmpty(gps_pos))
|
||||||
player.gps_pos = gps_pos;
|
player.gps_pos = gps_pos;
|
||||||
|
|
||||||
|
Global.logger.info("joinRoom - 播放器设置完成-PlayerId: {}, Nick: {}, isConnect: {}, Sender: {}",
|
||||||
|
player.playerid, player.nick, player.isConnect, player.sender);
|
||||||
|
|
||||||
ITObject data = new TObject();
|
ITObject data = new TObject();
|
||||||
if (reload) {
|
if (reload) {
|
||||||
data.putTObject("reloadInfo", owner.getReloadInfo(player));
|
data.putTObject("reloadInfo", owner.getReloadInfo(player));
|
||||||
|
|
|
||||||
|
|
@ -114,7 +114,8 @@ public abstract class MainServer extends Extension implements IEventListener{
|
||||||
* @param recipients 客户端session列表
|
* @param recipients 客户端session列表
|
||||||
*/
|
*/
|
||||||
public void sendEvent(String cmdName, ITObject params, List<Session> recipients) {
|
public void sendEvent(String cmdName, ITObject params, List<Session> recipients) {
|
||||||
TPServer.me().getController().sendEvent(cmdName, params, recipients);
|
TPServer.me().getController().sendEv
|
||||||
|
ent(cmdName, params, recipients);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -191,23 +191,28 @@ public class Player {
|
||||||
public void setSender(Session sender) {
|
public void setSender(Session sender) {
|
||||||
// 服务器从崩溃中重启
|
// 服务器从崩溃中重启
|
||||||
if (sender == null) {
|
if (sender == null) {
|
||||||
|
Global.logger.error("setSender - 为Player设置空会话: {}, PlayerId: {}, Nick: {}, changing isConnect to false",
|
||||||
|
this.toString(), this.playerid, this.nick);
|
||||||
this.isReload = true;
|
this.isReload = true;
|
||||||
this.isConnect = false;
|
this.isConnect = false;
|
||||||
this.stateMachine.changeState(Global.getState(PlayerReloadState.class));
|
this.stateMachine.changeState(Global.getState(PlayerReloadState.class));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (this.isConnect && this.sender != null && this.sender != sender) {
|
if (this.isConnect && this.sender != null && this.sender != sender) {
|
||||||
|
Global.logger.warn("setSender - 替换Player的现有会话: {}, PlayerId: {}, Old sender: {}, New sender: {}",
|
||||||
|
this.toString(), this.playerid, this.sender, sender);
|
||||||
Global.sessionMgr.deleteSession(this.sender);
|
Global.sessionMgr.deleteSession(this.sender);
|
||||||
TPServer.me().getController().disconnect(this.sender);
|
TPServer.me().getController().disconnect(this.sender);
|
||||||
}
|
}
|
||||||
// 已经连接
|
// 已经连接
|
||||||
this.sender = sender;
|
this.sender = sender;
|
||||||
Global.sessionMgr.putPlayer(sender, this);
|
Global.sessionMgr.putPlayer(sender, this);
|
||||||
this.isConnect = true;
|
this.isConnect = true; // 这里设置连接状态为 true
|
||||||
|
Global.logger.info("setSender - 已成功为玩家设置会话: {}, PlayerId: {}, Nick: {}, isConnect: true",
|
||||||
|
this.toString(), this.playerid, this.nick);
|
||||||
// if (this.stateMachine.curState == null || this.isReload) {
|
// if (this.stateMachine.curState == null || this.isReload) {
|
||||||
// this.stateMachine.changeState(Global.getState(PlayerInitState.class));
|
// this.stateMachine.changeState(Global.getState(PlayerInitState.class));
|
||||||
this.isReload = false;
|
this.isReload = false;
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -416,8 +421,13 @@ public class Player {
|
||||||
* @param param
|
* @param param
|
||||||
*/
|
*/
|
||||||
public void sendEvent(String cmd, ITObject param) {
|
public void sendEvent(String cmd, ITObject param) {
|
||||||
if (!this.isConnect)
|
if (!this.isConnect) {
|
||||||
|
Global.logger.error("sendEvent failed - Player: {}, PlayerId: {}, Nick: {}, isConnect: false, Cmd: {}",
|
||||||
|
this.toString(), this.playerid, this.nick, cmd);
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
Global.logger.info("sendEvent success - Player: {}, PlayerId: {}, Nick: {}, isConnect: true, Cmd: {}",
|
||||||
|
this.toString(), this.playerid, this.nick, cmd);
|
||||||
MainServer.instance.sendEvent(cmd, param, this.sender);
|
MainServer.instance.sendEvent(cmd, param, this.sender);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -721,9 +721,13 @@ public class Room implements Runnable {
|
||||||
* @param reload
|
* @param reload
|
||||||
*/
|
*/
|
||||||
public void addPlayer(Player player, boolean reload, boolean onseat) {
|
public void addPlayer(Player player, boolean reload, boolean onseat) {
|
||||||
|
Global.logger.info("addPlayer-将玩家添加到房间-房间: {}, PlayerId: {}, Nick: {}, Reload: {}, OnSeat: {}",
|
||||||
|
this.roomid, player.playerid, player.nick, reload, onseat);
|
||||||
|
|
||||||
if (!reload) {
|
if (!reload) {
|
||||||
if (onseat) {
|
if (onseat) {
|
||||||
player.seat = this.getSeat();
|
player.seat = this.getSeat();
|
||||||
|
Global.logger.info("addPlayer-分配的座位: {} to player: {}", player.seat, player.playerid);
|
||||||
}
|
}
|
||||||
Redis.use().hset(player.session_id, "seat", player.seat + "");
|
Redis.use().hset(player.session_id, "seat", player.seat + "");
|
||||||
if (groupId > 0) {
|
if (groupId > 0) {
|
||||||
|
|
@ -740,10 +744,14 @@ public class Room implements Runnable {
|
||||||
}
|
}
|
||||||
if (onseat) {
|
if (onseat) {
|
||||||
this.playerMapBySeat.put(player.seat, player);
|
this.playerMapBySeat.put(player.seat, player);
|
||||||
|
Global.logger.info("addPlayer-将玩家添加到座位映射-座位 - Seat: {}, Player: {}", player.seat, player.playerid);
|
||||||
} else {
|
} else {
|
||||||
this.playerMapBySpectator.put(player.playerid, player);
|
this.playerMapBySpectator.put(player.playerid, player);
|
||||||
|
Global.logger.info("addPlayer-将玩家添加到观众映射中 - PlayerId: {}", player.playerid);
|
||||||
}
|
}
|
||||||
this.playerMapById.put(player.playerid, player);
|
this.playerMapById.put(player.playerid, player);
|
||||||
|
Global.logger.info("addPlayer-将玩家添加到ID映射中-房间中的玩家总数: {}, Player: {}",
|
||||||
|
this.playerMapById.size(), player.playerid);
|
||||||
|
|
||||||
if (!reload && onseat) {
|
if (!reload && onseat) {
|
||||||
updateRedisMap();
|
updateRedisMap();
|
||||||
|
|
@ -894,15 +902,33 @@ public class Room implements Runnable {
|
||||||
if (!isActive)
|
if (!isActive)
|
||||||
return;
|
return;
|
||||||
List<Session> list = new ArrayList<Session>();
|
List<Session> list = new ArrayList<Session>();
|
||||||
|
Global.logger.info("broadCastToClient-向房间中的玩家广播cmd: {}, to players in room: {}, total players: {}",
|
||||||
|
cmd, this.roomid, this.playerMapById.size());
|
||||||
|
|
||||||
|
int skippedPlayers = 0;
|
||||||
|
int addedPlayers = 0;
|
||||||
|
|
||||||
for (Entry<Integer, Player> entry : this.playerMapById.entrySet()) {
|
for (Entry<Integer, Player> entry : this.playerMapById.entrySet()) {
|
||||||
Player player = entry.getValue();
|
Player player = entry.getValue();
|
||||||
if (player.playerid == withOutPlayerid) {
|
if (player.playerid == withOutPlayerid) {
|
||||||
|
Global.logger.debug("broadCastToClient - 由于withOutPlayelid而跳过玩家: {}", player.playerid);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (!player.isConnect)
|
if (!player.isConnect) {
|
||||||
|
Global.logger.warn("broadCastToClient - 跳过玩家(未连接): {}, PlayerId: {}, Nick: {}, isConnect: {}",
|
||||||
|
player.toString(), player.playerid, player.nick, player.isConnect);
|
||||||
|
skippedPlayers++;
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
Global.logger.info("broadCastToClient - 将玩家添加到广播列表: {}, PlayerId: {}, Nick: {}, isConnect: {}",
|
||||||
|
player.toString(), player.playerid, player.nick, player.isConnect);
|
||||||
list.add(player.sender);
|
list.add(player.sender);
|
||||||
|
addedPlayers++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Global.logger.info("broadCastToClient - 最终广播列表大小: {}, Added: {}, Skipped: {}, Command: {}",
|
||||||
|
list.size(), addedPlayers, skippedPlayers, cmd);
|
||||||
|
|
||||||
MainServer.instance.sendEvent(cmd, param, list);
|
MainServer.instance.sendEvent(cmd, param, list);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,6 @@ import taurus.client.Message;
|
||||||
import taurus.client.TaurusClient;
|
import taurus.client.TaurusClient;
|
||||||
import taurus.util.CardUtil;
|
import taurus.util.CardUtil;
|
||||||
import taurus.util.ChangShaSuanFaTest;
|
import taurus.util.ChangShaSuanFaTest;
|
||||||
import taurus.util.HongZhongSuanFaTest;
|
|
||||||
|
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
|
||||||
|
|
@ -750,7 +750,8 @@ public class JiQiRens {
|
||||||
System.out.println(e);
|
System.out.println(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if ("108".equalsIgnoreCase(wanfaId)) {//转转麻将
|
}
|
||||||
|
else if ("108".equalsIgnoreCase(wanfaId)) {//转转麻将
|
||||||
if ("811".equalsIgnoreCase(command)) {//初始化收手牌
|
if ("811".equalsIgnoreCase(command)) {//初始化收手牌
|
||||||
huNanZhuanZhuan.cardInHead(command, message, client);
|
huNanZhuanZhuan.cardInHead(command, message, client);
|
||||||
} else if ("812".equalsIgnoreCase(command)) {//出牌广播
|
} else if ("812".equalsIgnoreCase(command)) {//出牌广播
|
||||||
|
|
@ -779,21 +780,27 @@ public class JiQiRens {
|
||||||
System.out.println(e);
|
System.out.println(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if ("10".equalsIgnoreCase(wanfaId)) {
|
}
|
||||||
|
else if ("10".equalsIgnoreCase(wanfaId)) {
|
||||||
//长沙麻将
|
//长沙麻将
|
||||||
System.out.println("11111-----------command" + command);
|
System.out.println("11111-----------command" + command);
|
||||||
if ("811".equalsIgnoreCase(command)) {//初始化收手牌
|
if ("811".equalsIgnoreCase(command)) {//初始化收手牌
|
||||||
huNanChangSha.cardInHead(command, message, client);
|
huNanChangSha.cardInHead(command, message, client);
|
||||||
} else if ("812".equalsIgnoreCase(command)) {//出牌广播
|
}
|
||||||
|
else if ("812".equalsIgnoreCase(command)) {//出牌广播
|
||||||
HuNanChangSha.drawCard(command, message);
|
HuNanChangSha.drawCard(command, message);
|
||||||
} else if ("819".equalsIgnoreCase(command)) {//摸牌
|
}
|
||||||
|
else if ("819".equalsIgnoreCase(command)) {//摸牌
|
||||||
huNanChangSha.getCard(command, message);
|
huNanChangSha.getCard(command, message);
|
||||||
} else if ("813".equalsIgnoreCase(command)) {//出牌提示
|
}
|
||||||
|
else if ("813".equalsIgnoreCase(command)) {//出牌提示
|
||||||
System.out.println("出牌++++++++++++++++++++++++");
|
System.out.println("出牌++++++++++++++++++++++++");
|
||||||
huNanChangSha.outCard(client);
|
huNanChangSha.outCard(client);
|
||||||
} else if ("814".equalsIgnoreCase(command)) {//放招提示
|
}
|
||||||
|
else if ("814".equalsIgnoreCase(command)) {//放招提示
|
||||||
huNanChangSha.actionCard(param, client);
|
huNanChangSha.actionCard(param, client);
|
||||||
} else if ("2009".equalsIgnoreCase(command)) {
|
}
|
||||||
|
else if ("2009".equalsIgnoreCase(command)) {
|
||||||
for (int i = 0; i < 7; i++) {
|
for (int i = 0; i < 7; i++) {
|
||||||
sleepTime(1000);
|
sleepTime(1000);
|
||||||
if (i == 6) {
|
if (i == 6) {
|
||||||
|
|
@ -872,7 +879,8 @@ public class JiQiRens {
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if ("817".equalsIgnoreCase(command)) {//结算
|
}
|
||||||
|
else if ("817".equalsIgnoreCase(command)) {//结算
|
||||||
huNanChangSha.getChangShaCardInhand().clear();
|
huNanChangSha.getChangShaCardInhand().clear();
|
||||||
huNanChangSha.getChuGuoCardInhand().clear();
|
huNanChangSha.getChuGuoCardInhand().clear();
|
||||||
huNanChangSha.getpongGroup().clear();
|
huNanChangSha.getpongGroup().clear();
|
||||||
|
|
@ -928,11 +936,15 @@ public class JiQiRens {
|
||||||
ready();
|
ready();
|
||||||
//写定时器
|
//写定时器
|
||||||
|
|
||||||
} else if ("815".equalsIgnoreCase(command)) { //服务器通知客户端有玩家执行了操作
|
}
|
||||||
|
else if ("815".equalsIgnoreCase(command)) { //服务器通知客户端有玩家执行了操作
|
||||||
huNanChangSha.shanchuchuguopai(param);
|
huNanChangSha.shanchuchuguopai(param);
|
||||||
} else if ("820".equalsIgnoreCase(command)) {//换牌提示
|
}
|
||||||
|
else if ("820".equalsIgnoreCase(command)) {//换牌提示
|
||||||
huNanChangSha.changePlayer(command, message);
|
huNanChangSha.changePlayer(command, message);
|
||||||
} else if ("2008".equalsIgnoreCase(command)) { //解散房间时候恢复机器人账号可以使用
|
}
|
||||||
|
else if ("2008".equalsIgnoreCase(command)) {
|
||||||
|
//解散房间时候恢复机器人账号可以使用
|
||||||
// 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;
|
||||||
//
|
//
|
||||||
|
|
@ -971,21 +983,24 @@ public class JiQiRens {
|
||||||
// } catch (SQLException e) {
|
// } catch (SQLException e) {
|
||||||
// System.out.println(e);
|
// System.out.println(e);
|
||||||
// }
|
// }
|
||||||
} else if ("825".equalsIgnoreCase(command)) {
|
}
|
||||||
|
else if ("825".equalsIgnoreCase(command)) {
|
||||||
ITObject params = TObject.newInstance();
|
ITObject params = TObject.newInstance();
|
||||||
params.putInt("qi", 0);
|
params.putInt("qi", 0);
|
||||||
params.putInt("id", 1);
|
params.putInt("id", 1);
|
||||||
client.send("612", params, response -> {
|
client.send("612", params, response -> {
|
||||||
System.out.println("操作成功: " + response.returnCode);
|
System.out.println("操作成功: " + response.returnCode);
|
||||||
});
|
});
|
||||||
} else if ("822".equalsIgnoreCase(command)) {
|
}
|
||||||
|
else if ("822".equalsIgnoreCase(command)) {
|
||||||
ITObject params = TObject.newInstance();
|
ITObject params = TObject.newInstance();
|
||||||
params.putInt("qi", 0);
|
params.putInt("qi", 0);
|
||||||
params.putInt("id", 1);
|
params.putInt("id", 1);
|
||||||
client.send("612", params, response -> {
|
client.send("612", params, response -> {
|
||||||
System.out.println("操作成功: " + response.returnCode);
|
System.out.println("操作成功: " + response.returnCode);
|
||||||
});
|
});
|
||||||
} else if ("835".equalsIgnoreCase(command)) { //听牌天听
|
}
|
||||||
|
else if ("835".equalsIgnoreCase(command)) { //听牌天听
|
||||||
ITObject params = TObject.newInstance();
|
ITObject params = TObject.newInstance();
|
||||||
params.putInt("qi", 0);
|
params.putInt("qi", 0);
|
||||||
params.putInt("id", 1);
|
params.putInt("id", 1);
|
||||||
|
|
|
||||||
|
|
@ -158,6 +158,11 @@ public class EXGameController extends GameController {
|
||||||
owner.getRoom().currenDiscardSeat = owner.seat;
|
owner.getRoom().currenDiscardSeat = owner.seat;
|
||||||
ITObject param = new TObject();
|
ITObject param = new TObject();
|
||||||
param.putBoolean("auto",owner.autoOutCard);
|
param.putBoolean("auto",owner.autoOutCard);
|
||||||
|
|
||||||
|
// 添加调试日志,检查连接状态
|
||||||
|
Global.logger.info("discardTipEvent - Player: {}, PlayerId: {}, Seat: {}, isConnect: {}, Sender: {}",
|
||||||
|
owner.nick, owner.playerid, owner.seat, owner.isConnect, owner.sender);
|
||||||
|
|
||||||
owner.sendEvent(Config.GAME_EVT_DISCARD_TIP, param);
|
owner.sendEvent(Config.GAME_EVT_DISCARD_TIP, param);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -98,36 +98,33 @@ 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";
|
||||||
|
|
||||||
/**
|
// 创建房间机器人协议
|
||||||
* 加入房间 - robot_mgr to robot_mj_cs 的内部协议号
|
public static final String CREATE_ROOM_ROBOT = "create_room_for_robot";
|
||||||
*/
|
|
||||||
|
// 加入房间协议
|
||||||
public static final String JOIN_ROOM = "2002";
|
public static final String JOIN_ROOM = "2002";
|
||||||
|
|
||||||
/**
|
// 加入房间CS协议
|
||||||
* 发送准备 - robot_mgr to robot_mj_cs 的内部协议号
|
|
||||||
*/
|
|
||||||
public static final String GAME_READY = "2003";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 退出房间 - robot_mgr to robot_mj_cs 的内部协议号
|
|
||||||
*/
|
|
||||||
public static final String EXIT_ROOM = "2005";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 发送准备 - robot_mj_cs to game_mj_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 JOIN_ROOM_CS = "1002";
|
||||||
|
|
||||||
/**
|
// 游戏准备协议
|
||||||
* 退出房间 - robot_mgr to game_mj_cs 的内部协议号
|
public static final String GAME_READY = "2003";
|
||||||
*/
|
|
||||||
public static final String EXIT_ROOM_CS = "1005";
|
// 游戏准备CS协议
|
||||||
|
public static final String GAME_READY_CS = "1003";
|
||||||
|
|
||||||
|
// 退出房间协议
|
||||||
|
public static final String EXIT_ROOM = "2004";
|
||||||
|
|
||||||
|
// 退出房间CS协议
|
||||||
|
public static final String EXIT_ROOM_CS = "1004";
|
||||||
|
|
||||||
|
// 其他可能的游戏相关协议
|
||||||
|
public static final String GAME_CHAT = "1006";
|
||||||
|
|
||||||
|
// 心跳协议
|
||||||
|
public static final String HEARTBEAT = "9000";
|
||||||
}
|
}
|
||||||
|
|
@ -5,12 +5,16 @@ 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.HuNanChangShaHandler;
|
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;
|
||||||
|
|
||||||
|
|
@ -20,6 +24,8 @@ import taurus.client.TaurusClient;
|
||||||
public class EXGameController extends GameController {
|
public class EXGameController extends GameController {
|
||||||
private static final Logger log = LoggerFactory.getLogger(EXGameController.class);
|
private static final Logger log = LoggerFactory.getLogger(EXGameController.class);
|
||||||
|
|
||||||
|
private static RobotConnectionManager connectionManager = new RobotConnectionManager();
|
||||||
|
|
||||||
public EXGameController() {
|
public EXGameController() {
|
||||||
super();
|
super();
|
||||||
log.info("长沙麻将游戏控制器已初始化");
|
log.info("长沙麻将游戏控制器已初始化");
|
||||||
|
|
@ -35,12 +41,13 @@ public class EXGameController extends GameController {
|
||||||
|
|
||||||
String type = params.getString("type");
|
String type = params.getString("type");
|
||||||
String client = params.getString("client");
|
String client = params.getString("client");
|
||||||
|
String sessionToken = params.getString("session");
|
||||||
|
|
||||||
log.info("客户端类型: {}, 客户端标识: {}", type, client);
|
log.info("客户端类型: {}, 客户端标识: {}", type, client);
|
||||||
|
|
||||||
// 验证参数
|
//验证参数
|
||||||
if ("manager_connection".equals(type) && "robot_mgr".equals(client)) {
|
if ("manager_connection".equals(type) && "robot_mgr".equals(client)) {
|
||||||
// 返回成功响应
|
//返回成功响应
|
||||||
ITObject response = TObject.newInstance();
|
ITObject response = TObject.newInstance();
|
||||||
response.putString("status", "success");
|
response.putString("status", "success");
|
||||||
response.putString("message", "初始化成功");
|
response.putString("message", "初始化成功");
|
||||||
|
|
@ -53,7 +60,6 @@ public class EXGameController extends GameController {
|
||||||
ITObject response = TObject.newInstance();
|
ITObject response = TObject.newInstance();
|
||||||
response.putString("status", "failed");
|
response.putString("status", "failed");
|
||||||
response.putString("message", "参数验证失败");
|
response.putString("message", "参数验证失败");
|
||||||
|
|
||||||
MainServer.instance.sendResponse(gid, 1, response, session);
|
MainServer.instance.sendResponse(gid, 1, response, session);
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
|
|
@ -73,8 +79,6 @@ public class EXGameController extends GameController {
|
||||||
@ActionKey(value = Config.CREATE_ROOM_ROBOT, validate = GameInterceptor.NOT_PLAYER)
|
@ActionKey(value = Config.CREATE_ROOM_ROBOT, validate = GameInterceptor.NOT_PLAYER)
|
||||||
public void createRoomForRobot(Session session, ITObject params, int gid) {
|
public void createRoomForRobot(Session session, ITObject params, int gid) {
|
||||||
try {
|
try {
|
||||||
log.info("收到robot_mgr的创建房间请求,Session: {}, GID: {}, 参数: {}", session, gid, params);
|
|
||||||
|
|
||||||
int reqGroupId = params.getInt("groupId");
|
int reqGroupId = params.getInt("groupId");
|
||||||
int wanfaId = params.getInt("wanfaId");
|
int wanfaId = params.getInt("wanfaId");
|
||||||
int robotId = params.getInt("robotId");
|
int robotId = params.getInt("robotId");
|
||||||
|
|
@ -97,17 +101,9 @@ public class EXGameController extends GameController {
|
||||||
MainServer.instance.sendResponse(gid, 0, response, session);
|
MainServer.instance.sendResponse(gid, 0, response, session);
|
||||||
} else {
|
} else {
|
||||||
log.error("创建房间失败,群组ID: {}, 玩法ID: {}", reqGroupId, wanfaId);
|
log.error("创建房间失败,群组ID: {}, 玩法ID: {}", reqGroupId, wanfaId);
|
||||||
ITObject errorResponse = TObject.newInstance();
|
|
||||||
errorResponse.putInt("error", 1);
|
|
||||||
errorResponse.putString("message", "创建房间失败");
|
|
||||||
MainServer.instance.sendResponse(gid, 1, errorResponse, session);
|
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("处理创建房间请求时发生错误", e);
|
log.error("处理创建房间请求时发生错误", e);
|
||||||
ITObject errorResponse = TObject.newInstance();
|
|
||||||
errorResponse.putInt("error", 1);
|
|
||||||
errorResponse.putString("message", "服务器内部错误: " + e.getMessage());
|
|
||||||
MainServer.instance.sendResponse(gid, 1, errorResponse, session);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -117,32 +113,40 @@ 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 {
|
||||||
log.info("收到robot_mgr的机器人准备请求,Session: {}, GID: {}, 参数: {}", session, gid, params);
|
System.out.println("收到加入房间请求,Session: {}, GID: {}, 参数: {}");
|
||||||
|
|
||||||
//在收到加入房间请求 建立到长沙麻将游戏服务器的连接
|
String connecId = params.getString("connecId");
|
||||||
TaurusClient client = GameServerConnector.getCsMjGameServerConnection();
|
TaurusClient client = null;// getCsMjGameServerConnection(connecId);
|
||||||
|
client = new TaurusClient("8.134.76.43" + ":" + "6311", "game", TaurusClient.ConnectionProtocol.Tcp);
|
||||||
|
client.connect();
|
||||||
if (client == null) {
|
if (client == null) {
|
||||||
log.error("无法连接到长沙麻将游戏服务器");
|
|
||||||
ITObject errorResponse = TObject.newInstance();
|
|
||||||
errorResponse.putInt("error", 1);
|
|
||||||
errorResponse.putString("message", "无法连接到游戏服务器");
|
|
||||||
MainServer.instance.sendResponse(gid, 1, errorResponse, session);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//设置session和token
|
||||||
|
String sessionToken = params.getString("session");
|
||||||
|
if (sessionToken != null && sessionToken.contains(",")) {
|
||||||
|
String[] sessionParts = sessionToken.split(",");
|
||||||
|
if (sessionParts.length >= 2) {
|
||||||
|
String actualSessionFromParams = sessionParts[0];
|
||||||
|
String token = sessionParts[1];
|
||||||
|
connectionManager.setSessionAndToken(actualSessionFromParams, token);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//发送准备请求
|
//发送加入房间请求
|
||||||
client.send(Config.JOIN_ROOM_CS, params, response -> {
|
client.send(Config.JOIN_ROOM_CS, params, response -> {
|
||||||
System.out.println("进入房间成功: " + response.returnCode);
|
System.out.println("csmj OnEvent " + response.returnCode);
|
||||||
|
log.info("加入房间请求发送结果: returnCode={}", response.returnCode);
|
||||||
|
});
|
||||||
|
client.addEventListener(TaurusClient.NetClientEvent.OnEvent, new IEventListener() {
|
||||||
|
@Override
|
||||||
|
public void handleEvent(Event event) {
|
||||||
|
System.out.println("csmj OnEvent 能监听:jefe " );
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
log.error("处理加入房间请求时发生错误", e);
|
||||||
ITObject errorResponse = TObject.newInstance();
|
|
||||||
errorResponse.putInt("error", 1);
|
|
||||||
errorResponse.putString("message", "服务器内部错误: " + e.getMessage());
|
|
||||||
MainServer.instance.sendResponse(gid, 1, errorResponse, session);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -152,79 +156,69 @@ public class EXGameController extends GameController {
|
||||||
@ActionKey(value = Config.GAME_READY, validate = GameInterceptor.NOT_PLAYER)
|
@ActionKey(value = Config.GAME_READY, validate = GameInterceptor.NOT_PLAYER)
|
||||||
public void robotReadyRoom(Session session, ITObject params, int gid) {
|
public void robotReadyRoom(Session session, ITObject params, int gid) {
|
||||||
try {
|
try {
|
||||||
log.info("收到robot_mgr的机器人准备请求,Session: {}, GID: {}, 参数: {}", session, gid, params);
|
String connecId = params.getString("connecId");
|
||||||
|
TaurusClient client = getCsMjGameServerConnection(connecId);
|
||||||
//在收到准备请求 建立到长沙麻将游戏服务器的连接
|
System.out.println("session: " + session);
|
||||||
TaurusClient client = GameServerConnector.getCsMjGameServerConnection();
|
System.out.println("client: " + client);
|
||||||
if (client == null) {
|
if (client == null) {
|
||||||
log.error("无法连接到长沙麻将游戏服务器");
|
|
||||||
ITObject errorResponse = TObject.newInstance();
|
|
||||||
errorResponse.putInt("error", 1);
|
|
||||||
errorResponse.putString("message", "无法连接到游戏服务器");
|
|
||||||
MainServer.instance.sendResponse(gid, 1, errorResponse, session);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
params.del("connecId");
|
||||||
|
client.send(Config.GAME_READY_CS, params, null);
|
||||||
|
|
||||||
|
ITObject paramsReq = TObject.newInstance();
|
||||||
//发送准备请求
|
paramsReq.putString("status", "success");
|
||||||
client.send(Config.GAME_READY_CS, params, new ICallback<MessageResponse>() {
|
MainServer.instance.sendResponse(gid, 0, paramsReq, session);
|
||||||
@Override
|
|
||||||
public void action(MessageResponse readyResponse) {
|
|
||||||
log.info("机器人准备请求发送结果: returnCode={}", readyResponse.returnCode);
|
|
||||||
|
|
||||||
if (readyResponse.returnCode == 0) {
|
|
||||||
log.info("机器人准备成功");
|
|
||||||
|
|
||||||
ITObject successResponse = TObject.newInstance();
|
|
||||||
successResponse.putString("status", "success");
|
|
||||||
successResponse.putString("message", "机器人准备成功");
|
|
||||||
MainServer.instance.sendResponse(gid, 0, successResponse, session);
|
|
||||||
} else {
|
|
||||||
log.error("机器人准备失败,返回码: {}", readyResponse.returnCode);
|
|
||||||
|
|
||||||
ITObject errorResponse = TObject.newInstance();
|
|
||||||
errorResponse.putInt("error", 1);
|
|
||||||
errorResponse.putString("message", "机器人准备失败");
|
|
||||||
MainServer.instance.sendResponse(gid, 1, errorResponse, session);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
|
||||||
log.error("处理机器人准备请求时发生错误", e);
|
log.error("处理机器人准备请求时发生错误", e);
|
||||||
ITObject errorResponse = TObject.newInstance();
|
|
||||||
errorResponse.putInt("error", 1);
|
|
||||||
errorResponse.putString("message", "服务器内部错误: " + e.getMessage());
|
|
||||||
MainServer.instance.sendResponse(gid, 1, errorResponse, session);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 接收来自robot_mgr的退出房间协议
|
* 接收来自robot_mgr的退出房间协议
|
||||||
|
* 断开与game_mj_cs的TCP连接
|
||||||
*/
|
*/
|
||||||
@ActionKey(value = Config.EXIT_ROOM, validate = GameInterceptor.NOT_PLAYER)
|
@ActionKey(value = Config.EXIT_ROOM, validate = GameInterceptor.NOT_PLAYER)
|
||||||
public void exitRoom(Session session, ITObject params, int gid) {
|
public void exitRoom(Session session, ITObject params, int gid) {
|
||||||
try {
|
try {
|
||||||
log.info("收到robot_mgr的机器人准备请求,Session: {}, GID: {}, 参数: {}", session, gid, params);
|
String connecId = params.getString("connecId");
|
||||||
|
TaurusClient client = getCsMjGameServerConnection(connecId);
|
||||||
|
|
||||||
TaurusClient client = GameServerConnector.getCsMjGameServerConnection();
|
if (client == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//发送退出房间请求
|
||||||
client.send(Config.EXIT_ROOM_CS, params, response -> {
|
client.send(Config.EXIT_ROOM_CS, params, response -> {
|
||||||
System.out.println("退出房间成功: " + response.returnCode);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
//断开与游戏服务器的连接
|
||||||
|
//connectionManager.disconnectFromGameServer(connecId);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
log.error("处理退出房间请求时发生错误", e);
|
||||||
ITObject errorResponse = TObject.newInstance();
|
String connecId = params.getString("connecId");
|
||||||
errorResponse.putInt("error", 1);
|
connectionManager.disconnectFromGameServer(connecId);
|
||||||
errorResponse.putString("message", "服务器内部错误: " + e.getMessage());
|
|
||||||
MainServer.instance.sendResponse(gid, 1, errorResponse, session);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据机器人ID和连接ID获取长沙麻将游戏服务器连接
|
||||||
|
*/
|
||||||
|
public static TaurusClient getCsMjGameServerConnection(String connecId) {
|
||||||
|
TaurusClient taurusClient = connectionManager.getGameServerConnection(connecId);
|
||||||
|
if (taurusClient != null) {
|
||||||
|
return taurusClient;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean connected = connectionManager.connectToGameServer(connecId);
|
||||||
|
if (connected) {
|
||||||
|
taurusClient = connectionManager.getGameServerConnection(connecId);
|
||||||
|
if (taurusClient != null) {
|
||||||
|
return taurusClient;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -1,6 +1,11 @@
|
||||||
package robot.mj;
|
package robot.mj;
|
||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
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 com.robot.GameController;
|
import com.robot.GameController;
|
||||||
import com.robot.Global;
|
import com.robot.Global;
|
||||||
|
|
@ -14,7 +19,7 @@ import com.taurus.permanent.core.TPEvents;
|
||||||
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.HuNanChangShaHandler;
|
import robot.mj.handler.HuNanChangSha;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 长沙麻将机器人主服务器
|
* 长沙麻将机器人主服务器
|
||||||
|
|
@ -27,7 +32,11 @@ public class EXMainServer extends MainServer{
|
||||||
private static RobotConnectionManager robotConnectionManager;
|
private static RobotConnectionManager robotConnectionManager;
|
||||||
|
|
||||||
//长沙麻将AI处理器
|
//长沙麻将AI处理器
|
||||||
private static HuNanChangShaHandler huNanChangShaHandler;
|
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() {
|
||||||
|
|
@ -41,24 +50,26 @@ public class EXMainServer extends MainServer{
|
||||||
initializeComponents();
|
initializeComponents();
|
||||||
|
|
||||||
//添加会话断开事件监听器
|
//添加会话断开事件监听器
|
||||||
TPServer.me().getEventManager().addEventListener(TPEvents.EVENT_SESSION_DISCONNECT, new IEventListener() {
|
/*TPServer.me().getEventManager().addEventListener(TPEvents.EVENT_SESSION_DISCONNECT, new IEventListener() {
|
||||||
@Override
|
@Override
|
||||||
public void handleEvent(Event event) {
|
public void handleEvent(Event event) {
|
||||||
Session session = (Session) event.getParameter(TPEvents.PARAM_SESSION);
|
Session session = (Session) event.getParameter(TPEvents.PARAM_SESSION);
|
||||||
log.info("会话断开: {}", session.getId());
|
String sessionId = String.valueOf(session.getId());
|
||||||
|
log.info("会话断开: {}", sessionId);
|
||||||
|
System.out.println("robot_mj_cs会话断开: " + sessionId);
|
||||||
|
|
||||||
Global.sessionMgr.disconnect(session);
|
Global.sessionMgr.disconnect(session);
|
||||||
}
|
}
|
||||||
});
|
});*/
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 初始化组件
|
* 初始化组件
|
||||||
*/
|
*/
|
||||||
private void initializeComponents() {
|
private void initializeComponents() {
|
||||||
robotConnectionManager = RobotConnectionManager.getInstance();
|
robotConnectionManager = new RobotConnectionManager();
|
||||||
|
|
||||||
//长沙麻将AI处理器
|
//长沙麻将AI处理器
|
||||||
huNanChangShaHandler = new HuNanChangShaHandler();
|
huNanChangSha = new HuNanChangSha();
|
||||||
|
|
||||||
log.info("长沙麻将机器人服务器组件初始化完成");
|
log.info("长沙麻将机器人服务器组件初始化完成");
|
||||||
}
|
}
|
||||||
|
|
@ -68,14 +79,12 @@ public class EXMainServer extends MainServer{
|
||||||
return new EXRoom(roomid, redis_room_map);
|
return new EXRoom(roomid, redis_room_map);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Player newPlayer(int playerid, Room room, String session_id) {
|
public Player newPlayer(int i, Room room, String s) {
|
||||||
return new EXPlayer(playerid, room, session_id);
|
return new EXPlayer(i, room, s);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected GameController newController() {
|
protected GameController newController() {
|
||||||
return new EXGameController();
|
return new EXGameController();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,114 +0,0 @@
|
||||||
package robot.mj;
|
|
||||||
|
|
||||||
import com.taurus.core.util.ICallback;
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
import taurus.client.TaurusClient;
|
|
||||||
import taurus.client.Message;
|
|
||||||
import taurus.client.SocketCode;
|
|
||||||
import taurus.client.MessageResponse;
|
|
||||||
import com.taurus.core.entity.ITObject;
|
|
||||||
import com.taurus.core.entity.TObject;
|
|
||||||
import com.taurus.core.events.Event;
|
|
||||||
import com.taurus.core.events.IEventListener;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 游戏服务器连接器 - 管理到长沙麻将游戏服务器的连接
|
|
||||||
*/
|
|
||||||
public class GameServerConnector {
|
|
||||||
private static final Logger log = LoggerFactory.getLogger(GameServerConnector.class);
|
|
||||||
|
|
||||||
//长沙麻将服务器地址
|
|
||||||
private static final String CS_MJ_SERVER_ADDRESS = "8.134.76.43:6311";
|
|
||||||
|
|
||||||
//长沙麻将服务器连接
|
|
||||||
private static volatile TaurusClient csMjConnection;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取长沙麻将游戏服务器连接
|
|
||||||
*/
|
|
||||||
public static TaurusClient getCsMjGameServerConnection() {
|
|
||||||
if (csMjConnection != null && csMjConnection.isConnected()) {
|
|
||||||
return csMjConnection;
|
|
||||||
}
|
|
||||||
|
|
||||||
synchronized (GameServerConnector.class) {
|
|
||||||
if (csMjConnection != null) {
|
|
||||||
return csMjConnection;
|
|
||||||
}
|
|
||||||
|
|
||||||
csMjConnection = createConnection(CS_MJ_SERVER_ADDRESS, "长沙麻将");
|
|
||||||
if (csMjConnection != null) {
|
|
||||||
log.info("成功创建到长沙麻将游戏服务器的连接: {}", CS_MJ_SERVER_ADDRESS);
|
|
||||||
} else {
|
|
||||||
log.error("无法连接到长沙麻将游戏服务器: {}", CS_MJ_SERVER_ADDRESS);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return csMjConnection;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 创建到游戏服务器的连接
|
|
||||||
*/
|
|
||||||
private static TaurusClient createConnection(String serverAddress, String gameName) {
|
|
||||||
try {
|
|
||||||
log.info("正在连接到{}服务器: {}", gameName, serverAddress);
|
|
||||||
|
|
||||||
TaurusClient client = new TaurusClient(serverAddress, "game", TaurusClient.ConnectionProtocol.Tcp);
|
|
||||||
|
|
||||||
//添加连接事件监听器
|
|
||||||
client.addEventListener(TaurusClient.NetClientEvent.Connect, new IEventListener() {
|
|
||||||
@Override
|
|
||||||
public void handleEvent(Event event) {
|
|
||||||
SocketCode code = (SocketCode) event.getParameter("code");
|
|
||||||
if (code == SocketCode.Connect) {
|
|
||||||
log.info("成功连接到{}服务器: {}", gameName, serverAddress);
|
|
||||||
} else {
|
|
||||||
log.warn("连接到{}服务器失败: {},错误码: {}", gameName, serverAddress, code);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
//添加消息接收事件监听器
|
|
||||||
client.addEventListener(TaurusClient.NetClientEvent.OnEvent, new IEventListener() {
|
|
||||||
@Override
|
|
||||||
public void handleEvent(Event event) {
|
|
||||||
Message message = (Message) event.getParameter("msg");
|
|
||||||
if (message != null) {
|
|
||||||
log.debug("从{}服务器收到消息: 命令={},参数={}", gameName, message.command, message.param);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
client.connect();
|
|
||||||
Thread.sleep(100);
|
|
||||||
|
|
||||||
return client;
|
|
||||||
} catch (Exception e) {
|
|
||||||
log.error("连接到{}服务器时发生错误: {}", gameName, serverAddress, e);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 发送协议到长沙麻将游戏服务器
|
|
||||||
*/
|
|
||||||
public static void sendProtocolToCsMj(String protocol, ITObject params, ICallback<MessageResponse> responseCallback) {
|
|
||||||
TaurusClient connection = getCsMjGameServerConnection();
|
|
||||||
if (connection != null) {
|
|
||||||
connection.send(protocol, params, responseCallback);
|
|
||||||
} else {
|
|
||||||
log.error("无法发送协议到长沙麻将游戏服务器,连接不可用");
|
|
||||||
// 在回调中返回错误
|
|
||||||
if (responseCallback != null) {
|
|
||||||
MessageResponse errorResponse = new MessageResponse();
|
|
||||||
errorResponse.returnCode = 1;
|
|
||||||
errorResponse.messageData = new taurus.client.Message();
|
|
||||||
errorResponse.messageData.param = new com.taurus.core.entity.TObject();
|
|
||||||
responseCallback.action(errorResponse);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -4,6 +4,7 @@ import com.taurus.core.entity.ITArray;
|
||||||
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.Event;
|
||||||
|
import com.taurus.core.events.IEventListener;
|
||||||
import com.taurus.core.plugin.redis.Redis;
|
import com.taurus.core.plugin.redis.Redis;
|
||||||
import com.taurus.core.plugin.database.DataBase;
|
import com.taurus.core.plugin.database.DataBase;
|
||||||
import com.taurus.core.util.Logger;
|
import com.taurus.core.util.Logger;
|
||||||
|
|
@ -11,9 +12,16 @@ import com.taurus.core.util.StringUtil;
|
||||||
import taurus.client.Message;
|
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.HuNanChangShaHandler;
|
import robot.mj.handler.HuNanChangSha;
|
||||||
|
import taurus.client.business.GroupRoomBusiness;
|
||||||
|
import taurus.util.ChangShaSuanFaTest;
|
||||||
|
import taurus.util.TinHuChi;
|
||||||
|
|
||||||
|
import java.sql.SQLException;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
import java.util.concurrent.*;
|
||||||
|
|
||||||
|
import static java.lang.Thread.sleep;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 机器人连接管理器 - 管理与游戏服务器的连接
|
* 机器人连接管理器 - 管理与游戏服务器的连接
|
||||||
|
|
@ -21,59 +29,105 @@ import java.util.*;
|
||||||
public class RobotConnectionManager {
|
public class RobotConnectionManager {
|
||||||
|
|
||||||
private Logger log = Logger.getLogger(RobotConnectionManager.class);
|
private Logger log = Logger.getLogger(RobotConnectionManager.class);
|
||||||
private static RobotConnectionManager instance;
|
|
||||||
private Map<String, TaurusClient> gameClients;
|
private Map<String, TaurusClient> gameClients;
|
||||||
//存储全局的长沙麻将AI处理器
|
//存储全局的长沙麻将AI处理器
|
||||||
private HuNanChangShaHandler huNanChangShaHandler;
|
private HuNanChangSha huNanChangSha;
|
||||||
|
|
||||||
private RobotConnectionManager() {
|
private final String host="8.134.76.43";
|
||||||
|
private final int port=6311;
|
||||||
|
|
||||||
|
private TaurusClient client = null;
|
||||||
|
|
||||||
|
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 int groupId = 0;
|
||||||
|
private int pid = 0;
|
||||||
|
private int playerId = 0;
|
||||||
|
private String playKey = "";
|
||||||
|
private Map<Integer, Integer> count = new HashMap<Integer, Integer>();
|
||||||
|
|
||||||
|
|
||||||
|
public RobotConnectionManager() {
|
||||||
gameClients = new HashMap<>();
|
gameClients = new HashMap<>();
|
||||||
huNanChangShaHandler = new HuNanChangShaHandler();
|
huNanChangSha = new HuNanChangSha();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static synchronized RobotConnectionManager getInstance() {
|
/**
|
||||||
if (instance == null) {
|
* 获取所有session列表
|
||||||
instance = new RobotConnectionManager();
|
*/
|
||||||
|
public Set<String> getAllSessions() {
|
||||||
|
return new HashSet<>(gameClients.keySet());
|
||||||
}
|
}
|
||||||
return instance;
|
|
||||||
|
/**
|
||||||
|
* 设置会话和令牌
|
||||||
|
*/
|
||||||
|
public void setSessionAndToken(String session, String token) {
|
||||||
|
huNanChangSha.session = session;
|
||||||
|
huNanChangSha.token = token;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 连接到长沙麻将游戏服务器
|
* 连接到长沙麻将游戏服务器
|
||||||
*/
|
*/
|
||||||
public boolean connectToGameServer(String host, int port, int playerId, int groupId, String roomId) {
|
public boolean connectToGameServer(String connecId) {
|
||||||
try {
|
try {
|
||||||
//检查是否已经连接到该房间
|
//检查是否已经连接
|
||||||
if (gameClients.containsKey(roomId)) {
|
if (gameClients.containsKey(connecId)) {
|
||||||
TaurusClient existingClient = gameClients.get(roomId);
|
TaurusClient existingClient = gameClients.get(connecId);
|
||||||
if (existingClient.isConnected()) {
|
if (existingClient.isConnected()) {
|
||||||
log.info("房间 " + roomId + " 已经连接到游戏服务器: " + host + ":" + port);
|
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
//如果连接已断开 先移除旧的客户端
|
//连接断开 移除旧的客户端
|
||||||
gameClients.remove(roomId);
|
disconnectFromGameServer(connecId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//创建Taurus客户端
|
//创建Taurus客户端
|
||||||
TaurusClient client = new TaurusClient(host + ":" + port, "game", TaurusClient.ConnectionProtocol.Tcp);
|
client = new TaurusClient(host + ":" + port, "game", TaurusClient.ConnectionProtocol.Tcp);
|
||||||
|
|
||||||
//连接到游戏服务器
|
|
||||||
client.connect();
|
client.connect();
|
||||||
|
|
||||||
//添加事件监听器处理网络消息
|
|
||||||
client.addEventListener(TaurusClient.NetClientEvent.OnEvent, new com.taurus.core.events.IEventListener() {
|
|
||||||
|
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() {
|
||||||
@Override
|
@Override
|
||||||
public void handleEvent(Event event) {
|
public void handleEvent(Event event) {
|
||||||
|
System.out.println("csmj OnEvent 能监听: " );
|
||||||
|
|
||||||
//获取 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
ITObject param = message.param;
|
ITObject param = message.param;
|
||||||
//回调协议号
|
//回调协议号
|
||||||
String command = message.command;
|
String command = message.command;
|
||||||
|
System.out.println("csmj OnEvent msg: " + command);
|
||||||
|
|
||||||
|
// 添加更详细的日志
|
||||||
|
System.out.println("收到协议命令: " + command + " params: " + param);
|
||||||
|
|
||||||
//根据玩法ID处理不同的回调
|
//根据玩法ID处理不同的回调
|
||||||
if (StringUtil.isNotEmpty(command)) {
|
if (StringUtil.isNotEmpty(command)) {
|
||||||
|
|
@ -84,282 +138,248 @@ public class RobotConnectionManager {
|
||||||
});
|
});
|
||||||
|
|
||||||
//添加连接状态监听器
|
//添加连接状态监听器
|
||||||
client.addEventListener(TaurusClient.NetClientEvent.Connect, new com.taurus.core.events.IEventListener() {
|
client.addEventListener(TaurusClient.NetClientEvent.Connect, new IEventListener() {
|
||||||
@Override
|
@Override
|
||||||
public void handleEvent(Event event) {
|
public void handleEvent(Event event) {
|
||||||
log.info("长沙麻将AI机器人连接成功到游戏服务器: " + host + ":" + port + ",房间: " + roomId);
|
System.out.println("Connect");
|
||||||
|
System.out.println("csmj Connect connecId: " + connecId);
|
||||||
//通知robot_mgr连接成功
|
|
||||||
notifyConnectionStatus(roomId, playerId + "", host, port, "connected");
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
//添加断开连接监听器
|
|
||||||
client.addEventListener(TaurusClient.NetClientEvent.OnEvent, new com.taurus.core.events.IEventListener() {
|
|
||||||
@Override
|
|
||||||
public void handleEvent(com.taurus.core.events.Event event) {
|
|
||||||
log.info("长沙麻将AI机器人连接断开,房间: " + roomId);
|
|
||||||
//从连接列表中移除断开的客户端
|
|
||||||
for (Map.Entry<String, TaurusClient> entry : gameClients.entrySet()) {
|
|
||||||
if (entry.getValue() == client) {
|
|
||||||
gameClients.remove(entry.getKey());
|
|
||||||
log.info("已从连接列表中移除断开的连接: " + entry.getKey());
|
|
||||||
|
|
||||||
//通知robot_mgr连接断开
|
ITObject readyParam = new TObject();
|
||||||
notifyConnectionStatus(entry.getKey(), playerId + "", "", 0, "disconnected");
|
readyParam.putString("session","{user}:101555,c739ec6c3e93e9655e507397f78d857f");
|
||||||
break;
|
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);
|
||||||
});
|
});
|
||||||
|
|
||||||
HuNanChangShaHandler.playerId = playerId;
|
readyParam.del("connecId");
|
||||||
|
sleep(5000);
|
||||||
|
client.send(Config.GAME_READY_CS, readyParam, null);
|
||||||
|
|
||||||
gameClients.put(roomId, client);
|
|
||||||
|
|
||||||
log.info("长沙麻将AI机器人成功连接到游戏服务器: " + host + ":" + port + ",房间: " + roomId + ",玩家: " + playerId);
|
System.out.println(client);
|
||||||
|
System.out.println("client.getSession()2222" +client.getSession());
|
||||||
|
System.out.println("client.getId()2222" +client.getId());
|
||||||
|
gameClients.put(connecId, client);
|
||||||
|
System.out.println("gameClients" + gameClients.get(connecId));
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
log.error("连接到游戏服务器时发生异常", e);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 通知robot_mgr连接状态
|
* 断开与游戏服务器的连接
|
||||||
*/
|
*/
|
||||||
private void notifyConnectionStatus(String roomId, String robotId, String host, int port, String status) {
|
public void disconnectFromGameServer(String compositeKey) {
|
||||||
|
TaurusClient client = gameClients.remove(compositeKey);
|
||||||
|
if (client != null && client.isConnected()) {
|
||||||
try {
|
try {
|
||||||
Jedis jedis = Redis.use("group1_db11").getJedis();
|
client.killConnection();
|
||||||
try {
|
|
||||||
String notificationKey = "robot_connection_notify:" + roomId + ":" + robotId;
|
|
||||||
Map<String, String> notification = new HashMap<>();
|
|
||||||
notification.put("status", status);
|
|
||||||
if (!host.isEmpty()) {
|
|
||||||
notification.put("game_server", host + ":" + port);
|
|
||||||
}
|
|
||||||
notification.put("room_id", roomId);
|
|
||||||
notification.put("robot_id", robotId);
|
|
||||||
notification.put("robot_server", "robot_mj_cs");
|
|
||||||
notification.put("timestamp", String.valueOf(System.currentTimeMillis()));
|
|
||||||
|
|
||||||
jedis.hmset(notificationKey, notification);
|
|
||||||
jedis.expire(notificationKey, 300); //5分钟过期
|
|
||||||
|
|
||||||
} finally {
|
|
||||||
jedis.close();
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
log.error("断开客户端连接时发生异常", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
RobotConnectionManager rb=new RobotConnectionManager();
|
||||||
|
boolean i = rb.connectToGameServer("1");
|
||||||
|
System.out.println(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据connecId获取游戏服务器连接
|
||||||
|
*/
|
||||||
|
public TaurusClient getGameServerConnection(String connecId) {
|
||||||
|
TaurusClient client = gameClients.get(connecId);
|
||||||
|
|
||||||
|
if (client == null) {
|
||||||
|
System.out.println("Attempting to reconnect: " + connecId);
|
||||||
|
// 尝试重新连接
|
||||||
|
connectToGameServer(connecId);
|
||||||
|
client = gameClients.get(connecId);
|
||||||
|
}
|
||||||
|
|
||||||
|
return client;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 处理接收到的游戏协议
|
* 处理接收到的游戏协议
|
||||||
*/
|
*/
|
||||||
private void handleProtocol(String command, taurus.client.Message message, TaurusClient client) {
|
private void handleProtocol(String command, taurus.client.Message message, TaurusClient client) {
|
||||||
ITObject param = message.param;
|
ITObject param = message.param;
|
||||||
|
try (Jedis jedis0 = Redis.use().getJedis()){
|
||||||
switch (command) {
|
switch (command) {
|
||||||
case "811": //初始化手牌
|
case "811": //初始化手牌
|
||||||
handleInitCards(command, message, client);
|
huNanChangSha.cardInHead(command, message, client);
|
||||||
break;
|
break;
|
||||||
case "812": //出牌广播
|
case "812": //出牌广播
|
||||||
handleDiscardBroadcast(command, message);
|
ITArray outcard_map = param.getTArray("outcard_map");
|
||||||
|
ITArray opchicards = param.getTArray("opchicards");
|
||||||
|
ITArray oppengcards = param.getTArray("oppengcards");
|
||||||
|
ITArray opmingcards = param.getTArray("opmingcards");
|
||||||
|
ITArray opzicards = param.getTArray("opzicards");
|
||||||
|
|
||||||
|
// 清空旧数据,用新数据完全覆盖
|
||||||
|
playerOutcardsMap.clear();
|
||||||
|
playerchisMap.clear();
|
||||||
|
playerpengsMap.clear();
|
||||||
|
playermingsMap.clear();
|
||||||
|
playerzisMap.clear();
|
||||||
|
//出过的牌
|
||||||
|
if (outcard_map != null) {
|
||||||
|
for (int i = 0; i < outcard_map.size(); i++) {
|
||||||
|
ITObject playerData = outcard_map.getTObject(i);
|
||||||
|
int playerId = playerData.getInt("playerId");
|
||||||
|
ITArray outcardsArray = playerData.getTArray("outcards");
|
||||||
|
|
||||||
|
// 转换为List<Integer>
|
||||||
|
List<Integer> outcardsList = new ArrayList<>();
|
||||||
|
for (int j = 0; j < outcardsArray.size(); j++) {
|
||||||
|
outcardsList.add(outcardsArray.getInt(j));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 存储到Map中(覆盖旧数据)
|
||||||
|
playerOutcardsMap.put(playerId, outcardsList);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//吃的牌
|
||||||
|
if (opchicards != null) {
|
||||||
|
for (int i = 0; i < opchicards.size(); i++) {
|
||||||
|
ITObject playerData = opchicards.getTObject(i);
|
||||||
|
int playerId = playerData.getInt("playerId");
|
||||||
|
ITArray outchiArray = playerData.getTArray("opchicards");
|
||||||
|
|
||||||
|
List<Integer> outchiList = new ArrayList<>();
|
||||||
|
for (int j = 0; j < outchiArray.size(); j++) {
|
||||||
|
outchiList.add(outchiArray.getInt(j));
|
||||||
|
}
|
||||||
|
playerchisMap.put(playerId, outchiList);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//碰的牌
|
||||||
|
if (oppengcards != null) {
|
||||||
|
for (int i = 0; i < oppengcards.size(); i++) {
|
||||||
|
ITObject playerData = oppengcards.getTObject(i);
|
||||||
|
int playerId = playerData.getInt("playerId");
|
||||||
|
ITArray outpengArray = playerData.getTArray("oppengcards");
|
||||||
|
|
||||||
|
List<Integer> outpengList = new ArrayList<>();
|
||||||
|
for (int j = 0; j < outpengArray.size(); j++) {
|
||||||
|
outpengList.add(outpengArray.getInt(j));
|
||||||
|
}
|
||||||
|
playerpengsMap.put(playerId, outpengList);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//明杠的牌
|
||||||
|
if (opmingcards != null) {
|
||||||
|
for (int i = 0; i < opmingcards.size(); i++) {
|
||||||
|
ITObject playerData = opmingcards.getTObject(i);
|
||||||
|
int playerId = playerData.getInt("playerId");
|
||||||
|
ITArray outmingArray = playerData.getTArray("opmingcards");
|
||||||
|
|
||||||
|
List<Integer> outmingList = new ArrayList<>();
|
||||||
|
for (int j = 0; j < outmingArray.size(); j++) {
|
||||||
|
outmingList.add(outmingArray.getInt(j));
|
||||||
|
}
|
||||||
|
playermingsMap.put(playerId, outmingList);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//暗杠的牌
|
||||||
|
if (opzicards != null) {
|
||||||
|
for (int i = 0; i < opzicards.size(); i++) {
|
||||||
|
ITObject playerData = opzicards.getTObject(i);
|
||||||
|
int playerId = playerData.getInt("playerId");
|
||||||
|
ITArray outziArray = playerData.getTArray("opzicards");
|
||||||
|
|
||||||
|
List<Integer> outziList = new ArrayList<>();
|
||||||
|
for (int j = 0; j < outziArray.size(); j++) {
|
||||||
|
outziList.add(outziArray.getInt(j));
|
||||||
|
}
|
||||||
|
playerzisMap.put(playerId, outziList);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
HuNanChangSha.drawCard(command, message);
|
||||||
break;
|
break;
|
||||||
case "819": //摸牌
|
case "819": //摸牌
|
||||||
handleDrawCard(command, message);
|
System.out.println("Handling 819 - Draw card");
|
||||||
|
huNanChangSha.getCard(command, message);
|
||||||
break;
|
break;
|
||||||
case "813": //出牌提示
|
case "813": //出牌提示
|
||||||
handleDiscardPrompt(client);
|
System.out.println("Handling 813 - Discard card tip received!");
|
||||||
|
huNanChangSha.outCard(client,playerOutcardsMap,playerchisMap,playerpengsMap,playermingsMap,playerzisMap);
|
||||||
break;
|
break;
|
||||||
case "814": //操作提示(吃碰杠胡)
|
case "814": //操作提示(吃碰杠胡)
|
||||||
handleActionPrompt(param, client);
|
System.out.println("Handling 814 - Action tips (Chi, Peng, Gang, Hu)");
|
||||||
break;
|
huNanChangSha.actionCard(param, client);
|
||||||
case "817": //结算
|
|
||||||
handleSettlement(param, client);
|
|
||||||
break;
|
|
||||||
case "815": //服务器通知客户端有玩家执行了操作
|
|
||||||
handleServerNotification(param);
|
|
||||||
break;
|
|
||||||
case "820": //换牌提示
|
|
||||||
handleChangeCardTip(command, message);
|
|
||||||
break;
|
|
||||||
case "825":
|
|
||||||
case "822":
|
|
||||||
case "835": //听牌相关
|
|
||||||
handleTingPai(command, client);
|
|
||||||
break;
|
|
||||||
case "2008": //解散房间
|
|
||||||
handleRoomDisband();
|
|
||||||
break;
|
break;
|
||||||
case "2009": //其他操作 - 房间检查和踢人逻辑
|
case "2009": //其他操作 - 房间检查和踢人逻辑
|
||||||
handleRoomCheckAndKick(param, client);
|
System.out.println("Handling 2009 - Other operations");
|
||||||
break;
|
|
||||||
case "838": //补杠事件
|
|
||||||
handleBuGang(param, client);
|
|
||||||
break;
|
|
||||||
case "816": //抢杠胡
|
|
||||||
handleQiangGangHu(param, client);
|
|
||||||
break;
|
|
||||||
case "821": //吃牌
|
|
||||||
handleChiCard(param, client);
|
|
||||||
break;
|
|
||||||
case "823": //杠后补牌
|
|
||||||
handleGangBuPai(param, client);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
handleUnknownCommand(command, param, client);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 处理初始化手牌协议
|
|
||||||
*/
|
|
||||||
private void handleInitCards(String command, taurus.client.Message message, TaurusClient client) {
|
|
||||||
huNanChangShaHandler.cardInHead(command, message, client);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 处理出牌广播协议
|
|
||||||
*/
|
|
||||||
private void handleDiscardBroadcast(String command, taurus.client.Message message) {
|
|
||||||
HuNanChangShaHandler.drawCard(command, message);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 处理摸牌协议
|
|
||||||
*/
|
|
||||||
private void handleDrawCard(String command, taurus.client.Message message) {
|
|
||||||
huNanChangShaHandler.getCard(command, message);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 处理出牌提示协议
|
|
||||||
*/
|
|
||||||
private void handleDiscardPrompt(TaurusClient client) {
|
|
||||||
huNanChangShaHandler.outCard(client, new HashMap<>(), new HashMap<>(), new HashMap<>(), new HashMap<>(), new HashMap<>());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 处理操作提示协议(吃碰杠胡)
|
|
||||||
*/
|
|
||||||
private void handleActionPrompt(com.taurus.core.entity.ITObject param, TaurusClient client) {
|
|
||||||
huNanChangShaHandler.actionCard(param, client);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 处理结算协议
|
|
||||||
*/
|
|
||||||
private void handleSettlement(com.taurus.core.entity.ITObject param, TaurusClient client) {
|
|
||||||
|
|
||||||
huNanChangShaHandler.getChangShaCardInhand().clear();
|
|
||||||
huNanChangShaHandler.getChuGuoCardInhand().clear();
|
|
||||||
huNanChangShaHandler.getPongGroup().clear();
|
|
||||||
huNanChangShaHandler.getChowGroup().clear();
|
|
||||||
|
|
||||||
// 发送准备协议
|
|
||||||
sendReadyCommand(client);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 处理服务器通知协议
|
|
||||||
*/
|
|
||||||
private void handleServerNotification(com.taurus.core.entity.ITObject param) {
|
|
||||||
huNanChangShaHandler.shanchuchuguopai(param);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 处理换牌提示协议
|
|
||||||
*/
|
|
||||||
private void handleChangeCardTip(String command, taurus.client.Message message) {
|
|
||||||
HuNanChangShaHandler.changePlayer(command, message);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 处理听牌协议
|
|
||||||
*/
|
|
||||||
private void handleTingPai(String command, TaurusClient client) {
|
|
||||||
com.taurus.core.entity.ITObject params = new com.taurus.core.entity.TObject();
|
|
||||||
params.putInt("qi", 0);
|
|
||||||
params.putInt("id", 1);
|
|
||||||
params.putString("session", HuNanChangShaHandler.session + "," + HuNanChangShaHandler.token);
|
|
||||||
|
|
||||||
client.send("612", params, response -> {
|
|
||||||
System.out.println("听牌操作: " + response.returnCode);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 处理解散房间协议
|
|
||||||
*/
|
|
||||||
private void handleRoomDisband() {
|
|
||||||
log.info("房间解散,准备下一局");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 处理房间检查和踢人逻辑
|
|
||||||
*/
|
|
||||||
private void handleRoomCheckAndKick(ITObject param, TaurusClient client) {
|
|
||||||
try {
|
try {
|
||||||
Jedis jedis0 = Redis.use().getJedis();
|
Jedis jedis22 = Redis.use().getJedis();
|
||||||
Jedis jedis11 = Redis.use("group1_db11").getJedis();
|
// 使用JiQiRens的sleepTime方法
|
||||||
|
|
||||||
try {
|
try {
|
||||||
for (int i = 0; i < 7; i++) {
|
sleep(3000);
|
||||||
Thread.sleep(1000);
|
} catch (InterruptedException e) {
|
||||||
if (i == 6) {
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
ITObject readyParams = new TObject();
|
ITObject params = TObject.newInstance();
|
||||||
String[] playerIds2 = null;
|
String[] playerIds2 = null;
|
||||||
Set<String> roomIds = jedis0.keys("room:*");
|
|
||||||
String roomKey = "";
|
|
||||||
|
|
||||||
//获取所有机器人ID
|
Set<String> roomIds = jedis22.keys("room:*");
|
||||||
|
String roomKey = "";
|
||||||
|
//拿到所有的机器人
|
||||||
List<Integer> robotIdsList = new ArrayList<>();
|
List<Integer> robotIdsList = new ArrayList<>();
|
||||||
String sql2 = "SELECT id FROM `account` WHERE jiqiren=9998";
|
String sql2 = "SELECT id FROM `account` WHERE jiqiren=9998";
|
||||||
ITArray robotId2 = null;
|
ITArray robotId2 = null;
|
||||||
try {
|
try {
|
||||||
robotId2 = DataBase.use().executeQueryByTArray(sql2);
|
robotId2 = DataBase.use().executeQueryByTArray(sql2);
|
||||||
} catch (Exception e) {
|
} catch (SQLException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
|
for (int j = 0; j < Objects.requireNonNull(robotId2).size(); j++) {
|
||||||
if (robotId2 != null) {
|
|
||||||
for (int j = 0; j < robotId2.size(); j++) {
|
|
||||||
robotIdsList.add(robotId2.getTObject(j).getInt("id"));
|
robotIdsList.add(robotId2.getTObject(j).getInt("id"));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
for (String roomId : roomIds) {
|
for (String roomId : roomIds) {
|
||||||
String roomId1 = roomId.substring(roomId.indexOf(":") + 1);
|
String roomId1 = roomId.substring(roomId.indexOf(":") + 1);
|
||||||
roomKey = "room:" + roomId1;
|
roomKey = "room:" + roomId1;
|
||||||
log.info("roomKey +++++++++++++++++" + roomKey);
|
|
||||||
|
|
||||||
if (jedis0.hget(roomKey, "players") != null) {
|
if (jedis22.hget(roomKey, "players") != null) {
|
||||||
String players = jedis0.hget(roomKey, "players");
|
String players = jedis22.hget(roomKey, "players");
|
||||||
if (!players.equals("[]")) {
|
if (!players.equals("[]")) {
|
||||||
players = players.substring(1, players.length() - 1);
|
players = players.substring(1, players.length() - 1);
|
||||||
playerIds2 = players.split(",");
|
playerIds2 = players.split(",");
|
||||||
log.info("playerIds2 ++++++===========" + Arrays.toString(playerIds2));
|
|
||||||
|
|
||||||
if (playerIds2.length == 1) {
|
if (playerIds2.length == 1) {
|
||||||
for (String s : playerIds2) {
|
for (String s : playerIds2) {
|
||||||
if (robotIdsList.contains(Integer.parseInt(s))) { //房间里的人是机器人
|
if (robotIdsList.contains(Integer.parseInt(s))) { //房间里的人是机器人
|
||||||
String gpid = jedis0.hget(roomKey, "gpid");
|
String gpid = jedis22.hget(roomKey, "gpid");
|
||||||
String gpId = jedis0.hget(roomKey, "group");
|
String gpId = jedis22.hget(roomKey, "group");
|
||||||
String key = "g{" + gpId + "}:play:" + gpid;
|
String key = "g{" + gpId + "}:play:" + gpid;
|
||||||
if (!players.equals("[]")) {
|
if (!players.equals("[]") && pid == Integer.parseInt(gpid)) {
|
||||||
System.out.println("roomKey ++++" + roomKey);
|
|
||||||
System.out.println("gpid ++++++" + gpid);
|
|
||||||
System.out.println("groupid ++++++" + gpId);
|
|
||||||
System.out.println("key +++++++" + key);
|
|
||||||
System.out.println("===================清空机器人准备时间超过六秒的房间 8888888888888888");
|
|
||||||
|
|
||||||
if (HuNanChangShaHandler.changShaCard != 0) {
|
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);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Jedis jedis20 = Redis.use("group1_db11").getJedis();
|
Jedis jedis20 = Redis.use("group1_db11").getJedis();
|
||||||
|
|
||||||
jedis20.hincrBy(key, "leftover_robot", 1);
|
jedis20.hincrBy(key, "leftover_robot", 1);
|
||||||
|
|
@ -368,109 +388,212 @@ public class RobotConnectionManager {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
DataBase.use().executeUpdate(sql);
|
DataBase.use().executeUpdate(sql);
|
||||||
} catch (Exception e) {
|
} catch (SQLException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
|
|
||||||
readyParams.putString("session", HuNanChangShaHandler.session + "," + HuNanChangShaHandler.token);
|
client.send("1005", params, response -> {
|
||||||
|
|
||||||
client.send("601", readyParams, response -> {
|
|
||||||
System.out.println("机器人准备操作: " + response.returnCode);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
jedis22.close();
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "817": //结算
|
||||||
|
huNanChangSha.getChangShaCardInhand().clear();
|
||||||
|
huNanChangSha.getChuGuoCardInhand().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();
|
||||||
|
Integer type = param.getInt("type");
|
||||||
|
if (type == 1 || type == 2) { //为1为大结算 为2为解散
|
||||||
|
Jedis jedis11s = Redis.use("group1_db11").getJedis();
|
||||||
|
try {
|
||||||
|
String key = "g{" + groupId + "}:play:" + pid;
|
||||||
|
jedis11s.hincrBy(key, "leftover_robot", 1);
|
||||||
|
//
|
||||||
|
if (count != null && count.containsKey(pid)) {
|
||||||
|
Integer currentValue = count.get(pid);
|
||||||
|
if (currentValue > 0) {
|
||||||
|
count.put(pid, currentValue - 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
String sql = String.format("UPDATE `account` SET start = %d WHERE id = %d", 0, playerId);
|
||||||
|
try {
|
||||||
|
DataBase.use().executeUpdate(sql);
|
||||||
|
} catch (SQLException e) {
|
||||||
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
}
|
} catch (Exception e) {
|
||||||
}
|
e.printStackTrace();
|
||||||
} finally {
|
} finally {
|
||||||
jedis0.close();
|
jedis11s.close();
|
||||||
jedis11.close();
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//发送准备协议
|
if (count != null && count.containsKey(pid)) {
|
||||||
sendReadyCommand(client);
|
Integer value = count.get(pid);
|
||||||
|
|
||||||
|
// 如果找到了对应的 pid
|
||||||
|
Jedis jedis12 = Redis.use("group1_db11").getJedis();
|
||||||
|
|
||||||
|
String shangxianRobot = jedis12.hget(playKey, "shangxian_robot");
|
||||||
|
String leftoverRobot = jedis12.hget(playKey, "leftover_robot");
|
||||||
|
|
||||||
|
if (shangxianRobot != null && leftoverRobot != null) {
|
||||||
|
if (value == 0) {
|
||||||
|
jedis12.hset(playKey, "leftover_robot", shangxianRobot);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 处理补杠协议
|
|
||||||
*/
|
|
||||||
private void handleBuGang(ITObject param, TaurusClient client) {
|
|
||||||
int card = param.getInt("card");
|
|
||||||
ITObject params = new TObject();
|
|
||||||
params.putInt("type", 21); // 胡牌类型
|
|
||||||
params.putInt("card", card);
|
|
||||||
params.putString("session", HuNanChangShaHandler.session + "," + HuNanChangShaHandler.token);
|
|
||||||
|
|
||||||
client.send("612", params, response -> {
|
|
||||||
log.info("补杠胡操作: " + response.returnCode);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
jedis12.close();
|
||||||
/**
|
|
||||||
* 处理抢杠胡协议
|
|
||||||
*/
|
|
||||||
private void handleQiangGangHu(ITObject param, TaurusClient client) {
|
|
||||||
|
|
||||||
int card = param.getInt("card");
|
|
||||||
ITObject params = new TObject();
|
|
||||||
params.putInt("type", 21); //胡牌类型
|
|
||||||
params.putInt("card", card);
|
|
||||||
params.putString("session", HuNanChangShaHandler.session + "," + HuNanChangShaHandler.token);
|
|
||||||
|
|
||||||
client.send("612", params, response -> {
|
|
||||||
log.info("抢杠胡操作: " + response.returnCode);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 处理吃牌协议
|
|
||||||
*/
|
|
||||||
private void handleChiCard(ITObject param, TaurusClient client) {
|
|
||||||
|
|
||||||
int card = param.getInt("card");
|
|
||||||
ITObject params = new TObject();
|
|
||||||
params.putInt("type", 21); //吃牌类型
|
|
||||||
params.putInt("card", card);
|
|
||||||
params.putString("session", HuNanChangShaHandler.session + "," + HuNanChangShaHandler.token);
|
|
||||||
|
|
||||||
client.send("612", params, response -> {
|
|
||||||
log.info("吃牌操作响应: " + response.returnCode);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
// playerState.pongGroups.clear();;
|
||||||
|
// playerState.handCards.clear();
|
||||||
|
// playerState.chiGroups.clear();
|
||||||
|
// playerState.gangGroups.clear();;
|
||||||
|
|
||||||
/**
|
|
||||||
* 处理杠后补牌协议
|
|
||||||
*/
|
|
||||||
private void handleGangBuPai(ITObject param, TaurusClient client) {
|
|
||||||
//处理杠后补牌逻辑
|
|
||||||
int card = param.getInt("card");
|
|
||||||
huNanChangShaHandler.getChangShaCardInhand().add(card);
|
|
||||||
log.info("杠后补牌: " + card + ", 当前手牌: " + huNanChangShaHandler.getChangShaCardInhand());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
// 发送准备协议
|
||||||
* 处理未知协议命令
|
ITObject readyParams = new TObject();
|
||||||
*/
|
readyParams.putString("session", HuNanChangSha.session + "," + HuNanChangSha.token);
|
||||||
private void handleUnknownCommand(String command, ITObject param, TaurusClient client) {
|
client.send("1005", readyParams, response -> {
|
||||||
log.info("收到未知协议命令: " + command + ", 参数: " + param);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 发送准备命令
|
|
||||||
*/
|
|
||||||
private void sendReadyCommand(TaurusClient client) {
|
|
||||||
com.taurus.core.entity.ITObject params = new com.taurus.core.entity.TObject();
|
|
||||||
params.putString("session", HuNanChangShaHandler.session + "," + HuNanChangShaHandler.token);
|
|
||||||
|
|
||||||
client.send("601", params, response -> {
|
|
||||||
System.out.println("准备操作响应: " + response.returnCode);
|
System.out.println("准备操作响应: " + response.returnCode);
|
||||||
});
|
});
|
||||||
|
break;
|
||||||
|
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}
|
||||||
|
huNanChangSha.shanchuchuguopai(param);
|
||||||
|
break;
|
||||||
|
case "820": //换牌提示
|
||||||
|
System.out.println("Handling 820 - Change card tips");
|
||||||
|
HuNanChangSha.changePlayer(command, message);
|
||||||
|
break;
|
||||||
|
case "825":
|
||||||
|
System.out.println("Handling 825");
|
||||||
|
ITObject params25 = TObject.newInstance();
|
||||||
|
params25.putInt("qi", 0);
|
||||||
|
params25.putInt("id", 1);
|
||||||
|
params25.putString("session", HuNanChangSha.session + "," + HuNanChangSha.token);
|
||||||
|
client.send("612", params25, response -> {
|
||||||
|
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
case "822":
|
||||||
|
System.out.println("Handling 822");
|
||||||
|
ITObject params22 = TObject.newInstance();
|
||||||
|
//params.putInt("qi", 0);
|
||||||
|
params22.putInt("id", 1);
|
||||||
|
params22.putString("session", HuNanChangSha.session + "," + HuNanChangSha.token);
|
||||||
|
//[TCP->822] data:{"tip_list":[{"type":8,"id":1,"opcard":[],"weight":8,"card":0}],"types":[{"type":21,"value":1}]}
|
||||||
|
//板胡Event [TCP->823] data:{"type":8,"seat":1,"data":[{"opcard":[204,204,204,108,108,108],"type":21,"value":1}]}
|
||||||
|
client.send("612", params22, response -> {
|
||||||
|
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
case "2008": //解散房间时候恢复机器人账号可以使用
|
||||||
|
System.out.println("Handling 2008 - Restore robot accounts when room is dismissed");
|
||||||
|
// Jedis jedis11s = Redis.use("group1_db11").getJedis();
|
||||||
|
// String key = "g{" + groupId + "}:play:" + pid;
|
||||||
|
//
|
||||||
|
// jedis11s.hincrBy(key, "leftover_robot", 1);
|
||||||
|
// jedis11s.close();
|
||||||
|
// try {
|
||||||
|
|
||||||
|
Set<String> roomIds08 = jedis0.keys("room:*");
|
||||||
|
String[] playerIds08 = null;
|
||||||
|
for (String roomId : roomIds08) {
|
||||||
|
String rid = roomId.substring(roomId.indexOf(":") + 1);
|
||||||
|
String roomKey08 = "room:" + rid;
|
||||||
|
|
||||||
|
if (jedis0.hget(roomKey08, "players") != null) {
|
||||||
|
String players = jedis0.hget(roomKey08, "players");
|
||||||
|
|
||||||
|
if (!players.equals("[]")) {
|
||||||
|
players = players.substring(1, players.length() - 1);
|
||||||
|
playerIds08 = players.split(",");
|
||||||
|
|
||||||
|
for (String pyids : playerIds08) {
|
||||||
|
|
||||||
|
if (Integer.parseInt(pyids) == playerId) {
|
||||||
|
jedis0.del(roomId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "838": //补杠事件
|
||||||
|
System.out.println("Handling 838 - Bu Gang event");
|
||||||
|
int card838 = param.getInt("card");
|
||||||
|
ITObject params838 = new TObject();
|
||||||
|
params838.putInt("card", card838);
|
||||||
|
params838.putString("session", HuNanChangSha.session + "," + HuNanChangSha.token);
|
||||||
|
client.send("839", params838, response -> {
|
||||||
|
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
case "816": //抢杠胡
|
||||||
|
System.out.println("Handling 816 - Qiang Gang Hu");
|
||||||
|
int card816 = param.getInt("card");
|
||||||
|
ITObject params816 = new TObject();
|
||||||
|
params816.putInt("type", 21); //胡牌类型
|
||||||
|
params816.putInt("card", card816);
|
||||||
|
params816.putString("session", HuNanChangSha.session + "," + HuNanChangSha.token);
|
||||||
|
client.send("612", params816, response -> {
|
||||||
|
log.info("抢杠胡操作: " + response.returnCode);
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
case "821": //吃牌
|
||||||
|
System.out.println("Handling 821 - Chi Pai");
|
||||||
|
int card821 = param.getInt("card");
|
||||||
|
ITObject params821 = new TObject();
|
||||||
|
params821.putInt("type", 21); //吃牌类型
|
||||||
|
params821.putInt("card", card821);
|
||||||
|
params821.putString("session", HuNanChangSha.session + "," + HuNanChangSha.token);
|
||||||
|
client.send("612", params821, response -> {
|
||||||
|
log.info("吃牌操作响应: " + response.returnCode);
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
case "823": //杠后补牌
|
||||||
|
System.out.println("Handling 823 - Gang after draw card");
|
||||||
|
//处理杠后补牌逻辑
|
||||||
|
int card823 = param.getInt("card");
|
||||||
|
huNanChangSha.getChangShaCardInhand().add(card823);
|
||||||
|
log.info("杠后补牌: " + card823 + ", 当前手牌: " + huNanChangSha.getChangShaCardInhand());
|
||||||
|
break;
|
||||||
|
case "835": //听牌相关
|
||||||
|
System.out.println("Handling 835 - Ting Pai related");
|
||||||
|
ITObject params835 = new TObject();
|
||||||
|
params835.putInt("qi", 0);
|
||||||
|
params835.putInt("id", 1);
|
||||||
|
params835.putString("session", HuNanChangSha.session + "," + HuNanChangSha.token);
|
||||||
|
client.send("612", params835, response -> {
|
||||||
|
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
System.out.println("Received unknown protocol command: " + command + ", params: " + param);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -1,582 +0,0 @@
|
||||||
package robot.mj.handler;
|
|
||||||
|
|
||||||
import com.robot.Util;
|
|
||||||
import com.taurus.core.entity.ITArray;
|
|
||||||
import com.taurus.core.entity.ITObject;
|
|
||||||
import com.taurus.core.entity.TObject;
|
|
||||||
import com.taurus.core.plugin.database.DataBase;
|
|
||||||
import com.taurus.core.util.Logger;
|
|
||||||
import taurus.client.Message;
|
|
||||||
import taurus.client.TaurusClient;
|
|
||||||
import taurus.util.CardUtil;
|
|
||||||
import taurus.util.ChangShaSuanFaTest;
|
|
||||||
import taurus.util.ChangshaWinSplitCard;
|
|
||||||
|
|
||||||
import java.sql.SQLException;
|
|
||||||
import java.util.*;
|
|
||||||
|
|
||||||
public class HuNanChangShaHandler {
|
|
||||||
|
|
||||||
public static int changShaCard = 0;
|
|
||||||
public static boolean isTinChi = false;
|
|
||||||
public static boolean isTinPeng = false;
|
|
||||||
|
|
||||||
private static final Logger log = Logger.getLogger(HuNanChangShaHandler.class);
|
|
||||||
|
|
||||||
|
|
||||||
//湖南长沙麻将手牌
|
|
||||||
private final List<Integer> changShaCardInhand = new ArrayList<>();
|
|
||||||
|
|
||||||
private final List<Integer> changShaCardInhandgang = new ArrayList<>();
|
|
||||||
|
|
||||||
//长沙麻将出过的牌
|
|
||||||
private final List<Integer> changShachuguopai = new ArrayList<>();
|
|
||||||
|
|
||||||
private final Map<Integer, Integer> chuGuoPainum = new HashMap<>();
|
|
||||||
|
|
||||||
//杠的牌
|
|
||||||
private final List<Integer> gangdepai = new ArrayList<>();
|
|
||||||
|
|
||||||
//碰牌
|
|
||||||
private final List<Integer> pongGroup = new ArrayList<>();
|
|
||||||
|
|
||||||
//吃牌
|
|
||||||
private final List<Integer> chowGroup = new ArrayList<>();
|
|
||||||
|
|
||||||
//玩家座位号
|
|
||||||
public static int seat = 0;
|
|
||||||
|
|
||||||
public static int playerId = 0;
|
|
||||||
|
|
||||||
public static int cardToOut1 = 0;
|
|
||||||
|
|
||||||
//会话标识
|
|
||||||
public static String session = "";
|
|
||||||
//访问令牌
|
|
||||||
public static String token = "";
|
|
||||||
|
|
||||||
private static final ChangShaSuanFaTest changShaSuanFaTest = new ChangShaSuanFaTest();
|
|
||||||
|
|
||||||
|
|
||||||
//公共的getter和setter方法
|
|
||||||
public List<Integer> getChangShaCardInhand() {
|
|
||||||
return changShaCardInhand;
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<Integer> getGangdepai() {
|
|
||||||
return gangdepai;
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<Integer> getChangShaCardInhandgang() {
|
|
||||||
return changShaCardInhandgang;
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<Integer> getPongGroup() {
|
|
||||||
return pongGroup;
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<Integer> getChowGroup() {
|
|
||||||
return chowGroup;
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<Integer> getChuGuoCardInhand() {
|
|
||||||
return changShachuguopai;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Map<Integer, Integer> getChuGuoPainum() {
|
|
||||||
return chuGuoPainum;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 设置会话和令牌
|
|
||||||
*/
|
|
||||||
public void setSessionAndToken(String session, String token) {
|
|
||||||
HuNanChangShaHandler.session = session;
|
|
||||||
HuNanChangShaHandler.token = token;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 出牌广播协议 812
|
|
||||||
*
|
|
||||||
* @param command 协议号
|
|
||||||
* @param message 消息对象
|
|
||||||
*/
|
|
||||||
public static void drawCard(String command, Message message) {
|
|
||||||
if (command.equalsIgnoreCase("812")) {
|
|
||||||
ITObject param = message.param;
|
|
||||||
if (param == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
changShaCard = param.getInt("card");
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 摸牌协议 819
|
|
||||||
*
|
|
||||||
* @param command 协议号
|
|
||||||
* @param message 消息对象
|
|
||||||
*/
|
|
||||||
public void getCard(String command, Message message) {
|
|
||||||
if (command.equalsIgnoreCase("819")) {
|
|
||||||
ITObject param = message.param;
|
|
||||||
if (param == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (param.getInt("player") != null) {
|
|
||||||
int drawnCard = param.getInt("card");
|
|
||||||
changShaSuanFaTest.drawnCards = drawnCard;
|
|
||||||
changShaCardInhand.add(drawnCard);
|
|
||||||
changShaSuanFaTest.analyzeHand(changShaCardInhand);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 初始化手牌协议 811
|
|
||||||
*
|
|
||||||
* @param command 协议号
|
|
||||||
* @param message 消息对象
|
|
||||||
*/
|
|
||||||
public void cardInHead(String command, Message message, TaurusClient client) {
|
|
||||||
if (command.equalsIgnoreCase("811")) {
|
|
||||||
ITObject param = message.param;
|
|
||||||
if (param == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
ITArray cardList = param.getTArray("card_list");
|
|
||||||
changShaCardInhand.clear();
|
|
||||||
for (int i = 0; i < cardList.size(); i++) {
|
|
||||||
changShaCardInhand.add(cardList.getInt(i));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 处理 吃,碰,杠,补,胡
|
|
||||||
*/
|
|
||||||
public void actionCard(ITObject param, TaurusClient client) {
|
|
||||||
ITArray tipList = param.getTArray("tip_list");
|
|
||||||
log.info("tipList" +tipList);
|
|
||||||
ITObject params = TObject.newInstance();
|
|
||||||
int card = 0;
|
|
||||||
|
|
||||||
//循环
|
|
||||||
List<Integer> yupanhandcard = new ArrayList<>(changShaCardInhand);
|
|
||||||
//进行操作之前能否下听
|
|
||||||
List<Integer> shifoutingpai = ChangShaSuanFaTest.handscardshifoutingpai(changShaCardInhand,chowGroup,pongGroup,gangdepai);
|
|
||||||
//记录操作之前的下听状态
|
|
||||||
boolean beforelisten = false;
|
|
||||||
if (!shifoutingpai.isEmpty()) {
|
|
||||||
beforelisten = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
//如果杠了之后还能继续听牌则杠
|
|
||||||
//如果下听了,可以杠
|
|
||||||
for (int i = 0; i < tipList.size(); i++) {
|
|
||||||
TObject firstTip = (TObject) tipList.get(i).getObject();
|
|
||||||
int type = firstTip.getInt("type");
|
|
||||||
int id = firstTip.getInt("id");
|
|
||||||
int weight = firstTip.getInt("weight");
|
|
||||||
card = firstTip.getInt("card");
|
|
||||||
|
|
||||||
|
|
||||||
if (type == 6){
|
|
||||||
params.putString("session", session + "," + token);
|
|
||||||
params.putInt("qi", 0);
|
|
||||||
params.putInt("id", id);
|
|
||||||
client.send("612", params, response -> {
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((type == 5 || type == 3 || type==4)&&weight==4) {
|
|
||||||
//判断开杠后是否能下听
|
|
||||||
List<Integer> gangusecars = new ArrayList<>(changShaCardInhand);
|
|
||||||
|
|
||||||
if (type == 3) {
|
|
||||||
Util.removeCard(gangusecars,card,3);
|
|
||||||
List<Integer> shifoutingpai3 = ChangShaSuanFaTest.handscardshifoutingpai(gangusecars,chowGroup,pongGroup,gangdepai);
|
|
||||||
log.info(shifoutingpai3);
|
|
||||||
|
|
||||||
if (!shifoutingpai3.isEmpty()) {
|
|
||||||
//开杠
|
|
||||||
//判断是否杠了之后没有牌可以听
|
|
||||||
List<Integer> allList = new ArrayList<>();
|
|
||||||
allList.addAll(changShaCardInhand);
|
|
||||||
allList.addAll(changShachuguopai);
|
|
||||||
int jutingnum = ChangShaSuanFaTest.getTingPainum(shifoutingpai3,allList);
|
|
||||||
if (jutingnum==0){
|
|
||||||
params.putString("session", session + "," + token);
|
|
||||||
params.putInt("qi", 0);
|
|
||||||
params.putInt("id", 0);
|
|
||||||
client.send("612", params, response -> {
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Util.removeCard(changShaCardInhand,card,3);
|
|
||||||
params.putString("session", session + "," + token);
|
|
||||||
params.putInt("qi", 0);
|
|
||||||
params.putInt("id", id);
|
|
||||||
client.send("612", params, response -> {
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}else{
|
|
||||||
params.putString("session", session + "," + token);
|
|
||||||
params.putInt("qi", 0);
|
|
||||||
params.putInt("id", 0);
|
|
||||||
client.send("612", params, response -> {
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (type == 4) {
|
|
||||||
Util.removeCard(gangusecars,card,4);
|
|
||||||
List<Integer> shifoutingpai4 = ChangShaSuanFaTest.handscardshifoutingpai(gangusecars,chowGroup,pongGroup,gangdepai);
|
|
||||||
if (!shifoutingpai4.isEmpty()) {
|
|
||||||
//开杠
|
|
||||||
//判断是否杠了之后没有牌可以听
|
|
||||||
List<Integer> allList = new ArrayList<>();
|
|
||||||
allList.addAll(changShaCardInhand);
|
|
||||||
allList.addAll(changShachuguopai);
|
|
||||||
int jutingnum = ChangShaSuanFaTest.getTingPainum(shifoutingpai4,allList);
|
|
||||||
if (jutingnum==0){
|
|
||||||
params.putString("session", session + "," + token);
|
|
||||||
params.putInt("qi", 0);
|
|
||||||
params.putInt("id", 0);
|
|
||||||
client.send("612", params, response -> {
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Util.removeCard(changShaCardInhand,card,4);
|
|
||||||
params.putString("session", session + "," + token);
|
|
||||||
params.putInt("qi", 0);
|
|
||||||
params.putInt("id", id);
|
|
||||||
client.send("612", params, response -> {
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}else{
|
|
||||||
params.putString("session", session + "," + token);
|
|
||||||
params.putInt("qi", 0);
|
|
||||||
params.putInt("id", 0);
|
|
||||||
client.send("612", params, response -> {
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (type == 5) {
|
|
||||||
|
|
||||||
Util.removeCard(gangusecars,card,1);
|
|
||||||
List<Integer> shifoutingpai5 = ChangShaSuanFaTest.handscardshifoutingpai(gangusecars,chowGroup,pongGroup,gangdepai);
|
|
||||||
if (!shifoutingpai5.isEmpty()) {
|
|
||||||
//开杠
|
|
||||||
//判断是否杠了之后没有牌可以听
|
|
||||||
List<Integer> allList = new ArrayList<>();
|
|
||||||
allList.addAll(changShaCardInhand);
|
|
||||||
allList.addAll(changShachuguopai);
|
|
||||||
int jutingnum = ChangShaSuanFaTest.getTingPainum(shifoutingpai5,allList);
|
|
||||||
if (jutingnum==0){
|
|
||||||
params.putString("session", session + "," + token);
|
|
||||||
params.putInt("qi", 0);
|
|
||||||
params.putInt("id", 0);
|
|
||||||
client.send("612", params, response -> {
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Util.removeCard(changShaCardInhand,card,1);
|
|
||||||
params.putString("session", session + "," + token);
|
|
||||||
params.putInt("qi", 0);
|
|
||||||
params.putInt("id", id);
|
|
||||||
client.send("612", params, response -> {
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}else{
|
|
||||||
params.putString("session", session + "," + token);
|
|
||||||
params.putInt("qi", 0);
|
|
||||||
params.putInt("id", 0);
|
|
||||||
client.send("612", params, response -> {
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//判断是否是大胡
|
|
||||||
int beforeIsDahu = 0;
|
|
||||||
beforeIsDahu = ChangShaSuanFaTest.checkDahu(yupanhandcard,chowGroup,pongGroup,gangdepai);
|
|
||||||
//5、门清
|
|
||||||
if (yupanhandcard.size()==13&&beforelisten){
|
|
||||||
beforeIsDahu = 5;//门清
|
|
||||||
}
|
|
||||||
|
|
||||||
//操作之前出现的牌
|
|
||||||
List<Integer> allSeeCard = new ArrayList<>();
|
|
||||||
|
|
||||||
Map<Integer,ITObject> pingfenResult = new HashMap<>();
|
|
||||||
Map<Integer,ITObject> idObject = new HashMap<>();
|
|
||||||
for (int i = 0; i < tipList.size(); i++) {
|
|
||||||
TObject firstTip = (TObject) tipList.get(i).getObject();
|
|
||||||
int type = firstTip.getInt("type");
|
|
||||||
int id = firstTip.getInt("id");
|
|
||||||
int weight = firstTip.getInt("weight");
|
|
||||||
card = firstTip.getInt("card");
|
|
||||||
ITArray opcard = firstTip.getTArray("opcard");
|
|
||||||
if (type == 6){
|
|
||||||
params.putString("session", session + "," + token);
|
|
||||||
params.putInt("qi", 0);
|
|
||||||
params.putInt("id", id);
|
|
||||||
client.send("612", params, response -> {
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
//对应的数据
|
|
||||||
ITObject tmp = new TObject();
|
|
||||||
//处理听的结果
|
|
||||||
switch (type) {
|
|
||||||
case 1:
|
|
||||||
//吃
|
|
||||||
tmp = ChangShaSuanFaTest.pingguChi( beforelisten,card,opcard,yupanhandcard,beforeIsDahu,allSeeCard,chowGroup,pongGroup,gangdepai,changShachuguopai);
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
//碰
|
|
||||||
tmp = ChangShaSuanFaTest.pingguPeng(beforelisten,card,opcard,yupanhandcard,beforeIsDahu,allSeeCard,chowGroup,pongGroup,gangdepai,changShachuguopai);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
//记录下来事件
|
|
||||||
if(tmp.size()>0){
|
|
||||||
pingfenResult.put(id,tmp);
|
|
||||||
}
|
|
||||||
ITObject sj = new TObject();
|
|
||||||
sj.putInt("weight", weight);
|
|
||||||
sj.putTArray("opcard", opcard);
|
|
||||||
idObject.put(id,sj);
|
|
||||||
}
|
|
||||||
//计算分数
|
|
||||||
log.info(pingfenResult);
|
|
||||||
if(!pingfenResult.isEmpty()){
|
|
||||||
int changeid= ChangShaSuanFaTest.suanfen(pingfenResult);
|
|
||||||
log.info("changeid:"+changeid);
|
|
||||||
//选择最优的分数
|
|
||||||
if (changeid==0){
|
|
||||||
params.putString("session", session + "," + token);
|
|
||||||
params.putInt("qi", 0);
|
|
||||||
params.putInt("id", 0);
|
|
||||||
client.send("612", params, response -> {
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}else {
|
|
||||||
//获取
|
|
||||||
for(Map.Entry<Integer,ITObject> entry : idObject.entrySet()){
|
|
||||||
if(entry.getKey()==changeid){
|
|
||||||
ITObject tmp = entry.getValue();
|
|
||||||
if (tmp.getInt("weight")==2){
|
|
||||||
//碰
|
|
||||||
ITArray outcards = tmp.getTArray("opcard");
|
|
||||||
for (int i = 0; i < outcards.size(); i++) {
|
|
||||||
Util.removeCard(changShaCardInhand,outcards.getInt(0),2);
|
|
||||||
}
|
|
||||||
}else if (tmp.getInt("weight")==1){
|
|
||||||
//吃
|
|
||||||
ITArray outcards = tmp.getTArray("opcard");
|
|
||||||
for (int i = 0; i < outcards.size(); i++) {
|
|
||||||
Util.removeCard(changShaCardInhand,outcards.getInt(i),1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
params.putString("session", session + "," + token);
|
|
||||||
params.putInt("qi", 0);
|
|
||||||
params.putInt("id", changeid);
|
|
||||||
client.send("612", params, response -> {
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//计算牌数
|
|
||||||
|
|
||||||
//如果 不吃,不碰,而且差三手牌情况,则补
|
|
||||||
for (int i = 0; i < tipList.size(); i++) {
|
|
||||||
TObject firstTip = (TObject) tipList.get(i).getObject();
|
|
||||||
int type = firstTip.getInt("type");
|
|
||||||
int id = firstTip.getInt("id");
|
|
||||||
int weight = firstTip.getInt("weight");
|
|
||||||
card = firstTip.getInt("card");
|
|
||||||
|
|
||||||
Map<String, Object> map = new HashMap<>();
|
|
||||||
List<Integer> tmpChangSch = new ArrayList<>(yupanhandcard);
|
|
||||||
ChangshaWinSplitCard.checkNormalHu(tmpChangSch, map);
|
|
||||||
System.out.println("map:" + map);
|
|
||||||
|
|
||||||
if (!map.isEmpty() && weight==3) {
|
|
||||||
|
|
||||||
if (Integer.parseInt(map.get("remainingMelds").toString()) > 2) {
|
|
||||||
params.putString("session", session + "," + token);
|
|
||||||
params.putInt("qi", 0);
|
|
||||||
params.putInt("id", id);
|
|
||||||
|
|
||||||
if (type == 3) {
|
|
||||||
Util.removeCard(changShaCardInhand,card,3);
|
|
||||||
}
|
|
||||||
if (type == 4) {
|
|
||||||
Util.removeCard(changShaCardInhand,card,4);
|
|
||||||
}
|
|
||||||
if (type == 5) {
|
|
||||||
Util.removeCard(changShaCardInhand,card,1);
|
|
||||||
}
|
|
||||||
client.send("612", params, response -> {
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
params.putString("session", session + "," + token);
|
|
||||||
params.putInt("qi", 0);
|
|
||||||
params.putInt("id", 0);
|
|
||||||
client.send("612", params, response -> {
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
params.putString("session", session + "," + token);
|
|
||||||
params.putInt("qi", 0);
|
|
||||||
params.putInt("id", 0);
|
|
||||||
client.send("612", params, response -> {
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 出牌方法
|
|
||||||
*/
|
|
||||||
public void outCard(TaurusClient client, Map<Integer, List<Integer>> playerOutcardsMap,
|
|
||||||
Map<Integer, List<Integer>> playerchisMap, Map<Integer, List<Integer>> playerpengsMap,
|
|
||||||
Map<Integer, List<Integer>> playermingsMap, Map<Integer, List<Integer>> playerzisMap) {
|
|
||||||
//整合所有其他玩家的出牌信息
|
|
||||||
List<Integer> resultList = new ArrayList<>();
|
|
||||||
for (List<Integer> cards : playerOutcardsMap.values()) {
|
|
||||||
resultList.addAll(cards);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (List<Integer> chis : playerchisMap.values()) {
|
|
||||||
resultList.addAll(chis);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (List<Integer> pengs : playerpengsMap.values()) {
|
|
||||||
resultList.addAll(pengs);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (List<Integer> minggangs : playermingsMap.values()) {
|
|
||||||
resultList.addAll(minggangs);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (List<Integer> zigang : playerzisMap.values()) {
|
|
||||||
resultList.addAll(zigang);
|
|
||||||
}
|
|
||||||
|
|
||||||
ITObject params = TObject.newInstance();
|
|
||||||
int cardToOut;
|
|
||||||
|
|
||||||
if (!changShaCardInhand.isEmpty()) {
|
|
||||||
//使用长沙麻将算法计算最优出牌
|
|
||||||
ChangShaSuanFaTest changShaSuanFaTest = new ChangShaSuanFaTest();
|
|
||||||
String cardStr = changShaSuanFaTest.outCardSuanFa(changShaCardInhand, pongGroup, chowGroup, gangdepai, resultList);
|
|
||||||
try {
|
|
||||||
cardToOut = Integer.parseInt(cardStr);
|
|
||||||
} catch (NumberFormatException e) {
|
|
||||||
//如果算法出错,使用第一张牌
|
|
||||||
cardToOut = changShaCardInhand.get(0);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return; //没有牌可出
|
|
||||||
}
|
|
||||||
|
|
||||||
params.putInt("card", cardToOut);
|
|
||||||
|
|
||||||
int outCountBefore = changShachuguopai.size(); //当前历史出牌数量
|
|
||||||
|
|
||||||
//第n次出牌时,发送前n-1张出牌
|
|
||||||
if (outCountBefore >= 1) {
|
|
||||||
//发送前n-1张(所有历史出牌)
|
|
||||||
List<Integer> cardsToSend = changShachuguopai.subList(0, outCountBefore);
|
|
||||||
params.putTArray("outcard_list", CardUtil.maJiangToTArray(cardsToSend));
|
|
||||||
}
|
|
||||||
params.putTArray("card_list", CardUtil.maJiangToTArray(changShaCardInhand));
|
|
||||||
|
|
||||||
|
|
||||||
//将当前出的牌添加到历史出牌列表
|
|
||||||
changShachuguopai.add(cardToOut);
|
|
||||||
//从手牌中移除
|
|
||||||
changShaCardInhand.remove(Integer.valueOf(cardToOut));
|
|
||||||
|
|
||||||
params.putString("session", session + "," + token);
|
|
||||||
client.send("611", params, response -> {
|
|
||||||
});
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 删除出过的牌组
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public void shanchuchuguopai(ITObject param) {
|
|
||||||
if (param == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Integer card = param.getInt("card"); //操作牌值
|
|
||||||
Integer type = param.getInt("type"); //操作类型
|
|
||||||
Integer from_seat = param.getInt("from_seat"); //牌来源座位
|
|
||||||
|
|
||||||
|
|
||||||
Integer playerid = param.getInt("playerid");
|
|
||||||
|
|
||||||
|
|
||||||
String sql2 = "SELECT id FROM `account` WHERE jiqiren=9998";
|
|
||||||
try {
|
|
||||||
ITArray robotId2 = DataBase.use().executeQueryByTArray(sql2);
|
|
||||||
List<Integer> robotIdsList = new ArrayList<>();
|
|
||||||
|
|
||||||
for (int j = 0; j < robotId2.size(); j++) {
|
|
||||||
robotIdsList.add(robotId2.getTObject(j).getInt("id"));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!robotIdsList.contains(playerid)) {
|
|
||||||
if (type == 2 || type == 3 || type == 5 || type == 1) { //碰,杠
|
|
||||||
getChuGuoCardInhand().remove(card);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} catch (SQLException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 位置转换协议 820
|
|
||||||
*
|
|
||||||
* @param command 协议号
|
|
||||||
* @param message 消息对象
|
|
||||||
*/
|
|
||||||
public static void changePlayer(String command, Message message) {
|
|
||||||
if (command.equalsIgnoreCase("820")) {
|
|
||||||
ITObject param = message.param;
|
|
||||||
if (param == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
seat = param.getInt("seat");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
package taurus.util;
|
package taurus.util;
|
||||||
|
|
||||||
import com.robot.Util;
|
import com.robot.Util;
|
||||||
import robot.mj.handler.HuNanChangShaHandler;
|
import robot.mj.handler.HuNanChangSha;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
|
|
@ -627,7 +627,7 @@ public class TinHuChi {
|
||||||
// 5. 检查打牌后是否能听牌
|
// 5. 检查打牌后是否能听牌
|
||||||
boolean canTing = checkCanTing(afterDiscard, needs258, targetSizeAfterDiscard);
|
boolean canTing = checkCanTing(afterDiscard, needs258, targetSizeAfterDiscard);
|
||||||
if (canTing) {
|
if (canTing) {
|
||||||
HuNanChangShaHandler.isTinChi = true;
|
HuNanChangSha.isTinChi = true;
|
||||||
ChangShaSuanFaTest.isChi=true;
|
ChangShaSuanFaTest.isChi=true;
|
||||||
System.out.println(" ✓ 听牌!");
|
System.out.println(" ✓ 听牌!");
|
||||||
foundTing = true;
|
foundTing = true;
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,404 @@
|
||||||
|
package taurus.util;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
public class TinHuGang {
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断是否能杠牌(检查杠牌后是否立即听牌)
|
||||||
|
*/
|
||||||
|
public static boolean canGang(List<Integer> handCards, int card, boolean isMingGang) {
|
||||||
|
int type = card / 100;
|
||||||
|
int value = card % 100;
|
||||||
|
|
||||||
|
System.out.println("\n检查" + (isMingGang ? "明" : "暗") + "杠" + value + getTypeName(type) + ":");
|
||||||
|
|
||||||
|
// 检查是否符合杠牌条件
|
||||||
|
int count = Collections.frequency(handCards, card);
|
||||||
|
|
||||||
|
if (isMingGang) {
|
||||||
|
// 明杠:手牌中需要有三张相同的牌
|
||||||
|
if (count < 3) {
|
||||||
|
System.out.println(" 手牌中没有三张相同的" + value + getTypeName(type) + ",不能明杠");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
System.out.println(" 发现三张" + value + getTypeName(type) + ",可以明杠");
|
||||||
|
} else {
|
||||||
|
// 暗杠:手牌中需要有四张相同的牌
|
||||||
|
if (count < 4) {
|
||||||
|
System.out.println(" 手牌中没有四张相同的" + value + getTypeName(type) + ",不能暗杠");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
System.out.println(" 发现四张" + value + getTypeName(type) + ",可以暗杠");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查杠牌后是否立即听牌(杠牌后手牌本身就是听牌状态)
|
||||||
|
return canTingImmediatelyAfterGang(handCards, card, isMingGang);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查杠牌后是否能立即听牌
|
||||||
|
*/
|
||||||
|
private static boolean canTingImmediatelyAfterGang(List<Integer> handCards, int gangCard, boolean isMingGang) {
|
||||||
|
int type = gangCard / 100;
|
||||||
|
int value = gangCard % 100;
|
||||||
|
|
||||||
|
System.out.println("\n模拟" + (isMingGang ? "明" : "暗") + "杠" + value + getTypeName(type) + ":");
|
||||||
|
|
||||||
|
// 1. 模拟杠牌:移除手牌中的牌
|
||||||
|
List<Integer> afterGang = new ArrayList<>(handCards);
|
||||||
|
|
||||||
|
if (isMingGang) {
|
||||||
|
// 明杠:移除手牌中的三张牌
|
||||||
|
for (int i = 0; i < 3; i++) {
|
||||||
|
afterGang.remove(Integer.valueOf(gangCard));
|
||||||
|
}
|
||||||
|
// 杠牌后手牌数:13张 → 10张
|
||||||
|
} else {
|
||||||
|
// 暗杠:移除手牌中的四张牌
|
||||||
|
for (int i = 0; i < 4; i++) {
|
||||||
|
afterGang.remove(Integer.valueOf(gangCard));
|
||||||
|
}
|
||||||
|
// 暗杠后需要补牌,但这里先不处理
|
||||||
|
}
|
||||||
|
|
||||||
|
Collections.sort(afterGang);
|
||||||
|
|
||||||
|
System.out.println(" 杠后手牌(" + afterGang.size() + "张): " + convertToReadable(afterGang));
|
||||||
|
|
||||||
|
// 2. 检查是否需要258将
|
||||||
|
boolean needs258 = !checkSuitCount(afterGang);
|
||||||
|
if (needs258) {
|
||||||
|
System.out.println(" 花色牌数不足10张,需要258做将");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. 检查杠牌后手牌本身是否就是听牌状态
|
||||||
|
// 注意:杠牌后手牌数是10张,这10张牌本身应该是听牌状态
|
||||||
|
// 也就是说,随便摸一张牌(任何牌)都能胡牌
|
||||||
|
|
||||||
|
System.out.println("\n 检查杠后手牌是否听牌:");
|
||||||
|
|
||||||
|
if (afterGang.size() != 10) {
|
||||||
|
System.out.println(" 手牌数不是10张,不符合听牌条件");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查这10张牌是否听牌
|
||||||
|
boolean canTing = checkIfHandIsTingPai(afterGang, needs258);
|
||||||
|
|
||||||
|
if (canTing) {
|
||||||
|
System.out.println(" ✓ 杠后手牌是听牌状态!");
|
||||||
|
|
||||||
|
// 显示听哪些牌
|
||||||
|
Set<Integer> tingCards = getTingCards(afterGang, needs258);
|
||||||
|
if (!tingCards.isEmpty()) {
|
||||||
|
System.out.print(" 听" + tingCards.size() + "张牌: ");
|
||||||
|
List<String> tingStrs = new ArrayList<>();
|
||||||
|
for (int tingCard : tingCards) {
|
||||||
|
tingStrs.add((tingCard%100) + getTypeName(tingCard/100));
|
||||||
|
}
|
||||||
|
System.out.println(String.join(", ", tingStrs));
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
System.out.println(" ✗ 杠后手牌不是听牌状态");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查手牌是否处于听牌状态
|
||||||
|
*/
|
||||||
|
private static boolean checkIfHandIsTingPai(List<Integer> hand, boolean needs258) {
|
||||||
|
if (hand.size() != 10) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 听牌状态:再摸任何一张牌都能胡牌
|
||||||
|
// 我们需要检查是否至少有一张牌能让这手牌胡牌
|
||||||
|
Set<Integer> allCards = getAllCards();
|
||||||
|
int tingCount = 0;
|
||||||
|
|
||||||
|
for (int testCard : allCards) {
|
||||||
|
List<Integer> tempHand = new ArrayList<>(hand);
|
||||||
|
tempHand.add(testCard);
|
||||||
|
|
||||||
|
if (canHu(tempHand, needs258)) {
|
||||||
|
tingCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
System.out.println(" 可胡" + tingCount + "张牌");
|
||||||
|
return tingCount > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取听哪些牌
|
||||||
|
*/
|
||||||
|
private static Set<Integer> getTingCards(List<Integer> hand, boolean needs258) {
|
||||||
|
Set<Integer> tingCards = new HashSet<>();
|
||||||
|
|
||||||
|
if (hand.size() != 10) {
|
||||||
|
return tingCards;
|
||||||
|
}
|
||||||
|
|
||||||
|
Set<Integer> allCards = getAllCards();
|
||||||
|
|
||||||
|
for (int testCard : allCards) {
|
||||||
|
List<Integer> tempHand = new ArrayList<>(hand);
|
||||||
|
tempHand.add(testCard);
|
||||||
|
|
||||||
|
if (canHu(tempHand, needs258)) {
|
||||||
|
tingCards.add(testCard);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return tingCards;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查手牌是否能胡牌
|
||||||
|
*/
|
||||||
|
private static boolean canHu(List<Integer> handCards, boolean needs258) {
|
||||||
|
// 手牌排序
|
||||||
|
List<Integer> sorted = new ArrayList<>(handCards);
|
||||||
|
Collections.sort(sorted);
|
||||||
|
|
||||||
|
// 胡牌时手牌数必须是3n+2
|
||||||
|
if (sorted.size() != 11 && sorted.size() != 14) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查七对子
|
||||||
|
if (checkQiDuiZi(sorted)) {
|
||||||
|
// 七对子不需要258将
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果需要258将,检查普通胡牌(必须有258将)
|
||||||
|
if (needs258) {
|
||||||
|
return checkNormalHuWith258(sorted);
|
||||||
|
} else {
|
||||||
|
// 不需要258将,检查普通胡牌
|
||||||
|
return checkNormalHu(sorted);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查七对子
|
||||||
|
*/
|
||||||
|
private static boolean checkQiDuiZi(List<Integer> handCards) {
|
||||||
|
if (handCards.size() != 14) return false;
|
||||||
|
|
||||||
|
Map<Integer, Integer> countMap = new HashMap<>();
|
||||||
|
for (int card : handCards) {
|
||||||
|
countMap.put(card, countMap.getOrDefault(card, 0) + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查是否都是对子
|
||||||
|
for (int count : countMap.values()) {
|
||||||
|
if (count != 2) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查普通胡牌(必须有258将)
|
||||||
|
*/
|
||||||
|
private static boolean checkNormalHuWith258(List<Integer> handCards) {
|
||||||
|
// 尝试每种258作为将牌
|
||||||
|
for (int card : handCards) {
|
||||||
|
int value = card % 100;
|
||||||
|
// 检查是否是258
|
||||||
|
if (value == 2 || value == 5 || value == 8) {
|
||||||
|
// 检查是否有至少2张相同的牌做将
|
||||||
|
int count = Collections.frequency(handCards, card);
|
||||||
|
if (count >= 2) {
|
||||||
|
// 移除将牌
|
||||||
|
List<Integer> remaining = new ArrayList<>(handCards);
|
||||||
|
for (int i = 0; i < 2; i++) {
|
||||||
|
remaining.remove(Integer.valueOf(card));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查剩余牌是否能组成顺子/刻子
|
||||||
|
if (canGroup(remaining)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查普通胡牌(不需要258将)
|
||||||
|
*/
|
||||||
|
private static boolean checkNormalHu(List<Integer> handCards) {
|
||||||
|
return checkNormalHuRecursive(new ArrayList<>(handCards), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean checkNormalHuRecursive(List<Integer> handCards, boolean hasJiang) {
|
||||||
|
if (handCards.isEmpty()) {
|
||||||
|
return true; // 所有牌都分组成功
|
||||||
|
}
|
||||||
|
|
||||||
|
Collections.sort(handCards);
|
||||||
|
|
||||||
|
// 统计第一张牌的数量
|
||||||
|
int firstCard = handCards.get(0);
|
||||||
|
int count = Collections.frequency(handCards, firstCard);
|
||||||
|
|
||||||
|
// 尝试作为刻子(三张相同)
|
||||||
|
if (count >= 3) {
|
||||||
|
List<Integer> remaining = new ArrayList<>(handCards);
|
||||||
|
for (int i = 0; i < 3; i++) {
|
||||||
|
remaining.remove(Integer.valueOf(firstCard));
|
||||||
|
}
|
||||||
|
if (checkNormalHuRecursive(remaining, hasJiang)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 尝试作为顺子(三张连续)
|
||||||
|
int type = firstCard / 100;
|
||||||
|
int value = firstCard % 100;
|
||||||
|
|
||||||
|
if (type < 4 && value <= 7) { // 字牌和8、9不能组成顺子
|
||||||
|
int second = type * 100 + (value + 1);
|
||||||
|
int third = type * 100 + (value + 2);
|
||||||
|
|
||||||
|
if (handCards.contains(second) && handCards.contains(third)) {
|
||||||
|
List<Integer> remaining = new ArrayList<>(handCards);
|
||||||
|
remaining.remove(Integer.valueOf(firstCard));
|
||||||
|
remaining.remove(Integer.valueOf(second));
|
||||||
|
remaining.remove(Integer.valueOf(third));
|
||||||
|
if (checkNormalHuRecursive(remaining, hasJiang)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 尝试作为将(对子)- 只能有一个将
|
||||||
|
if (!hasJiang && count >= 2) {
|
||||||
|
List<Integer> remaining = new ArrayList<>(handCards);
|
||||||
|
remaining.remove(Integer.valueOf(firstCard));
|
||||||
|
remaining.remove(Integer.valueOf(firstCard));
|
||||||
|
if (checkNormalHuRecursive(remaining, true)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查牌是否能组成顺子或刻子
|
||||||
|
*/
|
||||||
|
private static boolean canGroup(List<Integer> cards) {
|
||||||
|
if (cards.isEmpty()) {
|
||||||
|
return true; // 所有牌都分组成功
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Integer> sorted = new ArrayList<>(cards);
|
||||||
|
Collections.sort(sorted);
|
||||||
|
|
||||||
|
int firstCard = sorted.get(0);
|
||||||
|
int count = Collections.frequency(sorted, firstCard);
|
||||||
|
|
||||||
|
// 尝试作为刻子(三张相同)
|
||||||
|
if (count >= 3) {
|
||||||
|
List<Integer> remaining = new ArrayList<>(sorted);
|
||||||
|
for (int i = 0; i < 3; i++) {
|
||||||
|
remaining.remove(Integer.valueOf(firstCard));
|
||||||
|
}
|
||||||
|
if (canGroup(remaining)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 尝试作为顺子(三张连续)
|
||||||
|
int type = firstCard / 100;
|
||||||
|
int value = firstCard % 100;
|
||||||
|
|
||||||
|
if (type < 4 && value <= 7) { // 字牌和8、9不能组成顺子
|
||||||
|
int second = type * 100 + (value + 1);
|
||||||
|
int third = type * 100 + (value + 2);
|
||||||
|
|
||||||
|
if (sorted.contains(second) && sorted.contains(third)) {
|
||||||
|
List<Integer> remaining = new ArrayList<>(sorted);
|
||||||
|
remaining.remove(Integer.valueOf(firstCard));
|
||||||
|
remaining.remove(Integer.valueOf(second));
|
||||||
|
remaining.remove(Integer.valueOf(third));
|
||||||
|
if (canGroup(remaining)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查手牌花色牌数是否>=10张
|
||||||
|
*/
|
||||||
|
private static boolean checkSuitCount(List<Integer> hand) {
|
||||||
|
Map<Integer, Integer> suitCount = new HashMap<>();
|
||||||
|
for (int card : hand) {
|
||||||
|
int type = card / 100;
|
||||||
|
if (type < 4) {
|
||||||
|
suitCount.put(type, suitCount.getOrDefault(type, 0) + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int count : suitCount.values()) {
|
||||||
|
if (count >= 10) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取所有麻将牌
|
||||||
|
*/
|
||||||
|
private static Set<Integer> getAllCards() {
|
||||||
|
Set<Integer> allCards = new HashSet<>();
|
||||||
|
for (int type = 1; type <= 3; type++) {
|
||||||
|
for (int value = 1; value <= 9; value++) {
|
||||||
|
allCards.add(type * 100 + value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return allCards;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 转换为可读格式
|
||||||
|
*/
|
||||||
|
private static String convertToReadable(List<Integer> cards) {
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
for (int card : cards) {
|
||||||
|
int type = card / 100;
|
||||||
|
int value = card % 100;
|
||||||
|
sb.append(value).append(getTypeName(type)).append(" ");
|
||||||
|
}
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取牌型名称
|
||||||
|
*/
|
||||||
|
private static String getTypeName(int type) {
|
||||||
|
switch(type) {
|
||||||
|
case 1: return "万";
|
||||||
|
case 2: return "筒";
|
||||||
|
case 3: return "条";
|
||||||
|
default: return "字";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,425 @@
|
||||||
|
package taurus.util;
|
||||||
|
|
||||||
|
|
||||||
|
import robot.mj.handler.HuNanChangSha;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
public class TinHuPeng {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断是否能碰牌(包含碰牌后的听牌检查)
|
||||||
|
*/
|
||||||
|
public boolean canPeng(List<Integer> handCards, int card) {
|
||||||
|
int type = card / 100;
|
||||||
|
int value = card % 100;
|
||||||
|
|
||||||
|
if (type >= 4) return false; // 字牌不能碰(长沙麻将没有字牌)
|
||||||
|
|
||||||
|
System.out.println("\n要碰的牌: " + value + getTypeName(type));
|
||||||
|
System.out.println("当前手牌数量: " + handCards.size() + "张");
|
||||||
|
|
||||||
|
// 检查基本碰牌条件:手牌至少有2张相同的牌
|
||||||
|
if (!canPengBasic(handCards, card)) {
|
||||||
|
System.out.println(" 基本碰牌条件不满足:手牌没有2张" + value + getTypeName(type));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
System.out.println(" ✓ 手牌有2张" + value + getTypeName(type) + ",可以碰");
|
||||||
|
ChangShaSuanFaTest.isPeng = true;
|
||||||
|
// 检查碰牌后是否能听牌
|
||||||
|
return canTingAfterPengAndDiscard(handCards, card);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查基本碰牌条件
|
||||||
|
*/
|
||||||
|
private boolean canPengBasic(List<Integer> handCards, int card) {
|
||||||
|
// 碰牌:手牌有2张相同的牌,别人打出第3张
|
||||||
|
int count = 0;
|
||||||
|
for (int c : handCards) {
|
||||||
|
if (c == card) {
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return count >= 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查碰牌并打出一张后是否能听牌
|
||||||
|
*/
|
||||||
|
private boolean canTingAfterPengAndDiscard(List<Integer> handCards, int pengCard) {
|
||||||
|
// 1. 模拟碰牌:移除两张相同的牌,碰的牌不加入手牌
|
||||||
|
List<Integer> afterPeng = new ArrayList<>(handCards);
|
||||||
|
|
||||||
|
// 移除2张相同的牌
|
||||||
|
int removed = 0;
|
||||||
|
for (int i = 0; i < handCards.size() && removed < 2; i++) {
|
||||||
|
if (handCards.get(i) == pengCard) {
|
||||||
|
afterPeng.remove(Integer.valueOf(pengCard));
|
||||||
|
removed++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Collections.sort(afterPeng);
|
||||||
|
|
||||||
|
System.out.println(" 碰后手牌(" + afterPeng.size() + "张): " + convertToReadable(afterPeng));
|
||||||
|
|
||||||
|
// 2. 检查是否需要258将(花色是否>=10张)
|
||||||
|
boolean needs258 = !checkSuitCount(afterPeng);
|
||||||
|
if (needs258) {
|
||||||
|
System.out.println(" 花色牌数不足10张,需要258做将");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. 根据碰后手牌数确定目标手牌数
|
||||||
|
// 碰牌前后手牌数变化:碰前N张 -> 碰后(N-2)张 -> 打后(N-3)张
|
||||||
|
int targetSizeAfterDiscard = afterPeng.size() - 1;
|
||||||
|
System.out.println(" 目标手牌数: " + targetSizeAfterDiscard);
|
||||||
|
|
||||||
|
// 4. 尝试打每一张不同的牌
|
||||||
|
Set<Integer> uniqueCards = new HashSet<>(afterPeng);
|
||||||
|
boolean foundTing = false;
|
||||||
|
|
||||||
|
for (int discardCard : uniqueCards) {
|
||||||
|
List<Integer> afterDiscard = new ArrayList<>(afterPeng);
|
||||||
|
afterDiscard.remove(Integer.valueOf(discardCard));
|
||||||
|
Collections.sort(afterDiscard);
|
||||||
|
|
||||||
|
int discardType = discardCard / 100;
|
||||||
|
int discardValue = discardCard % 100;
|
||||||
|
|
||||||
|
System.out.print("\n 打" + discardValue + getTypeName(discardType) +
|
||||||
|
" → 剩余" + afterDiscard.size() + "张: " +
|
||||||
|
convertToReadable(afterDiscard));
|
||||||
|
|
||||||
|
// 5. 检查打牌后是否能听牌
|
||||||
|
boolean canTing = checkCanTing(afterDiscard, needs258, targetSizeAfterDiscard);
|
||||||
|
|
||||||
|
if (canTing) {
|
||||||
|
HuNanChangSha.isTinPeng = true;
|
||||||
|
System.out.println(" ✓ 听牌!");
|
||||||
|
foundTing = true;
|
||||||
|
|
||||||
|
// 分析听牌详情
|
||||||
|
analyzeTingDetails(afterDiscard, needs258);
|
||||||
|
} else {
|
||||||
|
System.out.println(" ✗ 不听");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return foundTing;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查手牌是否能听牌
|
||||||
|
*/
|
||||||
|
private boolean checkCanTing(List<Integer> hand, boolean needs258, int targetSize) {
|
||||||
|
if (hand.size() != targetSize) {
|
||||||
|
System.out.print(" [手牌数" + hand.size() + "≠目标" + targetSize + "]");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取所有可能的牌
|
||||||
|
Set<Integer> allCards = getAllCards();
|
||||||
|
|
||||||
|
for (int testCard : allCards) {
|
||||||
|
List<Integer> tempHand = new ArrayList<>(hand);
|
||||||
|
tempHand.add(testCard);
|
||||||
|
Collections.sort(tempHand);
|
||||||
|
|
||||||
|
// 检查是否能胡牌
|
||||||
|
if (canHu(tempHand, needs258)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查手牌是否能胡牌(考虑258将要求)
|
||||||
|
*/
|
||||||
|
private boolean canHu(List<Integer> handCards, boolean needs258) {
|
||||||
|
// 手牌排序
|
||||||
|
List<Integer> sorted = new ArrayList<>(handCards);
|
||||||
|
Collections.sort(sorted);
|
||||||
|
|
||||||
|
// 胡牌时手牌数必须是3n+2
|
||||||
|
if (sorted.size() % 3 != 2) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查七对子(特殊胡牌)
|
||||||
|
if (checkQiDuiZi(sorted)) {
|
||||||
|
// 七对子不需要258将
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果需要258将,检查普通胡牌(必须有258将)
|
||||||
|
if (needs258) {
|
||||||
|
return checkNormalHuWith258(sorted);
|
||||||
|
} else {
|
||||||
|
// 不需要258将,检查普通胡牌
|
||||||
|
return checkNormalHu(sorted);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分析听牌详情
|
||||||
|
*/
|
||||||
|
private void analyzeTingDetails(List<Integer> hand, boolean needs258) {
|
||||||
|
Set<Integer> tingCards = new HashSet<>();
|
||||||
|
Set<Integer> allCards = getAllCards();
|
||||||
|
|
||||||
|
for (int testCard : allCards) {
|
||||||
|
List<Integer> tempHand = new ArrayList<>(hand);
|
||||||
|
tempHand.add(testCard);
|
||||||
|
|
||||||
|
if (canHu(tempHand, needs258)) {
|
||||||
|
tingCards.add(testCard);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!tingCards.isEmpty()) {
|
||||||
|
System.out.print(" 听" + tingCards.size() + "张牌: ");
|
||||||
|
List<String> tingCardStrs = new ArrayList<>();
|
||||||
|
for (int card : tingCards) {
|
||||||
|
int type = card / 100;
|
||||||
|
int value = card % 100;
|
||||||
|
tingCardStrs.add(value + getTypeName(type));
|
||||||
|
}
|
||||||
|
System.out.println(String.join(", ", tingCardStrs));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查手牌花色牌数是否>=10张
|
||||||
|
*/
|
||||||
|
private boolean checkSuitCount(List<Integer> hand) {
|
||||||
|
// 统计万、筒、条各自的数量
|
||||||
|
Map<Integer, Integer> suitCount = new HashMap<>();
|
||||||
|
for (int card : hand) {
|
||||||
|
int type = card / 100;
|
||||||
|
if (type < 4) { // 只统计万筒条
|
||||||
|
suitCount.put(type, suitCount.getOrDefault(type, 0) + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查是否有某种花色>=10张
|
||||||
|
for (int count : suitCount.values()) {
|
||||||
|
if (count >= 10) {
|
||||||
|
return true; // 有花色>=10张,不需要258将
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false; // 没有花色>=10张,需要258将
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查七对子
|
||||||
|
*/
|
||||||
|
private boolean checkQiDuiZi(List<Integer> handCards) {
|
||||||
|
if (handCards.size() != 14) return false;
|
||||||
|
|
||||||
|
Map<Integer, Integer> countMap = new HashMap<>();
|
||||||
|
for (int card : handCards) {
|
||||||
|
countMap.put(card, countMap.getOrDefault(card, 0) + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查是否都是对子
|
||||||
|
for (int count : countMap.values()) {
|
||||||
|
if (count != 2) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查普通胡牌(必须有258将)
|
||||||
|
*/
|
||||||
|
private boolean checkNormalHuWith258(List<Integer> handCards) {
|
||||||
|
// 尝试每种258作为将牌
|
||||||
|
for (int card : handCards) {
|
||||||
|
int value = card % 100;
|
||||||
|
// 检查是否是258
|
||||||
|
if (value == 2 || value == 5 || value == 8) {
|
||||||
|
// 检查是否有至少2张相同的牌做将
|
||||||
|
int count = Collections.frequency(handCards, card);
|
||||||
|
if (count >= 2) {
|
||||||
|
// 移除将牌
|
||||||
|
List<Integer> remaining = new ArrayList<>(handCards);
|
||||||
|
for (int i = 0; i < 2; i++) {
|
||||||
|
remaining.remove(Integer.valueOf(card));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查剩余牌是否能组成顺子/刻子
|
||||||
|
if (canGroup(remaining)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查普通胡牌(不需要258将)
|
||||||
|
*/
|
||||||
|
private boolean checkNormalHu(List<Integer> handCards) {
|
||||||
|
return checkNormalHuRecursive(new ArrayList<>(handCards), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean checkNormalHuRecursive(List<Integer> handCards, boolean hasJiang) {
|
||||||
|
if (handCards.isEmpty()) {
|
||||||
|
return true; // 所有牌都分组成功
|
||||||
|
}
|
||||||
|
|
||||||
|
Collections.sort(handCards);
|
||||||
|
|
||||||
|
// 统计第一张牌的数量
|
||||||
|
int firstCard = handCards.get(0);
|
||||||
|
int count = Collections.frequency(handCards, firstCard);
|
||||||
|
|
||||||
|
// 尝试作为刻子(三张相同)
|
||||||
|
if (count >= 3) {
|
||||||
|
List<Integer> remaining = new ArrayList<>(handCards);
|
||||||
|
for (int i = 0; i < 3; i++) {
|
||||||
|
remaining.remove(Integer.valueOf(firstCard));
|
||||||
|
}
|
||||||
|
if (checkNormalHuRecursive(remaining, hasJiang)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 尝试作为顺子(三张连续)
|
||||||
|
int type = firstCard / 100;
|
||||||
|
int value = firstCard % 100;
|
||||||
|
|
||||||
|
if (type < 4 && value <= 7) { // 字牌和8、9不能组成顺子
|
||||||
|
int second = type * 100 + (value + 1);
|
||||||
|
int third = type * 100 + (value + 2);
|
||||||
|
|
||||||
|
if (handCards.contains(second) && handCards.contains(third)) {
|
||||||
|
List<Integer> remaining = new ArrayList<>(handCards);
|
||||||
|
remaining.remove(Integer.valueOf(firstCard));
|
||||||
|
remaining.remove(Integer.valueOf(second));
|
||||||
|
remaining.remove(Integer.valueOf(third));
|
||||||
|
if (checkNormalHuRecursive(remaining, hasJiang)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 尝试作为将(对子)- 只能有一个将
|
||||||
|
if (!hasJiang && count >= 2) {
|
||||||
|
List<Integer> remaining = new ArrayList<>(handCards);
|
||||||
|
remaining.remove(Integer.valueOf(firstCard));
|
||||||
|
remaining.remove(Integer.valueOf(firstCard));
|
||||||
|
if (checkNormalHuRecursive(remaining, true)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查牌是否能组成顺子或刻子
|
||||||
|
*/
|
||||||
|
private boolean canGroup(List<Integer> cards) {
|
||||||
|
if (cards.isEmpty()) {
|
||||||
|
return true; // 所有牌都分组成功
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Integer> sorted = new ArrayList<>(cards);
|
||||||
|
Collections.sort(sorted);
|
||||||
|
|
||||||
|
int firstCard = sorted.get(0);
|
||||||
|
int count = Collections.frequency(sorted, firstCard);
|
||||||
|
|
||||||
|
// 尝试作为刻子(三张相同)
|
||||||
|
if (count >= 3) {
|
||||||
|
List<Integer> remaining = new ArrayList<>(sorted);
|
||||||
|
for (int i = 0; i < 3; i++) {
|
||||||
|
remaining.remove(Integer.valueOf(firstCard));
|
||||||
|
}
|
||||||
|
if (canGroup(remaining)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 尝试作为顺子(三张连续)
|
||||||
|
int type = firstCard / 100;
|
||||||
|
int value = firstCard % 100;
|
||||||
|
|
||||||
|
if (type < 4 && value <= 7) { // 字牌和8、9不能组成顺子
|
||||||
|
int second = type * 100 + (value + 1);
|
||||||
|
int third = type * 100 + (value + 2);
|
||||||
|
|
||||||
|
if (sorted.contains(second) && sorted.contains(third)) {
|
||||||
|
List<Integer> remaining = new ArrayList<>(sorted);
|
||||||
|
remaining.remove(Integer.valueOf(firstCard));
|
||||||
|
remaining.remove(Integer.valueOf(second));
|
||||||
|
remaining.remove(Integer.valueOf(third));
|
||||||
|
if (canGroup(remaining)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取所有麻将牌
|
||||||
|
*/
|
||||||
|
private Set<Integer> getAllCards() {
|
||||||
|
Set<Integer> allCards = new HashSet<>();
|
||||||
|
// 万条筒 1-9
|
||||||
|
for (int type = 1; type <= 3; type++) {
|
||||||
|
for (int value = 1; value <= 9; value++) {
|
||||||
|
allCards.add(type * 100 + value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return allCards;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 转换为可读格式
|
||||||
|
*/
|
||||||
|
private String convertToReadable(List<Integer> cards) {
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
for (int card : cards) {
|
||||||
|
int type = card / 100;
|
||||||
|
int value = card % 100;
|
||||||
|
sb.append(value).append(getTypeName(type)).append(" ");
|
||||||
|
}
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取牌型名称
|
||||||
|
*/
|
||||||
|
private String getTypeName(int type) {
|
||||||
|
switch(type) {
|
||||||
|
case 1: return "万";
|
||||||
|
case 2: return "筒";
|
||||||
|
case 3: return "条";
|
||||||
|
default: return "字";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 手牌分析类
|
||||||
|
*/
|
||||||
|
class HandAnalysis {
|
||||||
|
int keziCount = 0; // 刻子数量
|
||||||
|
int pairCount = 0; // 对子数量
|
||||||
|
int shunziCount = 0; // 顺子数量
|
||||||
|
int singleCount = 0; // 单张数量
|
||||||
|
List<Integer> singles = new ArrayList<>(); // 单张列表
|
||||||
|
boolean has258Jiang = false; // 是否有258将
|
||||||
|
List<Integer> pairs = new ArrayList<>(); // 对子列表(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue