ludo-重构匹配逻辑

This commit is contained in:
2025-04-14 01:57:15 +08:00
committed by khalil
parent bf8f9a71f9
commit 653f88f9c4
19 changed files with 461 additions and 412 deletions

View File

@@ -1302,10 +1302,8 @@ public enum RedisKey {
//游戏匹配
mini_game_match_wait,
mini_game_match_round,
//游戏匹配开始
mini_game_match_round_start_lock,
//游戏匹配关闭锁
mini_game_match_round_close_lock,
//游戏匹配锁
mini_game_match_round_lock,
//已使用
chat_room,

View File

@@ -0,0 +1,11 @@
package com.accompany.business.message;
import com.accompany.business.model.miniGame.MiniGameMatchRound;
import lombok.Data;
@Data
public class MiniGameMatchRoundMessage extends BaseMessage {
private MiniGameMatchRound round;
}

View File

@@ -12,8 +12,8 @@ import com.accompany.business.event.MiniGameSettlementEvent;
import com.accompany.business.model.chat.ChatRoom;
import com.accompany.business.model.miniGame.MiniGameMatch;
import com.accompany.business.model.miniGame.MiniGameMatchRound;
import com.accompany.business.service.SendSysMsgService;
import com.accompany.business.service.chat.ChatRoomService;
import com.accompany.business.service.miniGame.MiniGameForNavService;
import com.accompany.business.service.miniGame.MiniGameForSudService;
import com.accompany.business.service.miniGame.MiniGameMatchRoundService;
import com.accompany.business.service.miniGame.MiniGameMatchService;
@@ -21,17 +21,14 @@ import com.accompany.business.service.purse.UserPurseService;
import com.accompany.business.service.rank.IRank;
import com.accompany.business.service.rank.RankServiceFactory;
import com.accompany.business.service.record.BillRecordService;
import com.accompany.common.constant.Constant;
import com.accompany.common.netease.ErBanNetEaseService;
import com.accompany.common.redis.RedisKey;
import com.accompany.common.utils.GsonUtil;
import com.accompany.core.enumeration.BillObjTypeEnum;
import com.accompany.core.model.Users;
import com.accompany.core.service.SysConfService;
import com.accompany.core.service.common.JedisService;
import com.accompany.core.service.user.UsersBaseService;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RMap;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;
@@ -53,15 +50,15 @@ public class MiniGameForNavSettleListener implements ApplicationListener<MiniGam
private static final int WINNER_STATUS = 2;
@Autowired
private MiniGameForNavService miniGameForNavService;
@Autowired
private MiniGameMatchService miniGameMatchService;
@Autowired
private MiniGameMatchRoundService miniGameMatchRoundService;
@Autowired
private SysConfService sysConfService;
@Autowired
private UsersBaseService usersBaseService;
@@ -74,18 +71,12 @@ public class MiniGameForNavSettleListener implements ApplicationListener<MiniGam
@Autowired
private ChatRoomService chatRoomService;
@Autowired
private SendSysMsgService sendSysMsgService;
@Autowired
private ErBanNetEaseService erBanNetEaseService;
@Autowired
private MiniGameForSudService miniGameForSudService;
@Autowired
private JedisService jedisService;
@Transactional(rollbackFor = Exception.class)
@Override
public void onApplicationEvent(MiniGameSettlementEvent event) {
@@ -100,36 +91,19 @@ public class MiniGameForNavSettleListener implements ApplicationListener<MiniGam
return;
}
Long roomId = Long.valueOf(roomIdStr);
String roundStr = jedisService.get(RedisKey.mini_game_match_round.getKey(String.valueOf(roomId)));
if (StrUtil.isEmpty(roundStr)) {
RMap<Long, Long> roundCacheMap = miniGameMatchRoundService.getMatchRoundMap();
Long roundId = roundCacheMap.remove(roomId);
if (null == roundId){
return;
}
String[] roundArray = roundStr.split(StrUtil.UNDERLINE);
Long matchRoundId = Long.valueOf(roundArray[2]);
List<MiniGameMatchRound> miniGameMatchRounds = miniGameMatchRoundService.list(Wrappers.<MiniGameMatchRound>lambdaQuery()
.eq(MiniGameMatchRound::getId, matchRoundId)
.eq(MiniGameMatchRound::getRoundStatus, NavGameRoundStatusEnum.PROCESS.ordinal()));
if (CollectionUtil.isEmpty(miniGameMatchRounds)) {
return;
}
MiniGameMatchRound miniGameMatchRound = miniGameMatchRounds.get(0);
Long fromMatchId = miniGameMatchRound.getFromMatchId();
Long toMatchId = miniGameMatchRound.getToMatchId();
MiniGameMatch fromMiniGameMatch = miniGameMatchService.getById(fromMatchId);
if (fromMiniGameMatch == null) {
return;
}
MiniGameMatch toMiniGameMatch = miniGameMatchService.getById(toMatchId);
if (toMiniGameMatch == null) {
return;
}
if (fromMiniGameMatch.getMatchStatus() == NavGameMatchStatusEnum.FINISH.ordinal() || toMiniGameMatch.getMatchStatus() == NavGameMatchStatusEnum.FINISH.ordinal()) {
return;
}
MiniGameForNavConfigDto config = sysConfService.getJsonValueById(Constant.SysConfId.MINI_GAME_FOR_NAV, MiniGameForNavConfigDto.class);
if (config == null) {
MiniGameMatchRound miniGameMatchRound = miniGameMatchRoundService.getById(roundId);
if (null == miniGameMatchRound || miniGameMatchRound.getRoundStatus() != NavGameRoundStatusEnum.PROCESS.ordinal()){
return;
}
MiniGameForNavConfigDto config = miniGameForNavService.getConfigDto();
String mgId = config.getMgId();
if (!gameEndDto.getMg_id_str().equals(mgId)) {
log.info("config mgId : {}, game end mgId : {}", mgId, gameEndDto.getMg_id_str());
@@ -154,9 +128,11 @@ public class MiniGameForNavSettleListener implements ApplicationListener<MiniGam
miniGameMatchRound.setWinUid(winUid);
miniGameMatchRound.setWinNum(winner);
miniGameMatchRound.setPlatformNum(platform);
userPurseService.addDiamond(winUid, winner, BillObjTypeEnum.MINI_GAME_MATCH_WINNER_IN,
(userPurse -> billRecordService.insertGeneralBillRecord(userPurse.getUid(), miniGameMatchRound.getId().toString(),
BillObjTypeEnum.MINI_GAME_MATCH_WINNER_IN, winner, userPurse)));
//榜单
Map<String, IRank> rankMap = RankServiceFactory.getServiceByType(RedisKey.mini_game_rank.name());
if (CollectionUtil.isNotEmpty(rankMap)) {
@@ -167,23 +143,30 @@ public class MiniGameForNavSettleListener implements ApplicationListener<MiniGam
}
}
}
//更新匹配
miniGameMatchRound.setRoundStatus(NavGameRoundStatusEnum.END.ordinal());
miniGameMatchRoundService.updateById(miniGameMatchRound);
fromMiniGameMatch.setMatchStatus(NavGameMatchStatusEnum.FINISH.ordinal());
miniGameMatchService.updateById(fromMiniGameMatch);
toMiniGameMatch.setMatchStatus(NavGameMatchStatusEnum.FINISH.ordinal());
miniGameMatchService.updateById(toMiniGameMatch);
Long fromMatchId = miniGameMatchRound.getFromMatchId();
Long toMatchId = miniGameMatchRound.getToMatchId();
miniGameMatchService.lambdaUpdate()
.set(MiniGameMatch::getMatchStatus, NavGameMatchStatusEnum.FINISH.ordinal())
.in(MiniGameMatch::getId, fromMatchId, toMatchId)
.eq(MiniGameMatch::getMatchStatus, NavGameMatchStatusEnum.SUCCESS.ordinal())
.update();
//释放房间
chatRoomService.releaseByRoomId(miniGameMatchRound.getRoomId());
ChatRoom chatRoom = chatRoomService.getByRoomId(miniGameMatchRound.getRoomId());
if (chatRoom != null) {
jedisService.del(RedisKey.room_mic_list.getKey(String.valueOf(chatRoom.getChatRoomId())));
//房间踢人
erBanNetEaseService.kickMember(String.valueOf(chatRoom.getRoomId()), String.valueOf(fromMiniGameMatch.getUid()), String.valueOf(chatRoom.getChatRoomId()), null);
erBanNetEaseService.kickMember(String.valueOf(chatRoom.getRoomId()), String.valueOf(toMiniGameMatch.getUid()), String.valueOf(chatRoom.getChatRoomId()), null);
erBanNetEaseService.kickMember(String.valueOf(chatRoom.getRoomId()), String.valueOf(miniGameMatchRound.getFromUid()), String.valueOf(chatRoom.getChatRoomId()), null);
erBanNetEaseService.kickMember(String.valueOf(chatRoom.getRoomId()), String.valueOf(miniGameMatchRound.getToUid()), String.valueOf(chatRoom.getChatRoomId()), null);
//房间清理
miniGameForSudService.pushRoomClearEvent(fromMiniGameMatch.getMgId(), chatRoom.getRoomId());
miniGameForSudService.pushRoomClearEvent(mgId, chatRoom.getRoomId());
}
}
}

