package pointmatch 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 EliminateScore int // 起始淘汰分数 ShrinkSec int // 改变淘汰分数时间 ShrinkScore int // 改变淘汰分数delta WinnerCount int // 最终剩下多少人赢 config *matchconfig currentRound int lastShrink int64 // 上一次缩圈时间 SecToShrink int // 还有多少秒缩圈 lastArrageTime int64 timerArrageUser *time.Timer } func newMatchInstance(matchNo, userId int, gameId int, gameRule string, totalUserCount int, tableUserCount int, enrollFee int, prize int, playTimeout int, config *matchconfig, eliminateScore, shringSec, shrinkScore, 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{}, Status: matchbase.MatchStatus_Free, config: config, PlayTimeout: playTimeout, EliminateScore: eliminateScore, ShrinkSec: shringSec, ShrinkScore: shrinkScore, WinnerCount: winnerCount, } return mi } func (mi *matchinstance) getCopy() matchinstance { var ret matchinstance d, _ := json.Marshal(mi) json.Unmarshal(d, &ret) return ret } func (mi *matchinstance) nextRound() { if mi.Status == matchbase.MatchStatus_Ended { return } mi.currentRound++ mi.EliminateScore += mi.ShrinkScore mi.lastShrink = time.Now().Unix() mi.SecToShrink = mi.ShrinkSec log.Debug("pointmatch matchNo[%d] EliminateScore[%d]", mi.MatchNo, mi.EliminateScore) // 检查一下是否存在没有玩的玩家并且已达淘汰分数 /* mi.lock.RLock() leftUserCount := len(mi.UserList) mi.lock.RUnlock() users := mi.getFreeUsers() flag := false for _, mu := range users { if mu.getTotalScore() < mi.EliminateScore && leftUserCount > mi.WinnerCount { rank := mi.addEleminatedUser(mu.UserId) postUserEliminationNotification(mu.UserId, mi.MatchNo, rank) leftUserCount-- flag = true } } // 如果有淘汰,则延迟检查是否结束 if flag && mi.checkRoundEnd() { return } */ time.AfterFunc(time.Second*time.Duration(mi.ShrinkSec), mi.nextRound) ni := matchbase.Match_notificationInfo{Msg: matchbase.Match_noti_shrink, ShrinkScore: mi.EliminateScore} d, _ := json.Marshal(ni) mi.sendNotification(-1, string(d)) } 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) log.Release(" Round[%d] EliminateScore[%d] ShrinkScore[%d] ShrinkSec[%d] WinnerCount[%d]", mi.currentRound, mi.EliminateScore, mi.ShrinkScore, mi.ShrinkSec, mi.WinnerCount) //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]", v.UserId, v.NickName, v.Score, 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],Room[%d],Chair[%d]", v.UserId, v.NickName, v.Score, 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) 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) 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("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, "pointmatch", "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.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, "pointmatch", "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, "pointmatch", "fee return", "") } } mi.lock.RUnlock() if mi.Prize > 0 && mi.Owner > 0 { cash.GiveMoney(mi.Owner, mi.Prize, common.LOGTYPE_POINTMATCH_CREATE_RETURN, "pointmatch", "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 } time.AfterFunc(time.Second*time.Duration(mi.ShrinkSec), mi.nextRound) // 人满了,可以开始 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_POINTMATCH_OWNER_COLLECT, "pointmatch", "owner", "") } if oldStatus != mi.Status { go postMatchStatusChangedNotificaiton(mi.MatchNo, oldStatus, mi.Status) } if oldStatus == matchbase.MatchStatus_Free { mi.lastShrink = time.Now().Unix() mi.SecToShrink = mi.ShrinkSec 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) { ret = append(ret, v) } } mi.lock.RUnlock() return ret } func (mi *matchinstance) isUserFree(userId int, lastEndTime int) bool { for _, v := range mi.liveRooms { if v.isEnded() { continue } if v.isUserExist(userId) { return false } } // 判断下最短时间 return int(time.Now().Unix())-lastEndTime >= match_timeoff_sec } func (mi *matchinstance) arrangeUsers() { mi.timerArrageUser = nil if mi.Status == matchbase.MatchStatus_Ended { log.Debug("pointmatch.matchinstance.arrangeUsers 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(len(mi.UserList)) for _, v := range users { am.addUser(v.UserId, v.GameCount, "", false) freeUserIds = append(freeUserIds, v.UserId) } log.Debug("pointmatch.matchinstance.arrangeUsers users %v", freeUserIds) tableUsers := am.checkAndArrange() tableCount := len(tableUsers) if tableCount == 0 { log.Release("pointmatch.matchinstance.arrangeUsers tableCount == 0") return } log.Debug("pointmatch.matchinstance.arrangeUsers arranged %v", tableUsers) 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("pointmatch.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 } 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 } go task.DoTaskAction(v, task.TaskAction_playmatch, 1, task.TaskScope{GameName: game.GetGameNameByGameId(mi.GameId)}) mu.GameCount++ rh.Users = append(rh.Users, matchbase.RoomHistoryUser{UserId: v, Score: mi.getUserScore(v)}) if mu.getTotalScore() < mi.EliminateScore && leftUserCount > mi.WinnerCount { rank := mi.addEleminatedUser(v) postUserEliminationNotification(v, mi.MatchNo, rank) mi.postOnUserEliminatedToReceivers(v, rank) leftUserCount-- } else { mu.clearRoomInfo() } if mi.isUserIn(v, winners) { mu.WinCount++ } } mi.RoomHistory = append(mi.RoomHistory, rh) mi.removeLiveRoom(roomNo) //mi.arrangeUsers() // 延迟以下,继续分配 if !mi.checkRoundEnd() && leftUserCount > mi.WinnerCount && mi.timerArrageUser == nil { mi.timerArrageUser = time.AfterFunc(time.Second*match_timeoff_sec, mi.arrangeUsers) } } 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.Score += 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, "pointmatch", "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, "pointmatch", "fee return", "") } } mi.lock.RUnlock() if mi.Prize > 0 && mi.Owner > 0 { cash.GiveMoney(mi.Owner, mi.Prize, common.LOGTYPE_POINTMATCH_CREATE_RETURN, "pointmatch", "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() } func (mi *matchinstance) resetSecToShrink() { if mi.Status == matchbase.MatchStatus_Playing { mi.SecToShrink = mi.ShrinkSec - int(time.Now().Unix()-mi.lastShrink) } else { mi.SecToShrink = 0 } if mi.SecToShrink < 0 { mi.SecToShrink = 0 } }