| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595 |
- package sngmatch
- 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/simplematch"
- platformconfig "bet24.com/servers/micros/platformconfig/proto"
- robot "bet24.com/servers/micros/userservices/proto"
- user "bet24.com/servers/micros/userservices/proto"
- )
- const config_key = "sngmatch_config"
- const refresh_config_sec = 600
- const match_time_out_ended = 120
- type sngmatchMgr struct {
- MatchConfigs []*matchconfig
- matches map[int][]*matchInfo
- lock *sync.RWMutex
- lockConfig *sync.RWMutex
- }
- var matchMgr *sngmatchMgr
- func getMatchManager() *sngmatchMgr {
- if matchMgr == nil {
- matchMgr = new(sngmatchMgr)
- matchMgr.lock = &sync.RWMutex{}
- matchMgr.lockConfig = &sync.RWMutex{}
- matchMgr.matches = make(map[int][]*matchInfo)
- }
- return matchMgr
- }
- func (mm *sngmatchMgr) run() {
- mm.loadConfig()
- go mm.checkTimeout()
- }
- func (mm *sngmatchMgr) loadConfig() {
- defer func() {
- time.AfterFunc(refresh_config_sec*time.Second, mm.loadConfig)
- }()
- configString := platformconfig.GetConfig(config_key)
- if configString == "" {
- data, err := os.ReadFile("serviceconf/sngmatch.json")
- if err != nil {
- log.Release("sngmatch.sngmatchMgr.loadData read json failed")
- return
- }
- configString = string(data)
- platformconfig.SetConfig(config_key, configString)
- }
- var configs []*matchconfig
- err := json.Unmarshal([]byte(configString), &configs)
- if err != nil {
- log.Release("sngmatch.sngmatchMgr.loadData Unmarshal failed err:%v", err)
- return
- }
- for _, v := range configs {
- v.calTotalPrize()
- mm.updateConfig(v)
- }
- }
- func (mm *sngmatchMgr) getOnlineUserCount(matchId int) int {
- ret := 0
- mm.lock.RLock()
- matches, ok := mm.matches[matchId]
- mm.lock.RUnlock()
- if !ok {
- return ret
- }
- for _, v := range matches {
- ret += v.getOnlineUserCount()
- }
- return ret
- }
- func (mm *sngmatchMgr) updateConfig(config *matchconfig) {
- mm.lockConfig.Lock()
- defer mm.lockConfig.Unlock()
- //for _,v := range mm.MatchConfigs {
- 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 *sngmatchMgr) 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 *sngmatchMgr) dump(param1, param2 string) {
- log.Release("-------------------------------")
- log.Release("sngmatch.sngmatchMgr.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 == "dismiss" {
- matchNo, err := strconv.Atoi(param2)
- if err != nil {
- log.Release("invalid param %s", param2)
- return
- }
- mm.dismissMatch(matchNo)
- return
- }
- mm.lock.RLock()
- for k, v := range mm.matches {
- log.Release(" MatchId[%d]", k)
- for _, v1 := range v {
- v1.dump()
- }
- log.Release(" -------------")
- }
- mm.lock.RUnlock()
- }
- func (mm *sngmatchMgr) dismissMatch(matchNo int) {
- mi := mm.getMatchByMatchNo(matchNo)
- if mi == nil {
- log.Release("sngmatchMgr.dismissMatch [%d] not found", matchNo)
- return
- }
- config := mm.getConfig(mi.MatchId)
- if config == nil {
- log.Release("sngmatchMgr.dismissMatch matchId[%d] not found", mi.MatchId)
- return
- }
- if mi.getStatus() == matchbase.MatchStatus_Ended {
- log.Release("sngmatchMgr.dismissMatch matchId[%d] ended", mi.MatchId)
- return
- }
- userList := mi.getUserList()
- for _, v := range userList {
- // 退钱
- if len(config.EnrollFee) > 0 {
- itm := mi.getUserFee(v, true)
- if itm.Count > 0 {
- inventory.AddItems(v, []item.ItemPack{itm},
- "sngmatch fee return", common.LOGTYPE_SNGMATCH_ENTER_RETURN)
- } else if config.DailyFreeCount > 0 {
- getFreeCountManager().reduceFreeCount(v, config.MatchId)
- }
- }
- }
- simplematch.DismissMatch(matchNo)
- }
- func (mm *sngmatchMgr) enrollSngMatch(matchId int, userId int, nickname string, faceId int, faceUrl string, feeIndex int) (int, string) {
- config := mm.getConfig(matchId)
- if config == nil {
- log.Release("sngmatchMgr.enrollSngMatch matchId[%d] not found", matchId)
- return 0, "Wrong MatchId"
- }
- log.Debug("enrollSngMatch matchId = %d config = %v", matchId, config)
- if !config.IsInTime() {
- log.Release("sngmatchMgr.enrollSngMatch matchId[%d] not open %v", matchId, config)
- return 0, "Not in match time"
- }
- if mm.isUserPlaying(userId) {
- return 0, "Already in a match"
- }
- mi := mm.getOrCreateMatch(matchId, config)
- if mi == nil {
- log.Release("sngmatchMgr.enrollSngMatch matchId[%d] getOrCreateMatch failed", matchId)
- return 0, "Serve error"
- }
- 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_SNGMATCH_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("sngmatch.enrollSngMatch failed %s", errMsg)
- return 0, errMsg
- }
- mi.setUserFee(userId, config.EnrollFee[feeIndex])
- }
- }
- mi.addEnrollUser(userId)
- // 玩家加入
- retCode, errMsg := simplematch.EnrollMatch(userId, nickname, faceId, faceUrl, mi.MatchNo)
- if retCode != 1 {
- return 0, errMsg
- }
- config.addOnline(1)
- return mi.MatchNo, "OK"
- }
- func (mm *sngmatchMgr) quitSngMatch(matchId int, userId int) bool {
- config := mm.getConfig(matchId)
- if config == nil {
- log.Release("sngmatchMgr.quitSngMatch 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("sngmatchMgr.quitSngMatch matchId[%d] no match found", matchId)
- return false
- }
- for _, v := range matches {
- if v.getStatus() == matchbase.MatchStatus_Free && v.isUserEnrolled(userId) {
- // 退钱
- if len(config.EnrollFee) > 0 {
- itm := v.getUserFee(userId, true)
- if itm.Count > 0 {
- inventory.AddItems(userId, []item.ItemPack{itm},
- "sngmatch fee return", common.LOGTYPE_SNGMATCH_ENTER_RETURN)
- } else if config.DailyFreeCount > 0 {
- getFreeCountManager().reduceFreeCount(userId, config.MatchId)
- }
- }
- ok := simplematch.QuitMatch(userId, v.MatchNo)
- if ok {
- config.addOnline(-1)
- }
- return ok
- }
- }
- return false
- }
- func (mm *sngmatchMgr) 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 *sngmatchMgr) 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 *sngmatchMgr) getOrCreateMatch(matchId int, config *matchconfig) *matchInfo {
- ret := mm.getCurrentMatch(matchId)
- if ret != nil {
- return ret
- }
- // 创建一个比赛
- matchNo, err := simplematch.CreateMatch(-1, config.GameId, config.GameRule, config.TotalUser,
- config.Target, config.TableUser, 0, 0, config.PlayTime, config.EleminateByScore, config.WinnerCount)
- if matchNo == 0 {
- log.Release("sngmatchMgr.getOrCreateMatch CreateMatch failed %s", err)
- return nil
- }
- mi := simplematch.GetMatchInstance(matchNo)
- if mi == nil {
- log.Release("sngmatchMgr.getOrCreateMatch GetMatchInstance == nil")
- return nil
- }
- matchInfo := newMatchInfo(config.MatchId, matchNo, mi, mm, config.RobotConfig)
- mi.RegisterReceiver(mm)
- mm.lock.Lock()
- mm.matches[matchId] = append(mm.matches[matchId], matchInfo)
- mm.lock.Unlock()
- return matchInfo
- }
- // MatchInstanceReceiver
- func (mm *sngmatchMgr) OnMatchStart(matchNo int) {
- log.Debug("sngmatchMgr.OnMatchStart [%d]", matchNo)
- mi := mm.getMatchByMatchNo(matchNo)
- if mi == nil {
- log.Release("sngmatchMgr.OnMatchStart [%d] matchInfo not found", matchNo)
- return
- }
- mi.StartTime = time.Now().Unix()
- go mi.onMatchStart()
- }
- func (mm *sngmatchMgr) OnMatchCancelled(matchNo int) {
- log.Debug("sngmatchMgr.OnMatchCancelled [%d]", matchNo)
- mi := mm.getMatchByMatchNo(matchNo)
- if mi == nil {
- log.Release("sngmatchMgr.OnMatchCancelled [%d] matchInfo not found", matchNo)
- return
- }
- config := mm.getConfig(mi.MatchId)
- if config == nil {
- log.Release("sngmatchMgr.OnMatchCancelled [%d] config not found", matchNo)
- return
- }
- matchInstance := simplematch.GetMatchInstance(matchNo)
- if matchInstance == nil {
- log.Release("sngmatchMgr.OnMatchCancelled [%d] matchInstance not found", matchNo)
- return
- }
- // 退费
- userList := matchInstance.GetUserList()
- for _, userId := range userList {
- // 退钱
- if len(config.EnrollFee) > 0 {
- itm := mi.getUserFee(userId, true)
- if itm.Count > 0 {
- inventory.AddItems(userId, []item.ItemPack{itm},
- "sngmatch fee return", common.LOGTYPE_SNGMATCH_ENTER_RETURN)
- } else if config.DailyFreeCount > 0 {
- getFreeCountManager().reduceFreeCount(userId, config.MatchId)
- }
- }
- }
- config.addOnline(-len(userList))
- }
- func (mm *sngmatchMgr) OnMatchEnd(matchNo int) {
- log.Debug("sngmatchMgr.OnMatchEnd [%d]", matchNo)
- mi := mm.getMatchByMatchNo(matchNo)
- if mi == nil {
- log.Release("sngmatchMgr.OnMatchEnd [%d] matchInfo not found", matchNo)
- return
- }
- mi.EndTime = time.Now().Unix()
- config := mm.getConfig(mi.MatchId)
- if config == nil {
- log.Release("sngmatchMgr.OnMatchEnd matchId[%d] not found", mi.MatchId)
- return
- }
- // 找出胜利者给发奖励
- matchInstance := simplematch.GetMatchInstance(matchNo)
- if matchInstance == nil {
- log.Release("sngmatchMgr.OnMatchEnd [%d] matchInstance not found", matchNo)
- return
- }
- winners := matchInstance.GetWinners()
- if len(winners) == 0 {
- log.Release("sngmatchMgr.OnMatchEnd [%d] no winners", matchNo)
- return
- }
- config.addOnline(-config.TotalUser)
- // 加入历史记录
- var h snghistory
- h.matchconfig = *config
- h.RobotConfig = nil
- h.MatchNo = matchNo
- h.StartTime = mi.StartTime
- h.EndTime = mi.EndTime
- h.Winners = winners
- matchUsers := matchInstance.GetAllMatchUsers()
- // 所有参与人员
- sort.Slice(matchUsers, func(i, j int) bool {
- return matchUsers[i].Rank < matchUsers[j].Rank
- })
- for _, v := range matchUsers {
- enrollFee := mi.getUserFee(v.UserId, false)
- h.EnrollUsers = append(h.EnrollUsers, historyUser{
- MatchUserBrief: *v.ToBrief(),
- enrollFeeItemId: enrollFee.ItemId,
- enrollFeeCount: enrollFee.Count,
- enrollTime: int(v.EnrollTime),
- prize: config.getPrizes(v.Rank),
- })
- // 已淘汰用户不再发奖励
- if mi.isUserAwarded(v.UserId) {
- continue
- }
- prize := config.getPrizes(v.Rank)
- if len(prize) > 0 {
- inventory.AddItems(v.UserId, prize, "sng_prize", common.LOGTYPE_SNGMATCH_PRIZE)
- postUserRankNotification(v.UserId, config.MatchId, matchNo, v.Rank, prize)
- log.Debug("OnMatchEnd 发送通知和奖励 [%d] %v", v.UserId, prize)
- mi.setUserAwarded(v.UserId)
- }
- /*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
- })*/
- }
- // 最后把所有报名记录都加上
- h.setAllEnrolledUsers(mi.enrolledUsers)
- getHistoryManager().addHistory(h)
- go writeRoomRecordToDB(&h)
- }
- func (mm *sngmatchMgr) OnUserEliminated(matchNo int, userId int, rank int) {
- log.Debug("sngmatchMgr.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)
- postUserRankNotification(userId, config.MatchId, matchNo, 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 *sngmatchMgr) getMatchByMatchNo(matchNo int) *matchInfo {
- mm.lock.RLock()
- defer mm.lock.RUnlock()
- for _, v := range mm.matches {
- for _, v1 := range v {
- if v1.MatchNo == matchNo {
- return v1
- }
- }
- }
- return nil
- }
- func (mm *sngmatchMgr) 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 *sngmatchMgr) getUserMatchId(userId int) int {
- mm.lock.RLock()
- defer mm.lock.RUnlock()
- for _, v := range mm.matches {
- for _, v1 := range v {
- if v1.isUserPlaying(userId) {
- return v1.MatchId
- }
- }
- }
- return 0
- }
- func (mm *sngmatchMgr) addARobot(matchId int) bool {
- m := mm.getCurrentMatch(matchId)
- if m == nil {
- log.Release("sngmatchMgr.addARobot matchId[%d] has no live match", matchId)
- return false
- }
- loopCount := 0
- for {
- loopCount++
- if loopCount > 20 {
- log.Release("sngmatchMgr.addARobot matchId[%d] get a robot failed", matchId)
- return false
- }
- robotId := robot.GetARobot()
- if mm.isUserPlaying(robotId) {
- continue
- }
- usr := user.GetUserInfo(robotId)
- if usr == nil {
- continue
- }
- mm.enrollSngMatch(matchId, robotId, usr.NickName, usr.FaceId, usr.FaceUrl, 0)
- break
- }
- return true
- }
- func (mm *sngmatchMgr) isUserPlaying(userId int) bool {
- mm.lock.RLock()
- defer mm.lock.RUnlock()
- for _, m := range mm.matches {
- for _, mi := range m {
- if mi.isUserPlaying(userId) {
- return true
- }
- }
- }
- return false
- }
|