View File

@@ -1,17 +1,13 @@
package com.accompany.business.event.listener.miniGame;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import com.accompany.business.dto.miniGame.GameStartDto;
import com.accompany.business.enums.game.NavGameRoundStatusEnum;
import com.accompany.business.event.MiniGameStartEvent;
import com.accompany.business.model.miniGame.MiniGameMatchRound;
import com.accompany.business.service.miniGame.MiniGameMatchRoundService;
import com.accompany.common.redis.RedisKey;
import com.accompany.common.utils.GsonUtil;
import com.accompany.core.service.common.JedisService;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RMap;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;
@@ -30,10 +26,6 @@ public class MiniGameForNavStartListener implements ApplicationListener<MiniGame
@Autowired
private MiniGameMatchRoundService miniGameMatchRoundService;
@Autowired
private JedisService jedisService;
@Override
public void onApplicationEvent(MiniGameStartEvent event) {
Object source = event.getSource();
@@ -47,19 +39,14 @@ public class MiniGameForNavStartListener implements ApplicationListener<MiniGame
return;
}
Long roomId = Long.valueOf(roomIdStr);
String roundStr = jedisService.get(RedisKey.mini_game_match_round.getKey(String.valueOf(roomId)));
if (StrUtil.isEmpty(roundStr)) {
RMap<Long, Long> roundCacheMap = miniGameMatchRoundService.getMatchRoundMap();
Long roundId = roundCacheMap.get(roomId);
if (null == roundId){
return;
}
String[] roundArray = roundStr.split(StrUtil.UNDERLINE);
Long matchRoundId = Long.valueOf(roundArray[2]);
List<MiniGameMatchRound> miniGameMatchRounds = miniGameMatchRoundService.list(Wrappers.<MiniGameMatchRound>lambdaQuery()
.eq(MiniGameMatchRound::getId, matchRoundId)
.eq(MiniGameMatchRound::getRoundStatus, NavGameRoundStatusEnum.PROCESS.ordinal()));
if (CollectionUtil.isEmpty(miniGameMatchRounds)) {
return;
}
MiniGameMatchRound miniGameMatchRound = miniGameMatchRounds.get(0);
MiniGameMatchRound miniGameMatchRound = miniGameMatchRoundService.getById(roundId);
miniGameMatchRound.setGameRoundId(gameStartDto.getGame_round_id());
miniGameMatchRoundService.updateById(miniGameMatchRound);
}

View File

