package simplematch import ( "bet24.com/log" "bet24.com/servers/common" game "bet24.com/servers/micros/game/proto" "bet24.com/servers/micros/matches/handler/matchbase" cash "bet24.com/servers/micros/money/proto" notification "bet24.com/servers/micros/notification/proto" privateroom "bet24.com/servers/micros/privateroom/proto" task "bet24.com/servers/micros/task/proto" robot "bet24.com/servers/micros/userservices/proto" "encoding/json" "fmt" "math/rand" "sort" "sync" "time" ) type matchinstance struct { Owner int GameId int GameRule string TotalUser int Target int TableUser int PlayTimeout int Fee int Prize int MatchNo int CurrentRound int // 当前轮次 StartTime string startTime int64 Status int createTime int64 UserList []*matchuser `json:",omitempty"` EliminateUsers []*matchuser `json:",omitempty"` // 已淘汰玩家 promotedUsers []int // 本轮晋级玩家 liveRooms []*matchroom // 目前正在进行的私人房间号 lock *sync.RWMutex RoomHistory []matchbase.RoomHistory receivers []matchbase.MatchInstanceReceiver eleminateByScore bool config *matchconfig WinnerCount int lockRoomEnd *sync.RWMutex } func newMatchInstance(matchNo, userId int, gameId int, gameRule string, totalUserCount int, target int, tableUserCount int, enrollFee int, prize int, playTimeout int, config *matchconfig, eleminateByScore bool, winnerCount int) *matchinstance { mi := &matchinstance{ MatchNo: matchNo, Owner: userId, GameId: gameId, GameRule: gameRule, TotalUser: totalUserCount, Target: target, TableUser: tableUserCount, Fee: enrollFee, Prize: prize, createTime: time.Now().Unix(), lock: &sync.RWMutex{}, lockRoomEnd: &sync.RWMutex{}, Status: matchbase.MatchStatus_Free, config: config, PlayTimeout: playTimeout, eleminateByScore: eleminateByScore, WinnerCount: winnerCount, } return mi } func (mi *matchinstance) isTimeout(timeoutFree, timeoutPlay, timeoutEnd int64) bool { if mi.Status == matchbase.MatchStatus_Playing { return time.Now().Unix()-mi.createTime >= timeoutPlay } else if mi.Status == matchbase.MatchStatus_Ended { return time.Now().Unix()-mi.createTime >= timeoutEnd } return time.Now().Unix()-mi.createTime >= timeoutFree } func (mi *matchinstance) dump() { log.Release(" MatchNo[%d] Owner[%d] Idled[%d] Rule[%s] TotalUser[%d] TableUser[%d] Fee[%d] Status[%d] Start[%s]", mi.MatchNo, mi.Owner, mi.getIdle(), mi.GameRule, mi.TotalUser, mi.TableUser, mi.Fee, mi.Status, mi.StartTime) //common.TimeStampToString(mi.StartTime)) mi.lock.RLock() defer mi.lock.RUnlock() if len(mi.UserList) > 0 { log.Release(" UserList:") for _, v := range mi.UserList { log.Release(" UserId[%d],NickName[%s],Score[%d],Room[%d],Chair[%d],Team[%d]", v.UserId, v.NickName, v.Score, v.RoomNo, v.ChairId, v.teamId) } } if len(mi.EliminateUsers) > 0 { log.Release(" EliminateUsers:") for _, v := range mi.EliminateUsers { log.Release(" UserId[%d],NickName[%s],Score[%d],Room[%d],Chair[%d],Team[%d]", v.UserId, v.NickName, v.Score, v.RoomNo, v.ChairId, v.teamId) } } if len(mi.liveRooms) > 0 { log.Release(" liveRooms:") for _, v := range mi.liveRooms { v.dump() } } if len(mi.RoomHistory) > 0 { log.Release(" RoomHistory:") for _, v := range mi.RoomHistory { v.Dump() } } } func (mi *matchinstance) getIdle() int64 { return time.Now().Unix() - mi.createTime } func (mi *matchinstance) getCopy() matchinstance { var ret matchinstance d, _ := json.Marshal(mi) json.Unmarshal(d, &ret) return ret } func (mi *matchinstance) getUser(userId int) *matchuser { mi.lock.RLock() defer mi.lock.RUnlock() for _, v := range mi.UserList { if v.UserId == userId { return v } } return nil } func (mi *matchinstance) getUserScore(userId int) int { mu := mi.getUser(userId) if mu == nil { return 0 } return mu.Score } func (mi *matchinstance) addUser(userId int, nickname string, faceId int, faceUrl string, score int) (ok bool, errMsg string) { ok = false errMsg = "ok" if mi.Status != matchbase.MatchStatus_Free { errMsg = "Match has Started" log.Release("matchinstance.addUser[%d] failed %s", userId, errMsg) return } // 已存在? mu := mi.getUser(userId) if mu != nil { ok = true return } if len(mi.UserList) >= mi.TotalUser { errMsg = "full of users" log.Release("matchinstance.addUser[%d] failed %s", userId, errMsg) return } // 扣钱 if mi.Fee > 0 && !cash.ReduceMoney(userId, mi.Fee, common.LOGTYPE_SIMPLEMATCH_ENTER, "simplematch", "enter", "") { errMsg = fmt.Sprintf("not enough cash[%d] for play", mi.Fee) log.Release("matchinstance.addUser failed %s", errMsg) return } mi.lock.Lock() mi.UserList = append(mi.UserList, newMatchUser(userId, nickname, faceId, faceUrl, score, mi.config.BaseScore)) mi.lock.Unlock() ok = true mi.checkAndStartRound() return } func (mi *matchinstance) removeUser(userId int) bool { if mi.Status == matchbase.MatchStatus_Playing { log.Release("matchinstance.removeUser[%d] failed match playing", userId) return false } idx := -1 mi.lock.RLock() for i := 0; i < len(mi.UserList); i++ { if mi.UserList[i].UserId == userId { idx = i break } } mi.lock.RUnlock() if idx == -1 { log.Release("matchinstance.removeUser[%d] not found", userId) return false } if mi.Fee > 0 && mi.Status == matchbase.MatchStatus_Free { } mi.lock.Lock() mi.UserList = append(mi.UserList[:idx], mi.UserList[idx+1:]...) mi.lock.Unlock() return true } func (mi *matchinstance) closeByOwner(userId int) (bool, string) { if userId != mi.Owner { return false, "Not match owner" } if mi.Status >= matchbase.MatchStatus_Playing { return false, "Match has started" } mi.closeMatch("owner close") return true, "ok" } func (mi *matchinstance) closeMatch(reason string) { isCancelled := false // 如果有玩家,也退费 if mi.Status < matchbase.MatchStatus_Playing { mi.lock.RLock() for _, v := range mi.UserList { if v == nil { continue } if mi.Fee > 0 { cash.GiveMoney(v.UserId, mi.Fee, common.LOGTYPE_SIMPLEMATCH_ENTER_RETURN, "simplematch", "fee return", "") } } mi.lock.RUnlock() if mi.Prize > 0 && mi.Owner > 0 { cash.GiveMoney(mi.Owner, mi.Prize, common.LOGTYPE_SIMPLEMATCH_CREATE_RETURN, "simplematch", "create return", "") } isCancelled = true } if mi.Status != matchbase.MatchStatus_Ended { mi.Status = matchbase.MatchStatus_Ended if !isCancelled { mi.postOnMatchEndToReceivers() } else { mi.postOnMatchCancelledToReceivers() } } mi.lock.Lock() mi.UserList = nil mi.EliminateUsers = nil mi.lock.Unlock() } func (mi *matchinstance) dismiss() { isCancelled := false if mi.Status < matchbase.MatchStatus_Ended { mi.lock.RLock() for _, v := range mi.UserList { if v == nil { continue } if mi.Fee > 0 { cash.GiveMoney(v.UserId, mi.Fee, common.LOGTYPE_SIMPLEMATCH_ENTER_RETURN, "simplematch", "fee return", "") } } mi.lock.RUnlock() if mi.Prize > 0 && mi.Owner > 0 { cash.GiveMoney(mi.Owner, mi.Prize, common.LOGTYPE_SIMPLEMATCH_CREATE_RETURN, "simplematch", "create return", "") } isCancelled = true } if mi.Status != matchbase.MatchStatus_Ended { mi.Status = matchbase.MatchStatus_Ended if !isCancelled { mi.postOnMatchEndToReceivers() } else { mi.postOnMatchCancelledToReceivers() } } mi.lock.Lock() mi.UserList = nil mi.EliminateUsers = nil mi.lock.Unlock() } func (mi *matchinstance) setUserRanks() []int { // 不是比分淘汰不排名 if !mi.isEleminateByScore() { return []int{} } mi.lock.RLock() userlist := make([]*matchuser, len(mi.UserList)) for i := 0; i < len(mi.UserList); i++ { userlist[i] = mi.UserList[i] } mi.lock.RUnlock() if len(userlist) == 0 { return []int{} } sort.Slice(userlist, func(i, j int) bool { return userlist[i].IsBetterThan(&userlist[j].MatchUser) }) ret := make([]int, len(userlist)) for i := 0; i < len(userlist); i++ { userlist[i].Rank = i + 1 ret[i] = userlist[i].UserId } /* log.Debug("simplematch.matchinstance.setUserRanks") for i := 0; i < len(userlist); i++ { log.Debug(" Rank %d: %d score %d", userlist[i].Rank, userlist[i].UserId, userlist[i].Score) }*/ return ret } // 检查比赛开始 func (mi *matchinstance) checkAndStartRound() { mi.lock.RLock() userCount := len(mi.UserList) mi.lock.RUnlock() // 第一轮必须人满 if userCount < mi.TotalUser && mi.CurrentRound == 0 { return } if userCount < mi.TableUser { log.Release("matchinstance.checkAndStartRound userCount[%d] < mi.TableUser[%d]", userCount, mi.TableUser) return } // 不是第一轮,所有房间都结束 if mi.CurrentRound > 0 { for _, v := range mi.liveRooms { if v == nil { continue } if !v.isEnded() { return } } } // 需要几桌? tableCount := userCount / mi.TableUser if tableCount == 0 { log.Release("matchinstance.checkAndStartRound tableCount == 0") mi.dump() return } // 用户排名 mi.setUserRanks() // 清理本轮晋级玩家 mi.promotedUsers = []int{} // 先创建出来 mi.liveRooms = make([]*matchroom, tableCount) var rooms []int for i := 0; i < tableCount; i++ { roomNo, err := privateroom.CreatePrivateRoomByUser(mi.Owner, mi.GameId, mi.GameRule, mi.Target, mi.TableUser, 0, 0, privateroom.RoomType_SimpleMatch, mi.PlayTimeout, false, "") if roomNo == 0 { log.Release("checkAndStartRound createRoom failed %s", err) mi.closeMatch("normal end") return } mi.liveRooms[i] = newMatchRoom(roomNo, mi) // 注册私人场事件 //go privateroom.RegisterRoomStatus(mi, roomNo) rooms = append(rooms, roomNo) } log.Release("matchinstance.checkAndStartRound [%d] rooms%v have been created", mi.MatchNo, rooms) // 人满了,可以开始 oldStatus := mi.Status mi.Status = matchbase.MatchStatus_Playing // 把报名费给Owner now := time.Now() mi.startTime = now.Unix() mi.StartTime = common.TimeStampToString(mi.startTime) if mi.Fee > 0 && mi.CurrentRound == 0 && mi.Owner > 0 { cash.GiveMoney(mi.Owner, mi.Fee*userCount, common.LOGTYPE_SIMPLEMATCH_OWNER_COLLECT, "simplematch", "owner", "") } if oldStatus != mi.Status { mi.postMatchStatusChangedNotificaiton(oldStatus, mi.Status) } if oldStatus == matchbase.MatchStatus_Free { mi.postOnMatchStartToReceivers() } // 把玩家随机分配到各个房间去 userIdx := make([]int, userCount) // 是否需要组队? teamMatch := false if mi.config.TeamGame && mi.CurrentRound > 0 { for { teamCount := mi.TableUser / 2 teamUsers := make(map[int][]int) for _, v := range mi.UserList { teamUsers[v.teamId] = append(teamUsers[v.teamId], v.UserId) } var teamIds []int for k, v := range teamUsers { teamIds = append(teamIds, k) if len(v) != teamCount { log.Release("matchinstance.checkAndStartRound teamIds[%d]:%v + teamCount=%d", k, v, teamCount) break } } if len(teamIds) != tableCount/teamCount { log.Release("matchinstance.checkAndStartRound teamIds%v tableCount=%d", teamIds, tableCount) break } // 随机打乱tameIds for i := len(teamIds) - 1; i > 1; i-- { pos := rand.Intn(i) teamIds[pos], teamIds[i] = teamIds[i], teamIds[pos] } for _, teamId := range teamIds { for _, uid := range teamUsers[teamId] { userIdx = append(userIdx, uid) } } teamMatch = true break } } if !teamMatch { for i := 0; i < len(mi.UserList); i++ { userIdx[i] = i } // 打乱 for i := userCount - 1; i > 1; i-- { pos := rand.Intn(i) userIdx[pos], userIdx[i] = userIdx[i], userIdx[pos] } } // 玩家都分配好了,加入私人场 mi.lock.RLock() for r := 0; r < len(mi.liveRooms); r++ { for u := 0; u < mi.TableUser; u++ { usr := mi.UserList[userIdx[r*mi.TableUser+u]] // 根据第一轮的情况组队 if mi.config.TeamGame && mi.CurrentRound == 0 { usr.teamId = 1 + r*2 + u/2 } mi.liveRooms[r].addUser(usr.UserId) toChairId := u if u == 1 { toChairId = 2 } else if toChairId == 2 { toChairId = 1 } go func(roomIndex int, chairId int) { var ret struct { ErrMsg string ServerAddr string TableId int ChairId int } retString := privateroom.UserRequestSit(mi.liveRooms[roomIndex].RoomNo, usr.UserId, usr.NickName, usr.FaceId, usr.FaceUrl, chairId, usr.Score, usr.BaseScore, usr.GameCount) if err := json.Unmarshal([]byte(retString), &ret); err != nil { log.Release("matchinstance.checkAndStartRound try enter privateroom unmarshal failed %v", err) return } if ret.ServerAddr == "" { log.Release("matchinstance.checkAndStartRound try enter privateroom failed %s", ret.ErrMsg) return } log.Debug("matchinstance.checkAndStartRound MatchId[%d] user[%d] enter room %d chair %d", mi.MatchNo, usr.UserId, mi.liveRooms[roomIndex].RoomNo, ret.ChairId) usr.arrangeRoom(mi.liveRooms[roomIndex].RoomNo, ret.ServerAddr, ret.TableId, ret.ChairId) go mi.postUserMatchRoomNotification(usr.UserId, ret.ServerAddr, ret.TableId, ret.ChairId) sec := 60 if robot.IsRobot(usr.UserId) { sec = 5 } privateroom.ForceUserEnter(usr.UserId, usr.RoomNo, ret.ChairId, sec) }(r, toChairId) } } mi.lock.RUnlock() } func (mi *matchinstance) getRoom(roomNo int) *matchroom { for _, v := range mi.liveRooms { if v == nil { log.Release("matchinstance[%d].getRoom [%d] v == nil", mi.MatchNo, roomNo) continue } if v.RoomNo == roomNo { return v } } // log.Release("matchinstance[%d].getRoom [%d] not found", mi.MatchNo, roomNo) return nil } // 比赛进程 func (mi *matchinstance) OnRoomStart(roomNo int) { if mi == nil { log.Release("simplematch.matchinstance.OnRoomStart mi == nil") return } mr := mi.getRoom(roomNo) if mr == nil { return } log.Debug("simplematch.OnRoomStart %d ", roomNo) mr.Status = privateroom.PrivateRoomStatus_Playing } func (mi *matchinstance) onRoomEndEleminateByScore() { // 重置排名 rankedUserIds := mi.setUserRanks() // 名次重排后,广播给所有人 //if room != nil { mi.lock.RLock() for _, v := range mi.UserList { go func(userId, rank int) { ni := matchbase.Match_notificationInfo{Msg: matchbase.Match_noti_rank_changed, Rank: rank} d, _ := json.Marshal(ni) mi.sendNotification(userId, string(d)) }(v.UserId, v.Rank) } mi.lock.RUnlock() //} // 看下是否所有房间都结束了 for _, v := range mi.liveRooms { if !v.isEnded() { return } } // 一半的人淘汰 lastRound := mi.isLastRound() winnerCount := len(rankedUserIds) / 2 if lastRound && mi.WinnerCount != 0 { winnerCount = mi.WinnerCount } //for _, v := range winners { for i := 0; i < len(rankedUserIds); i++ { v := rankedUserIds[i] if lastRound { go task.DoTaskAction(v, task.TaskAction_matchfinal, 1, task.TaskScope{GameName: game.GetGameNameByGameId(mi.GameId)}) } // 完成一局比赛 go task.DoTaskAction(v, task.TaskAction_playmatch, 1, task.TaskScope{GameName: game.GetGameNameByGameId(mi.GameId)}) if i < winnerCount { if lastRound { go task.DoTaskAction(v, task.TaskAction_matchchampion, 1, task.TaskScope{GameName: game.GetGameNameByGameId(mi.GameId)}) } mi.addPromotedUser(v) mi.postUserRankNotification(v, i+1, 0) } else { rank := mi.addEleminatedUser(v, i+1) if lastRound { mi.postUserRankNotification(v, rank, 0) } else { mi.postUserEliminationNotification(v, rank) mi.postOnUserEliminatedToReceivers(v, rank) } } } // 继续下一轮 mi.checkRoundEnd() } func (mi *matchinstance) OnRoomEnd(roomNo int, winners []int) { mr := mi.getRoom(roomNo) if mr == nil { return } log.Debug("simplematch.OnRoomEnd %d winners %v", roomNo, winners) if !mr.isValidUsers(winners) { log.Release("matchinstance[%d].onRoomEnd[%d] winners not exist", mi.MatchNo, roomNo) return } // 如果同时触发OnRoomEnd,则流程会异常 mi.lockRoomEnd.Lock() defer mi.lockRoomEnd.Unlock() mr.Status = privateroom.PrivateRoomStatus_Ended mr.setWinners(winners) var rh matchbase.RoomHistory rh.RoomNo = roomNo rh.EndTime = time.Now().Unix() // 如果是积分淘汰制,则需要等所有人结束才能淘汰 if mi.isEleminateByScore() { // 先加入历史记录 for _, v := range mr.Users { mu := mi.getUser(v) if mu == nil { continue } if mi.isUserIn(v, winners) { mu.WinCount++ } mu.clearRoomInfo() rh.Users = append(rh.Users, matchbase.RoomHistoryUser{UserId: v, Score: mi.getUserScore(v), IsPromote: false}) } mi.RoomHistory = append(mi.RoomHistory, rh) mi.onRoomEndEleminateByScore() return } lastRound := mi.isLastRound() for _, v := range winners { if lastRound { go task.DoTaskAction(v, task.TaskAction_matchchampion, 1, task.TaskScope{GameName: game.GetGameNameByGameId(mi.GameId)}) } mi.addPromotedUser(v) rh.Users = append(rh.Users, matchbase.RoomHistoryUser{UserId: v, Score: mi.getUserScore(v), IsPromote: true}) } // 发淘汰信息 for _, v := range mr.Users { if lastRound { go task.DoTaskAction(v, task.TaskAction_matchfinal, 1, task.TaskScope{GameName: game.GetGameNameByGameId(mi.GameId)}) } // 完成一局比赛 go task.DoTaskAction(v, task.TaskAction_playmatch, 1, task.TaskScope{GameName: game.GetGameNameByGameId(mi.GameId)}) if !mi.isUserIn(v, winners) { rh.Users = append(rh.Users, matchbase.RoomHistoryUser{UserId: v, Score: mi.getUserScore(v), IsPromote: false}) rank := mi.addEleminatedUser(v, 0) if lastRound { mi.postUserRankNotification(v, rank, 0) } else { mi.postUserEliminationNotification(v, rank) mi.postOnUserEliminatedToReceivers(v, rank) } } } mi.RoomHistory = append(mi.RoomHistory, rh) mi.checkRoundEnd() } func (mi *matchinstance) OnRoomUserScoreChanged(roomNo int, userId int, score int) { mr := mi.getRoom(roomNo) if mr == nil { //log.Release("matchinstance[%d].OnRoomUserScoreChanged[%d] room not exist", mi.MatchNo, roomNo) return } mu := mi.getUser(userId) if mu == nil { log.Release("matchinstance[%d].OnRoomUserScoreChanged[%d] user not exist", mi.MatchNo, userId) return } if mi.isEleminateByScore() { mu.Score += score } else { mu.Score = score } } func (mi *matchinstance) OnRoomStatusChanged(roomNo int, old, new int) { //log.Debug("matchinstance.OnRoomStatusChanged %d %d->%d", roomNo, old, new) } func (mi *matchinstance) isEleminateByScore() bool { return mi.eleminateByScore } func (mi *matchinstance) addPromotedUser(userId int) { mu := mi.getUser(userId) if mu == nil { return } go task.DoTaskAction(userId, task.TaskAction_matchpromote, 1, task.TaskScope{GameName: game.GetGameNameByGameId(mi.GameId)}) mu.clearRoomInfo() mi.promotedUsers = append(mi.promotedUsers, userId) if len(mi.liveRooms) > 1 { mi.postUserPromotionNotification(userId) } } func (mi *matchinstance) addEleminatedUser(userId int, rank int) int { ret := 0 mu := mi.getUser(userId) if mu == nil { return ret } mu.clearRoomInfo() mi.lock.Lock() //for _, v := range mi.UserList { for i := 0; i < len(mi.UserList); i++ { v := mi.UserList[i] if v.UserId == userId { mi.EliminateUsers = append(mi.EliminateUsers, v) //mi.roundElimiate = append(mi.roundElimiate, v) v.Round = mi.CurrentRound if rank <= 0 { rank = len(mi.UserList) } v.Rank = rank ret = v.Rank // delete mi.UserList = append(mi.UserList[:i], mi.UserList[i+1:]...) } } mi.lock.Unlock() return ret } func (mi *matchinstance) checkRoundEnd() { // 看下是否所有房间都结束了 for _, v := range mi.liveRooms { if !v.isEnded() { return } } // 结束了,把非晋级玩家清理 mi.lock.Lock() //for _, v := range mi.UserList { for i := 0; i < len(mi.UserList); { v := mi.UserList[i] if !mi.isUserIn(v.UserId, mi.promotedUsers) { mi.EliminateUsers = append(mi.EliminateUsers, v) v.Round = mi.CurrentRound v.Rank = len(mi.UserList) // delete mi.UserList = append(mi.UserList[:i], mi.UserList[i+1:]...) } else { i++ } } leftUserCount := len(mi.UserList) mi.lock.Unlock() // 如果人数已经不足开桌,那么比赛就结束了 if leftUserCount < mi.TableUser { // 剩下的玩家都为第一名 mi.lock.Lock() for i := 0; i < len(mi.UserList); i++ { mi.UserList[i].Rank = 1 } mi.lock.Unlock() mi.onMatchEnded(leftUserCount) return } mi.CurrentRound++ // 延迟进行下一轮 time.AfterFunc(time.Second*time.Duration(mi.config.getRoundTimeOff()), mi.checkAndStartRound) } func (mi *matchinstance) isUserIn(userId int, userIds []int) bool { for _, v := range userIds { if userId == v { return true } } return false } func (mi *matchinstance) onMatchEnded(winnerCount int) { mi.Status = matchbase.MatchStatus_Ended if winnerCount == 0 { log.Release("matchinstance.onMatchEnded winnerCount == 0") return } // 给最后的用户发奖金 prize := mi.Prize / winnerCount tax := prize * getMatchManager().TaxRate / 100 prize -= tax mi.lock.RLock() for _, v := range mi.UserList { if prize > 0 { cash.ModifyMoneyWithTax(v.UserId, prize, tax, common.LOGTYPE_SIMPLEMATCH_PRIZE, "simplematch", "prize", "") } // 发通知 go mi.postUserRankNotification(v.UserId, 1, prize) } mi.lock.RUnlock() getHistoryManager().addHistory(*mi) mi.postOnMatchEndToReceivers() } func (mi *matchinstance) SendNotification(userId int, data string) { mi.sendNotification(userId, data) } func (mi *matchinstance) GetUserList() []int { var ret []int mi.lock.RLock() for _, v := range mi.UserList { ret = append(ret, v.UserId) } mi.lock.RUnlock() return ret } func (mi *matchinstance) sendNotification(userId int, data string) { if userId == -1 { // send all mi.lock.RLock() for _, v := range mi.UserList { notification.AddNotification(v.UserId, notification.Notification_Match, data) } mi.lock.RUnlock() return } notification.AddNotification(userId, notification.Notification_Match, data) } func (mi *matchinstance) setPrizeAndTax(userId int, prize, tax int) { mi.lock.Lock() defer mi.lock.Unlock() for _, v := range mi.UserList { if v == nil { continue } if v.UserId == userId { v.tax = tax v.prize = prize return } } } func (mi *matchinstance) getUsersDesc() string { type userDesc struct { UserId int Score int Prize int } var users []userDesc mi.lock.Lock() for _, v := range mi.UserList { if v == nil { continue } users = append(users, userDesc{UserId: v.UserId, Score: v.Score, Prize: v.prize}) } mi.lock.Unlock() d, _ := json.Marshal(users) return string(d) } func (mi *matchinstance) getUsersDescForDB() string { var ret string mi.lock.Lock() for _, v := range mi.UserList { if v == nil { continue } ret = fmt.Sprintf("%s%d,%d,%d,%d;", ret, v.UserId, mi.Fee, v.tax, v.prize) } mi.lock.Unlock() return ret } func (mi *matchinstance) getTotalTax() int { ret := 0 mi.lock.RLock() defer mi.lock.RUnlock() for _, v := range mi.UserList { if v == nil { continue } ret += v.tax } return ret } // MatchInstance func (mi *matchinstance) GetStatus() int { return mi.Status } func (mi *matchinstance) IsFull() bool { mi.lock.RLock() defer mi.lock.RUnlock() return len(mi.UserList) == mi.TotalUser } func (mi *matchinstance) IsUserEnrolled(userId int) bool { return mi.getUser(userId) != nil } func (mi *matchinstance) RegisterReceiver(receiver matchbase.MatchInstanceReceiver) { for _, v := range mi.receivers { if v == receiver { return } } mi.receivers = append(mi.receivers, receiver) } func (mi *matchinstance) GetWinners() []int { var ret []int if mi.Status == matchbase.MatchStatus_Ended { mi.lock.RLock() for _, v := range mi.UserList { if v == nil { continue } ret = append(ret, v.UserId) } mi.lock.RUnlock() } return ret } func (mi *matchinstance) postOnMatchCancelledToReceivers() { for _, v := range mi.receivers { v.OnMatchCancelled(mi.MatchNo) } } func (mi *matchinstance) postOnMatchEndToReceivers() { for _, v := range mi.receivers { v.OnMatchEnd(mi.MatchNo) } } func (mi *matchinstance) postOnMatchStartToReceivers() { for _, v := range mi.receivers { v.OnMatchStart(mi.MatchNo) } } func (mi *matchinstance) postOnUserEliminatedToReceivers(userId, rank int) { for _, v := range mi.receivers { v.OnUserEliminated(mi.MatchNo, userId, rank) } } func (mi *matchinstance) GetAllMatchUsers() []matchbase.MatchUser { var ret []matchbase.MatchUser mi.lock.RLock() for _, v := range mi.UserList { ret = append(ret, v.MatchUser) } for _, v := range mi.EliminateUsers { ret = append(ret, v.MatchUser) } mi.lock.RUnlock() return ret } func (mi *matchinstance) GetUser(userId int) *matchbase.MatchUser { ret := mi.getUser(userId) if ret == nil { return nil } return &ret.MatchUser } func (mi *matchinstance) isLastRound() bool { mi.lock.RLock() defer mi.lock.RUnlock() return len(mi.UserList) <= mi.TableUser }