diff --git a/dbproxy/svc/l_matchawardlog.go b/dbproxy/svc/l_matchawardlog.go index bbc8dfd..d482031 100644 --- a/dbproxy/svc/l_matchawardlog.go +++ b/dbproxy/svc/l_matchawardlog.go @@ -75,8 +75,9 @@ func (svc *MatchAwardSvc) GetMatchAward(plt string, ret *model.MatchAward) (err err = c.Find(nil).One(ret) if err != nil && err != mgo.ErrNotFound { logger.Logger.Errorf("GetMatchAward err:%v", err) + return err } - return err + return nil } func init() { diff --git a/worldsrv/action_login.go b/worldsrv/action_login.go index c66ccc9..296cbd6 100644 --- a/worldsrv/action_login.go +++ b/worldsrv/action_login.go @@ -216,7 +216,7 @@ func (this *CSLoginHandler) Process(s *netlib.Session, packetid int, data interf if player != nil { waitMatch, _ = TournamentMgr.IsMatchWaiting(player.Platform, player.SnId) } - if len(lss) > 0 && (player != nil && (player.scene != nil || player.thrscene != 0 || waitMatch || TournamentMgr.IsMatching(player.SnId))) { + if len(lss) > 0 && (player != nil && (player.scene != nil || player.thrscene != 0 || waitMatch || TournamentMgr.IsGaming(player.SnId))) { sendSCLogin(login_proto.OpResultCode_OPRC_LoginOtherPlace) sendSCDisconnect(common.KickReason_Logining) return nil diff --git a/worldsrv/action_tournament.go b/worldsrv/action_tournament.go index 64d889a..eb5286f 100644 --- a/worldsrv/action_tournament.go +++ b/worldsrv/action_tournament.go @@ -82,8 +82,8 @@ func CSSignRace(s *netlib.Session, packetid int, data interface{}, sid int64) er } default: // 取消报名 - if TournamentMgr.IsMatching(p.SnId) { - logger.Logger.Warnf("player(%v) IsMatching.", p.SnId) + if TournamentMgr.IsGaming(p.SnId) { + logger.Logger.Warnf("player(%v) IsGaming.", p.SnId) } else { //取消报名 TournamentMgr.CancelSignUp(platform, tmId, p.SnId) @@ -115,7 +115,7 @@ func CSMatchList(s *netlib.Session, packetId int, data interface{}, sid int64) e // 开始时间排序 sort.Slice(list, func(i, j int) bool { - return list[i].StartTime < list[j].StartTime + return list[i].StartTime.Compare(list[j].StartTime) == -1 }) for _, v := range list { diff --git a/worldsrv/matchscenemgr.go b/worldsrv/matchscenemgr.go index 83aacdc..29bb005 100644 --- a/worldsrv/matchscenemgr.go +++ b/worldsrv/matchscenemgr.go @@ -1,12 +1,14 @@ package main import ( - "mongo.games.com/game/srvdata" + "time" + "mongo.games.com/goserver/core/logger" "mongo.games.com/game/common" "mongo.games.com/game/proto" "mongo.games.com/game/protocol/server" + "mongo.games.com/game/srvdata" ) var MatchSceneMgrSingleton = &MatchSceneMgr{} @@ -119,6 +121,7 @@ func (ms *MatchSceneMgr) MatchStart(tm *TmMatch) { // NewRoundStart 开始非首轮比赛 func (ms *MatchSceneMgr) NewRoundStart(tm *TmMatch, mct []*PlayerMatchContext, finals bool, round int32) { + tm.RoundTime = time.Now() var scene *Scene csp := CoinSceneMgrSingleton.GetCoinScenePool(tm.Platform, tm.dbGameFree.GetId()) if csp == nil { diff --git a/worldsrv/scene.go b/worldsrv/scene.go index 06327ea..0907ad8 100644 --- a/worldsrv/scene.go +++ b/worldsrv/scene.go @@ -899,7 +899,7 @@ func (this *Scene) TryForceDeleteMatchInfo() { if players, exist := TournamentMgr.players[this.MatchSortId]; exist { for _, player := range this.players { if player != nil && !player.IsRob { - if TournamentMgr.IsMatching(player.SnId) { + if TournamentMgr.IsGaming(player.SnId) { delete(players, player.SnId) } } diff --git a/worldsrv/tmmatch.go b/worldsrv/tmmatch.go index ec50184..0da47f7 100644 --- a/worldsrv/tmmatch.go +++ b/worldsrv/tmmatch.go @@ -1,6 +1,7 @@ package main import ( + "fmt" "math" "math/rand" "sort" @@ -49,10 +50,17 @@ type TmMatch struct { robotGrades map[int][]*TmGradeInfo // 第几轮:玩家积分 copyRobotGrades []*TmGradeInfo // 最近一轮的机器人积分备份 useRobot int32 // 是否使用机器人 - StartTime int64 // 本场比赛开始时间 + StartTime time.Time // 本场比赛开始时间 + RoundTime time.Time // 本轮开始时间 +} + +func (tm *TmMatch) String() string { + return fmt.Sprintf("比赛配置id: %v 比赛id:%v 开启机器人:%v 比赛开始时间: %v 本轮开始时间:%v 比赛玩家: %v", + tm.TMId, tm.SortId, tm.useRobot, tm.StartTime, tm.RoundTime, tm.TmPlayer) } func NewTmMatch(platform string, match *webapi_proto.GameMatchDate, players map[int32]*TmPlayer) *TmMatch { + now := time.Now() ret := &TmMatch{ SortId: getSortId(), TMId: match.Id, @@ -63,7 +71,8 @@ func NewTmMatch(platform string, match *webapi_proto.GameMatchDate, players map[ dbGameFree: srvdata.PBDB_GameFreeMgr.GetData(match.GameFreeId), robotGrades: make(map[int][]*TmGradeInfo), useRobot: match.UseRobot, - StartTime: time.Now().Unix(), + StartTime: now, + RoundTime: now, } ret.copyPlayers(players) diff --git a/worldsrv/tournament.go b/worldsrv/tournament.go index 4fd672f..3dd4624 100644 --- a/worldsrv/tournament.go +++ b/worldsrv/tournament.go @@ -84,16 +84,18 @@ type PlayerRoundInfo struct { type Tournament struct { common.BaseClockSinker - TypeList map[string]*webapiproto.GameMatchType // 比赛类型列表 平台id:比赛类型列表 - GameMatchDateList map[string]map[int32]*webapiproto.GameMatchDate // 比赛配置,platform:比赛场配置id:比赛配置 - singleSignupPlayers map[int32]*SignupInfo // 开启机器人时,报名的玩家,玩家Id:报名信息 - signupPlayers map[string]map[int32]*SignInfo // 报名的玩家 platform:比赛配置id:报名人 - playerWaitStart map[int32]int64 // 等待时间 玩家Id:等待时长秒 - matches map[int32]map[int64]*TmMatch // 开始比赛的数据,比赛配置Id:比赛顺序序号:一场开始的比赛数据 - players map[int64]map[int32]*PlayerMatchContext // 比赛中玩家 比赛顺序序号:玩家id:玩家信息 - roundPlayers map[int64]map[int32]*PlayerRoundInfo // 每轮比赛数据备份 比赛顺序序号:第几轮 - finalPerRank map[int64][]*PerRankInfo // 本场比赛排名,每淘汰一位记录一位,最后记录决赛玩家 比赛顺序序号 - MatchAwardNum map[string]map[int32]int32 // 比赛配置Id:比赛奖励次數 + TypeList map[string]*webapiproto.GameMatchType // 平台id:比赛类型列表 + GameMatchDateList map[string]map[int32]*webapiproto.GameMatchDate // 平台id:比赛场配置id:比赛配置 + + singleSignupPlayers map[int32]*SignupInfo // 玩家Id:报名信息; 使用机器人时的报名信息 + signupPlayers map[string]map[int32]*SignInfo // 平台id:比赛配置id:报名信息; 不使用机器人时的报名信息 + MatchAwardNum map[string]map[int32]int32 // 平台id:比赛配置Id:发第一名奖励次数 + + playerWaitStart map[int32]int64 // 玩家Id:等待时长秒; 玩家报名后等待比赛开始 + matches map[int32]map[int64]*TmMatch // 比赛配置Id:比赛顺序序号:开始的比赛数据 + players map[int64]map[int32]*PlayerMatchContext // 比赛顺序序号:玩家id:玩家信息 + roundPlayers map[int64]map[int32]*PlayerRoundInfo // 比赛顺序序号:第几轮:结算记录 + finalPerRank map[int64][]*PerRankInfo // 比赛顺序序号:本场比赛排名,每淘汰一位记录一位,最后记录决赛玩家 } func NewTournament() *Tournament { @@ -111,6 +113,61 @@ func NewTournament() *Tournament { return ret } +func (this *Tournament) ModuleName() string { + return "Tournament" +} + +func (this *Tournament) Init() { + logger.Logger.Trace("Tournament Init") + for _, v := range PlatformMgrSingleton.GetPlatforms() { + if v == nil || v.IdStr == "0" { + continue + } + ret, err := model.GetMatchAward(v.IdStr) + if err != nil { + logger.Logger.Warnf("GetMatchAward error %v", err) + continue + } + if this.MatchAwardNum == nil { + this.MatchAwardNum = make(map[string]map[int32]int32) + } + this.MatchAwardNum[v.IdStr] = ret.Award + } +} + +func (this *Tournament) Update() { + // 使用机器人的情况 + for snId, info := range this.singleSignupPlayers { + if info == nil || info.Ts <= 0 { + continue + } + matchInfo := this.GetMatchInfo(info.Platform, info.TmId, 0) + if this.IsMatchOn(matchInfo) && !this.IsOutTime(matchInfo) && this.IsRobotOn(matchInfo) { + needTime := this.playerWaitStart[snId] + if time.Now().Unix()-info.Ts > needTime { + signInfo := &SignInfo{ + signup: make(map[int32]*TmPlayer), + Platform: info.Platform, + MaxCnt: int(matchInfo.MatchNumebr), + } + seq := rand.Intn(int(matchInfo.MatchNumebr)) + 1 + signInfo.signup[snId] = &TmPlayer{SnId: snId, seq: seq} + this.signupPlayers[info.Platform][info.TmId] = signInfo + + //倒计时结束 开始比赛 + this.Start(info.Platform, info.TmId) + } + } else { + this.CancelSignUpAll(info.Platform, info.TmId) + } + } +} + +func (this *Tournament) Shutdown() { + this.SaveMatchAward() + module.UnregisteModule(this) +} + // 检查下数据是否合法(主要检查报名人数和晋级方式) n n|...|4|1 func (this *Tournament) checkData(cfg *webapiproto.GameMatchDate) bool { if cfg == nil { @@ -486,8 +543,8 @@ func (this *Tournament) GetAllMatchInfo(platform string) map[int32]*webapiproto. return nil } -// IsMatching 判断是否在比赛中 -func (this *Tournament) IsMatching(snId int32) bool { +// IsGaming 判断是否在比赛中 +func (this *Tournament) IsGaming(snId int32) bool { if this.players != nil { for _, v := range this.players { if v != nil { @@ -666,7 +723,7 @@ func (this *Tournament) SignUp(tmId int32, p *Player) (bool, int32) { } // 已报名 isWaiting, _ := this.IsMatchWaiting(p.Platform, p.SnId) - if this.IsMatching(p.SnId) || isWaiting { + if this.IsGaming(p.SnId) || isWaiting { return false, int32(tournament.SignRaceCode_OPRC_Repeat) } if this.GetMatchAwardNum(p.Platform, tmId) <= 0 { @@ -783,7 +840,7 @@ func (this *Tournament) CancelSignUpAll(platform string, tmId int32) { func (this *Tournament) Quit(platform string, snid int32) { logger.Logger.Tracef("TournamentMgr.Quit: snId:%d", snid) isWaiting, tmid := this.IsMatchWaiting(platform, snid) - if isWaiting && !this.IsMatching(snid) { + if isWaiting && !this.IsGaming(snid) { this.CancelSignUp(platform, tmid, snid) } } @@ -861,6 +918,7 @@ func (this *Tournament) Start(platform string, tmId int32) { // 开始比赛,清除报名数据 for _, v := range signInfo.signup { delete(this.singleSignupPlayers, v.SnId) + delete(this.playerWaitStart, v.SnId) TaskSubjectSingleton.Touch(common.TaskTypeJoinMatch, &TaskData{ SnId: v.SnId, GameID: int(tm.dbGameFree.GetGameId()), @@ -880,9 +938,10 @@ func (this *Tournament) Start(platform string, tmId int32) { // StopMatch 比赛结束 func (this *Tournament) StopMatch(tmId int32, sortId int64) { logger.Logger.Tracef("StopMatch:%v, %v", tmId, sortId) + var tm *TmMatch //房间清理 if this.matches[tmId] != nil && this.matches[tmId][sortId] != nil { - tm := this.matches[tmId][sortId] + tm = this.matches[tmId][sortId] matchLog := this.MakeMatchLog(tm.Platform, tmId, sortId) this.saveMatchLog(matchLog) tm.Stop() @@ -1030,6 +1089,25 @@ func (this *Tournament) GetRank(sortId int64, snid int32) int32 { } } +func (this *Tournament) stopMatch(matchId int32, sortId int64) (isOver bool) { + if this.players[sortId] != nil { + hasReal := false + for snId, context := range this.players[sortId] { + if !context.p.IsRob && !this.isOut(sortId, snId) { // 有真人没有淘汰 + hasReal = true + break + } + } + //没有真人比赛解散 + if !hasReal { + isOver = true + logger.Logger.Trace("没有真人比赛解散") + this.StopMatch(matchId, sortId) + } + } + return +} + // UpdateMatchInfo 玩家比赛结束 更新积分 func (this *Tournament) UpdateMatchInfo(p *Player, sortId int64, grade, isWin int32, matchRobotGrades map[int32]int32) { logger.Logger.Tracef("UpdateMatchInfo: sortId:%v, grade:%v, isWin: %v, matchRobotGrades:%v", sortId, grade, isWin, matchRobotGrades) @@ -1083,25 +1161,6 @@ func (this *Tournament) UpdateMatchInfo(p *Player, sortId int64, grade, isWin in } } -func (this *Tournament) stopMatch(matchId int32, sortId int64) (isOver bool) { - if this.players[sortId] != nil { - hasReal := false - for snId, context := range this.players[sortId] { - if !context.p.IsRob && !this.isOut(sortId, snId) { // 有真人没有淘汰 - hasReal = true - break - } - } - //没有真人比赛解散 - if !hasReal { - isOver = true - logger.Logger.Trace("没有真人比赛解散") - this.StopMatch(matchId, sortId) - } - } - return -} - // NextRoundStartSingle 下一轮是否开始 // 开启机器人时使用 func (this *Tournament) NextRoundStartSingle(sortId int64, playerCtx *PlayerMatchContext, matchRobotGrades map[int32]int32) { @@ -1283,6 +1342,7 @@ func (this *Tournament) NextRoundStart(sortId int64, playerCtx *PlayerMatchConte willOut = true } else { if !meIn { //自己暂时没晋级 + logger.Logger.Tracef("待定 %+v", info.players) this.sendPromotionInfo(playerCtx, sortId, DaiDing, false, false) //待定 } } @@ -1307,23 +1367,23 @@ func (this *Tournament) NextRoundStart(sortId int64, playerCtx *PlayerMatchConte }), nil, time.Second*7, 1) } } else { - this.sendPromotionInfo(playerCtx, sortId, DaiDing, false, false) //待定 + // 待定 + logger.Logger.Tracef("待定 %+v", info.players) + this.sendPromotionInfo(playerCtx, sortId, DaiDing, false, false) } } else { - if len(info.players) == 4 { - MatchContextSlice(info.players).Sort(true) - for _, mc := range info.players { - outCode := TaoTai - if mc.rank == 1 { - outCode = JinJi - } - this.sendPromotionInfo(mc, sortId, outCode, true, true) //晋级 + MatchContextSlice(info.players).Sort(true) + for _, mc := range info.players { + outCode := TaoTai + if mc.rank == 1 { + outCode = JinJi } - logger.Logger.Trace("比赛结束!!! ") - - // 比赛结束 - this.StopMatch(playerCtx.tm.TMId, sortId) + this.sendPromotionInfo(mc, sortId, outCode, true, true) //晋级 } + logger.Logger.Trace("比赛结束!!! ") + + // 比赛结束 + this.StopMatch(playerCtx.tm.TMId, sortId) } } @@ -1877,7 +1937,7 @@ func (this *Tournament) MakeMatchLog(platform string, tmId int32, sortId int64) matchLog.MatchName = gameMatchDate.MatchName matchLog.Platform = platform matchLog.GameFreeId = gameMatchDate.GameFreeId - matchLog.StartTime = time.Unix(this.matches[tmId][sortId].StartTime, 0) + matchLog.StartTime = this.matches[tmId][sortId].StartTime matchLog.EndTime = time.Now() matchLog.SortId = sortId return matchLog @@ -1898,84 +1958,6 @@ func (this *Tournament) saveMatchLog(matchLog *model.MatchLog) { })).StartByFixExecutor("saveMatchLogTask") } -func (this *Tournament) ModuleName() string { - return "Tournament" -} - -func (this *Tournament) Init() { - logger.Logger.Trace("Tournament Init") - for _, v := range PlatformMgrSingleton.GetPlatforms() { - if v == nil || v.IdStr == "0" { - continue - } - ret, err := model.GetMatchAward(v.IdStr) - if err != nil { - logger.Logger.Warnf("GetMatchAward error %v", err) - continue - } - if this.MatchAwardNum == nil { - this.MatchAwardNum = make(map[string]map[int32]int32) - } - this.MatchAwardNum[v.IdStr] = ret.Award - } -} - -func (this *Tournament) Update() { - // 使用机器人的情况 - for snId, info := range this.singleSignupPlayers { - if info == nil || info.Ts <= 0 { - continue - } - matchInfo := this.GetMatchInfo(info.Platform, info.TmId, 0) - if this.IsMatchOn(matchInfo) && !this.IsOutTime(matchInfo) && this.IsRobotOn(matchInfo) { - needTime := this.playerWaitStart[snId] - if time.Now().Unix()-info.Ts > needTime { - signInfo := &SignInfo{ - signup: make(map[int32]*TmPlayer), - Platform: info.Platform, - MaxCnt: int(matchInfo.MatchNumebr), - } - seq := rand.Intn(int(matchInfo.MatchNumebr)) + 1 - signInfo.signup[snId] = &TmPlayer{SnId: snId, seq: seq} - this.signupPlayers[info.Platform][info.TmId] = signInfo - - //倒计时结束 开始比赛 - this.Start(info.Platform, info.TmId) - } - } else { - this.CancelSignUpAll(info.Platform, info.TmId) - } - } - - // 防止内存泄露 - now := time.Now().Unix() - for _, v := range this.matches { - for _, vv := range v { - if vv != nil && now-vv.StartTime > int64(time.Hour.Seconds()*5) { - for _, p := range vv.TmPlayer { - this.ForceQuit(vv.Platform, p.SnId) - break - } - } - } - } -} - -func (this *Tournament) OnDayTimer() { - for k := range this.MatchAwardNum { - this.MatchAwardNum[k] = make(map[int32]int32) - } - task.New(nil, task.CallableWrapper(func(o *basic.Object) interface{} { - this.SaveMatchAward() - return nil - }), nil, "save_match_award_times").Start() -} - -func (this *Tournament) Shutdown() { - this.SaveMatchAward() - module.UnregisteModule(this) -} - func (this *Tournament) SaveMatchAward() { if this.MatchAwardNum == nil { return @@ -2047,11 +2029,44 @@ func (this *Tournament) FixMatchTimeStamp(d *webapiproto.GameMatchDate) { } func (this *Tournament) OnHourTimer() { + now := time.Now() for _, v := range this.GameMatchDateList { for _, vv := range v { this.FixMatchTimeStamp(vv) } } + // 防止异常情况卡房间 + for _, v := range this.matches { + for _, vv := range v { + if vv != nil && (now.Sub(vv.RoundTime).Hours() >= 1 || now.Sub(vv.StartTime).Hours() > 5) { + logger.Logger.Errorf("比赛异常 %v", vv) + this.StopMatch(vv.TMId, vv.SortId) + } + } + } + for sortId := range this.players { + for _, tm := range this.matches { + if _, ok := tm[sortId]; !ok { + for _, v := range this.players[sortId] { + if v != nil { + logger.Logger.Errorf("比赛异常 %v", v.tm) + } + break + } + this.StopMatch(0, sortId) + } + } + } +} + +func (this *Tournament) OnDayTimer() { + for k := range this.MatchAwardNum { + this.MatchAwardNum[k] = make(map[int32]int32) + } + task.New(nil, task.CallableWrapper(func(o *basic.Object) interface{} { + this.SaveMatchAward() + return nil + }), nil, "save_match_award_times").Start() } // GetMatchAwardNum 剩余奖励数量 @@ -2080,6 +2095,7 @@ func (this *Tournament) GetMatchAwardNum(platform string, id int32) int32 { return num } +// GetRound 获取当前轮次 func (this *Tournament) GetRound(sortId int64) int32 { d, ok := this.roundPlayers[sortId] if !ok || d == nil {