@@ -10,10 +10,6 @@ import com.baomidou.mybatisplus.extension.service.IService;
*/
public interface ChatRoomService extends IService<ChatRoom> {
default ChatRoom getOrOpen(Long uid, Integer roomType) {
return getOrOpen(null, uid, roomType);
}
/**
* 获取/开启聊天室
* @param roomId
@@ -23,11 +19,7 @@ public interface ChatRoomService extends IService<ChatRoom> {
*/
ChatRoom getOrOpen(Long roomId, Long uid, Integer roomType);
/**
* 释放聊天室
* @param uid
*/
void releaseByUid(Long uid);
ChatRoom getRoomByUid(Long uid);
/**
* 释放聊天室

View File

@@ -18,6 +18,8 @@ public interface IChatRoom {
*/
ChatRoomTypeEnum roomType();
ChatRoom getRoomByUid(Long uid);
/**
* 获取扩展属性
* @param chatRoom
@@ -31,13 +33,6 @@ public interface IChatRoom {
*/
Integer[] wheatBit();
/**
* 获取房间ID
* @param uid
* @return
*/
Long getRoomIdByUid(Long uid);
/**
* 初始化
* @param chatRoom

View File

@@ -5,10 +5,10 @@ import cn.hutool.core.util.StrUtil;
import com.accompany.business.dto.chat.ChatRoomForMiniGameDto;
import com.accompany.business.dto.miniGame.GameModeDto;
import com.accompany.business.dto.miniGame.MiniGameForNavConfigDto;
import com.accompany.business.dto.miniGame.MiniGameMatchRoundDto;
import com.accompany.business.enums.chat.ChatRoomTypeEnum;
import com.accompany.business.enums.game.NavGameMatchStatusEnum;
import com.accompany.business.enums.game.NavGameRoundStatusEnum;
import com.accompany.business.message.MiniGameMatchRoundMessage;
import com.accompany.business.model.chat.ChatRoom;
import com.accompany.business.model.miniGame.MiniGame;
import com.accompany.business.model.miniGame.MiniGameMatch;
@@ -20,6 +20,7 @@ import com.accompany.business.service.miniGame.MiniGameForNavService;
import com.accompany.business.service.miniGame.MiniGameMatchRoundService;
import com.accompany.business.service.miniGame.MiniGameMatchService;
import com.accompany.business.service.miniGame.MiniGameService;
import com.accompany.business.service.mq.RocketMQService;
import com.accompany.business.vo.chat.ChatRoomVo;
import com.accompany.common.constant.Constant;
import com.accompany.common.redis.RedisKey;
@@ -30,14 +31,12 @@ import com.accompany.core.service.common.JedisService;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RMap;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
/**
* @author: liaozetao
@@ -72,14 +71,26 @@ public class ChatRoomForMiniGameService implements IChatRoom {
@Autowired
private SendSysMsgService sendSysMsgService;
@Resource(name = "bizExecutor")
private ThreadPoolExecutor bizExecutor;
@Autowired
private RocketMQService rocketMQService;
@Override
public ChatRoomTypeEnum roomType() {
return ChatRoomTypeEnum.MINI_GAME;
}
@Override
public ChatRoom getRoomByUid(Long uid) {
MiniGameMatch miniGameMatch = miniGameMatchService.getOne(Wrappers.<MiniGameMatch>lambdaQuery()
.eq(MiniGameMatch::getUid, uid)
.notIn(MiniGameMatch::getMatchStatus, NavGameMatchStatusEnum.FINISH.ordinal(), NavGameMatchStatusEnum.FAIL.ordinal())
.orderByDesc(MiniGameMatch::getId), false);
if (null == miniGameMatch){
return null;
}
return chatRoomService.getRoomByUid(uid);
}
@Override
public Map<String, Object> getExtraData(ChatRoom chatRoom) {
Long chatRoomId = chatRoom.getChatRoomId();
@@ -170,19 +181,6 @@ public class ChatRoomForMiniGameService implements IChatRoom {
return new Integer[]{0, 1};
}
@Override
public Long getRoomIdByUid(Long uid) {
List<MiniGameMatch> miniGameMatches = miniGameMatchService.list(Wrappers.<MiniGameMatch>lambdaQuery()
.eq(MiniGameMatch::getUid, uid)
.notIn(MiniGameMatch::getMatchStatus, NavGameMatchStatusEnum.FINISH.ordinal(), NavGameMatchStatusEnum.FAIL.ordinal())
.orderByDesc(MiniGameMatch::getCreateTime));
if (CollectionUtil.isEmpty(miniGameMatches)) {
return null;
}
MiniGameMatch miniGameMatch = miniGameMatches.get(0);
return miniGameMatch.getRoomId();
}
@Override
public void init(ChatRoom chatRoom) {
jedisService.del(RedisKey.room_mic_list.getKey(String.valueOf(chatRoom.getChatRoomId())));
@@ -190,7 +188,8 @@ public class ChatRoomForMiniGameService implements IChatRoom {
@Override
public void close(Long roomId, Long uid) {
jedisService.del(RedisKey.mini_game_match_round.getKey(String.valueOf(uid)));
RMap<Long, Long> roundCacheMap = miniGameMatchRoundService.getMatchRoundMap();
roundCacheMap.fastRemove(roomId);
List<MiniGameMatch> miniGameMatches = miniGameMatchService.list(Wrappers.<MiniGameMatch>lambdaQuery()
.eq(MiniGameMatch::getRoomId, roomId)
@@ -199,56 +198,36 @@ public class ChatRoomForMiniGameService implements IChatRoom {
if (CollectionUtil.isNotEmpty(miniGameMatches)) {
//释放资源
for (MiniGameMatch miniGameMatch : miniGameMatches) {
miniGameForNavService.matchForFail(miniGameMatch.getId());
miniGameForNavService.matchForFail(miniGameMatch);
}
}
miniGameForNavService.closeGame(roomId);
}
@Override
public void enter(Long roomId, Long uid) {
if (!jedisService.exits(RedisKey.mini_game_match_round.getKey(String.valueOf(uid)))) {
jedisService.setex(RedisKey.mini_game_match_round.getKey(String.valueOf(uid)), 24 * 60 * 60, String.valueOf(roomId));
}
List<MiniGameMatchRound> miniGameMatchRounds = miniGameMatchRoundService.list(Wrappers.<MiniGameMatchRound>lambdaQuery()
.eq(MiniGameMatchRound::getRoomId, roomId)
.eq(MiniGameMatchRound::getRoundStatus, NavGameRoundStatusEnum.PROCESS.ordinal()));
if (CollectionUtil.isEmpty(miniGameMatchRounds)) {
RMap<Long, Long> roundCacheMap = miniGameMatchRoundService.getMatchRoundMap();
if (!roundCacheMap.containsKey(roomId)){
return;
}
MiniGameForNavConfigDto config = miniGameForNavService.getConfigDto();
MiniGameMatchRound miniGameMatchRound = miniGameMatchRounds.get(0);
Long matchRoundId = miniGameMatchRound.getId();
Long fromUid = miniGameMatchRound.getFromUid();
Long toUid = miniGameMatchRound.getToUid();
if (!jedisService.exits(RedisKey.mini_game_match_round.getKey(String.valueOf(roomId)))) {
return;
}
if (jedisService.exits(RedisKey.mini_game_match_round.getKey(String.valueOf(fromUid)))
&& jedisService.exits(RedisKey.mini_game_match_round.getKey(String.valueOf(toUid)))) {
//聊天室
ChatRoomVo chatRoomVo = SpringContextHolder.getBean(ChatRoomManageServiceImpl.class).getByRoomId(roomId);
//匹配成功
sendSysMsgService.sendSingleRoomMessage(roomId, chatRoomVo.getChatRoomId().toString(), Constant.DefMsgType.MINI_GAME_MATCH, Constant.DefMsgType.MINI_GAME_MATCH_FOR_CHANGE, chatRoomVo);
Integer successSeconds = config.getSuccessSeconds();
bizExecutor.submit(() -> {
try {
for (int i = 0; i < successSeconds; i++) {
log.info("roomId : {}, uid : {}, polling success match second : {}", roomId, uid, i);
if (miniGameForNavService.matchForSuccess(matchRoundId)) {
return;
}
TimeUnit.SECONDS.sleep(1);
}
//平局
miniGameForNavService.matchForEqualize(matchRoundId);
//匹配失败
sendSysMsgService.sendSingleRoomMessage(roomId, chatRoomVo.getChatRoomId().toString(), Constant.DefMsgType.MINI_GAME_MATCH, Constant.DefMsgType.MINI_GAME_MATCH_FOR_FAIL, new MiniGameMatchRoundDto());
} catch (Exception e) {
log.error(e.getMessage(), e);
}
});
MiniGameMatchRound miniGameMatchRound = miniGameMatchRoundService.getOne(Wrappers.<MiniGameMatchRound>lambdaQuery()
.eq(MiniGameMatchRound::getRoomId, roomId)
.eq(MiniGameMatchRound::getRoundStatus, NavGameRoundStatusEnum.PROCESS.ordinal())
.orderByDesc(MiniGameMatchRound::getId), false);
if (null == miniGameMatchRound) {
roundCacheMap.fastRemove(roomId);
return;
}
//聊天室
ChatRoomVo chatRoomVo = SpringContextHolder.getBean(ChatRoomManageServiceImpl.class).getByRoomId(roomId);
//匹配成功
sendSysMsgService.sendSingleRoomMessage(roomId, chatRoomVo.getChatRoomId().toString(), Constant.DefMsgType.MINI_GAME_MATCH, Constant.DefMsgType.MINI_GAME_MATCH_FOR_CHANGE, chatRoomVo);
MiniGameMatchRoundMessage message = new MiniGameMatchRoundMessage();
message.setRound(miniGameMatchRound);
rocketMQService.sendMiniGameMatchRoundMsg(message);
}
}

View File

@@ -50,13 +50,19 @@ public class ChatRoomManageServiceImpl implements ChatRoomManageService {
ChatRoomVo vo = new ChatRoomVo();
vo.setRoomId(roomId);
ChatRoom chatRoom = chatRoomService.getByRoomId(roomId);
if (chatRoom == null) {
return getByRoom(chatRoom);
}
public ChatRoomVo getByRoom(ChatRoom chatRoom) {
if (null == chatRoom){
return null;
}
Long chatRoomId = chatRoom.getChatRoomId();
vo.setChatRoomId(chatRoomId);
ChatRoomVo vo = new ChatRoomVo();
vo.setRoomId(chatRoom.getRoomId());
vo.setChatRoomId(chatRoom.getChatRoomId());
vo.setRoomType(chatRoom.getRoomType());
vo.setRoomMics(getRoomMics(chatRoomId));
vo.setRoomMics(getRoomMics(chatRoom.getChatRoomId()));
IChatRoom iChatRoom = ChatRoomServiceFactory.getServiceByType(chatRoom.getRoomType());
if (iChatRoom != null) {
vo.setData(iChatRoom.getExtraData(chatRoom));
@@ -66,16 +72,13 @@ public class ChatRoomManageServiceImpl implements ChatRoomManageService {
@Override
public ChatRoomVo getByUidAndType(Long uid, Integer roomType) {
Long roomId = ChatRoomServiceFactory.getServiceByType(roomType).getRoomIdByUid(uid);
if (roomId == null) {
return null;
}
return getByRoomId(roomId);
ChatRoom chatRoom = ChatRoomServiceFactory.getServiceByType(roomType).getRoomByUid(uid);
return getByRoom(chatRoom);
}
@Override
public List<RoomMic> getRoomMics(Long chatRoomId) {
ChatRoom chatRoom = chatRoomService.getById(chatRoomId);
ChatRoom chatRoom = chatRoomService.getByRoomId(chatRoomId);
if (chatRoom == null) {
return Collections.emptyList();
}
@@ -165,8 +168,6 @@ public class ChatRoomManageServiceImpl implements ChatRoomManageService {
ChatRoomServiceFactory.getServiceByType(roomType).close(roomId, uid);
//解除关联
chatRoomService.releaseByRoomId(roomId);
//清除缓存
jedisService.del(RedisKey.room_mic_list.getKey(String.valueOf(roomId)));
}
@Override

View File

@@ -15,6 +15,7 @@ import com.accompany.common.utils.BeanUtil;
import com.accompany.common.utils.UUIDUtil;
import com.accompany.core.exception.ServiceException;
import com.accompany.core.service.account.NetEaseService;
import com.accompany.core.service.common.JedisService;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.SneakyThrows;
@@ -27,7 +28,6 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
@@ -41,6 +41,9 @@ import java.util.concurrent.TimeUnit;
@Service
public class ChatRoomServiceImpl extends ServiceImpl<ChatRoomMapper, ChatRoom> implements ChatRoomService, InitializingBean {
@Autowired
private JedisService jedisService;
@Autowired
private NetEaseService netEaseService;
@@ -50,7 +53,7 @@ public class ChatRoomServiceImpl extends ServiceImpl<ChatRoomMapper, ChatRoom> i
@Autowired
private RedissonClient redissonClient;
private RMap<Long, ChatRoom> chatRoomCacheMap;
private RMap<Long, ChatRoom> workingChatRoomCacheMap;
@SneakyThrows
@Override
@@ -69,7 +72,7 @@ public class ChatRoomServiceImpl extends ServiceImpl<ChatRoomMapper, ChatRoom> i
throw new ServiceException(BusiStatus.SERVERBUSY);
}
Set<Long> roomIdSet = chatRoomCacheMap.keySet();
Set<Long> roomIdSet = workingChatRoomCacheMap.keySet();
ChatRoom chatRoom = getOne(Wrappers.<ChatRoom>lambdaQuery()
.isNull(ChatRoom::getRefUid)
.notIn(CollectionUtil.isNotEmpty(roomIdSet), ChatRoom::getRoomId, roomIdSet)
@@ -109,7 +112,7 @@ public class ChatRoomServiceImpl extends ServiceImpl<ChatRoomMapper, ChatRoom> i
log.info("chat room new : {}", chatRoom.getRoomId());
}
chatRoomCacheMap.put(chatRoom.getRoomId(), chatRoom);
workingChatRoomCacheMap.fastPut(chatRoom.getRoomId(), chatRoom);
return chatRoom;
@@ -121,14 +124,21 @@ public class ChatRoomServiceImpl extends ServiceImpl<ChatRoomMapper, ChatRoom> i
}
@Override
public void releaseByUid(Long uid) {
List<ChatRoom> chatRooms = list(Wrappers.<ChatRoom>lambdaQuery()
.eq(ChatRoom::getRefUid, uid));
release(chatRooms);
public ChatRoom getRoomByUid(Long uid){
Map<Long, ChatRoom> workingChatRoomMap = workingChatRoomCacheMap.readAllMap();
if (CollectionUtil.isEmpty(workingChatRoomMap)){
return null;
}
return workingChatRoomMap.values().stream()
.filter(chatRoom -> uid.equals(chatRoom.getRefUid()))
.findFirst().orElse(null);
}
@Override
public void releaseByRoomId(Long roomId) {
workingChatRoomCacheMap.fastRemove(roomId);
ChatRoom chatRoom = getOne(Wrappers.<ChatRoom>lambdaQuery()
.eq(ChatRoom::getRoomId, roomId), false);
if (null == chatRoom){
@@ -138,27 +148,22 @@ public class ChatRoomServiceImpl extends ServiceImpl<ChatRoomMapper, ChatRoom> i
chatRoom.setUpdateTime(new Date());
updateById(chatRoom);
chatRoomCacheMap.fastRemove(roomId);
}
private void release(List<ChatRoom> chatRooms) {
Date now = new Date();
for (ChatRoom chatRoom : chatRooms) {
chatRoom.setRefUid(null);
chatRoom.setUpdateTime(now);
}
updateBatchById(chatRooms);
chatRoomCacheMap.fastRemove(chatRooms.stream().map(ChatRoom::getRoomId).toArray(Long[]::new));
//清除缓存
jedisService.del(RedisKey.room_mic_list.getKey(String.valueOf(roomId)));
}
@Override
public ChatRoom getByRoomId(Long roomId) {
ChatRoom woringChatRoom = workingChatRoomCacheMap.get(roomId);
if (null != woringChatRoom){
return woringChatRoom;
}
return getOne(Wrappers.<ChatRoom>lambdaQuery()
.eq(ChatRoom::getRoomId, roomId), false);
}
@Override
public void afterPropertiesSet() throws Exception {
chatRoomCacheMap = redissonClient.getMap(RedisKey.chat_room.getKey());
workingChatRoomCacheMap = redissonClient.getMap(RedisKey.chat_room.getKey());
}
}

View File

@@ -1,6 +1,7 @@
package com.accompany.business.service.miniGame;
import com.accompany.business.dto.miniGame.MiniGameForNavConfigDto;
import com.accompany.business.model.miniGame.MiniGameMatch;
import com.accompany.business.vo.chat.ChatRoomVo;
import com.accompany.business.vo.miniGame.MiniGameVo;
@@ -25,20 +26,7 @@ public interface MiniGameForNavService {
*/
void start(String mgId, Integer gameMode);
/**
*
* @param roomId
* @param mgId
* @param gameMode
* @return
*/
boolean matchForPolling(Long roomId, String mgId, Integer gameMode);
/**
* 匹配失败
* @param miniGameMatchId
*/
void matchForFail(Long miniGameMatchId);
void matchForFail(MiniGameMatch miniGameMatch);
/**
* 匹配成功
@@ -54,10 +42,10 @@ public interface MiniGameForNavService {
/**
* 匹配
* @param fromMatchId
* @param toMatchId
* @param fromMiniGameMatch
* @param toMiniGameMatch
*/
void match(Long fromMatchId, Long toMatchId);
void match(MiniGameMatch fromMiniGameMatch, MiniGameMatch toMiniGameMatch);
/**
* 关闭游戏

View File

@@ -2,6 +2,7 @@ package com.accompany.business.service.miniGame;
import com.accompany.business.model.miniGame.MiniGameMatchRound;
import com.baomidou.mybatisplus.extension.service.IService;
import org.redisson.api.RMap;
/**
* @author: liaozetao
@@ -9,4 +10,5 @@ import com.baomidou.mybatisplus.extension.service.IService;
* @description:
*/
public interface MiniGameMatchRoundService extends IService<MiniGameMatchRound> {
RMap<Long, Long> getMatchRoundMap();
}

View File

@@ -2,6 +2,7 @@ package com.accompany.business.service.miniGame;
import com.accompany.business.model.miniGame.MiniGameMatch;
import com.baomidou.mybatisplus.extension.service.IService;
import org.redisson.api.RMap;
/**
* @author: liaozetao
@@ -9,4 +10,7 @@ import com.baomidou.mybatisplus.extension.service.IService;
* @description:
*/
public interface MiniGameMatchService extends IService<MiniGameMatch> {
RMap<Long, MiniGameMatch> getWaitMatchMap(String mgId, Integer gameMode, Integer partitionId);
}

View File

@@ -38,11 +38,10 @@ import com.accompany.core.enumeration.BillObjTypeEnum;
import com.accompany.core.exception.ServiceException;
import com.accompany.core.model.Users;
import com.accompany.core.service.SysConfService;
import com.accompany.core.service.common.JedisLockService;
import com.accompany.core.service.common.JedisService;
import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RMap;
import org.redisson.api.RedissonClient;
import org.springframework.beans.BeanUtils;
@@ -97,12 +96,6 @@ public class MiniGameForNavServiceImpl implements MiniGameForNavService {
@Autowired
private SendSysMsgService sendSysMsgService;
@Autowired
private JedisService jedisService;
@Autowired
private JedisLockService jedisLockService;
@Resource(name = "bizExecutor")
private ThreadPoolExecutor bizExecutor;
@@ -114,6 +107,7 @@ public class MiniGameForNavServiceImpl implements MiniGameForNavService {
@Autowired
private UserInRoomService userInRoomService;
@Autowired
private RedissonClient redissonClient;
@@ -210,85 +204,90 @@ public class MiniGameForNavServiceImpl implements MiniGameForNavService {
//扣减钱包,创建完轮次后再插入账单
UserPurse afterPurse = userPurseService.subDiamond(uid, diamondNum, BillObjTypeEnum.MINI_GAME_MATCH_ENTER_OUT, BusiStatus.DIAMONDNUMNOTENOUGH, UserPurse::getDiamonds);
Long roomId = null;
//别的玩家已经发起等待的房间
MiniGameMatch fromMiniGameMatch = null;
RMap<Long, MiniGameMatch> waitMatchMap = getWaitMatchMap(mgId, gameMode, partitionId);
List<MiniGameMatch> waitMatchList = waitMatchMap.values().stream()
Long roomId = null;
RMap<Long, MiniGameMatch> waitMatchMap = miniGameMatchService.getWaitMatchMap(mgId, gameMode, partitionId);
List<MiniGameMatch> otherWaitMatchList = waitMatchMap.values().stream()
.filter(miniGameMatch -> !miniGameMatch.getUid().equals(uid))
.sorted(Comparator.comparing(MiniGameMatch::getCreateTime))
.collect(Collectors.toList());
if (CollectionUtil.isNotEmpty(waitMatchList)) {
RMap<Long, Long> matchRoundMap = miniGameMatchRoundService.getMatchRoundMap();
if (CollectionUtil.isNotEmpty(otherWaitMatchList)) {
for (int i = 0, j = 0; j < 3 && (fromMiniGameMatch == null
|| jedisService.exits(RedisKey.mini_game_match_round.getKey(String.valueOf(fromMiniGameMatch.getUid()))));
i = RandomUtil.randomByRange(0, waitMatchList.size()), j++) {
fromMiniGameMatch = waitMatchList.get(i);
|| matchRoundMap.containsKey(fromMiniGameMatch.getRoomId()));
i = RandomUtil.randomByRange(0, otherWaitMatchList.size()), j++) {
fromMiniGameMatch = otherWaitMatchList.get(i);
}
}
if (fromMiniGameMatch != null) {
if (!jedisService.exits(RedisKey.mini_game_match_round.getKey(String.valueOf(fromMiniGameMatch.getRoomId())))) {
if (!matchRoundMap.containsKey(fromMiniGameMatch.getRoomId())) {
roomId = fromMiniGameMatch.getRoomId();
}
}
boolean isInit = (roomId == null);
ChatRoom chatRoom = chatRoomService.getOrOpen(roomId, uid, ChatRoomTypeEnum.MINI_GAME.ordinal());
if (chatRoom == null) {
ChatRoom toChatRoom = chatRoomService.getOrOpen(roomId, uid, ChatRoomTypeEnum.MINI_GAME.ordinal());
if (toChatRoom == null) {
throw new ServiceException(BusiStatus.SERVERERROR);
}
roomId = chatRoom.getRoomId();
//初始化
if (isInit) {
ChatRoomServiceFactory.getServiceByType(ChatRoomTypeEnum.MINI_GAME.ordinal()).init(chatRoom);
if (null == roomId){
ChatRoomServiceFactory.getServiceByType(ChatRoomTypeEnum.MINI_GAME.ordinal()).init(toChatRoom);
}
MiniGameMatch miniGameMatch = new MiniGameMatch();
miniGameMatch.setUid(uid);
miniGameMatch.setRoomId(roomId);
miniGameMatch.setMgId(mgId);
miniGameMatch.setGameMode(gameMode);
miniGameMatch.setMatchStatus(NavGameMatchStatusEnum.WAIT.ordinal());
miniGameMatch.setTicket(diamondNum);
miniGameMatch.setPartitionId(partitionId);
miniGameMatch.setCreateTime(now);
miniGameMatch.setUpdateTime(now);
//保存匹配记录
MiniGameMatch toMiniGameMatch = new MiniGameMatch();
toMiniGameMatch.setUid(uid);
toMiniGameMatch.setRoomId(roomId);
toMiniGameMatch.setMgId(mgId);
toMiniGameMatch.setGameMode(gameMode);
toMiniGameMatch.setMatchStatus(NavGameMatchStatusEnum.WAIT.ordinal());
toMiniGameMatch.setTicket(diamondNum);
toMiniGameMatch.setPartitionId(partitionId);
toMiniGameMatch.setCreateTime(now);
toMiniGameMatch.setUpdateTime(now);
List<MiniGameMatch> matches = miniGameMatchService.list(Wrappers.<MiniGameMatch>lambdaQuery()
MiniGameMatch dbMatch = miniGameMatchService.getOne(Wrappers.<MiniGameMatch>lambdaQuery()
.eq(MiniGameMatch::getUid, uid)
.eq(MiniGameMatch::getMgId, mgId)
.eq(MiniGameMatch::getGameMode, gameMode)
.eq(MiniGameMatch::getMatchStatus, NavGameMatchStatusEnum.WAIT.ordinal())
.eq(MiniGameMatch::getPartitionId, partitionId));
if (CollectionUtil.isNotEmpty(matches)) {
MiniGameMatch match = matches.get(0);
miniGameMatch.setId(match.getId());
.eq(MiniGameMatch::getPartitionId, partitionId), false);
if (null != dbMatch) {
toMiniGameMatch.setId(dbMatch.getId());
miniGameMatchService.updateById(toMiniGameMatch);
} else {
miniGameMatchService.save(toMiniGameMatch);
}
miniGameMatchService.saveOrUpdate(miniGameMatch);
billRecordService.insertGeneralBillRecord(uid, miniGameMatch.getId().toString(), BillObjTypeEnum.MINI_GAME_MATCH_ENTER_OUT, diamondNum, afterPurse);
billRecordService.insertGeneralBillRecord(uid, toMiniGameMatch.getId().toString(), BillObjTypeEnum.MINI_GAME_MATCH_ENTER_OUT, diamondNum, afterPurse);
if (fromMiniGameMatch != null) {
//匹配
match(fromMiniGameMatch.getId(), miniGameMatch.getId());
match(fromMiniGameMatch, toMiniGameMatch);
} else {
//发起人
chatRoomManageService.upMic(chatRoom.getChatRoomId(), uid);
chatRoomManageService.upMic(toChatRoom.getChatRoomId(), uid);
//放入缓存
waitMatchMap.fastPut(miniGameMatch.getId(), miniGameMatch);
waitMatchMap.fastPut(toMiniGameMatch.getId(), toMiniGameMatch);
//匹配时长
Integer matchSeconds = config.getMatchSeconds();
Long finalRoomId = roomId;
bizExecutor.submit(() -> {
try {
for (int i = 0; i < matchSeconds; i++) {
log.info("fromMatchId : {}, roomId : {}, polling process match second : {}", miniGameMatch.getId(), finalRoomId, i);
if (matchForPolling(finalRoomId, mgId, gameMode)) {
log.info("fromMatchId : {}, roomId : {}, polling process match second : {}", toMiniGameMatch.getId(), toMiniGameMatch.getRoomId(), i);
if (matchForPolling(toMiniGameMatch)) {
return;
}
TimeUnit.SECONDS.sleep(1);
}
//匹配失败
matchForFail(miniGameMatch.getId());
matchForFail(toMiniGameMatch);
} catch (Exception e) {
log.error(e.getMessage(), e);
}
@@ -296,43 +295,98 @@ public class MiniGameForNavServiceImpl implements MiniGameForNavService {
}
}
private RMap<Long, MiniGameMatch> getWaitMatchMap(String mgId, Integer gameMode, Integer partitionId){
return redissonClient.getMap(RedisKey.mini_game_match_wait.getKey(mgId, String.valueOf(gameMode), String.valueOf(partitionId)));
private boolean matchForPolling(MiniGameMatch fromMiniGameMatch) {
RMap<Long, Long> matchRoundMap = miniGameMatchRoundService.getMatchRoundMap();
Long roundId = matchRoundMap.get(fromMiniGameMatch.getRoomId());
if (null == roundId){
return false;
}
RMap<Long, MiniGameMatch> waitGameMatchMap = miniGameMatchService.getWaitMatchMap(fromMiniGameMatch.getMgId(), fromMiniGameMatch.getGameMode(), fromMiniGameMatch.getPartitionId());
if (waitGameMatchMap.containsKey(fromMiniGameMatch.getId())) {
return false;
}
MiniGameMatch dbFromMiniGameMatch = miniGameMatchService.getById(fromMiniGameMatch.getId());
if (null == dbFromMiniGameMatch
|| dbFromMiniGameMatch.getMatchStatus() == NavGameMatchStatusEnum.FINISH.ordinal()
|| dbFromMiniGameMatch.getMatchStatus() == NavGameMatchStatusEnum.FAIL.ordinal()){
throw new ServiceException(BusiStatus.SERVERERROR);
}
if (dbFromMiniGameMatch.getMatchStatus() == NavGameMatchStatusEnum.WAIT.ordinal()){
matchForFail(dbFromMiniGameMatch);
throw new ServiceException(BusiStatus.SERVERERROR);
}
MiniGameMatchRound round = miniGameMatchRoundService.getById(roundId);
if (null == round || round.getRoundStatus() != NavGameRoundStatusEnum.PROCESS.ordinal()){
matchForFail(dbFromMiniGameMatch);
throw new ServiceException(BusiStatus.SERVERERROR);
}
MiniGameMatch toMiniGameMatch = miniGameMatchService.getById(round.getToMatchId());
if (null == toMiniGameMatch || toMiniGameMatch.getMatchStatus() != NavGameMatchStatusEnum.WAIT.ordinal()){
matchForFail(dbFromMiniGameMatch);
throw new ServiceException(BusiStatus.SERVERERROR);
}
boolean updateSuccess = miniGameMatchService.lambdaUpdate()
.set(MiniGameMatch::getMatchStatus, NavGameMatchStatusEnum.SUCCESS.ordinal())
.eq(MiniGameMatch::getId, toMiniGameMatch.getId())
.eq(MiniGameMatch::getMatchStatus, NavGameMatchStatusEnum.WAIT.ordinal())
.update();
if (!updateSuccess){
matchForFail(dbFromMiniGameMatch);
throw new ServiceException(BusiStatus.SERVERERROR);
}
//释放资源
chatRoomService.releaseByRoomId(toMiniGameMatch.getRoomId());
return true;
}
@Override
public void matchForFail(Long miniGameMatchId) {
MiniGameMatch miniGameMatch = miniGameMatchService.getById(miniGameMatchId);
if (miniGameMatch == null) {
public void matchForFail(MiniGameMatch miniGameMatch) {
if (null == miniGameMatch || null == miniGameMatch.getUid()) {
return;
}
Integer matchStatus = miniGameMatch.getMatchStatus();
if (NavGameMatchStatusEnum.WAIT.ordinal() != matchStatus) {
//更新
boolean updateSuccess = miniGameMatchService.lambdaUpdate()
.set(MiniGameMatch::getMatchStatus, NavGameMatchStatusEnum.FAIL.ordinal())
.eq(MiniGameMatch::getId, miniGameMatch.getId())
.eq(MiniGameMatch::getMatchStatus, NavGameMatchStatusEnum.WAIT.ordinal())
.update();
if (!updateSuccess){
return;
}
Long uid = miniGameMatch.getUid();
Long roomId = miniGameMatch.getRoomId();
Integer gameMode = miniGameMatch.getGameMode();
MiniGameForNavConfigDto config = getConfigDto();
Map<Integer, GameModeDto> gameModeMap = config.getGameModeMap();
//入场费
Double diamondNum = gameModeMap.get(gameMode).getTicket();
Double diamondNum = miniGameMatch.getTicket();
//聊天室
ChatRoom chatRoom = chatRoomService.getByRoomId(roomId);
//更新为失败
miniGameMatch.setMatchStatus(NavGameMatchStatusEnum.FAIL.ordinal());
miniGameMatchService.updateById(miniGameMatch);
if (null == chatRoom){
return;
}
Long chatRoomUid = chatRoom.getChatRoomId();
//匹配失败
sendSysMsgService.sendSingleRoomMessage(roomId, chatRoom.getChatRoomId().toString(), Constant.DefMsgType.MINI_GAME_MATCH, Constant.DefMsgType.MINI_GAME_MATCH_FOR_FAIL, new MiniGameMatchRoundDto());
//释放房间
chatRoomService.releaseByRoomId(roomId);
//增加钱包
userPurseService.addDiamond(uid, diamondNum, BillObjTypeEnum.MINI_GAME_MATCH_REFUND_IN,
(userPurse -> billRecordService.insertGeneralBillRecord(uid, miniGameMatch.getId().toString(), BillObjTypeEnum.MINI_GAME_MATCH_REFUND_IN, diamondNum, userPurse)));
//释放房间
chatRoomService.releaseByRoomId(roomId);
//房间踢人
erBanNetEaseService.kickMember(String.valueOf(roomId), String.valueOf(uid), String.valueOf(chatRoom.getChatRoomId()), null);
erBanNetEaseService.kickMember(String.valueOf(roomId), String.valueOf(uid), String.valueOf(chatRoomUid), null);
//房间清理
miniGameForSudService.pushRoomClearEvent(miniGameMatch.getMgId(), miniGameMatch.getRoomId());
miniGameForSudService.pushRoomClearEvent(miniGameMatch.getMgId(), roomId);
}
@Override
@@ -361,6 +415,7 @@ public class MiniGameForNavServiceImpl implements MiniGameForNavService {
boolean isRefund = StrUtil.isEmpty(gameMatchRound.getGameRoundId()) && gameMatchRound.getWinUid() == null && gameMatchRound.getWinNum() == 0;
gameMatchRound.setRoundStatus(NavGameRoundStatusEnum.END.ordinal());
miniGameMatchRoundService.updateById(gameMatchRound);
Long fromMatchId = gameMatchRound.getFromMatchId();
Long toMatchId = gameMatchRound.getToMatchId();
MiniGameMatch fromMatch = miniGameMatchService.getById(fromMatchId);
@@ -393,118 +448,85 @@ public class MiniGameForNavServiceImpl implements MiniGameForNavService {
}
@Override
public boolean matchForPolling(Long roomId, String mgId, Integer gameMode) {
ChatRoom chatRoom = chatRoomService.getByRoomId(roomId);
if (chatRoom == null) {
return false;
public void match(MiniGameMatch fromMiniGameMatch, MiniGameMatch toMiniGameMatch) {
if (fromMiniGameMatch == null || toMiniGameMatch == null
|| !fromMiniGameMatch.getMgId().equals(toMiniGameMatch.getMgId())
|| !fromMiniGameMatch.getGameMode().equals(toMiniGameMatch.getGameMode())
|| !fromMiniGameMatch.getPartitionId().equals(toMiniGameMatch.getPartitionId())){
throw new ServiceException(BusiStatus.SERVERERROR);
}
Long refUid = chatRoom.getRefUid();
List<MiniGameMatch> fromMiniGameMatches = miniGameMatchService.list(Wrappers.<MiniGameMatch>lambdaQuery()
.eq(MiniGameMatch::getUid, refUid)
.eq(MiniGameMatch::getRoomId, roomId)
.eq(MiniGameMatch::getMgId, mgId)
.eq(MiniGameMatch::getGameMode, gameMode)
.eq(MiniGameMatch::getMatchStatus, NavGameMatchStatusEnum.WAIT.ordinal())
.orderByDesc(MiniGameMatch::getCreateTime));
if (CollectionUtil.isEmpty(fromMiniGameMatches)) {
return false;
if (fromMiniGameMatch.getMatchStatus() == NavGameMatchStatusEnum.SUCCESS.ordinal()
|| toMiniGameMatch.getMatchStatus() == NavGameMatchStatusEnum.SUCCESS.ordinal()) {
return;
}
MiniGameMatch fromMiniGameMatch = fromMiniGameMatches.get(0);
Integer partitionId = fromMiniGameMatch.getPartitionId();
List<MiniGameMatch> toMiniGameMatches = miniGameMatchService.list(Wrappers.<MiniGameMatch>lambdaQuery()
.ne(MiniGameMatch::getUid, refUid)
.eq(MiniGameMatch::getMgId, mgId)
.eq(MiniGameMatch::getGameMode, gameMode)
.eq(MiniGameMatch::getPartitionId, partitionId)
.eq(MiniGameMatch::getMatchStatus, NavGameMatchStatusEnum.WAIT.ordinal())
.orderByDesc(MiniGameMatch::getCreateTime));
if (CollectionUtil.isEmpty(toMiniGameMatches)) {
return false;
Long roomId = fromMiniGameMatch.getRoomId();
boolean locked = false;
String redisKey = RedisKey.mini_game_match_round_lock.getKey(String.valueOf(roomId));
RLock lock = redissonClient.getLock(redisKey);
try {
locked = lock.tryLock(3, TimeUnit.SECONDS);
if (!locked) {
log.error("[ludo] 匹配 获取锁超时 {} {}", fromMiniGameMatch.getUid(), toMiniGameMatch.getUid());
throw new ServiceException(BusiStatus.SERVERERROR);
}
RMap<Long, MiniGameMatch> waitMatchMap = miniGameMatchService.getWaitMatchMap(fromMiniGameMatch.getMgId(), fromMiniGameMatch.getGameMode(), fromMiniGameMatch.getPartitionId());
if (!waitMatchMap.containsKey(fromMiniGameMatch.getId())){
log.error("[ludo] 匹配 waitMatchMap 没有 from Id");
throw new ServiceException(BusiStatus.SERVERERROR);
}
boolean updateFromSuccess = miniGameMatchService.lambdaUpdate()
.set(MiniGameMatch::getMatchStatus, NavGameMatchStatusEnum.SUCCESS.ordinal())
.eq(MiniGameMatch::getId, fromMiniGameMatch.getId())
.eq(MiniGameMatch::getMatchStatus, NavGameMatchStatusEnum.WAIT.ordinal())
.update();
if (!updateFromSuccess){
log.error("[ludo] 匹配 修改 from db状态失败");
throw new ServiceException(BusiStatus.SERVERERROR);
}
Date now = new Date();
//创建匹配轮次
MiniGameMatchRound round = new MiniGameMatchRound();
round.setRoomId(fromMiniGameMatch.getRoomId());
round.setFromMatchId(fromMiniGameMatch.getId());
round.setFromUid(fromMiniGameMatch.getUid());
round.setToMatchId(toMiniGameMatch.getId());
round.setToUid(toMiniGameMatch.getUid());
round.setGameMode(fromMiniGameMatch.getGameMode());
round.setCreateTime(now);
round.setUpdateTime(now);
round.setRoundStatus(NavGameRoundStatusEnum.PROCESS.ordinal());
miniGameMatchRoundService.save(round);
//设置麦位信息
Long fromUid = fromMiniGameMatch.getUid();
Long toUid = toMiniGameMatch.getUid();
//聊天室
ChatRoom fromChatRoom = chatRoomService.getByRoomId(fromMiniGameMatch.getRoomId());
ChatRoom toChatRoom = chatRoomService.getByRoomId(toMiniGameMatch.getRoomId());
//上麦
chatRoomManageService.upMic(fromChatRoom.getChatRoomId(), toUid);
//下麦
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();
}
}
int index = RandomUtil.randomByRange(0, toMiniGameMatches.size());
MiniGameMatch toMiniGameMatch = toMiniGameMatches.get(index);
Integer fromMatchStatus = fromMiniGameMatch.getMatchStatus();
Integer toMatchStatus = toMiniGameMatch.getMatchStatus();
if (fromMatchStatus == NavGameMatchStatusEnum.SUCCESS.ordinal() || toMatchStatus == NavGameMatchStatusEnum.SUCCESS.ordinal()) {
return true;
}
//释放资源
chatRoomService.releaseByRoomId(roomId);
//匹配
match(fromMiniGameMatch.getId(), toMiniGameMatch.getId());
return true;
}
@Override
public void match(Long fromMatchId, Long toMatchId) {
bizExecutor.submit(() -> {
MiniGameMatch fromMiniGameMatch = miniGameMatchService.getById(fromMatchId);
MiniGameMatch toMiniGameMatch = miniGameMatchService.getById(toMatchId);
if (fromMiniGameMatch == null || toMiniGameMatch == null) {
return;
}
Integer fromMatchStatus = fromMiniGameMatch.getMatchStatus();
Integer toMatchStatus = toMiniGameMatch.getMatchStatus();
if (fromMatchStatus == NavGameMatchStatusEnum.SUCCESS.ordinal() || toMatchStatus == NavGameMatchStatusEnum.SUCCESS.ordinal()) {
return;
}
Long roomId = fromMiniGameMatch.getRoomId();
String redisKey = RedisKey.mini_game_match_round_start_lock.getKey(String.valueOf(roomId));
String lockVal = jedisLockService.lock(redisKey, 60 * 1000);
if (StrUtil.isEmpty(lockVal)) {
return;
}
try {
Date now = new Date();
Long fromRoomId = fromMiniGameMatch.getRoomId();
Integer gameMode = fromMiniGameMatch.getGameMode();
Long toRoomId = toMiniGameMatch.getRoomId();
//更新
fromMiniGameMatch.setMatchStatus(NavGameMatchStatusEnum.SUCCESS.ordinal());
miniGameMatchService.updateById(fromMiniGameMatch);
toMiniGameMatch.setRoomId(fromRoomId);
toMiniGameMatch.setMatchStatus(NavGameMatchStatusEnum.SUCCESS.ordinal());
miniGameMatchService.updateById(toMiniGameMatch);
//创建匹配轮次
MiniGameMatchRound round = new MiniGameMatchRound();
round.setRoomId(fromRoomId);
round.setFromMatchId(fromMiniGameMatch.getId());
round.setFromUid(fromMiniGameMatch.getUid());
round.setToMatchId(toMiniGameMatch.getId());
round.setToUid(toMiniGameMatch.getUid());
round.setGameMode(gameMode);
round.setCreateTime(now);
round.setUpdateTime(now);
round.setRoundStatus(NavGameRoundStatusEnum.PROCESS.ordinal());
miniGameMatchRoundService.save(round);
//设置麦位信息
Long fromUid = fromMiniGameMatch.getUid();
Long toUid = toMiniGameMatch.getUid();
//聊天室
ChatRoom fromChatRoom = chatRoomService.getByRoomId(fromRoomId);
ChatRoom toChatRoom = chatRoomService.getByRoomId(toRoomId);
//上麦
chatRoomManageService.upMic(fromChatRoom.getChatRoomId(), toUid);
//下麦
chatRoomManageService.downMic(toChatRoom.getChatRoomId(), toUid);
//设置匹配标识
Long matchRoundId = round.getId();
jedisService.setex(RedisKey.mini_game_match_round.getKey(String.valueOf(fromRoomId)), 24 * 60 * 60,
fromUid + StrUtil.UNDERLINE + toUid + StrUtil.UNDERLINE + matchRoundId);
RMap<Long, MiniGameMatch> waitMatchMap = getWaitMatchMap(fromMiniGameMatch.getMgId(), fromMiniGameMatch.getGameMode(), fromMiniGameMatch.getPartitionId());
waitMatchMap.fastRemove(fromMiniGameMatch.getId());
} catch (Exception e) {
log.error(e.getMessage(), e);
} finally {
if (StringUtils.hasText(lockVal)) {
jedisLockService.unlock(redisKey, lockVal);
}
}
});
}
@Transactional(rollbackFor = Exception.class)
@@ -521,30 +543,34 @@ public class MiniGameForNavServiceImpl implements MiniGameForNavService {
}
//下麦
chatRoomManageService.downMic(chatRoomId, uid);
List<MiniGameMatchRound> miniGameMatchRounds = miniGameMatchRoundService.list(Wrappers.<MiniGameMatchRound>lambdaQuery()
.eq(MiniGameMatchRound::getRoomId, roomId)
.eq(MiniGameMatchRound::getRoundStatus, NavGameRoundStatusEnum.PROCESS.ordinal())
.orderByDesc(MiniGameMatchRound::getCreateTime));
if (CollectionUtil.isEmpty(miniGameMatchRounds)) {
return;
}
if (miniGameMatchRounds.stream().noneMatch(v -> v.getFromUid().equals(uid) || v.getToUid().equals(uid))) {
RMap<Long, Long> roundCacheMap = miniGameMatchRoundService.getMatchRoundMap();
Long roundId = roundCacheMap.remove(roomId);
if (null == roundId){
return;
}
MiniGameForNavConfigDto config = getConfigDto();
//通知结果
MiniGameMatchRound miniGameMatchRound = miniGameMatchRounds.get(0);
String lockKey = RedisKey.mini_game_match_round_close_lock.getKey(String.valueOf(roomId));
String lockVal = jedisLockService.lock(lockKey, 5 * 10);
if (StrUtil.isEmpty(lockVal)) {
log.info("closeGame is error...");
MiniGameMatchRound miniGameMatchRound = miniGameMatchRoundService.getById(roundId);
if (null == miniGameMatchRound || miniGameMatchRound.getRoundStatus() != NavGameRoundStatusEnum.PROCESS.ordinal()){
return;
}
boolean locked = false;
String lockKey = RedisKey.mini_game_match_round_lock.getKey(String.valueOf(roomId));
RLock lock = redissonClient.getLock(lockKey);
try {
locked = lock.tryLock(3L, TimeUnit.SECONDS);
if (!locked){
throw new ServiceException(BusiStatus.SERVERERROR);
}
Integer gameMode = miniGameMatchRound.getGameMode();
GameModeDto gameModeDto = config.getGameModeMap().get(gameMode);
Double winner = gameModeDto.getWinner();
Double platform = gameModeDto.getPlatform();
MiniGameMatch fromMiniGameMatch = miniGameMatchService.getById(miniGameMatchRound.getFromMatchId());
MiniGameMatch toMiniGameMatch = miniGameMatchService.getById(miniGameMatchRound.getToMatchId());
if (fromMiniGameMatch == null || toMiniGameMatch == null) {
@@ -554,13 +580,14 @@ public class MiniGameForNavServiceImpl implements MiniGameForNavService {
miniGameMatchService.updateById(fromMiniGameMatch);
toMiniGameMatch.setMatchStatus(NavGameMatchStatusEnum.FINISH.ordinal());
miniGameMatchService.updateById(toMiniGameMatch);
//游戏提前失败结果
MiniGameMatchRoundDto roundDto = new MiniGameMatchRoundDto();
roundDto.setChatRoomId(chatRoomId);
roundDto.setRoomId(roomId);
roundDto.setMatchStatus(NavGameMatchStatusEnum.FINISH.ordinal());
roundDto.setRoundStatus(NavGameRoundStatusEnum.END.ordinal());
Long fromUid = fromMiniGameMatch.getUid();
Long fromUid = miniGameMatchRound.getFromUid();
Users fromUser = usersService.getUsersByUid(fromUid);
List<MiniGamePlayerResultDto> results = new ArrayList<>();
MiniGamePlayerResultDto fromResultDto = new MiniGamePlayerResultDto();
@@ -592,6 +619,7 @@ public class MiniGameForNavServiceImpl implements MiniGameForNavService {
fromResultDto.setRank(2);
}
results.add(fromResultDto);
Long toUid = toMiniGameMatch.getUid();
Users toUser = usersService.getUsersByUid(toUid);
MiniGamePlayerResultDto toResultDto = new MiniGamePlayerResultDto();
@@ -624,42 +652,38 @@ public class MiniGameForNavServiceImpl implements MiniGameForNavService {
}
miniGameMatchRound.setRoundStatus(NavGameRoundStatusEnum.END.ordinal());
miniGameMatchRoundService.updateById(miniGameMatchRound);
results.add(toResultDto);
roundDto.setResults(results.stream().sorted(Comparator.comparingInt(MiniGamePlayerResultDto::getRank)).collect(Collectors.toList()));
sendSysMsgService.sendSingleRoomMessage(roomId, chatRoomId.toString(), Constant.DefMsgType.MINI_GAME_MATCH, Constant.DefMsgType.MINI_GAME_MATCH_FOR_RESULT, roundDto);
//删除缓存
jedisService.del(RedisKey.mini_game_match_round.getKey(String.valueOf(fromUid)));
jedisService.del(RedisKey.mini_game_match_round.getKey(String.valueOf(toUid)));
jedisService.del(RedisKey.mini_game_match_round.getKey(String.valueOf(roomId)));
//房间踢人
erBanNetEaseService.kickMember(String.valueOf(roomId), String.valueOf(fromUid), String.valueOf(chatRoomId), null);
erBanNetEaseService.kickMember(String.valueOf(roomId), String.valueOf(toUid), String.valueOf(chatRoomId), null);
//房间清理
miniGameForSudService.pushRoomClearEvent(fromMiniGameMatch.getMgId(), fromMiniGameMatch.getRoomId());
//清理旧的匹配
for (int i = 1, len = miniGameMatchRounds.size(); i < len; i++) {
MiniGameMatchRound gameMatchRound = miniGameMatchRounds.get(i);
matchForEqualize(gameMatchRound.getId());
}
} catch (Exception e) {
log.error(e.getMessage(), e);
} finally {
jedisLockService.unlock(lockKey, lockVal);
if (locked){
lock.unlock();
}
}
}
@Override
public ChatRoomVo resumeRoom(Long uid) {
List<MiniGameMatchRound> miniGameMatchRounds = miniGameMatchRoundService.list(Wrappers.<MiniGameMatchRound>lambdaQuery()
MiniGameMatchRound miniGameMatchRound = miniGameMatchRoundService.getOne(Wrappers.<MiniGameMatchRound>lambdaQuery()
.and(w -> w.eq(MiniGameMatchRound::getFromUid, uid)
.or()
.eq(MiniGameMatchRound::getToUid, uid))
.eq(MiniGameMatchRound::getRoundStatus, NavGameRoundStatusEnum.PROCESS.ordinal())
.orderByDesc(MiniGameMatchRound::getCreateTime));
if (CollectionUtil.isEmpty(miniGameMatchRounds)) {
.orderByDesc(MiniGameMatchRound::getId), false);
if (null == miniGameMatchRound){
return null;
}
MiniGameMatchRound miniGameMatchRound = miniGameMatchRounds.get(0);
Long roomId = miniGameMatchRound.getRoomId();
return chatRoomManageService.getByRoomId(roomId);
}

View File

@@ -3,8 +3,13 @@ package com.accompany.business.service.miniGame.impl;
import com.accompany.business.model.miniGame.MiniGameMatchRound;
import com.accompany.business.mybatismapper.miniGame.MiniGameMatchRoundMapper;
import com.accompany.business.service.miniGame.MiniGameMatchRoundService;
import com.accompany.common.redis.RedisKey;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RMap;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
/**
@@ -14,5 +19,20 @@ import org.springframework.stereotype.Service;
*/
@Slf4j
@Service
public class MiniGameMatchRoundServiceImpl extends ServiceImpl<MiniGameMatchRoundMapper, MiniGameMatchRound> implements MiniGameMatchRoundService {
public class MiniGameMatchRoundServiceImpl extends ServiceImpl<MiniGameMatchRoundMapper, MiniGameMatchRound> implements MiniGameMatchRoundService, InitializingBean {
@Autowired
private RedissonClient redissonClient;
private RMap<Long, Long> matchRoundMap;
@Override
public RMap<Long, Long> getMatchRoundMap(){
return matchRoundMap;
}
@Override
public void afterPropertiesSet() throws Exception {
matchRoundMap = redissonClient.getMap(RedisKey.mini_game_match_round.getKey());
}
}

View File

@@ -3,16 +3,24 @@ package com.accompany.business.service.miniGame.impl;
import com.accompany.business.model.miniGame.MiniGameMatch;
import com.accompany.business.mybatismapper.miniGame.MiniGameMatchMapper;
import com.accompany.business.service.miniGame.MiniGameMatchService;
import com.accompany.common.redis.RedisKey;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
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.stereotype.Service;
/**
* @author: liaozetao
* @date: 2024/5/20 11:10
* @description:
*/
@Slf4j
@Service
public class MiniGameMatchServiceImpl extends ServiceImpl<MiniGameMatchMapper, MiniGameMatch> implements MiniGameMatchService {
@Autowired
private RedissonClient redissonClient;
@Override
public RMap<Long, MiniGameMatch> getWaitMatchMap(String mgId, Integer gameMode, Integer partitionId){
return redissonClient.getMap(RedisKey.mini_game_match_wait.getKey(mgId, String.valueOf(gameMode), String.valueOf(partitionId)));
}
}

View File

@@ -2,6 +2,7 @@ package com.accompany.business.service.mq;
import com.accompany.business.message.*;
import com.accompany.business.message.linearlypool.LinearlyPoolPrizeMessage;
import com.accompany.business.model.miniGame.MiniGameMatchRound;
import com.accompany.mq.constant.MqConstant;
import com.accompany.mq.producer.MQMessageProducer;
import com.alibaba.fastjson.JSON;
@@ -133,4 +134,9 @@ public class RocketMQService {
});
}
public void sendMiniGameMatchRoundMsg(MiniGameMatchRoundMessage msg) {
mqMessageProducer.send(MqConstant.MINI_GAME_MATCH_ROUND_TOPIC, msg, sendResult -> log.info("sendMiniGameMatchRoundMsg success message: {}", JSON.toJSONString(msg)), throwable ->
log.error("sendMiniGameMatchRoundMsg fail message: {}", JSON.toJSONString(msg), throwable), 4);
}
}

View File

@@ -36,7 +36,7 @@ public class MiniGameForNavController {
* @return
*/
@ApiOperation("游戏配置")
@GetMapping("config")
@GetMapping("/config")
public BusiResult<MiniGameVo> config() {
return BusiResult.success(miniGameForNavService.getConfig());
}
@@ -48,7 +48,7 @@ public class MiniGameForNavController {
* @return
*/
@ApiOperation("开始游戏")
@PostMapping("start")
@PostMapping("/start")
public BusiResult<Void> start(String mgId, Integer gameMode) {
miniGameForNavService.start(mgId, gameMode);
return BusiResult.success();
@@ -60,7 +60,7 @@ public class MiniGameForNavController {
* @return
*/
@ApiOperation("关闭")
@GetMapping("close")
@GetMapping("/close")
public BusiResult<Void> close(Long roomId) {
chatRoomManageService.close(roomId, UidContextHolder.get());
return BusiResult.success();
@@ -72,7 +72,7 @@ public class MiniGameForNavController {
*/
@ApiOperation("恢复房间")
@ApiImplicitParam(name = "roomType", value = "房间类型 0 小游戏")
@GetMapping("resumeRoom")
@GetMapping("/resumeRoom")
public BusiResult<ChatRoomVo> resumeRoom() {
return BusiResult.success(miniGameForNavService.resumeRoom(UidContextHolder.get()));
}

View File

@@ -21,15 +21,12 @@ public interface MqConstant {
String YI_DUN_TEXT_ANTI_CONSUME_GROUP = "yidun_text_anti_consume_group";
String CHANGE_TOPIC = "charge_topic";
String CHARGE_CONSUME_GROUP = "charge_consume_group";
String ACT_USER_TASK_TOPIC = "act_user_task_topic";
String ACT_USER_TASK_CONSUME_GROUP = "act_user_task_consume_group";
String ACT_TASK_REWARD_TOPIC = "act_task_reward_topic";
String ACT_TASK_REWARD_CONSUME_GROUP = "act_task_reward_consume_group";
String LUCKY_24_TOPIC = "lucky_24_topic";
@@ -41,4 +38,7 @@ public interface MqConstant {
String BRAVO_TOPIC = "bravo_topic";
String BRAVO_CONSUME_GROUP = "bravo_consume_group";
String MINI_GAME_MATCH_ROUND_TOPIC = "mini_game_match_round_topic";
String MINI_GAME_MATCH_ROUND_CONSUME_GROUP = "mini_game_match_round_consume_group";
}

View File

@@ -0,0 +1,46 @@
package com.accompany.mq.consumer;
import com.accompany.business.dto.miniGame.MiniGameMatchRoundDto;
import com.accompany.business.message.MiniGameMatchRoundMessage;
import com.accompany.business.model.miniGame.MiniGameMatchRound;
import com.accompany.business.service.SendSysMsgService;
import com.accompany.business.service.chat.ChatRoomManageService;
import com.accompany.business.service.miniGame.MiniGameForNavService;
import com.accompany.business.vo.chat.ChatRoomVo;
import com.accompany.common.constant.Constant;
import com.accompany.mq.constant.MqConstant;
import com.accompany.mq.listener.AbstractMessageListener;
import lombok.extern.slf4j.Slf4j;
import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Component;
@Slf4j
@Component
@ConditionalOnProperty(name = "spring.application.name", havingValue = "web")
@RocketMQMessageListener(topic = MqConstant.MINI_GAME_MATCH_ROUND_TOPIC, consumerGroup = MqConstant.MINI_GAME_MATCH_ROUND_CONSUME_GROUP)
public class MiniGameMatchRoundMessageConsumer extends AbstractMessageListener<MiniGameMatchRoundMessage> {
@Autowired
private MiniGameForNavService navService;
@Autowired
private ChatRoomManageService chatRoomManageService;
@Autowired
private SendSysMsgService sendSysMsgService;
@Override
protected void onMessage(MiniGameMatchRoundMessage message) {
log.info("onMessage miniGameMatchRoundMessage: {}", message.toString());
MiniGameMatchRound round = message.getRound();
if (navService.matchForSuccess(round.getId())){
return;
}
navService.matchForEqualize(round.getId());
//聊天室
ChatRoomVo chatRoomVo = chatRoomManageService.getByRoomId(round.getRoomId());
//匹配失败
sendSysMsgService.sendSingleRoomMessage(round.getRoomId(), chatRoomVo.getChatRoomId().toString(), Constant.DefMsgType.MINI_GAME_MATCH, Constant.DefMsgType.MINI_GAME_MATCH_FOR_FAIL, new MiniGameMatchRoundDto());
}
}