package combomatch import ( "os" "bet24.com/log" "bet24.com/servers/common" //gameHistory "bet24.com/servers/micros/gameHistory/proto" "encoding/json" "fmt" "sort" "strconv" "sync" "time" inventory "bet24.com/servers/micros/item_inventory/proto" item "bet24.com/servers/micros/item_inventory/proto" "bet24.com/servers/micros/matches/handler/matchbase" "bet24.com/servers/micros/matches/handler/pointmatch" "bet24.com/servers/micros/matches/handler/setsmatch" "bet24.com/servers/micros/matches/handler/simplematch" pb "bet24.com/servers/micros/matches/proto" platformconfig "bet24.com/servers/micros/platformconfig/proto" robot "bet24.com/servers/micros/userservices/proto" user "bet24.com/servers/micros/userservices/proto" ) const config_key = "combomatch_config" const refresh_config_sec = 600 const match_time_out_ended = 120 type combomatchMgr struct { MatchConfigs []*matchconfig matches map[int][]*matchInfo lock *sync.RWMutex lockConfig *sync.RWMutex lockWating *sync.RWMutex waitingNextRoundMatches []*matchInfo lastConfigString string } var matchMgr *combomatchMgr func getMatchManager() *combomatchMgr { if matchMgr == nil { matchMgr = new(combomatchMgr) matchMgr.lock = &sync.RWMutex{} matchMgr.lockConfig = &sync.RWMutex{} matchMgr.matches = make(map[int][]*matchInfo) matchMgr.lockWating = &sync.RWMutex{} } return matchMgr } func (mm *combomatchMgr) run() { mm.loadConfig() go mm.checkTimeout() } func (mm *combomatchMgr) loadConfig() { defer func() { time.AfterFunc(refresh_config_sec*time.Second, mm.loadConfig) }() configString := platformconfig.GetConfig(config_key) if configString == "" { data, err := os.ReadFile("serviceconf/combomatch.json") if err != nil { log.Release("combomatch.combomatchMgr.loadData read json failed") return } configString = string(data) platformconfig.SetConfig(config_key, configString) } if configString == mm.lastConfigString { return } mm.lastConfigString = configString var configs []*matchconfig err := json.Unmarshal([]byte(configString), &configs) if err != nil { log.Release("combomatch.combomatchMgr.loadData Unmarshal failed err:%v", err) return } for _, v := range configs { v.calTotalPrize() mm.updateConfig(v) } // 有比赛删除 mm.checkDeleteConfig(configs) } func (mm *combomatchMgr) updateConfig(config *matchconfig) { mm.lockConfig.Lock() defer mm.lockConfig.Unlock() for i := 0; i < len(mm.MatchConfigs); i++ { v := mm.MatchConfigs[i] if v.MatchId == config.MatchId { config.OnlineUser = v.OnlineUser mm.MatchConfigs[i] = config return } } // 没有 mm.MatchConfigs = append(mm.MatchConfigs, config) } func (mm *combomatchMgr) checkDeleteConfig(configs []*matchconfig) { var toRemoveMatchIds []int mm.lockConfig.RLock() for _, v := range mm.MatchConfigs { found := false for _, v1 := range configs { if v.MatchId == v1.MatchId { found = true break } } if !found { toRemoveMatchIds = append(toRemoveMatchIds, v.MatchId) } } mm.lockConfig.RUnlock() if len(toRemoveMatchIds) == 0 { return } log.Release("combomatchMgr.checkDeleteConfig %v", toRemoveMatchIds) mm.lockConfig.Lock() for _, v := range toRemoveMatchIds { for i := 0; i < len(mm.MatchConfigs); { if mm.MatchConfigs[i].MatchId == v { mm.MatchConfigs = append(mm.MatchConfigs[:i], mm.MatchConfigs[i+1:]...) } else { i++ } } } mm.lockConfig.Unlock() } func (mm *combomatchMgr) checkTimeout() { time.AfterFunc(30*time.Second, mm.checkTimeout) mm.lock.Lock() for k, v := range mm.matches { for i := 0; i < len(v); { if v[i].isTimeout() { v = append(v[:i], v[i+1:]...) } else { i++ } } mm.matches[k] = v } mm.lock.Unlock() } func (mm *combomatchMgr) dump(param1, param2 string) { log.Release("-------------------------------") log.Release("combomatch.combomatchMgr.dump[%s,%s]", param1, param2) defer func() { log.Release("+++++++++++++++++++++++++++++++") log.Release("") }() if param1 == "config" { mm.lockConfig.RLock() defer mm.lockConfig.RUnlock() for _, v := range mm.MatchConfigs { v.dump() } return } if param1 == "history" { getHistoryManager().dump(param2) return } if param1 == "user" { userId, err := strconv.Atoi(param2) if err != nil { log.Release("invalid param %s", param2) return } ms := mm.getUserMatchId(userId) for _, v := range ms { log.Release(" %d,%d,%d", v.MatchId, v.MatchType, v.MatchNo) } return } if param1 == "dismiss" { matchNo, err := strconv.Atoi(param2) if err != nil { log.Release("invalid param %s", param2) return } mm.dismissMatch(matchNo) return } matchId, _ := strconv.Atoi(param1) mm.lock.RLock() for k, v := range mm.matches { if matchId != 0 && matchId != k { continue } config := mm.getConfig(k) startInfo := "" if config != nil && config.RangeTime != nil { startInfo = fmt.Sprintf("%d", config.RangeTime.Start) } log.Release(" MatchId[%d] %s", k, startInfo) for _, v1 := range v { v1.dump(matchId != 0) } log.Release(" -------------") } mm.lock.RUnlock() } func (mm *combomatchMgr) dismissMatch(matchNo int) { mi := mm.getMatchByMatchNo(matchNo) if mi == nil { log.Release("combomatchMgr.dismissMatch [%d] not found", matchNo) return } config := mm.getConfig(mi.MatchId) if config == nil { log.Release("combomatchMgr.dismissMatch matchId[%d] not found", mi.MatchId) return } if mi.getStatus() == matchbase.MatchStatus_Ended { log.Release("combomatchMgr.dismissMatch matchId[%d] ended", mi.MatchId) return } userList := mi.getUserList() for _, v := range userList { // 退钱 if len(config.EnrollFee) > 0 { itm := mi.getAndRemoveUserFee(v) if itm.Count > 0 { inventory.AddItems(v, []item.ItemPack{itm}, "combomatch fee return", common.LOGTYPE_COMBOMATCH_ENTER_RETURN) } else if config.DailyFreeCount > 0 { getFreeCountManager().reduceFreeCount(v, config.MatchId) } } } switch mi.getCurrentMatchType() { case matchbase.MatchType_SimpleMatch: simplematch.DismissMatch(matchNo) case matchbase.MatchType_PointMatch: pointmatch.DismissMatch(matchNo) case matchbase.MatchType_SetsMatch: setsmatch.DismissMatch(matchNo) } } func (mm *combomatchMgr) enrollComboMatch(matchId int, userId int, nickname string, faceId int, faceUrl string, feeIndex int, isRobot bool) (int, string) { config := mm.getConfig(matchId) if config == nil { log.Release("combomatchMgr.enrollComboMatch matchId[%d] not found", matchId) return 0, "Wrong MatchId" } if !config.IsInTime() { log.Debug("combomatchMgr.enrollComboMatch matchId[%d] not open", matchId) return 0, "Not in match time" } // 不是预报名的,不能同时报多个 if !config.IsPreEnroll() && mm.isUserPlaying(userId) { return 0, "Already in a match" } mi := mm.getOrCreateMatch(matchId, config) if mi == nil { log.Release("combomatchMgr.enrollComboMatch matchId[%d] getOrCreateMatch failed", matchId) return 0, "Serve error" } // 预报名,并且已经到达上线 if !mi.canEnroll() { return 0, "Quota is full" } if feeIndex >= len(config.EnrollFee) { feeIndex = len(config.EnrollFee) - 1 } // 如果有免费次数 if config.DailyFreeCount > 0 && getFreeCountManager().getUserFreeCount(userId, config.MatchId) < config.DailyFreeCount { getFreeCountManager().addFreeCount(userId, config.MatchId) } else { // 扣钱 if len(config.EnrollFee) > 0 && !robot.IsRobot(userId) { ok, err := inventory.Consume(userId, config.EnrollFee[feeIndex].ItemId, common.LOGTYPE_COMBOMATCH_ENTER, config.EnrollFee[feeIndex].Count, 0) if !ok { errMsg := fmt.Sprintf("not enough fee[%v] for play err = %s", config.EnrollFee[feeIndex], err) log.Release("combomatch.enrollComboMatch failed %s", errMsg) return 0, errMsg } mi.setUserFee(userId, config.EnrollFee[feeIndex]) } } // 如果是提前报名,则不创建比赛,本地保存 //if config.IsPreEnroll() { mi.addEnrollUser(userId, nickname, faceId, faceUrl, isRobot) // 发送通知 //postUserEnterNotification(userId, matchId, nickname, faceId, faceUrl) ni := ComboMatch_notificationInfo{Msg: ComboMatch_noti_userenter, UserId: userId, MatchId: matchId, FaceId: faceId, FaceUrl: faceUrl, Nickname: nickname} d, _ := json.Marshal(ni) mi.sendNotification(-1, string(d)) return 1, "OK" //} /* // 玩家加入 var retCode int var errMsg string if mi.isSimpleMatch() { retCode, errMsg = simplematch.EnrollMatch(userId, nickname, faceId, faceUrl, mi.getMatchNo()) } else { retCode, errMsg = pointmatch.EnrollMatch(userId, nickname, faceId, faceUrl, mi.getMatchNo()) } if retCode != 1 { return 0, errMsg } config.addOnline(1) return mi.getMatchNo(), "OK" */ } func (mm *combomatchMgr) quitComboMatch(matchId int, userId int) bool { config := mm.getConfig(matchId) if config == nil { log.Release("combomatchMgr.quitComboMatch matchId[%d] not found", matchId) return false } // 查询我的比赛 mm.lock.RLock() matches, ok := mm.matches[matchId] mm.lock.RUnlock() if !ok || len(matches) == 0 { log.Release("combomatchMgr.quitComboMatch matchId[%d] no match found", matchId) return false } for _, v := range matches { //if v.getStatus() == matchbase.MatchStatus_Free && v.isUserEnrolled(userId) { // 退出当前比赛 if v.isUserEnrolled(userId) { return v.quitUser(userId, true) } } log.Release("quitComboMatch MatchId[%d] UserId[%d] not in match", matchId, userId) return false } func (mm *combomatchMgr) getConfig(matchId int) *matchconfig { mm.lockConfig.RLock() defer mm.lockConfig.RUnlock() for _, v := range mm.MatchConfigs { if v.MatchId == matchId { return v } } return nil } func (mm *combomatchMgr) getCurrentMatch(matchId int) *matchInfo { mm.lock.RLock() matches, ok := mm.matches[matchId] mm.lock.RUnlock() if ok { for _, v := range matches { if v.getStatus() == matchbase.MatchStatus_Free && !v.isFull() { return v } } } return nil } func (mm *combomatchMgr) createMatch(matchId int, config *matchconfig, mi *matchInfo, totalUser int) *matchInfo { round := 0 if mi != nil { round = mi.CurrentRound + 1 } var matchNo int var matchInstance matchbase.MatchInstance var err string // 创建一个比赛,报名期间,先不创建比赛实例,等人满后再创建 if mi != nil { switch config.getMatchType(round) { case matchbase.MatchType_SimpleMatch: matchNo, err = simplematch.CreateMatch(-1, config.GameId, config.GameRule, totalUser, config.getTarget(round), config.TableUser, 0, 0, config.PlayTime, config.isEleminateByScore(round), config.getWinnerCount(round)) if matchNo == 0 { log.Release("combomatchMgr.getOrCreateMatch simplematch.CreateMatch failed %s", err) return nil } matchInstance = simplematch.GetMatchInstance(matchNo) case matchbase.MatchType_PointMatch: e, ssec, sscore, w := config.getPointMatchParams(round) matchNo, err = pointmatch.CreateMatch(-1, config.GameId, config.GameRule, totalUser, config.TableUser, 0, 0, config.PlayTime, e, ssec, sscore, w) if matchNo == 0 { log.Release("combomatchMgr.getOrCreateMatch pointmatch.CreateMatch failed %s", err) return nil } matchInstance = pointmatch.GetMatchInstance(matchNo) case matchbase.MatchType_SetsMatch: matchNo, err = setsmatch.CreateMatch(-1, config.GameId, config.GameRule, totalUser, config.TableUser, 0, 0, config.PlayTime, config.getWinnerCount(round)) if matchNo == 0 { log.Release("combomatchMgr.getOrCreateMatch setsmatch.CreateMatch failed %s", err) return nil } matchInstance = setsmatch.GetMatchInstance(matchNo) } if matchInstance == nil { log.Release("combomatchMgr.getOrCreateMatch GetMatchInstance == nil") return nil } matchInstance.RegisterReceiver(mm) } if mi == nil { mi = newMatchInfo(config.MatchId, mm, config.RobotConfig, config) } else { mi.addMatchInfo(matchNo, matchInstance) } return mi } func (mm *combomatchMgr) getOrCreateMatch(matchId int, config *matchconfig) *matchInfo { ret := mm.getCurrentMatch(matchId) if ret != nil { return ret } ret = mm.createMatch(matchId, config, nil, config.TotalUser) if ret == nil { return nil } mm.lock.Lock() mm.matches[matchId] = append(mm.matches[matchId], ret) mm.lock.Unlock() return ret } // MatchInstanceReceiver func (mm *combomatchMgr) OnMatchStart(matchNo int) { log.Debug("combomatchMgr.OnMatchStart [%d]", matchNo) mi := mm.getMatchByMatchNo(matchNo) if mi == nil { log.Release("combomatchMgr.OnMatchStart [%d] matchInfo not found", matchNo) return } mi.setStartTime(matchNo) } func (mm *combomatchMgr) OnMatchCancelled(matchNo int) { log.Debug("combomatchMgr.OnMatchCancelled [%d]", matchNo) mi := mm.getMatchByMatchNo(matchNo) if mi == nil { log.Release("combomatchMgr.OnMatchCancelled [%d] matchInfo not found", matchNo) return } config := mm.getConfig(mi.MatchId) if config == nil { log.Release("combomatchMgr.OnMatchCancelled [%d] config not found", matchNo) return } var matchInstance matchbase.MatchInstance switch mi.getCurrentMatchType() { case matchbase.MatchType_SimpleMatch: matchInstance = simplematch.GetMatchInstance(matchNo) case matchbase.MatchType_PointMatch: matchInstance = pointmatch.GetMatchInstance(matchNo) case matchbase.MatchType_SetsMatch: matchInstance = setsmatch.GetMatchInstance(matchNo) } if matchInstance == nil { log.Release("combomatchMgr.OnMatchCancelled [%d] matchInstance not found", matchNo) return } // 退费 userList := matchInstance.GetUserList() for _, userId := range userList { // 退钱 if len(config.EnrollFee) > 0 { itm := mi.getAndRemoveUserFee(userId) if itm.Count > 0 { inventory.AddItems(userId, []item.ItemPack{itm}, "combomatch fee return", common.LOGTYPE_COMBOMATCH_ENTER_RETURN) } else if config.DailyFreeCount > 0 { getFreeCountManager().reduceFreeCount(userId, config.MatchId) } } } } func (mm *combomatchMgr) OnMatchEnd(matchNo int) { log.Debug("combomatchMgr.OnMatchEnd [%d]", matchNo) mi := mm.getMatchByMatchNo(matchNo) if mi == nil { log.Release("combomatchMgr.OnMatchEnd [%d] matchInfo not found", matchNo) return } mi.setEndTime(matchNo) config := mm.getConfig(mi.MatchId) if config == nil { log.Release("combomatchMgr.OnMatchEnd matchId[%d] not found", mi.MatchId) return } // 找出胜利者给发奖励 var matchInstance matchbase.MatchInstance switch mi.getCurrentMatchType() { case matchbase.MatchType_SimpleMatch: matchInstance = simplematch.GetMatchInstance(matchNo) case matchbase.MatchType_PointMatch: matchInstance = pointmatch.GetMatchInstance(matchNo) case matchbase.MatchType_SetsMatch: matchInstance = setsmatch.GetMatchInstance(matchNo) } if matchInstance == nil { log.Release("combomatchMgr.OnMatchEnd [%d] matchInstance not found", matchNo) return } winners := matchInstance.GetWinners() if len(winners) == 0 { log.Release("combomatchMgr.OnMatchEnd [%d] no winners", matchNo) return } // 把名词更新一下 currentMatchUsers := matchInstance.GetAllMatchUsers() for _, v := range currentMatchUsers { mi.updateRankAndScore(v.UserId, v.Rank, v.Score, v.WinCount) } if mi.isEnded() { config.addOnline(-mi.getOnline()) // 加入历史记录 var h combohistory h.Name = config.Name h.MatchId = config.MatchId h.GameId = config.GameId h.GameName = config.GameName h.GameRule = config.GameRule h.Prizes = config.Prizes h.TableUser = config.TableUser h.TotalUser = config.TotalUser h.EnrollFee = config.EnrollFee //h.matchconfig = *config for i := 0; i < len(config.Rounds); i++ { h.Rounds = append(h.Rounds, historyRound{ MatchType: config.Rounds[i].MatchType, Target: config.Rounds[i].Target, WinnerCount: config.Rounds[i].WinnerCount, MatchNo: mi.Rounds[i].MatchNo, StartTime: mi.Rounds[i].StartTime, EndTime: mi.Rounds[i].EndTime, }) } h.StartTime = mi.getStartTime() h.EndTime = mi.getEndTime() h.Winners = winners enrollUsers := mi.getAllMatchUsers() for _, v := range enrollUsers { h.EnrollUsers = append(h.EnrollUsers, historyUser{ MatchUserBrief: *v.ToBrief(), enrollTime: int(v.EnrollTime), prize: config.getPrizes(v.Rank), }) } // 所有参与人员 sort.Slice(h.EnrollUsers, func(i, j int) bool { return h.EnrollUsers[i].Rank < h.EnrollUsers[j].Rank }) for _, v := range h.EnrollUsers { // 已淘汰用户不再发奖励 if mi.isUserAwarded(v.UserId) { continue } prize := config.getPrizes(v.Rank) if len(prize) > 0 { inventory.AddItems(v.UserId, prize, "配置赛奖励", common.LOGTYPE_COMBOMATCH_PRIZE) log.Debug("OnMatchEnd 发送通知和奖励 [%d] Rank:[%d] %v", v.UserId, v.Rank, prize) } mi.postUserRankNotification(v.UserId, v.Rank, prize) /*gameHistory.MyMatch_Write(v.UserId, &gameHistory.MyMatchInfo{ UserId: v.UserId, //int `json:"UserId, omitempty"` // 用户ID NickName: v.NickName, //string `json:"NickName, omitempty"` // 昵称 MatchName: config.Name, //string // 比赛名称 Rank: v.Rank, //int // 名次 Items: prize, //int // 道具ID })*/ mi.setUserAwarded(v.UserId) } // 最后把所有报名记录都加上 h.setAllEnrolledUsers(mi.enrolledUsers) getHistoryManager().addHistory(h) go writeRoomRecordToDB(&h) mi.dump(true) return } mi.setRoundWinners(winners) mm.lockWating.Lock() mm.waitingNextRoundMatches = append(mm.waitingNextRoundMatches, mi) mm.lockWating.Unlock() log.Debug("combomatchMgr.OnMatchEnd match[%d] waiting to enter next round", matchNo) mi.dump(false) time.AfterFunc(6*time.Second, mm.enterNextRound) } func (mm *combomatchMgr) OnUserEliminated(matchNo int, userId int, rank int) { log.Debug("combomatchMgr.OnUserEliminated [%d] UserId[%d] Rank[%d]", matchNo, userId, rank) mi := mm.getMatchByMatchNo(matchNo) if mi == nil { log.Release("combomatchMgr.OnUserEliminated [%d] matchInfo not found", matchNo) return } config := mm.getConfig(mi.MatchId) if config == nil { log.Release("combomatchMgr.OnUserEliminated matchId[%d] not found", mi.MatchId) return } prize := config.getPrizes(rank) if len(prize) > 0 { inventory.AddItems(userId, prize, "配置赛奖励", common.LOGTYPE_COMBOMATCH_PRIZE) mi.postUserRankNotification(userId, rank, prize) log.Debug("OnMatchEnd 发送通知和奖励 [%d] %v", userId, prize) } mi.setUserAwarded(userId) /*usr := mi.getUser(userId) var myInfo gameHistory.MyMatchInfo myInfo.UserId = userId myInfo.MatchName = config.Name myInfo.Rank = rank myInfo.Items = prize if usr != nil { myInfo.NickName = usr.NickName } gameHistory.MyMatch_Write(userId, &myInfo)*/ } func (mm *combomatchMgr) getAWatingNextRoundMatch() *matchInfo { var ret *matchInfo mm.lockWating.Lock() defer mm.lockWating.Unlock() if len(mm.waitingNextRoundMatches) > 0 { ret = mm.waitingNextRoundMatches[0] mm.waitingNextRoundMatches = mm.waitingNextRoundMatches[1:] } return ret } func (mm *combomatchMgr) enterNextRound() { mi := mm.getAWatingNextRoundMatch() if mi == nil { log.Release("combomatchMgr.enterNextRound no match waiting to next round") return } log.Debug("combomatchMgr.enterNextRound find a wating match [%d]", mi.getMatchNo()) config := mm.getConfig(mi.MatchId) if config == nil { log.Release("combomatchMgr.enterNextRound matchId[%d] not found", mi.MatchId) return } // 进行下一轮 newMatch := mm.createMatch(mi.MatchId, config, mi, len(mi.currentRoundWinners)) if newMatch == nil { log.Release("combomatchMgr.enterNextRound open new match failed") return } else { log.Debug("combomatchMgr.enterNextRound new match [%d] created userCount = %d", newMatch.getMatchNo(), len(mi.currentRoundWinners)) } for i := 0; i < len(mi.currentRoundWinners); i++ { var retCode int var errMsg string matchUser := &mi.currentRoundWinners[i] if matchUser == nil { log.Release("combomatchMgr.enterNextRound winners %v not found", mi.currentRoundWinners[i]) continue } switch mi.getCurrentMatchType() { case matchbase.MatchType_SimpleMatch: retCode, errMsg = simplematch.EnrollMatchWithInitialScore(matchUser.UserId, matchUser.NickName, matchUser.FaceId, matchUser.FaceUrl, mi.getMatchNo(), matchUser.Score) case matchbase.MatchType_PointMatch: retCode, errMsg = pointmatch.EnrollMatch(matchUser.UserId, matchUser.NickName, matchUser.FaceId, matchUser.FaceUrl, mi.getMatchNo()) case matchbase.MatchType_SetsMatch: retCode, errMsg = setsmatch.EnrollMatch(matchUser.UserId, matchUser.NickName, matchUser.FaceId, matchUser.FaceUrl, mi.getMatchNo()) } if retCode != 1 { log.Release("combomatchMgr.enterNextRound enrollMatch failed [%v] [%s]", mi.currentRoundWinners[i], errMsg) } } mi.setRoundWinners([]int{}) } func (mm *combomatchMgr) getMatchByMatchNo(matchNo int) *matchInfo { mm.lock.RLock() defer mm.lock.RUnlock() for _, v := range mm.matches { for _, v1 := range v { if v1.getMatchNo() == matchNo { return v1 } } } return nil } func (mm *combomatchMgr) getMatchList(userId int) string { var configs []matchconfig mm.lockConfig.RLock() for _, v := range mm.MatchConfigs { configs = append(configs, *v) } mm.lockConfig.RUnlock() for i := 0; i < len(configs); i++ { configs[i].setLeftFreeCount(userId) } d, _ := json.Marshal(configs) return string(d) } func (mm *combomatchMgr) getUserMatchId(userId int) []pb.UserComboMatchId { var ret []pb.UserComboMatchId mm.lock.RLock() defer mm.lock.RUnlock() for _, v := range mm.matches { for _, v1 := range v { if v1.isUserPlaying(userId) { ret = append(ret, pb.UserComboMatchId{ MatchId: v1.MatchId, MatchType: v1.getCurrentMatchType(), MatchNo: v1.getMatchNo(), SecsToStart: v1.getStartSeconds(), }) } } } return ret } func (mm *combomatchMgr) addARobot(matchId int) int { m := mm.getCurrentMatch(matchId) if m == nil { log.Release("combomatchMgr.addARobot matchId[%d] has no live match", matchId) return 0 } // 如果比赛没那么快开始 forceRemove := m.getStartSeconds() > 1800 // 如果没有真人了 if m.tryRemoveOneRobot(forceRemove) { return -1 } if forceRemove { return 0 } loopCount := 0 for { loopCount++ if loopCount > 20 { log.Release("combomatchMgr.addARobot matchId[%d] get a robot failed", matchId) return 0 } robotId := robot.GetARobot() if mm.isUserPlaying(robotId) { continue } usr := user.GetUserInfo(robotId) if usr == nil { continue } mm.enrollComboMatch(matchId, robotId, usr.NickName, usr.FaceId, usr.FaceUrl, 0, true) break } return 1 } func (mm *combomatchMgr) isUserPlaying(robotId int) bool { mm.lock.RLock() defer mm.lock.RUnlock() for _, m := range mm.matches { for _, mi := range m { if mi.isUserPlaying(robotId) { return true } } } return false } func (mm *combomatchMgr) getUserMatchInfo(matchId int, userId int) string { var mi *matchInfo mm.lock.RLock() matches, ok := mm.matches[matchId] mm.lock.RUnlock() if !ok { log.Debug("combomatchMgr.getUserMatchInfo matchId[%d] has no match instance", matchId) return "" } for _, v := range matches { if v.isUserPlaying(userId) { mi = v break } } if mi == nil { //log.Debug("combomatchMgr.getMatchInfo matchId[%d] userId[%d] has no match enrolled", matchId, userId) return "" } return mi.getMatchInfo() } func (mm *combomatchMgr) getConfirmCount(matchId int) int { mi := mm.getCurrentMatch(matchId) if mi == nil { //log.Release("combomatchMgr.getConfirmCount [%d] not found", matchId) return 0 } return mi.getConfirmCount() } func (mm *combomatchMgr) confirmMatch(matchId int, userId int) bool { mi := mm.getCurrentMatch(matchId) if mi == nil { log.Release("combomatchMgr.confirmMatch [%d] not found", matchId) return false } return mi.confirmMatch(userId) }