| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922 |
- package setsmatch
- 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"
- )
- const match_timeoff_sec = 5
- type matchinstance struct {
- Owner int
- GameId int
- GameRule string
- TotalUser int
- TableUser int
- PlayTimeout int
- Fee int
- Prize int
- MatchNo int
- StartTime string
- startTime int64
- endTime int64
- Status int
- createTime int64
- UserList []*matchuser `json:",omitempty"`
- EliminateUsers []*matchuser `json:",omitempty"` // 已淘汰玩家
- liveRooms []*matchroom // 目前正在进行的私人房间号
- lock *sync.RWMutex
- RoomHistory []matchbase.RoomHistory
- receivers []matchbase.MatchInstanceReceiver
- WinnerCount int // 最终剩下多少人赢
- config *matchconfig
- lastArrageTime int64
- lockRoomEnd *sync.RWMutex
- }
- func newMatchInstance(matchNo, userId int, gameId int,
- gameRule string, totalUserCount int,
- tableUserCount int, enrollFee int, prize int, playTimeout int,
- config *matchconfig, winnerCount int) *matchinstance {
- mi := &matchinstance{
- MatchNo: matchNo,
- Owner: userId,
- GameId: gameId,
- GameRule: gameRule,
- TotalUser: totalUserCount,
- TableUser: tableUserCount,
- Fee: enrollFee,
- Prize: prize,
- createTime: time.Now().Unix(),
- lock: &sync.RWMutex{},
- lockRoomEnd: &sync.RWMutex{},
- Status: matchbase.MatchStatus_Free,
- config: config,
- PlayTimeout: playTimeout,
- 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.endTime >= 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],BaseScore[%d],GameCount[%d],Room[%d],Chair[%d]",
- v.UserId, v.NickName, v.Score, v.BaseScore, v.GameCount, v.RoomNo, v.ChairId)
- }
- }
- if len(mi.EliminateUsers) > 0 {
- log.Release(" EliminateUsers:")
- for _, v := range mi.EliminateUsers {
- log.Release(" UserId[%d],NickName[%s],Score[%d],GameCount[%d],Room[%d],Chair[%d]",
- v.UserId, v.NickName, v.Score, v.GameCount, v.RoomNo, v.ChairId)
- }
- }
- 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()
- return mi.getUserWithoutLock(userId)
- }
- func (mi *matchinstance) getUserWithoutLock(userId int) *matchuser {
- 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.getTotalScore()
- }
- func (mi *matchinstance) getUserLastScore(userId int) int {
- mu := mi.getUser(userId)
- if mu == nil {
- return 0
- }
- return mu.getUserLastScore()
- }
- func (mi *matchinstance) addUser(userId int, nickname string, faceId int, faceUrl string) (ok bool, errMsg string) {
- ok = false
- errMsg = "ok"
- if mi.Status != matchbase.MatchStatus_Free {
- errMsg = "Match has Started"
- log.Release("setsmatch.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_POINTMATCH_ENTER, "setsmatch", "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, mi.config.InitialScore, mi.config.getBaseScore(0)))
- mi.lock.Unlock()
- ok = true
- mi.checkAndStartMatch()
- 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 {
- cash.GiveMoney(userId, mi.Fee, common.LOGTYPE_POINTMATCH_ENTER_RETURN, "setsmatch", "fee return", "")
- }
- 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_POINTMATCH_ENTER_RETURN,
- "setsmatch", "fee return", "")
- }
- }
- mi.lock.RUnlock()
- if mi.Prize > 0 && mi.Owner > 0 {
- cash.GiveMoney(mi.Owner, mi.Prize, common.LOGTYPE_POINTMATCH_CREATE_RETURN, "setsmatch", "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) checkAndStartMatch() {
- mi.lock.RLock()
- userCount := len(mi.UserList)
- mi.lock.RUnlock()
- // 第一轮必须人满
- if userCount < mi.TotalUser {
- return
- }
- if userCount < mi.TableUser {
- log.Release("matchinstance.checkAndStartMatch userCount[%d] < mi.TableUser[%d]", userCount, mi.TableUser)
- return
- }
- // 需要几桌?
- tableCount := userCount / mi.TableUser
- if tableCount == 0 {
- log.Release("matchinstance.checkAndStartMatch tableCount == 0")
- mi.dump()
- return
- }
- // 人满了,可以开始
- 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 && oldStatus == matchbase.MatchStatus_Free && mi.Owner > 0 {
- cash.GiveMoney(mi.Owner, mi.Fee*userCount, common.LOGTYPE_POINTMATCH_OWNER_COLLECT, "setsmatch", "owner", "")
- }
- if oldStatus != mi.Status {
- go postMatchStatusChangedNotificaiton(mi.MatchNo, oldStatus, mi.Status)
- }
- if oldStatus == matchbase.MatchStatus_Free {
- mi.postOnMatchStartToReceivers()
- }
- mi.arrangeUsers()
- }
- func (mi *matchinstance) getFreeUsers() []*matchuser {
- var ret []*matchuser
- mi.lock.RLock()
- for _, v := range mi.UserList {
- if mi.isUserFree(v.UserId, v.lastEndTime, v.lastArrageTime) {
- //v.lastArrageTime = int(time.Now().Unix())
- ret = append(ret, v)
- }
- }
- mi.lock.RUnlock()
- return ret
- }
- func (mi *matchinstance) isUserFree(userId int, lastEndTime int, lastArrageTime int) bool {
- for _, v := range mi.liveRooms {
- if v.isEnded() {
- continue
- }
- if v.isUserExist(userId) {
- return false
- }
- }
- // 判断下最短时间
- now := int(time.Now().Unix())
- if now-lastArrageTime <= 10 {
- return false
- }
- return now-lastEndTime >= match_timeoff_sec
- }
- func (mi *matchinstance) arrangeUsers() {
- if mi.Status == matchbase.MatchStatus_Ended {
- log.Debug("setsmatch.matchinstance.arrangeUsers Ended")
- return
- }
- totalUserCount := len(mi.UserList)
- if totalUserCount <= mi.WinnerCount {
- log.Debug("setsmatch.matchinstance.arrangeUsers winnercount ended")
- return
- }
- // 检查一下间隔
- now := time.Now().Unix()
- if now-mi.lastArrageTime < 2 {
- time.AfterFunc(2*time.Second, mi.arrangeUsers)
- return
- }
- mi.lastArrageTime = now
- am := createArrangeManager(mi.TableUser)
- users := mi.getFreeUsers()
- var freeUserIds []int
- am.setTotalUserCount(totalUserCount)
- for _, v := range users {
- am.addUser(v.UserId, v.GameCount, "", false)
- freeUserIds = append(freeUserIds, v.UserId)
- }
- //log.Debug("setsmatch.matchinstance.arrangeUsers users %v", freeUserIds)
- tableUsers := am.checkAndArrange()
- tableCount := len(tableUsers)
- if tableCount == 0 {
- //log.Release("setsmatch.matchinstance.arrangeUsers tableCount == 0")
- // 还可以继续匹配,防止死锁
- time.AfterFunc(5*time.Second, mi.arrangeUsers)
- return
- }
- log.Debug("setsmatch.matchinstance.arrangeUsers arranged %v", tableUsers)
- // 把已分配的用户锁住
- for _, t := range tableUsers {
- for _, userId := range t {
- usr := mi.getUserWithoutLock(userId)
- if usr != nil {
- usr.lastArrageTime = int(time.Now().Unix())
- }
- }
- }
- rooms := make([]*matchroom, tableCount)
- for i := 0; i < tableCount; i++ {
- // 创建私人场
- roomNo, err := privateroom.CreatePrivateRoomByUser(mi.Owner, mi.GameId, mi.GameRule, 1, mi.TableUser,
- 0, 0, privateroom.RoomType_SimpleMatch, mi.PlayTimeout, false, "")
- if roomNo == 0 {
- log.Release("matchinstance.arrangeUsers createRoom failed %s", err)
- mi.closeMatch("normal end")
- return
- }
- rooms[i] = newMatchRoom(roomNo, mi)
- }
- // 玩家都分配好了,加入私人场
- //mi.lock.RLock()
- for r := 0; r < len(rooms); r++ {
- for u := 0; u < mi.TableUser; u++ {
- usr := mi.getUserWithoutLock(tableUsers[r][u])
- if usr == nil {
- log.Release("matchinstance.arrangeUsers user [%d] not found", tableUsers[r][u])
- return
- }
- rooms[r].addUser(usr.UserId)
- go func(roomIndex int, chairId int) {
- var ret struct {
- ErrMsg string
- ServerAddr string
- TableId int
- ChairId int
- }
- retString := privateroom.UserRequestSit(rooms[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.checkAndStartMatch try enter privateroom unmarshal failed %v", err)
- return
- }
- if ret.ServerAddr == "" {
- log.Release("matchinstance.checkAndStartMatch try enter privateroom failed %s", ret.ErrMsg)
- return
- }
- log.Debug("%d user[%d] enter room %d chair %d", mi.MatchNo, usr.UserId, rooms[roomIndex].RoomNo, ret.ChairId)
- usr.arrangeRoom(rooms[roomIndex].RoomNo, ret.ServerAddr, ret.TableId, ret.ChairId)
- go postUserMatchRoomNotification(usr.UserId, mi.MatchNo, ret.ServerAddr, ret.TableId, ret.ChairId)
- sec := 10
- if robot.IsRobot(usr.UserId) {
- sec = 5
- }
- privateroom.ForceUserEnter(usr.UserId, usr.RoomNo, ret.ChairId, sec)
- }(r, u)
- }
- }
- //mi.lock.RUnlock()
- mi.lock.Lock()
- mi.liveRooms = append(mi.liveRooms, rooms...)
- mi.lock.Unlock()
- }
- func (mi *matchinstance) getRoom(roomNo int) *matchroom {
- for _, v := range mi.liveRooms {
- if v.RoomNo == roomNo {
- return v
- }
- }
- return nil
- }
- // 比赛进程
- func (mi *matchinstance) OnRoomStart(roomNo int) {
- mr := mi.getRoom(roomNo)
- if mr == nil {
- return
- }
- mr.Status = privateroom.PrivateRoomStatus_Playing
- }
- func (mi *matchinstance) OnRoomEnd(roomNo int, winners []int) {
- mr := mi.getRoom(roomNo)
- if mr == nil {
- log.Debug("setsmatch.matchinstance.OnRoomEnd[%d] room not found", roomNo)
- return
- }
- if !mr.isValidUsers(winners) {
- log.Release("matchinstance[%d].onRoomEnd[%d] winners not exist", mi.MatchNo, roomNo)
- return
- }
- mi.lockRoomEnd.Lock()
- defer mi.lockRoomEnd.Unlock()
- mr.Status = privateroom.PrivateRoomStatus_Ended
- var rh matchbase.RoomHistory
- rh.RoomNo = roomNo
- rh.EndTime = time.Now().Unix()
- mi.lock.RLock()
- leftUserCount := len(mi.UserList)
- mi.lock.RUnlock()
- // 发淘汰信息
- for _, v := range mr.Users {
- mu := mi.getUser(v)
- if mu == nil {
- continue
- }
- if mi.isUserIn(v, winners) {
- mu.WinCount++
- }
- go task.DoTaskAction(v, task.TaskAction_playmatch, 1, task.TaskScope{GameName: game.GetGameNameByGameId(mi.GameId)})
- mu.GameCount++
- mu.BaseScore = mi.config.getBaseScore(mu.GameCount)
- rh.Users = append(rh.Users, matchbase.RoomHistoryUser{UserId: v, Score: mi.getUserLastScore(v)})
- if mi.config.isEliminated(mu.GameCount-1, mu.Score) && leftUserCount > mi.WinnerCount {
- rank := mi.addEleminatedUser(v)
- postUserEliminationNotification(v, mi.MatchNo, rank)
- mi.postOnUserEliminatedToReceivers(v, rank)
- leftUserCount--
- } else {
- mu.clearRoomInfo()
- }
- }
- mi.RoomHistory = append(mi.RoomHistory, rh)
- mi.removeLiveRoom(roomNo)
- //mi.arrangeUsers()
- // 延迟以下,继续分配
- if !mi.checkRoundEnd() && leftUserCount > mi.WinnerCount {
- time.AfterFunc(time.Second*match_timeoff_sec, mi.arrangeUsers)
- }
- // 重新排名
- mi.setUserRanks()
- 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()
- }
- func (mi *matchinstance) setUserRanks() {
- 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
- }
- 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("setsmatch.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)
- }
- */
- }
- func (mi *matchinstance) removeLiveRoom(roomNo int) {
- mi.lock.Lock()
- defer mi.lock.Unlock()
- for i := 0; i < len(mi.liveRooms); i++ {
- if mi.liveRooms[i].RoomNo == roomNo {
- mi.liveRooms = append(mi.liveRooms[:i], mi.liveRooms[i+1:]...)
- return
- }
- }
- log.Release("poingmatch.matchinstance.removeLiveRoom %d not found", roomNo)
- }
- func (mi *matchinstance) OnRoomUserScoreChanged(roomNo int, userId int, score int) {
- mr := mi.getRoom(roomNo)
- if mr == nil {
- return
- }
- mu := mi.getUser(userId)
- if mu == nil {
- log.Release("matchinstance[%d].OnRoomUserScoreChanged[%d] user not exist", mi.MatchNo, userId)
- return
- }
- mu.addScore(score)
- }
- func (mi *matchinstance) OnRoomStatusChanged(roomNo int, old, new int) {
- }
- func (mi *matchinstance) addEleminatedUser(userId 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)
- v.Rank = len(mi.UserList)
- ret = v.Rank
- // delete
- mi.UserList = append(mi.UserList[:i], mi.UserList[i+1:]...)
- }
- }
- mi.lock.Unlock()
- return ret
- }
- func (mi *matchinstance) checkRoundEnd() bool {
- if mi.Status == matchbase.MatchStatus_Ended {
- return true
- }
- // 结束了,把非晋级玩家清理
- mi.lock.Lock()
- leftUserCount := len(mi.UserList)
- mi.lock.Unlock()
- if leftUserCount > mi.WinnerCount {
- return false
- }
- // 看下是否所有房间都结束了
- for _, v := range mi.liveRooms {
- if !v.isEnded() {
- return false
- }
- }
- if leftUserCount < mi.WinnerCount {
- mi.lock.Lock()
- for i := 0; i < mi.WinnerCount-leftUserCount; i++ {
- // 把淘汰的人补充进来
- if len(mi.EliminateUsers) > 0 {
- mi.UserList = append(mi.UserList, mi.EliminateUsers[len(mi.EliminateUsers)-1])
- mi.EliminateUsers = mi.EliminateUsers[:len(mi.EliminateUsers)-1]
- }
- }
- mi.lock.Unlock()
- }
- // 如果人数已经不足开桌,那么比赛就结束了
- mi.lock.Lock()
- sort.Slice(mi.UserList, func(i, j int) bool {
- return mi.UserList[i].getTotalScore() > mi.UserList[j].getTotalScore()
- })
- for i := 0; i < len(mi.UserList); i++ {
- mi.UserList[i].Rank = i + 1
- }
- mi.lock.Unlock()
- mi.onMatchEnded(mi.WinnerCount)
- return true
- }
- 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
- mi.endTime = time.Now().Unix()
- 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_POINTMATCH_PRIZE, "setsmatch", "prize", "")
- }
- go task.DoTaskAction(v.UserId, task.TaskAction_matchpromote, 1, task.TaskScope{GameName: game.GetGameNameByGameId(mi.GameId)})
- // 发通知
- go postUserRankNotification(v.UserId, mi.MatchNo, 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) 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) postOnMatchCancelledToReceivers() {
- for _, v := range mi.receivers {
- v.OnMatchCancelled(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
- }
- 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_POINTMATCH_ENTER_RETURN,
- "setsmatch", "fee return", "")
- }
- }
- mi.lock.RUnlock()
- if mi.Prize > 0 && mi.Owner > 0 {
- cash.GiveMoney(mi.Owner, mi.Prize, common.LOGTYPE_POINTMATCH_CREATE_RETURN, "setsmatch", "create return", "")
- }
- isCancelled = true
- }
- mi.Status = matchbase.MatchStatus_Ended
- if !isCancelled {
- mi.postOnMatchEndToReceivers()
- } else {
- mi.postOnMatchCancelledToReceivers()
- }
- mi.lock.Lock()
- mi.UserList = nil
- mi.EliminateUsers = nil
- mi.lock.Unlock()
- }
|