ludo-matchForAi

This commit is contained in:
khalil
2025-04-14 14:00:11 +08:00
parent 653f88f9c4
commit be2af4dcfe
10 changed files with 177 additions and 60 deletions

View File

@@ -227,7 +227,6 @@ public class RoomAdminController extends BaseController {
try {
int result = roomSearchAdminService.resetRoomTitleAndIntro(uid, title, roomDesc, introduction);
if (result > 0) {
usersService.updateUserTime(uid);
return new BusiResult<>(BusiStatus.SUCCESS);
}
} catch (Exception e) {

View File

@@ -1305,6 +1305,8 @@ public enum RedisKey {
//游戏匹配锁
mini_game_match_round_lock,
mini_game_match_ai_count,
//已使用
chat_room,

View File

@@ -44,9 +44,11 @@ public interface UsersMapperExpend {
*/
List<Users> getRobotUser(@Param("gender") Byte gender, @Param("limit") int limit);
int updateUserTime(@Param("uid") Long uid);
int updateUserTimeByErbanNo(@Param("erbanNo") Long erbanNo);
/**
* 获取机器人账号
* @return
*/
List<Users> listGameMatchRobotUser(@Param("partitionId") Integer partitionId);
List<Long> getUidByPage(@Param("offset") int offset, @Param("limit") int limit);

View File

@@ -95,25 +95,31 @@ public class ChatRoomForMiniGameService implements IChatRoom {
public Map<String, Object> getExtraData(ChatRoom chatRoom) {
Long chatRoomId = chatRoom.getChatRoomId();
Long roomId = chatRoom.getRoomId();
List<MiniGameMatch> miniGameMatches = miniGameMatchService.list(Wrappers.<MiniGameMatch>lambdaQuery()
.eq(MiniGameMatch::getRoomId, roomId)
.notIn(MiniGameMatch::getMatchStatus, NavGameMatchStatusEnum.FINISH.ordinal(), NavGameMatchStatusEnum.FAIL.ordinal())
.orderByDesc(MiniGameMatch::getCreateTime));
if (CollectionUtil.isEmpty(miniGameMatches)) {
RMap<Long, Long> matchRoundMap = miniGameMatchRoundService.getMatchRoundMap();
Long toMatchId = matchRoundMap.get(roomId);
if (null == toMatchId){
return Collections.emptyMap();
}
MiniGameMatch miniGameMatch = miniGameMatches.get(0);
Long miniGameMatchId = miniGameMatch.getId();
List<MiniGameMatchRound> miniGameMatchRounds = miniGameMatchRoundService.list(Wrappers.<MiniGameMatchRound>lambdaQuery()
.and(w -> w.eq(MiniGameMatchRound::getFromMatchId, miniGameMatchId).or().eq(MiniGameMatchRound::getToMatchId, miniGameMatchId))
.eq(MiniGameMatchRound::getRoundStatus, NavGameRoundStatusEnum.PROCESS.ordinal()));
MiniGameMatch miniGameMatch = miniGameMatchService.getById(toMatchId);
if (null == miniGameMatch
|| miniGameMatch.getMatchStatus().equals(NavGameMatchStatusEnum.FINISH.ordinal())
|| miniGameMatch.getMatchStatus().equals(NavGameMatchStatusEnum.FAIL.ordinal())){
return Collections.emptyMap();
}
MiniGameMatchRound miniGameMatchRound = miniGameMatchRoundService.getOne(Wrappers.<MiniGameMatchRound>lambdaQuery()
.eq(MiniGameMatchRound::getToMatchId, toMatchId)
.eq(MiniGameMatchRound::getRoundStatus, NavGameRoundStatusEnum.PROCESS.ordinal()), false);
if (null == miniGameMatchRound){
return Collections.emptyMap();
}
//匹配状态
Integer gameMode = miniGameMatch.getGameMode();
MiniGameForNavConfigDto config = sysConfService.getJsonValueById(Constant.SysConfId.MINI_GAME_FOR_NAV, MiniGameForNavConfigDto.class);
if (config == null) {
return Collections.emptyMap();
}
String mgId = config.getMgId();
MiniGameForNavConfigDto config = miniGameForNavService.getConfigDto();
Integer gameMode = miniGameMatchRound.getGameMode();
String mgId = miniGameMatch.getMgId();
MiniGame miniGame = miniGameService.queryMiniGameByMgId(Long.valueOf(mgId));
//游戏配置
ChatRoomForMiniGameDto dto = new ChatRoomForMiniGameDto();
@@ -124,19 +130,18 @@ public class ChatRoomForMiniGameService implements IChatRoom {
dto.setGameRoomIcon(gameRoomIcon.get(locale.getLanguage()));
}
dto.setMatchStatus(miniGameMatch.getMatchStatus());
if (CollectionUtil.isNotEmpty(miniGameMatchRounds)) {
MiniGameMatchRound miniGameMatchRound = miniGameMatchRounds.get(0);
dto.setMatchRoundId(miniGameMatchRound.getId());
dto.setRoundStatus(miniGameMatchRound.getRoundStatus());
Long fromUid = miniGameMatchRound.getFromUid();
Long toUid = miniGameMatchRound.getToUid();
if (fromUid != null) {
SpringContextHolder.getBean(ChatRoomManageServiceImpl.class).upMic(chatRoomId, 0, fromUid);
}
if (toUid != null) {
SpringContextHolder.getBean(ChatRoomManageServiceImpl.class).upMic(chatRoomId, 1, toUid);
}
dto.setMatchRoundId(miniGameMatchRound.getId());
dto.setRoundStatus(miniGameMatchRound.getRoundStatus());
Long fromUid = miniGameMatchRound.getFromUid();
Long toUid = miniGameMatchRound.getToUid();
if (fromUid != null) {
SpringContextHolder.getBean(ChatRoomManageServiceImpl.class).upMic(chatRoomId, 0, fromUid);
}
if (toUid != null) {
SpringContextHolder.getBean(ChatRoomManageServiceImpl.class).upMic(chatRoomId, 1, toUid);
}
Map<Integer, GameModeDto> gameModeMap = config.getGameModeMap();
GameModeDto gameModeDto = gameModeMap.get(gameMode);
String APP_COMMON_GAME_SETTING_SELECT_INFO = "app_common_game_setting_select_info";

View File

@@ -0,0 +1,102 @@
package com.accompany.business.service.miniGame;
import com.accompany.business.enums.game.NavGameMatchStatusEnum;
import com.accompany.business.model.miniGame.MiniGameMatch;
import com.accompany.business.mybatismapper.UsersMapperExpend;
import com.accompany.business.service.chat.ChatRoomManageService;
import com.accompany.business.service.user.UsersService;
import com.accompany.common.constant.Constant;
import com.accompany.common.redis.RedisKey;
import com.accompany.common.utils.AppVersionUtil;
import com.accompany.core.model.Users;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RMap;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import java.time.Instant;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
@Slf4j
@Service
public class MiniGameMatchAiService {
@Autowired
private RedissonClient redissonClient;
@Autowired
private UsersMapperExpend usersMapperExpend;
@Autowired
private UsersService usersService;
@Autowired
private MiniGameMatchService matchService;
@Autowired
@Lazy
private MiniGameForNavService miniGameForNavService;
@Autowired
private ChatRoomManageService chatRoomManageService;
private final String AI_ANDROID_APP_VERSION_LIMIT = "1.0.25";
private final String AI_IOS_APP_VERSION_LIMIT = "20.20.56";
public boolean matchForAi(MiniGameMatch fromMiniGameMatch) {
// Users u = usersService.getNotNullUsersByUid(fromMiniGameMatch.getUid());
// if (Constant.OsType.ANDROID.equalsIgnoreCase(u.getOs()) && AppVersionUtil.compareVersion(u.getAppVersion(), AI_ANDROID_APP_VERSION_LIMIT) <= 0){
// return false;
// } else if (Constant.OsType.IOS.equalsIgnoreCase(u.getOs()) && AppVersionUtil.compareVersion(u.getAppVersion(), AI_IOS_APP_VERSION_LIMIT) <= 0) {
// return false;
// }
List<Users> robotUsers = usersMapperExpend.listGameMatchRobotUser(fromMiniGameMatch.getPartitionId());
if (CollectionUtils.isEmpty(robotUsers)){
log.error("[ludo] 匹配ai 当前分区 {} 没有可用的赛事机器人了", fromMiniGameMatch.getPartitionId());
return false;
}
Set<Long> robotUidSet = robotUsers.stream().map(Users::getUid).collect(Collectors.toSet());
RMap<Long, Integer> matchAiCountMap = getMatchAiCountMap(fromMiniGameMatch.getUid());
Map<Long, Integer> matchCountMap = matchAiCountMap.getAll(robotUidSet);
int minMatchCount = !CollectionUtils.isEmpty(matchCountMap) ? matchCountMap.values().stream().min(Integer::compareTo).get(): 0;
Long robotUid = minMatchCount <= 0? robotUidSet.iterator().next():
matchCountMap.entrySet().stream().filter(it -> it.getValue().equals(minMatchCount)).map(Map.Entry::getKey).findAny().get();
Date now = new Date();
//保存匹配记录
MiniGameMatch toMiniGameMatch = new MiniGameMatch();
toMiniGameMatch.setUid(robotUid);
toMiniGameMatch.setRoomId(fromMiniGameMatch.getRoomId());
toMiniGameMatch.setMgId(fromMiniGameMatch.getMgId());
toMiniGameMatch.setGameMode(fromMiniGameMatch.getGameMode());
toMiniGameMatch.setMatchStatus(NavGameMatchStatusEnum.WAIT.ordinal());
toMiniGameMatch.setTicket(0d);
toMiniGameMatch.setPartitionId(fromMiniGameMatch.getPartitionId());
toMiniGameMatch.setCreateTime(now);
toMiniGameMatch.setUpdateTime(now);
matchService.save(toMiniGameMatch);
//匹配
miniGameForNavService.match(fromMiniGameMatch, toMiniGameMatch);
//手动触发进入聊天室
chatRoomManageService.enter(fromMiniGameMatch.getRoomId(), robotUid);
Integer afterNum = matchAiCountMap.addAndGet(robotUid, 1);
matchAiCountMap.expire(Instant.ofEpochSecond(now.getTime() + 60 * 60 * 24 * 7));
log.info("[ludo] 匹配ai 成功 fromMatch {} uid {} robotUid {} afterNum {}",
JSON.toJSONString(fromMiniGameMatch), fromMiniGameMatch.getUid(), robotUid, afterNum);
return true;
}
private RMap<Long, Integer> getMatchAiCountMap(Long uid){
return redissonClient.getMap(RedisKey.mini_game_match_ai_count.getKey(uid.toString()));
}
}

View File

@@ -108,6 +108,9 @@ public class MiniGameForNavServiceImpl implements MiniGameForNavService {
@Autowired
private UserInRoomService userInRoomService;
@Autowired
private MiniGameMatchAiService miniGameMatchAiService;
@Autowired
private RedissonClient redissonClient;
@@ -237,6 +240,7 @@ public class MiniGameForNavServiceImpl implements MiniGameForNavService {
//初始化
if (null == roomId){
ChatRoomServiceFactory.getServiceByType(ChatRoomTypeEnum.MINI_GAME.ordinal()).init(toChatRoom);
roomId = toChatRoom.getRoomId();
}
//保存匹配记录
@@ -281,9 +285,10 @@ public class MiniGameForNavServiceImpl implements MiniGameForNavService {
try {
for (int i = 0; i < matchSeconds; i++) {
log.info("fromMatchId : {}, roomId : {}, polling process match second : {}", toMiniGameMatch.getId(), toMiniGameMatch.getRoomId(), i);
if (matchForPolling(toMiniGameMatch)) {
if (matchForPolling(toMiniGameMatch, i)) {
return;
}
TimeUnit.SECONDS.sleep(1);
}
//匹配失败
@@ -295,11 +300,11 @@ public class MiniGameForNavServiceImpl implements MiniGameForNavService {
}
}
private boolean matchForPolling(MiniGameMatch fromMiniGameMatch) {
private boolean matchForPolling(MiniGameMatch fromMiniGameMatch, int second) {
RMap<Long, Long> matchRoundMap = miniGameMatchRoundService.getMatchRoundMap();
Long roundId = matchRoundMap.get(fromMiniGameMatch.getRoomId());
if (null == roundId){
return false;
return (second == 9 && matchForAi(fromMiniGameMatch));
}
RMap<Long, MiniGameMatch> waitGameMatchMap = miniGameMatchService.getWaitMatchMap(fromMiniGameMatch.getMgId(), fromMiniGameMatch.getGameMode(), fromMiniGameMatch.getPartitionId());
@@ -342,11 +347,17 @@ public class MiniGameForNavServiceImpl implements MiniGameForNavService {
}
//释放资源
chatRoomService.releaseByRoomId(toMiniGameMatch.getRoomId());
if (!fromMiniGameMatch.getRoomId().equals(toMiniGameMatch.getRoomId())){
chatRoomService.releaseByRoomId(toMiniGameMatch.getRoomId());
}
return true;
}
private boolean matchForAi(MiniGameMatch fromMiniGameMatch) {
return miniGameMatchAiService.matchForAi(fromMiniGameMatch);
}
@Override
public void matchForFail(MiniGameMatch miniGameMatch) {
if (null == miniGameMatch || null == miniGameMatch.getUid()) {
@@ -462,6 +473,9 @@ public class MiniGameForNavServiceImpl implements MiniGameForNavService {
}
Long roomId = fromMiniGameMatch.getRoomId();
RMap<Long, MiniGameMatch> waitMatchMap = miniGameMatchService.getWaitMatchMap(fromMiniGameMatch.getMgId(), fromMiniGameMatch.getGameMode(), fromMiniGameMatch.getPartitionId());
boolean quitWait = false;
boolean locked = false;
String redisKey = RedisKey.mini_game_match_round_lock.getKey(String.valueOf(roomId));
RLock lock = redissonClient.getLock(redisKey);
@@ -472,12 +486,14 @@ public class MiniGameForNavServiceImpl implements MiniGameForNavService {
throw new ServiceException(BusiStatus.SERVERERROR);
}
RMap<Long, MiniGameMatch> waitMatchMap = miniGameMatchService.getWaitMatchMap(fromMiniGameMatch.getMgId(), fromMiniGameMatch.getGameMode(), fromMiniGameMatch.getPartitionId());
if (!waitMatchMap.containsKey(fromMiniGameMatch.getId())){
MiniGameMatch waitFromMiniGameMatch = waitMatchMap.remove(fromMiniGameMatch.getId());
if (null == waitFromMiniGameMatch){
log.error("[ludo] 匹配 waitMatchMap 没有 from Id");
throw new ServiceException(BusiStatus.SERVERERROR);
}
quitWait = true;
boolean updateFromSuccess = miniGameMatchService.lambdaUpdate()
.set(MiniGameMatch::getMatchStatus, NavGameMatchStatusEnum.SUCCESS.ordinal())
.eq(MiniGameMatch::getId, fromMiniGameMatch.getId())
@@ -504,7 +520,6 @@ public class MiniGameForNavServiceImpl implements MiniGameForNavService {
miniGameMatchRoundService.save(round);
//设置麦位信息
Long fromUid = fromMiniGameMatch.getUid();
Long toUid = toMiniGameMatch.getUid();
//聊天室
ChatRoom fromChatRoom = chatRoomService.getByRoomId(fromMiniGameMatch.getRoomId());
@@ -512,20 +527,24 @@ public class MiniGameForNavServiceImpl implements MiniGameForNavService {
//上麦
chatRoomManageService.upMic(fromChatRoom.getChatRoomId(), toUid);
//下麦
chatRoomManageService.downMic(toChatRoom.getChatRoomId(), toUid);
if (!toChatRoom.getChatRoomId().equals(fromChatRoom.getChatRoomId())){
chatRoomManageService.downMic(toChatRoom.getChatRoomId(), toUid);
}
//设置匹配标识
RMap<Long, Long> matchRoundMap = miniGameMatchRoundService.getMatchRoundMap();
matchRoundMap.put(fromMiniGameMatch.getRoomId(), toMiniGameMatch.getId());
waitMatchMap.fastRemove(fromUid);
} catch (Exception e) {
log.error("[ludo] 匹配 异常", e);
} finally {
if (locked){
lock.unlock();
}
if (quitWait){
waitMatchMap.fastPut(fromMiniGameMatch.getId(), fromMiniGameMatch);
}
}
}

View File

@@ -86,8 +86,6 @@ public abstract class AbstractRoomService implements IRoom {
room.setBackPic(room.getDefBackpic());
}
}
//更新user的update time
usersService.updateUserTime(roomUid);
Room roomDb = roomService.getRoomByDB(roomUid);
if (roomDb != null) {
Byte roomType = room.getType();

View File

@@ -1055,7 +1055,6 @@ public class RoomService extends BaseService {
}
room.setAudioSdkType(getAudioSdkTypeInConfig());
insertRoom(room);
usersService.updateUserTime(room.getUid());
return room;
}

View File

@@ -704,14 +704,6 @@ public class UsersService extends BaseService {
return false;
}
public int updateUserTime(Long uid) {
return usersMapperExpend.updateUserTime(uid);
}
public int updateUserTimeByErbanNo(Long erbanNo) {
return usersMapperExpend.updateUserTimeByErbanNo(erbanNo);
}
public Users getUserByErbanNo(Long erbanNo) {
String userStr = this.jedisService.hget(RedisKey.user_erban_no.getKey(), erbanNo.toString());
if (!StringUtils.isEmpty(userStr)) {

View File

@@ -107,13 +107,6 @@
</foreach>
</update>
<update id="updateUserTime">
update users set update_time = now() where uid = #{uid}
</update>
<update id="updateUserTimeByErbanNo">
update users set update_time = now() where erban_no = #{erbanNo}
</update>
<select id="getRobotUser" resultType="com.accompany.core.model.Users">
SELECT <include refid="Base_Column_List"/> FROM users
<include refid="robot_user_condition"></include>
@@ -359,4 +352,10 @@
group by u.partition_id, u.region_id
</select>
<select id="listGameMatchRobotUser" resultMap="BaseResultMap">
select * from users u
where u.def_user = 6
and u.partition_id = #{partitionId}
</select>
</mapper>