2120 lines
59 KiB
Go
2120 lines
59 KiB
Go
package main
|
||
|
||
import (
|
||
"fmt"
|
||
"math/rand"
|
||
"sort"
|
||
"sync"
|
||
"time"
|
||
|
||
nowtool "github.com/jinzhu/now"
|
||
"mongo.games.com/goserver/core/basic"
|
||
"mongo.games.com/goserver/core/i18n"
|
||
"mongo.games.com/goserver/core/logger"
|
||
"mongo.games.com/goserver/core/module"
|
||
"mongo.games.com/goserver/core/task"
|
||
"mongo.games.com/goserver/core/timer"
|
||
|
||
"mongo.games.com/game/common"
|
||
"mongo.games.com/game/model"
|
||
"mongo.games.com/game/proto"
|
||
"mongo.games.com/game/protocol/tournament"
|
||
webapiproto "mongo.games.com/game/protocol/webapi"
|
||
"mongo.games.com/game/srvdata"
|
||
"mongo.games.com/game/webapi"
|
||
)
|
||
|
||
// 如果这里比赛类型没有,默认是锦标赛
|
||
const (
|
||
MatchTypeNormal = iota + 1 // 锦标赛
|
||
MatchTypeChampion // 冠军赛/实物赛
|
||
MatchTypeVIP // vip比赛
|
||
MatchTypePhone // 话费赛
|
||
MatchTypeMax // 最大比赛类型
|
||
)
|
||
|
||
const (
|
||
MatchSwitchStart = 1 // 开启
|
||
MatchSwitchClose = 2 // 关闭
|
||
)
|
||
|
||
const (
|
||
MatchUseRobot = 0 // 使用机器人
|
||
MatchNotUserRobot = 1 // 关闭机器人
|
||
)
|
||
|
||
const (
|
||
JinJi = 0 // 晋级
|
||
TaoTai = 1 // 淘汰
|
||
DaiDing = 2 // 待定
|
||
)
|
||
|
||
func init() {
|
||
module.RegisteModule(TournamentMgr, time.Second, 0)
|
||
common.ClockMgrSingleton.RegisterSinker(TournamentMgr)
|
||
}
|
||
|
||
var TournamentMgr = NewTournament()
|
||
|
||
type PerRankInfo struct {
|
||
Name string
|
||
SnId int32
|
||
RankId int32
|
||
Grade int32
|
||
}
|
||
|
||
type SignInfo struct {
|
||
signup map[int32]*TmPlayer //玩家Id
|
||
Platform string
|
||
MaxCnt int // 最大报名人数
|
||
}
|
||
|
||
type SignupInfo struct {
|
||
Platform string
|
||
TmId int32
|
||
SnId int32
|
||
Ts int64 // 报名时间
|
||
}
|
||
|
||
type PlayerRoundInfo struct {
|
||
players []*PlayerMatchContext // 本轮结算信息
|
||
ranks []*PlayerMatchContext // 本轮排名
|
||
num int // 本轮完成人数
|
||
}
|
||
|
||
type Tournament struct {
|
||
common.BaseClockSinker
|
||
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 {
|
||
ret := &Tournament{
|
||
TypeList: make(map[string]*webapiproto.GameMatchType),
|
||
GameMatchDateList: make(map[string]map[int32]*webapiproto.GameMatchDate),
|
||
singleSignupPlayers: make(map[int32]*SignupInfo),
|
||
signupPlayers: make(map[string]map[int32]*SignInfo),
|
||
playerWaitStart: make(map[int32]int64),
|
||
matches: make(map[int32]map[int64]*TmMatch),
|
||
players: make(map[int64]map[int32]*PlayerMatchContext),
|
||
roundPlayers: make(map[int64]map[int32]*PlayerRoundInfo),
|
||
finalPerRank: make(map[int64][]*PerRankInfo),
|
||
}
|
||
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 {
|
||
return false
|
||
}
|
||
l := len(cfg.MatchPromotion)
|
||
if l < 2 {
|
||
return false
|
||
}
|
||
if cfg.MatchPromotion[0] != cfg.MatchNumebr { //第一位必须和报名人数相同
|
||
//return false
|
||
cfg.MatchNumebr = cfg.MatchPromotion[0]
|
||
}
|
||
if cfg.MatchPromotion[l-1] != 1 { //最后一位必须是1
|
||
//return false
|
||
cfg.MatchPromotion[l-1] = 1
|
||
}
|
||
if cfg.MatchPromotion[l-2] != 4 { //倒数第二位必须是4
|
||
//return false
|
||
cfg.MatchPromotion[l-2] = 4
|
||
}
|
||
for i, num := range cfg.MatchPromotion {
|
||
if i < l-1 { //除了最后一位
|
||
if num%4 != 0 { //必须是4的整倍数
|
||
return false
|
||
}
|
||
//if num <= cfg.MatchPromotion[i+1] { //必须递减
|
||
// return false
|
||
//}
|
||
}
|
||
}
|
||
|
||
return true
|
||
}
|
||
|
||
// 记录淘汰人员
|
||
func (this *Tournament) addFinalPlayer(sortId int64, p *PerRankInfo) {
|
||
if this.finalPerRank[sortId] == nil {
|
||
this.finalPerRank[sortId] = []*PerRankInfo{}
|
||
}
|
||
this.finalPerRank[sortId] = append(this.finalPerRank[sortId], p)
|
||
}
|
||
|
||
// GetRoundPlayer 查询一场比赛某轮的历史数据
|
||
func (this *Tournament) GetRoundPlayer(sortId int64, round int32) *PlayerRoundInfo {
|
||
_, ok := this.roundPlayers[sortId]
|
||
if !ok {
|
||
return nil
|
||
}
|
||
if this.roundPlayers[sortId] == nil {
|
||
this.roundPlayers[sortId] = make(map[int32]*PlayerRoundInfo)
|
||
}
|
||
v, ok := this.roundPlayers[sortId][round]
|
||
if !ok || v == nil {
|
||
return nil
|
||
}
|
||
return v
|
||
}
|
||
|
||
// GetRemainNum 剩余比赛人数
|
||
func (this *Tournament) GetRemainNum(sortId int64) int32 {
|
||
tm := this.GetTm(sortId)
|
||
if tm == nil {
|
||
return 0
|
||
}
|
||
|
||
round := this.GetRound(sortId)
|
||
l := tm.gmd.GetMatchPromotion()
|
||
if round <= int32(len(l)) {
|
||
return l[round-1]
|
||
}
|
||
return 0
|
||
}
|
||
|
||
type MatchPlayerInfo struct {
|
||
SnId int32
|
||
RoleId int32
|
||
SkinId int32
|
||
Rank int32
|
||
Grade int32
|
||
}
|
||
|
||
// GetRemainPlayer 未淘汰的人
|
||
func (this *Tournament) GetRemainPlayer(sortId int64) []*MatchPlayerInfo {
|
||
tm := this.GetTm(sortId)
|
||
if tm == nil {
|
||
return nil
|
||
}
|
||
round := this.GetRound(sortId)
|
||
useRobot := this.IsRobotOn(tm.gmd)
|
||
|
||
var ret []*MatchPlayerInfo
|
||
|
||
realPlayer := func() {
|
||
for _, v := range tm.TmPlayer {
|
||
p := PlayerMgrSington.GetPlayerBySnId(v.SnId)
|
||
if p != nil {
|
||
ret = append(ret, &MatchPlayerInfo{
|
||
SnId: v.SnId,
|
||
RoleId: p.GetRoleId(),
|
||
SkinId: p.Skin.ModId,
|
||
Grade: 1000,
|
||
})
|
||
}
|
||
}
|
||
}
|
||
|
||
robotPlayer := func(n int) {
|
||
for _, v := range tm.robotGrades[n] {
|
||
if v.copySnid == 0 {
|
||
for _, vv := range tm.TmPlayer {
|
||
p := PlayerMgrSington.GetPlayerBySnId(vv.SnId)
|
||
if p != nil {
|
||
ret = append(ret, &MatchPlayerInfo{
|
||
SnId: vv.SnId,
|
||
RoleId: p.GetRoleId(),
|
||
SkinId: p.Skin.ModId,
|
||
Grade: v.grade,
|
||
})
|
||
}
|
||
break
|
||
}
|
||
continue
|
||
}
|
||
ret = append(ret, &MatchPlayerInfo{
|
||
SnId: v.copySnid,
|
||
RoleId: v.copyRoleId,
|
||
SkinId: v.CopySkinId,
|
||
Grade: v.grade,
|
||
})
|
||
}
|
||
}
|
||
|
||
if round <= 1 {
|
||
if useRobot {
|
||
robotPlayer(0)
|
||
realPlayer()
|
||
} else {
|
||
realPlayer()
|
||
}
|
||
} else {
|
||
if useRobot {
|
||
robotPlayer(int(round - 1))
|
||
} else {
|
||
if this.roundPlayers[sortId] != nil {
|
||
d := this.roundPlayers[sortId][round-1]
|
||
if d != nil {
|
||
for _, v := range d.ranks {
|
||
ret = append(ret, &MatchPlayerInfo{
|
||
SnId: v.copySnid,
|
||
RoleId: v.copyRoleId,
|
||
SkinId: v.copySkinId,
|
||
Grade: v.grade,
|
||
})
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
return ret
|
||
}
|
||
|
||
// GetSignUpPlayers 获取报名人员
|
||
// id 比赛配置id
|
||
func (this *Tournament) GetSignUpPlayers(platform string, id int32) map[int32]*TmPlayer {
|
||
v, ok := this.signupPlayers[platform]
|
||
if !ok {
|
||
return nil
|
||
}
|
||
vv, ok := v[id]
|
||
if !ok {
|
||
return nil
|
||
}
|
||
return vv.signup
|
||
}
|
||
|
||
// UpdateData 更新配置
|
||
// init: 通知客户端配置变更
|
||
func (this *Tournament) UpdateData(init bool, data *webapiproto.GameMatchDateList) {
|
||
if data.Platform == "0" {
|
||
return
|
||
}
|
||
|
||
// 参数校验
|
||
configs := make(map[int32]*webapiproto.GameMatchDate)
|
||
for _, v := range data.List {
|
||
if this.checkData(v) {
|
||
this.FixMatchTimeStamp(v)
|
||
configs[v.Id] = v
|
||
} else {
|
||
logger.Logger.Errorf("GameMatchDate check error: %v", v)
|
||
}
|
||
}
|
||
|
||
oldConfigs := this.GameMatchDateList[data.Platform]
|
||
// 配置修改取消报名
|
||
// 1.比赛开启变关闭
|
||
// 2.比赛不在时间段内
|
||
// 3.机器人开关有修改
|
||
// 4.删除配置
|
||
for _, v := range oldConfigs {
|
||
gmd := configs[v.Id]
|
||
if (gmd != nil && v.MatchSwitch == MatchSwitchStart && gmd.MatchSwitch != v.MatchSwitch) || //配置开启变关闭
|
||
(gmd != nil && !this.IsTimeRange(gmd)) || //或者不在时间段内
|
||
(gmd != nil && v.UseRobot != gmd.UseRobot) || //或者机器人开关有修改
|
||
gmd == nil { //或者删除
|
||
signInfo := this.GetSignUpPlayers(data.Platform, v.Id)
|
||
if signInfo != nil && len(signInfo) > 0 {
|
||
// 取消报名
|
||
this.CancelSignUpAll(data.Platform, v.Id)
|
||
}
|
||
}
|
||
}
|
||
|
||
// 新配置增加更新
|
||
for _, v := range configs {
|
||
oldConfig := oldConfigs[v.Id]
|
||
if oldConfig == nil || v.MatchSwitch == MatchSwitchStart {
|
||
if this.signupPlayers[data.Platform] == nil {
|
||
this.signupPlayers[data.Platform] = make(map[int32]*SignInfo)
|
||
}
|
||
this.signupPlayers[data.Platform][v.Id] = &SignInfo{
|
||
signup: make(map[int32]*TmPlayer),
|
||
Platform: data.Platform,
|
||
MaxCnt: int(v.MatchNumebr),
|
||
}
|
||
}
|
||
if v.MatchSwitch == MatchSwitchClose || !this.IsTimeRange(v) {
|
||
this.CancelSignUpAll(data.Platform, v.Id)
|
||
if v.MatchSwitch == MatchSwitchClose {
|
||
delete(this.signupPlayers[data.Platform], v.Id)
|
||
}
|
||
}
|
||
}
|
||
this.GameMatchDateList[data.Platform] = configs
|
||
// 通知平台玩家数据更新
|
||
if !init {
|
||
//todo 优化
|
||
for _, v := range PlayerMgrSington.playerOfPlatform[data.Platform] {
|
||
pack := TournamentMgr.GetSCTMInfosPack(data.Platform, v.AppChannel)
|
||
v.SendToClient(int(tournament.TOURNAMENTID_PACKET_TM_SCTMInfos), pack)
|
||
logger.Logger.Trace("SCTMInfos ", pack)
|
||
}
|
||
}
|
||
}
|
||
|
||
func (this *Tournament) UpdateTypeList(init bool, data *webapiproto.GameMatchType) {
|
||
if data.Platform == "0" {
|
||
return
|
||
}
|
||
this.TypeList[data.Platform] = data
|
||
if !init {
|
||
//todo 优化
|
||
for _, v := range PlayerMgrSington.playerOfPlatform[data.Platform] {
|
||
pack := TournamentMgr.GetSCTMInfosPack(data.Platform, v.AppChannel)
|
||
v.SendToClient(int(tournament.TOURNAMENTID_PACKET_TM_SCTMInfos), pack)
|
||
logger.Logger.Trace("SCTMInfos UpdateTypeList", pack)
|
||
}
|
||
}
|
||
}
|
||
|
||
// GetMatchInfo 比赛配置
|
||
// !!!没有sortId会获取最新配置
|
||
func (this *Tournament) GetMatchInfo(platform string, tmId int32, sortId int64) *webapiproto.GameMatchDate {
|
||
if sortId > 0 {
|
||
v := this.matches[tmId]
|
||
if v != nil {
|
||
vv := v[sortId]
|
||
if vv != nil {
|
||
return vv.gmd
|
||
}
|
||
}
|
||
return nil
|
||
}
|
||
if list, ok := this.GameMatchDateList[platform]; ok {
|
||
if gmd, ok1 := list[tmId]; ok1 {
|
||
return gmd
|
||
}
|
||
}
|
||
return nil
|
||
}
|
||
|
||
// MatchSwitch 比赛开关
|
||
func (this *Tournament) MatchSwitch(platform string, tmId int32) bool {
|
||
return this.IsMatchOn(this.GetMatchInfo(platform, tmId, 0))
|
||
}
|
||
|
||
// IsMatchOn 比赛开关
|
||
func (this *Tournament) IsMatchOn(match *webapiproto.GameMatchDate) bool {
|
||
return match != nil && match.MatchSwitch == MatchSwitchStart
|
||
}
|
||
|
||
// IsUseRobot 是否用机器人
|
||
func (this *Tournament) IsUseRobot(platform string, tmId int32, sortId int64) bool {
|
||
return this.IsRobotOn(this.GetMatchInfo(platform, tmId, sortId))
|
||
}
|
||
|
||
// IsRobotOn 是否用机器人
|
||
func (this *Tournament) IsRobotOn(match *webapiproto.GameMatchDate) bool {
|
||
return match != nil && match.UseRobot == MatchUseRobot
|
||
}
|
||
|
||
// IsTimeRange 判断是否在比赛时间段内
|
||
// 在时间段内才能报名
|
||
func (this *Tournament) IsTimeRange(gmd *webapiproto.GameMatchDate) bool {
|
||
if gmd == nil {
|
||
return false
|
||
}
|
||
|
||
if gmd.MatchType != MatchTypeChampion {
|
||
return true
|
||
}
|
||
|
||
// 冠军赛有时间限制
|
||
tNow := time.Now()
|
||
switch gmd.MatchTimeType { // 0无时效 1重复时间段 2一次性时间段
|
||
case 0:
|
||
return true
|
||
case 1:
|
||
week := this.getWeekDay()
|
||
for _, v := range gmd.MatchTimeWeek {
|
||
if week == int(v) {
|
||
if gmd.MatchTimeStamp != nil && len(gmd.MatchTimeStamp) > 1 {
|
||
this.FixMatchTimeStamp(gmd)
|
||
startStamp := gmd.MatchTimeStamp[0]
|
||
endStamp := gmd.MatchTimeStamp[1]
|
||
if tNow.Unix() >= startStamp && tNow.Unix() <= endStamp {
|
||
return true
|
||
}
|
||
}
|
||
return false
|
||
}
|
||
}
|
||
|
||
case 2:
|
||
if gmd.MatchTimeStamp != nil && len(gmd.MatchTimeStamp) > 1 {
|
||
startStamp := gmd.MatchTimeStamp[0]
|
||
endStamp := gmd.MatchTimeStamp[1]
|
||
if tNow.Unix() >= startStamp && tNow.Unix() <= endStamp {
|
||
return true
|
||
}
|
||
}
|
||
}
|
||
|
||
return false
|
||
}
|
||
|
||
// IsOutTime 是否过期,一次性比赛才有过期,一次性冠军赛
|
||
func (this *Tournament) IsOutTime(gmd *webapiproto.GameMatchDate) bool {
|
||
if !this.IsMatchOn(gmd) {
|
||
return true
|
||
}
|
||
if gmd.MatchType == MatchTypeChampion { //冠军赛的一次性时间段才有过期可能
|
||
switch gmd.MatchTimeType { // 0无时效 1重复时间段 2一次性时间段
|
||
case 2:
|
||
tNow := time.Now()
|
||
if gmd.MatchTimeStamp != nil && len(gmd.MatchTimeStamp) > 1 {
|
||
endStamp := gmd.MatchTimeStamp[1]
|
||
if tNow.Unix() >= endStamp { //当前时间大于截止时间
|
||
return true
|
||
}
|
||
}
|
||
}
|
||
}
|
||
return false
|
||
}
|
||
|
||
// GetAllMatchInfo 所有比赛配置数据
|
||
func (this *Tournament) GetAllMatchInfo(platform string) map[int32]*webapiproto.GameMatchDate {
|
||
if list, ok := this.GameMatchDateList[platform]; ok {
|
||
return list
|
||
}
|
||
return nil
|
||
}
|
||
|
||
// IsGaming 判断是否在比赛中
|
||
func (this *Tournament) IsGaming(snId int32) bool {
|
||
if this.players != nil {
|
||
for _, v := range this.players {
|
||
if v != nil {
|
||
for k := range v {
|
||
if k == snId {
|
||
return true
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
return false
|
||
}
|
||
|
||
// IsMatchWaiting 判断是否在匹配中,已报名
|
||
// 返回 是否匹配中,比赛配置id
|
||
func (this *Tournament) IsMatchWaiting(platform string, snId int32) (bool, int32) {
|
||
// 未使用机器人
|
||
for k, v := range this.signupPlayers[platform] {
|
||
if v.signup != nil {
|
||
if _, ok := v.signup[snId]; ok {
|
||
return ok, k
|
||
}
|
||
}
|
||
}
|
||
|
||
for k, v := range this.matches {
|
||
for _, vv := range v {
|
||
if _, ok := vv.TmPlayer[snId]; ok {
|
||
return true, k
|
||
}
|
||
}
|
||
}
|
||
|
||
// 使用机器人了
|
||
if v, ok := this.singleSignupPlayers[snId]; ok {
|
||
return true, v.TmId
|
||
}
|
||
return false, 0
|
||
}
|
||
|
||
// signUpCost 报名消耗
|
||
// tmId 比赛配置id
|
||
// cost true报名、false取消报名
|
||
// 报名费用 0成功 3道具不足 5金币不足 6钻石不足 7免费次数不足
|
||
func (this *Tournament) signUpCost(p *Player, tmId int32, cost bool) (bool, int32) {
|
||
logger.Logger.Tracef("signUpCost 比赛id:%v 玩家:%v 报名:%v", tmId, p.SnId, cost)
|
||
gmd := this.GetMatchInfo(p.Platform, tmId, 0)
|
||
if gmd == nil || p.IsRob {
|
||
return true, 0
|
||
}
|
||
|
||
// 真人费用检测
|
||
|
||
// VIP比赛场
|
||
if gmd.MatchType == MatchTypeVIP {
|
||
freeTimes := p.GetMatchFreeTimes() // VIP比赛场免费次数
|
||
freeTimes += p.GetSkillAdd(common.SkillIdVipTimes) // 皮肤技能加成次数
|
||
logger.Logger.Trace("报名费用免费次数: freeTimes: ", freeTimes, " p.VipMatchTimes: ", p.VipMatchTimes)
|
||
if freeTimes > 0 {
|
||
if cost {
|
||
if p.VipMatchTimes < freeTimes { //参与次数<免费次数
|
||
p.VipMatchTimes++
|
||
} else {
|
||
logger.Logger.Trace("免费次数不足1")
|
||
return false, int32(tournament.SignRaceCode_OPRC_Free)
|
||
}
|
||
} else {
|
||
if p.VipMatchTimes > 0 {
|
||
p.VipMatchTimes--
|
||
} else {
|
||
p.VipMatchTimes = 0
|
||
}
|
||
}
|
||
} else {
|
||
logger.Logger.Trace("免费次数不足2")
|
||
return false, int32(tournament.SignRaceCode_OPRC_Free)
|
||
}
|
||
}
|
||
// 金币
|
||
if gmd.SignupCostCoin > 0 {
|
||
logger.Logger.Tracef("比赛场报名消耗金币 报名:%v 金币:%v", cost, gmd.SignupCostCoin)
|
||
if cost {
|
||
if p.Coin < gmd.SignupCostCoin { //金币不足
|
||
logger.Logger.Trace("金币不足")
|
||
return false, int32(tournament.SignRaceCode_OPRC_Coin)
|
||
} else {
|
||
p.AddCoin(-gmd.SignupCostCoin, 0, common.GainWay_MatchSignup, "system", gmd.MatchName+"-报名消耗")
|
||
}
|
||
} else {
|
||
p.AddCoin(gmd.SignupCostCoin, 0, common.GainWay_MatchSignup, "system", gmd.MatchName+"-报名退还")
|
||
}
|
||
}
|
||
// 钻石
|
||
if gmd.SignupCostDiamond > 0 {
|
||
logger.Logger.Tracef("比赛场报名消耗钻石 报名:%v 钻石:%v", cost, gmd.SignupCostDiamond)
|
||
if cost {
|
||
if p.Diamond < gmd.SignupCostDiamond { //钻石不足
|
||
logger.Logger.Trace("钻石不足")
|
||
return false, int32(tournament.SignRaceCode_OPRC_Diamond)
|
||
} else {
|
||
p.AddDiamond(-gmd.SignupCostDiamond, 0, common.GainWay_MatchSignup, "system", gmd.MatchName+"-报名消耗")
|
||
}
|
||
} else {
|
||
p.AddDiamond(gmd.SignupCostDiamond, 0, common.GainWay_MatchSignup, "system", gmd.MatchName+"-报名退还")
|
||
}
|
||
}
|
||
// 道具
|
||
if gmd.SignupCostItem != nil && gmd.SignupCostItem.ItemNum > 0 {
|
||
logger.Logger.Tracef("比赛场报名消耗道具 报名:%v 道具:%v", cost, gmd.SignupCostItem.String())
|
||
item := BagMgrSingleton.GetItem(p.SnId, gmd.SignupCostItem.ItemId)
|
||
if item != nil {
|
||
gameId := int64(0)
|
||
gf := PlatformMgrSingleton.GetGameFree(p.Platform, gmd.GameFreeId)
|
||
if gf != nil && gf.GetDbGameFree() != nil {
|
||
gameId = int64(gf.GetDbGameFree().GameId)
|
||
}
|
||
if cost {
|
||
if item.ItemNum < gmd.SignupCostItem.ItemNum {
|
||
logger.Logger.Trace("道具不足")
|
||
return false, int32(tournament.SignRaceCode_OPRC_NoItem)
|
||
} else {
|
||
BagMgrSingleton.AddItems(&model.AddItemParam{
|
||
Platform: p.Platform,
|
||
SnId: p.SnId,
|
||
Change: []*model.Item{
|
||
{
|
||
ItemId: item.ItemId,
|
||
ItemNum: -gmd.SignupCostItem.ItemNum,
|
||
},
|
||
},
|
||
GainWay: common.GainWay_MatchSignup,
|
||
Operator: "player",
|
||
Remark: gmd.MatchName + "-报名消耗",
|
||
GameId: gameId,
|
||
GameFreeId: int64(gmd.GameFreeId),
|
||
})
|
||
}
|
||
} else {
|
||
BagMgrSingleton.AddItems(&model.AddItemParam{
|
||
Platform: p.Platform,
|
||
SnId: p.SnId,
|
||
Change: []*model.Item{
|
||
{
|
||
ItemId: item.ItemId,
|
||
ItemNum: gmd.SignupCostItem.ItemNum,
|
||
},
|
||
},
|
||
GainWay: common.GainWay_MatchSignup,
|
||
Operator: "player",
|
||
Remark: gmd.MatchName + "-报名退还",
|
||
GameId: gameId,
|
||
GameFreeId: int64(gmd.GameFreeId),
|
||
})
|
||
}
|
||
} else {
|
||
logger.Logger.Trace("道具不足")
|
||
return false, int32(tournament.SignRaceCode_OPRC_NoItem)
|
||
}
|
||
}
|
||
|
||
return true, 0
|
||
}
|
||
|
||
// SignUp 报名
|
||
// 0成功 1重复报名 2比赛没有开启 3道具不足 4不在报名时间段 5金币不足 6钻石不足 7免费次数不足
|
||
func (this *Tournament) SignUp(tmId int32, p *Player) (bool, int32) {
|
||
logger.Logger.Tracef("报名 比赛id:%v 玩家:%v", tmId, p.SnId)
|
||
// 开启
|
||
info := this.GetMatchInfo(p.Platform, tmId, 0)
|
||
if !this.IsMatchOn(info) {
|
||
return false, int32(tournament.SignRaceCode_OPRC_Close)
|
||
}
|
||
// 报名时间
|
||
if !this.IsTimeRange(info) {
|
||
return false, int32(tournament.SignRaceCode_OPRC_Time)
|
||
}
|
||
// 已报名
|
||
isWaiting, _ := this.IsMatchWaiting(p.Platform, p.SnId)
|
||
if this.IsGaming(p.SnId) || isWaiting {
|
||
return false, int32(tournament.SignRaceCode_OPRC_Repeat)
|
||
}
|
||
if this.GetMatchAwardNum(p.Platform, tmId) <= 0 {
|
||
return false, int32(tournament.SignRaceCode_OPRC_NoAward)
|
||
}
|
||
// 扣报名费
|
||
ok, code := this.signUpCost(p, tmId, true)
|
||
if !ok {
|
||
return false, code
|
||
}
|
||
|
||
if this.IsRobotOn(info) {
|
||
// 开启机器人时
|
||
signupInfo := &SignupInfo{
|
||
Platform: p.Platform,
|
||
TmId: tmId,
|
||
SnId: p.SnId,
|
||
Ts: time.Now().Unix(),
|
||
}
|
||
this.singleSignupPlayers[p.SnId] = signupInfo
|
||
} else {
|
||
// 不开机器人时
|
||
var platform = p.Platform
|
||
signInfo, ok := this.signupPlayers[platform][tmId]
|
||
if !ok {
|
||
signInfo = &SignInfo{
|
||
signup: make(map[int32]*TmPlayer),
|
||
Platform: platform,
|
||
MaxCnt: int(info.MatchNumebr),
|
||
}
|
||
this.signupPlayers[platform][tmId] = signInfo
|
||
}
|
||
|
||
_, ok = signInfo.signup[p.SnId]
|
||
if ok {
|
||
return false, int32(tournament.SignRaceCode_OPRC_Repeat)
|
||
}
|
||
|
||
n := len(signInfo.signup) + 1
|
||
signInfo.signup[p.SnId] = &TmPlayer{SnId: p.SnId, seq: n}
|
||
logger.Logger.Tracef("没使用机器人,真人报名,报名人数 %v 玩家:%v", n, p.SnId)
|
||
}
|
||
|
||
//(报名人数/20,报名人数/10)
|
||
minTime := info.MatchNumebr / 20
|
||
maxTime := info.MatchNumebr / 10
|
||
if info.MatchNumebr > 20 {
|
||
this.playerWaitStart[p.SnId] = int64(minTime + rand.Int31n(maxTime-minTime))
|
||
} else {
|
||
this.playerWaitStart[p.SnId] = 1
|
||
}
|
||
return true, 0
|
||
}
|
||
|
||
// CancelSignUp 取消玩家报名
|
||
func (this *Tournament) CancelSignUp(platform string, tmid, snid int32) {
|
||
delete(this.playerWaitStart, snid)
|
||
|
||
if this.signupPlayers[platform] != nil && this.signupPlayers[platform][tmid] != nil {
|
||
signInfo := this.signupPlayers[platform][tmid]
|
||
if _, ok := signInfo.signup[snid]; ok {
|
||
p := PlayerMgrSington.GetPlayerBySnId(snid)
|
||
if p != nil && p.scene == nil {
|
||
//退费
|
||
this.signUpCost(p, tmid, false)
|
||
delete(this.signupPlayers[platform][tmid].signup, snid)
|
||
//通知取消报名
|
||
pack := &tournament.SCSignRace{
|
||
OpCode: 1,
|
||
RetCode: 0,
|
||
}
|
||
p.SendToClient(int(tournament.TOURNAMENTID_PACKET_TM_SCSignRace), pack)
|
||
logger.Logger.Trace("SCSignRace ", pack)
|
||
return
|
||
}
|
||
}
|
||
}
|
||
|
||
if v, ok := this.singleSignupPlayers[snid]; ok {
|
||
p := PlayerMgrSington.GetPlayerBySnId(snid)
|
||
if p != nil && p.scene == nil {
|
||
//退费
|
||
this.signUpCost(p, v.TmId, false)
|
||
delete(this.singleSignupPlayers, snid)
|
||
//通知取消报名
|
||
pack := &tournament.SCSignRace{
|
||
OpCode: 1,
|
||
RetCode: 0,
|
||
}
|
||
p.SendToClient(int(tournament.TOURNAMENTID_PACKET_TM_SCSignRace), pack)
|
||
logger.Logger.Trace("SCSignRace ", pack)
|
||
return
|
||
}
|
||
}
|
||
}
|
||
|
||
// CancelSignUpAll 取消所有报名
|
||
func (this *Tournament) CancelSignUpAll(platform string, tmId int32) {
|
||
if this.signupPlayers[platform] != nil && this.signupPlayers[platform][tmId] != nil {
|
||
for _, tmp := range this.signupPlayers[platform][tmId].signup {
|
||
this.CancelSignUp(platform, tmId, tmp.SnId)
|
||
}
|
||
}
|
||
if this.singleSignupPlayers != nil {
|
||
for _, signupInfo := range this.singleSignupPlayers {
|
||
if signupInfo.TmId == tmId {
|
||
this.CancelSignUp(signupInfo.Platform, tmId, signupInfo.SnId)
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// Quit 如果正在等待比赛,退赛
|
||
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.IsGaming(snid) {
|
||
this.CancelSignUp(platform, tmid, snid)
|
||
}
|
||
}
|
||
|
||
// ForceQuit 强制退赛,异常时才使用
|
||
func (this *Tournament) ForceQuit(platform string, snId int32) {
|
||
logger.Logger.Tracef("TournamentMgr.ForceQuit: snId:%d", snId)
|
||
if snId <= 0 {
|
||
return
|
||
}
|
||
this.Quit(platform, snId)
|
||
|
||
p := PlayerMgrSington.GetPlayerBySnId(snId)
|
||
if p != nil {
|
||
if p.matchCtx != nil && p.matchCtx.tm != nil {
|
||
this.StopMatch(p.matchCtx.tm.TMId, p.matchCtx.tm.SortId)
|
||
return
|
||
}
|
||
}
|
||
|
||
for _, v := range this.matches {
|
||
for _, vv := range v {
|
||
if vv != nil && vv.TmPlayer[snId] != nil {
|
||
this.StopMatch(vv.TMId, vv.SortId)
|
||
return
|
||
}
|
||
}
|
||
}
|
||
|
||
for _, v := range this.players {
|
||
if info, ok := v[snId]; ok && info != nil && info.tm != nil {
|
||
this.StopMatch(info.tm.TMId, info.tm.SortId)
|
||
return
|
||
}
|
||
}
|
||
}
|
||
|
||
// CanStart 是否开赛
|
||
// 没有开机器人走这个判断
|
||
func (this *Tournament) CanStart(platform string, tmId int32) bool {
|
||
if this.signupPlayers != nil && this.signupPlayers[platform] != nil {
|
||
if signInfo, ok := this.signupPlayers[platform][tmId]; ok {
|
||
matchInfo := this.GetMatchInfo(signInfo.Platform, tmId, 0)
|
||
if matchInfo != nil {
|
||
n := 0
|
||
for _, v := range signInfo.signup {
|
||
p := PlayerMgrSington.GetPlayerBySnId(v.SnId)
|
||
if p == nil || p.scene != nil { //人不在或者在游戏内
|
||
this.CancelSignUp(platform, tmId, v.SnId)
|
||
break
|
||
}
|
||
n++
|
||
}
|
||
logger.Logger.Trace("TournamentMgr.CanStart: n: ", n, " matchInfo: ", matchInfo)
|
||
needNum := matchInfo.MatchNumebr / 4 * 4 //对4向下取整防止后台配置数据不是4的倍数
|
||
//所有人都准备好了
|
||
if needNum == int32(n) {
|
||
//人满 开始比赛
|
||
return true
|
||
}
|
||
}
|
||
}
|
||
}
|
||
return false
|
||
}
|
||
|
||
// Start 开赛
|
||
func (this *Tournament) Start(platform string, tmId int32) {
|
||
if this.signupPlayers[platform] == nil {
|
||
this.signupPlayers[platform] = make(map[int32]*SignInfo)
|
||
}
|
||
if this.matches[tmId] == nil {
|
||
this.matches[tmId] = make(map[int64]*TmMatch)
|
||
}
|
||
|
||
matchInfo := this.GetMatchInfo(platform, tmId, 0)
|
||
signInfo := this.signupPlayers[platform][tmId]
|
||
|
||
if matchInfo == nil || signInfo == nil || len(signInfo.signup) == 0 {
|
||
return
|
||
}
|
||
|
||
tm := NewTmMatch(platform, matchInfo, signInfo.signup)
|
||
this.matches[tmId][tm.SortId] = tm
|
||
|
||
logger.Logger.Tracef("开赛:%+v, 难度:%v", tm, tm.gml)
|
||
tm.Start()
|
||
|
||
// 开始比赛,清除报名数据
|
||
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()),
|
||
GameFreeID: tm.dbGameFree.GetId(),
|
||
Num: 1,
|
||
})
|
||
if matchInfo.GetSignupCostDiamond() > 0 {
|
||
TaskSubjectSingleton.Touch(common.TaskTypeCostDiamond, &TaskData{
|
||
SnId: v.SnId,
|
||
Num: matchInfo.GetSignupCostDiamond(),
|
||
})
|
||
}
|
||
}
|
||
this.signupPlayers[platform][tmId].signup = make(map[int32]*TmPlayer)
|
||
}
|
||
|
||
// 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]
|
||
matchLog := this.MakeMatchLog(tm.Platform, tmId, sortId)
|
||
this.saveMatchLog(matchLog)
|
||
tm.Stop()
|
||
}
|
||
|
||
if this.matches[tmId] != nil {
|
||
delete(this.matches[tmId], sortId)
|
||
}
|
||
|
||
//数据清理
|
||
delete(this.players, sortId)
|
||
delete(this.roundPlayers, sortId)
|
||
delete(this.finalPerRank, sortId)
|
||
}
|
||
|
||
// GetTm 获取比赛信息
|
||
func (this *Tournament) GetTm(sortId int64) *TmMatch {
|
||
for _, v := range this.matches {
|
||
if v == nil {
|
||
continue
|
||
}
|
||
if vv, ok := v[sortId]; ok {
|
||
return vv
|
||
}
|
||
}
|
||
return nil
|
||
}
|
||
|
||
// CreatePlayerMatchContext 创建玩家比赛信息
|
||
func (this *Tournament) CreatePlayerMatchContext(p *Player, m *TmMatch, seq int) *PlayerMatchContext {
|
||
roleId := int32(2000001)
|
||
if p.Roles != nil {
|
||
roleId = p.Roles.ModId
|
||
}
|
||
|
||
mc := NewMatchContext(p, m, 1000, p.SnId, 1, roleId, p.Skin.ModId, seq)
|
||
if mc != nil {
|
||
if this.players[m.SortId] == nil {
|
||
this.players[m.SortId] = make(map[int32]*PlayerMatchContext)
|
||
}
|
||
this.players[m.SortId][p.SnId] = mc
|
||
p.matchCtx = mc
|
||
return mc
|
||
}
|
||
return nil
|
||
}
|
||
|
||
// 是否淘汰
|
||
func (this *Tournament) isOut(sortId int64, snid int32) bool {
|
||
if this.finalPerRank[sortId] != nil {
|
||
for _, info := range this.finalPerRank[sortId] {
|
||
if info.SnId == snid {
|
||
return true
|
||
}
|
||
}
|
||
}
|
||
return false
|
||
}
|
||
|
||
// getRank 获取本轮排名
|
||
// 不适用机器人时
|
||
func (this *Tournament) getRank(sortId int64, round, snid int32, isFinals bool) int32 {
|
||
if _, ok := this.roundPlayers[sortId]; ok {
|
||
if rps, ok1 := this.roundPlayers[sortId][round]; ok1 && rps != nil {
|
||
MatchContextSlice(rps.ranks).Sort(isFinals)
|
||
for _, rp := range rps.ranks {
|
||
if rp.p.SnId == snid {
|
||
return rp.rank
|
||
}
|
||
}
|
||
}
|
||
}
|
||
return 0
|
||
}
|
||
|
||
// GetRank 获取排名
|
||
func (this *Tournament) GetRank(sortId int64, snid int32) int32 {
|
||
tm := this.GetTm(sortId)
|
||
if tm == nil {
|
||
return 0
|
||
}
|
||
round := this.GetRound(sortId)
|
||
useRobot := this.IsRobotOn(tm.gmd)
|
||
|
||
robotRankFunc := func(n int, snid int32) int32 {
|
||
rank := int32(0)
|
||
for _, v := range tm.robotGrades[n] {
|
||
if v.copySnid == snid {
|
||
return v.rank
|
||
}
|
||
if v.copySnid == 0 {
|
||
rank = v.rank
|
||
}
|
||
}
|
||
return rank
|
||
}
|
||
|
||
playerRankFunc := func(n int, snid int32) int32 {
|
||
d := this.GetRoundPlayer(sortId, int32(n))
|
||
if d != nil {
|
||
for _, v := range d.players {
|
||
if v.p.SnId == snid {
|
||
return v.rank
|
||
}
|
||
}
|
||
}
|
||
d = this.GetRoundPlayer(sortId, int32(n-1))
|
||
if d != nil {
|
||
for _, v := range d.players {
|
||
if v.p.SnId == snid {
|
||
return v.rank
|
||
}
|
||
}
|
||
}
|
||
return 0
|
||
}
|
||
|
||
if round <= 1 {
|
||
d := tm.TmPlayer[snid]
|
||
if d != nil {
|
||
return int32(d.seq)
|
||
}
|
||
if useRobot {
|
||
n := 0
|
||
for _, v := range tm.TmPlayer {
|
||
n = v.seq - 1
|
||
break
|
||
}
|
||
for k, v := range tm.robotGrades[0] {
|
||
if v.copySnid == snid {
|
||
if k < n {
|
||
return int32(k)
|
||
}
|
||
return int32(k + 2)
|
||
}
|
||
}
|
||
}
|
||
return 0
|
||
} else {
|
||
if useRobot {
|
||
return robotRankFunc(int(round-1), snid)
|
||
} else {
|
||
return playerRankFunc(int(round-1), snid)
|
||
}
|
||
}
|
||
}
|
||
|
||
func (this *Tournament) CanStopMatch(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.Tracef("没有真人比赛解散 matchId:%v sortId:%v", matchId, sortId)
|
||
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)
|
||
if this.GetTm(sortId) == nil {
|
||
logger.Logger.Tracef("UpdateMatchInfo: 比赛已经结束")
|
||
return
|
||
}
|
||
|
||
if _, ok := this.players[sortId]; !ok {
|
||
this.players[sortId] = make(map[int32]*PlayerMatchContext)
|
||
}
|
||
info, ok := this.players[sortId][p.SnId]
|
||
if !ok {
|
||
return
|
||
}
|
||
|
||
if _, ok = this.roundPlayers[sortId]; !ok {
|
||
this.roundPlayers[sortId] = make(map[int32]*PlayerRoundInfo)
|
||
}
|
||
if this.roundPlayers[sortId][info.round] == nil {
|
||
this.roundPlayers[sortId][info.round] = &PlayerRoundInfo{}
|
||
}
|
||
|
||
// 积分
|
||
info.grade = grade
|
||
// 完成人数
|
||
this.roundPlayers[sortId][info.round].num++
|
||
// 输赢统计
|
||
if info.record == nil {
|
||
info.record = make(map[int32]int32)
|
||
}
|
||
info.record[isWin]++
|
||
//轮数增加
|
||
info.round++
|
||
info.gaming = false
|
||
|
||
// 备份本轮比赛结算信息
|
||
mc := *info
|
||
if this.roundPlayers[sortId][info.round] == nil {
|
||
this.roundPlayers[sortId][info.round] = &PlayerRoundInfo{}
|
||
}
|
||
this.roundPlayers[sortId][info.round].players = append(this.roundPlayers[sortId][info.round].players, &mc)
|
||
// 计算排名用
|
||
this.roundPlayers[sortId][info.round].ranks = append(this.roundPlayers[sortId][info.round].ranks, &mc)
|
||
|
||
// 检查是否开始下一局
|
||
if this.IsRobotOn(info.tm.gmd) {
|
||
this.NextRoundStartSingle(sortId, info, matchRobotGrades)
|
||
} else {
|
||
this.NextRoundStart(sortId, info)
|
||
}
|
||
}
|
||
|
||
// NextRoundStartSingle 下一轮是否开始
|
||
// 开启机器人时使用
|
||
func (this *Tournament) NextRoundStartSingle(sortId int64, playerCtx *PlayerMatchContext, matchRobotGrades map[int32]int32) {
|
||
logger.Logger.Tracef("NextRoundStartSingle 当前第 %v 轮", playerCtx.round)
|
||
info := this.GetRoundPlayer(sortId, playerCtx.round)
|
||
if info == nil {
|
||
return
|
||
}
|
||
|
||
gmd := playerCtx.tm.gmd
|
||
// 需要晋级的人数
|
||
promotionNum := gmd.MatchPromotion[playerCtx.round]
|
||
|
||
updateRobotGrades := func() {
|
||
round := playerCtx.round
|
||
if promotionNum == 1 { // 决赛
|
||
round = playerCtx.round - 1
|
||
}
|
||
arr := playerCtx.tm.robotGrades[int(round)]
|
||
|
||
// 修改陪真人玩的机器人积分
|
||
if matchRobotGrades != nil {
|
||
logger.Logger.Trace("和真人比赛的机器人使用真实积分: ", matchRobotGrades)
|
||
for _, gradeInfo := range arr {
|
||
if grade, ok := matchRobotGrades[gradeInfo.copySnid]; ok {
|
||
gradeInfo.grade = grade
|
||
}
|
||
}
|
||
}
|
||
|
||
findMe := false
|
||
for _, v := range arr {
|
||
if v.copySnid == 0 { // 真人
|
||
v.grade = playerCtx.grade
|
||
findMe = true
|
||
break
|
||
}
|
||
}
|
||
if !findMe {
|
||
gradeInfo := &TmGradeInfo{
|
||
grade: playerCtx.grade,
|
||
copySnid: 0,
|
||
}
|
||
arr = append(arr, gradeInfo) // 添加了真人数据
|
||
}
|
||
|
||
sort.Slice(arr, func(i, j int) bool {
|
||
if arr[i].grade == arr[j].grade { // 真人在前
|
||
if arr[i].copySnid == 0 {
|
||
return true
|
||
}
|
||
if arr[j].copySnid == 0 {
|
||
return false
|
||
}
|
||
}
|
||
return arr[i].grade > arr[j].grade
|
||
})
|
||
for k, v := range arr {
|
||
v.rank = int32(k + 1)
|
||
}
|
||
playerCtx.tm.robotGrades[int(round)] = arr
|
||
|
||
for _, info := range arr {
|
||
logger.Logger.Tracef("NextRoundStart_Single 本轮积分排名 round:%v Snid:%v Grade:%v copyLv:%v copyRoleId:%v rank:%v",
|
||
playerCtx.round, info.copySnid, info.grade, info.copyLv, info.copyRoleId, info.rank)
|
||
}
|
||
|
||
// 获取排名
|
||
index := int32(0) //晋级淘汰
|
||
for i, v := range arr {
|
||
if playerCtx.grade >= v.grade {
|
||
index = int32(i) + 1
|
||
break
|
||
}
|
||
}
|
||
|
||
if promotionNum != 1 {
|
||
if int(promotionNum) < len(arr) {
|
||
arr = arr[:promotionNum]
|
||
}
|
||
playerCtx.tm.robotGrades[int(round)] = arr
|
||
}
|
||
|
||
if index == 0 { // 是最后一名
|
||
index = gmd.MatchPromotion[round]
|
||
}
|
||
playerCtx.rank = index
|
||
}
|
||
|
||
if promotionNum != 1 {
|
||
// 非决赛
|
||
if playerCtx.tm.robotGrades == nil || playerCtx.tm.robotGrades[int(playerCtx.round)] == nil {
|
||
playerCtx.tm.CreateRobotGrades(int(playerCtx.round))
|
||
}
|
||
|
||
if playerCtx.tm.robotGrades != nil && playerCtx.tm.robotGrades[int(playerCtx.round)] != nil {
|
||
updateRobotGrades()
|
||
if playerCtx.rank <= promotionNum {
|
||
// 晋级
|
||
this.sendPromotionInfo(playerCtx, sortId, JinJi, false, false) //晋级
|
||
|
||
// 开始下一轮
|
||
mct := []*PlayerMatchContext{playerCtx}
|
||
finals := false
|
||
if playerCtx.round == int32(len(gmd.MatchPromotion)-2) {
|
||
finals = true
|
||
}
|
||
timer.StartTimer(timer.TimerActionWrapper(func(h timer.TimerHandle, ud interface{}) bool {
|
||
MatchSceneMgrSingleton.NewRoundStart(playerCtx.tm, mct, finals, playerCtx.round+1)
|
||
return true
|
||
}), nil, time.Second*7, 1)
|
||
} else {
|
||
// 淘汰
|
||
this.sendPromotionInfo(playerCtx, sortId, TaoTai, true, false) //淘汰
|
||
}
|
||
}
|
||
} else {
|
||
// 比赛结束
|
||
updateRobotGrades()
|
||
outCode := TaoTai
|
||
if playerCtx.rank == 1 {
|
||
outCode = JinJi
|
||
}
|
||
this.sendPromotionInfo(playerCtx, sortId, outCode, true, true) //晋级
|
||
logger.Logger.Trace("比赛结束!!! ")
|
||
|
||
// 比赛结束
|
||
this.StopMatch(playerCtx.tm.TMId, sortId)
|
||
}
|
||
}
|
||
|
||
// NextRoundStart 下一轮是否开始
|
||
// 关闭机器时使用
|
||
func (this *Tournament) NextRoundStart(sortId int64, playerCtx *PlayerMatchContext) {
|
||
logger.Logger.Tracef("NextRoundStart 当前第 %v 轮", playerCtx.round)
|
||
info := this.GetRoundPlayer(sortId, playerCtx.round)
|
||
if info == nil {
|
||
return
|
||
}
|
||
|
||
gmd := playerCtx.tm.gmd
|
||
// 需要晋级的人数
|
||
promotionNum1 := int(gmd.MatchPromotion[playerCtx.round-1])
|
||
promotionNum := int(gmd.MatchPromotion[playerCtx.round])
|
||
n := len(info.players)
|
||
outNum := promotionNum1 - promotionNum
|
||
|
||
if promotionNum != 1 {
|
||
// 非决赛淘汰后开始配桌
|
||
// 已经晋级的人数减去一桌之后 剩余人数还能够满足本轮淘汰
|
||
logger.Logger.Tracef("非决赛开始淘汰晋级 等待人数: %v 淘汰人数:%v", n, outNum)
|
||
if n-4 >= outNum {
|
||
// 提前晋级的开始凑桌
|
||
MatchContextSlice(info.players).Sort(false)
|
||
// 晋级
|
||
var ps []*PlayerMatchContext
|
||
finals := false // 是否最后一局
|
||
meIn := false // 自己是否晋级
|
||
for i := 0; i < n-outNum; i++ {
|
||
this.sendPromotionInfo(info.players[i], sortId, JinJi, false, false) //晋级
|
||
|
||
v := *info.players[i]
|
||
v.rank = this.getRank(sortId, info.players[i].round, info.players[i].p.SnId, false)
|
||
ps = append(ps, &v)
|
||
logger.Logger.Tracef("凑桌成功:%+v", v)
|
||
|
||
if !finals && v.round == int32(len(gmd.MatchPromotion)-2) {
|
||
finals = true
|
||
}
|
||
if v.p.SnId == playerCtx.p.SnId {
|
||
meIn = true
|
||
}
|
||
}
|
||
info.players = info.players[len(ps):]
|
||
|
||
willOut := false
|
||
if promotionNum1 == this.GetRoundPlayer(sortId, playerCtx.round-1).num {
|
||
// 最后一个人打完了,确定要淘汰的人
|
||
willOut = true
|
||
} else {
|
||
if !meIn { //自己暂时没晋级
|
||
logger.Logger.Tracef("待定 %+v", info.players)
|
||
this.sendPromotionInfo(playerCtx, sortId, DaiDing, false, false) //待定
|
||
}
|
||
}
|
||
|
||
isOver := false
|
||
if willOut {
|
||
for _, v := range info.players {
|
||
logger.Logger.Tracef("淘汰 %+v", *v)
|
||
this.sendPromotionInfo(v, sortId, TaoTai, true, false) //淘汰
|
||
//真人被淘汰,如果剩下的都是机器人,比赛解散
|
||
if !v.p.IsRob {
|
||
isOver = this.CanStopMatch(playerCtx.tm.TMId, sortId)
|
||
}
|
||
}
|
||
}
|
||
|
||
if !isOver {
|
||
timer.StartTimer(timer.TimerActionWrapper(func(h timer.TimerHandle, ud interface{}) bool {
|
||
MatchSceneMgrSingleton.NewRoundStart(playerCtx.tm, ps, finals, playerCtx.round+1)
|
||
return true
|
||
}), nil, time.Second*7, 1)
|
||
}
|
||
} else {
|
||
// 待定
|
||
logger.Logger.Tracef("待定 %+v", info.players)
|
||
this.sendPromotionInfo(playerCtx, sortId, DaiDing, false, false)
|
||
}
|
||
} else {
|
||
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) //晋级
|
||
}
|
||
logger.Logger.Trace("比赛结束!!! ")
|
||
|
||
// 比赛结束
|
||
this.StopMatch(playerCtx.tm.TMId, sortId)
|
||
}
|
||
}
|
||
|
||
// 发送晋级信息
|
||
// outCode 0晋级 1淘汰 2待定
|
||
// isOver 玩家比赛结束
|
||
// isFinals 比赛结束
|
||
func (this *Tournament) sendPromotionInfo(mc *PlayerMatchContext, sortId int64, outCode int, isOver, isFinals bool) {
|
||
logger.Logger.Tracef("sendPromotionInfo %+v sortId:%v outCode:%v isOver:%v isFinals:%v", mc, sortId, outCode, isOver, isFinals)
|
||
if mc == nil || mc.tm == nil || mc.tm.gmd == nil {
|
||
return
|
||
}
|
||
|
||
// 淘汰或最后一局,记录排名
|
||
if outCode == TaoTai || isFinals {
|
||
pri := &PerRankInfo{
|
||
Name: mc.p.Name,
|
||
SnId: mc.p.SnId,
|
||
RankId: mc.rank,
|
||
Grade: mc.grade,
|
||
}
|
||
this.addFinalPlayer(sortId, pri)
|
||
}
|
||
|
||
if !this.IsRobotOn(mc.tm.gmd) { // 不使用机器人
|
||
mc.rank = this.getRank(sortId, mc.round, mc.p.SnId, isFinals)
|
||
}
|
||
|
||
// 通知晋级信息:0.晋级等待匹配 1.失败退出 2.等待判断是否晋级
|
||
pack := &tournament.SCPromotionInfo{
|
||
RetCode: int32(outCode),
|
||
Round: mc.round,
|
||
RankId: mc.rank,
|
||
RoundCoin: 100, //暂时用不到先写死
|
||
Record: mc.record,
|
||
MatchId: mc.tm.TMId,
|
||
MatchPromotion: mc.tm.gmd.GetMatchPromotion(),
|
||
MatchName: mc.tm.gmd.GetMatchName(),
|
||
}
|
||
// 真人发奖
|
||
if !mc.p.IsRob && isOver {
|
||
for _, award := range mc.tm.gmd.Award {
|
||
if mc.rank >= award.UpLimit && mc.rank <= award.DownLimit { //上下限是反的,我也是醉了
|
||
rankAward := &tournament.RankAward{
|
||
Coin: proto.Int64(award.Coin),
|
||
Diamond: proto.Int64(award.Diamond),
|
||
}
|
||
if award.ItemId != nil {
|
||
for _, info := range award.ItemId {
|
||
item := &tournament.ItemInfo{
|
||
ItemId: proto.Int32(info.ItemId),
|
||
ItemNum: proto.Int32(int32(info.ItemNum)),
|
||
Name: proto.String(info.Name),
|
||
}
|
||
rankAward.ItemInfo = append(rankAward.ItemInfo, item)
|
||
}
|
||
}
|
||
pack.RankAward = rankAward
|
||
if mc.rank == 1 {
|
||
if this.MatchAwardNum == nil {
|
||
this.MatchAwardNum = make(map[string]map[int32]int32)
|
||
}
|
||
if this.MatchAwardNum[mc.p.Platform] == nil {
|
||
this.MatchAwardNum[mc.p.Platform] = make(map[int32]int32)
|
||
}
|
||
this.MatchAwardNum[mc.p.Platform][mc.tm.gmd.Id] += 1
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
sendFunc := func() {
|
||
outStr := "晋级"
|
||
switch outCode {
|
||
case 1:
|
||
outStr = "淘汰"
|
||
case 2:
|
||
outStr = "待定"
|
||
}
|
||
ok := mc.p.SendToClient(int(tournament.TOURNAMENTID_PACKET_TM_SCPromotionInfo), pack)
|
||
logger.Logger.Trace("sendPromotionInfo: ", outStr, " snid: ", mc.p.SnId, " pack: ", pack)
|
||
|
||
if ok && !mc.p.IsRob && isOver {
|
||
if pack.RankAward != nil {
|
||
if pack.RankAward.Coin != 0 { //金币
|
||
mc.p.AddCoin(pack.RankAward.Coin, 0, common.GainWay_MatchSystemSupply, "system", mc.tm.gmd.MatchName+"排名奖励")
|
||
}
|
||
if pack.RankAward.Diamond != 0 { //钻石
|
||
mc.p.AddDiamond(pack.RankAward.Diamond, 0, common.GainWay_MatchSystemSupply, "system", mc.tm.gmd.MatchName+"排名奖励")
|
||
}
|
||
if pack.RankAward.ItemInfo != nil {
|
||
for _, info := range pack.RankAward.ItemInfo {
|
||
if info.ItemNum <= 0 {
|
||
continue
|
||
}
|
||
BagMgrSingleton.AddItems(&model.AddItemParam{
|
||
Platform: mc.p.Platform,
|
||
SnId: mc.p.SnId,
|
||
Change: []*model.Item{
|
||
{
|
||
ItemId: info.ItemId,
|
||
ItemNum: int64(info.ItemNum),
|
||
},
|
||
},
|
||
GainWay: common.GainWay_MatchSystemSupply,
|
||
Operator: "system",
|
||
Remark: mc.tm.gmd.MatchName + "排名奖励",
|
||
GameId: int64(mc.tm.dbGameFree.GetGameId()),
|
||
GameFreeId: int64(mc.tm.dbGameFree.GetId()),
|
||
})
|
||
}
|
||
}
|
||
}
|
||
}
|
||
if isOver { // 自己比赛结束
|
||
delete(this.players[sortId], mc.p.SnId)
|
||
//真人被淘汰,如果剩下的都是机器人,比赛解散
|
||
if !mc.p.IsRob {
|
||
this.CanStopMatch(mc.tm.TMId, sortId)
|
||
}
|
||
}
|
||
}
|
||
|
||
// 获取兑换码奖品
|
||
var has bool
|
||
wg := new(sync.WaitGroup)
|
||
if pack.GetRankAward() != nil {
|
||
for _, v := range pack.GetRankAward().GetItemInfo() {
|
||
data := srvdata.GameItemMgr.Get(mc.p.Platform, v.ItemId)
|
||
if data != nil && data.GetType() == common.ItemTypePhoneCode {
|
||
has = true
|
||
item := v // 并发需要复制
|
||
wg.Add(1)
|
||
// 兑换码奖品
|
||
var err error
|
||
var newMsg *model.Message
|
||
res := &webapiproto.SAGetMatchAwardCode{}
|
||
task.New(nil, task.CallableWrapper(func(o *basic.Object) interface{} {
|
||
// 获取兑换码
|
||
pack := &webapiproto.ASGetMatchAwardCode{
|
||
Platform: mc.p.Platform,
|
||
Snid: mc.p.SnId,
|
||
ItemID: data.GetId(),
|
||
Money: data.GetNum(),
|
||
Tel: mc.p.Tel,
|
||
CardType: mc.tm.gmd.CardType,
|
||
Remark: "比赛场获得奖励",
|
||
}
|
||
logger.Logger.Trace("GetMatchAwardCode ", pack)
|
||
var buff []byte
|
||
buff, err = webapi.APIGetMatchAwardCode(common.GetAppId(), pack)
|
||
if err != nil {
|
||
return err
|
||
}
|
||
if err = proto.Unmarshal(buff, res); err != nil {
|
||
return err
|
||
}
|
||
|
||
if res.GetCode() == "" || res.GetTag() != webapiproto.TagCode_SUCCESS {
|
||
return nil
|
||
}
|
||
|
||
var params []string
|
||
for range []string{"zh", "vi", "en", "kh"} {
|
||
params = append(params, res.GetMoney(), res.GetCode()) // 金额,兑换码
|
||
}
|
||
// 发送邮件
|
||
title := i18n.Tr("languages", "MatchAwardTitle")
|
||
content := i18n.Tr("languages", "MatchAward", params)
|
||
newMsg = model.NewMessage("", 0, "", mc.p.SnId, model.MSGTYPE_RANK_REWARD,
|
||
title, content, 0, 0, model.MSGSTATE_UNREAD, time.Now().Unix(), 0, "", nil, mc.p.Platform, model.HallTienlen, nil)
|
||
err := model.InsertMessage(mc.p.Platform, newMsg)
|
||
if err != nil {
|
||
logger.Logger.Errorf("发送邮件失败 snid:%v itemID:%v err:%v", mc.p.SnId, data.Id, err)
|
||
return err
|
||
}
|
||
return nil
|
||
}), task.CompleteNotifyWrapper(func(i interface{}, t task.Task) {
|
||
defer wg.Done()
|
||
if err != nil || res.GetCode() == "" || res.GetTag() != webapiproto.TagCode_SUCCESS {
|
||
logger.Logger.Errorf("获取兑换码失败 snid:%v itemID:%v res:%v err:%v", mc.p.SnId, data.Id, res, err)
|
||
return
|
||
}
|
||
item.Code = res.GetCode()
|
||
item.Msg = res.GetMoney()
|
||
p := PlayerMgrSington.GetPlayerBySnId(mc.p.SnId)
|
||
if p != nil {
|
||
p.AddMessage(newMsg)
|
||
//比赛场记录话费产出log
|
||
awardLog := model.AnnouncerLog{
|
||
Platform: p.Platform,
|
||
Snid: p.SnId,
|
||
Name: p.Name,
|
||
Phone: p.Tel,
|
||
ItemId: data.Id, //获得物品ID
|
||
TypeId: int32(1),
|
||
}
|
||
AwardLogMgr.UpdateAnnouncerLog(awardLog)
|
||
AwardLogMgr.UpdateAwardLog(p.Platform, item.ItemId, 1)
|
||
}
|
||
}), fmt.Sprintf("RankAward%d", mc.p.SnId)).Start()
|
||
}
|
||
}
|
||
}
|
||
|
||
if !has {
|
||
sendFunc()
|
||
return
|
||
}
|
||
task.New(nil, task.CallableWrapper(func(o *basic.Object) interface{} {
|
||
wg.Wait()
|
||
return nil
|
||
}), task.CompleteNotifyWrapper(func(i interface{}, t task.Task) {
|
||
sendFunc()
|
||
}), "sendPromotionInfo").Start()
|
||
}
|
||
|
||
// 更新段位
|
||
//func (this *Tournament) CheckAddMatchSeasonLv(mc *PlayerMatchContext) {
|
||
// if mc == nil {
|
||
// return
|
||
// }
|
||
// platform := mc.p.Platform
|
||
// if platform == DefaultPlatform {
|
||
// return
|
||
// }
|
||
// rank := mc.rank
|
||
// maxPlayerNum := mc.tm.gmd.MatchNumebr
|
||
// upLine := maxPlayerNum * 33 / 100
|
||
// downLine := maxPlayerNum * 67 / 100
|
||
// snid := mc.p.SnId
|
||
// ms := MatchSeasonMgrSington.GetMatchSeason(mc.p.SnId)
|
||
// msid := MatchSeasonMgrSington.GetMatchSeasonId(platform)
|
||
// if msid == nil {
|
||
// MatchSeasonMgrSington.UpdateMatchSeasonId(platform)
|
||
// }
|
||
// if ms == nil {
|
||
// task.New(nil, task.CallableWrapper(func(o *basic.Object) interface{} {
|
||
// ret, err := model.QueryMatchSeasonBySnid(platform, snid)
|
||
// if err != nil {
|
||
// return nil
|
||
// }
|
||
// return ret
|
||
// }), task.CompleteNotifyWrapper(func(data interface{}, tt task.Task) {
|
||
// var ret *model.MatchSeason
|
||
// dirty := false
|
||
// seasonId := int32(1)
|
||
// if msid != nil {
|
||
// seasonId = msid.SeasonId
|
||
// }
|
||
// if data == nil || data.(*model.MatchSeason) == nil {
|
||
// player := PlayerMgrSington.GetPlayerBySnId(snid)
|
||
// if player != nil {
|
||
// ret = model.NewMatchSeason(player.Platform, snid, player.Name, seasonId, 1)
|
||
// dirty = true
|
||
// } else {
|
||
// logger.Logger.Error("CSTMSeasonInfoHandler error: player == nil or msi == nil", snid)
|
||
// }
|
||
// } else {
|
||
// ret = data.(*model.MatchSeason)
|
||
// if ret.SeasonId < seasonId { //不同赛季段位继承
|
||
// num := seasonId - ret.SeasonId
|
||
// finalLv := ret.Lv
|
||
// for i := 0; i < int(num); i++ { //继承几次
|
||
// if i == int(num)-1 { //上个赛季
|
||
// ret.LastLv = finalLv
|
||
// }
|
||
// finalLv = MatchSeasonMgrSington.MatchSeasonInherit(finalLv)
|
||
// }
|
||
// ret.Lv = finalLv
|
||
// ret.SeasonId = seasonId
|
||
// ret.IsAward = false
|
||
// dirty = true
|
||
// }
|
||
// }
|
||
// ms = MatchSeasonMgrSington.exchangeModel2Cache(ret)
|
||
// ms.dirty = dirty
|
||
// MatchSeasonMgrSington.SetMatchSeason(ms)
|
||
// if rank <= upLine { //加分
|
||
// MatchSeasonMgrSington.UpdateMatchSeasonLv(mc.p, 1, dirty)
|
||
// } else if rank >= downLine && ms.Lv > 75 { //白银以上才触发减分
|
||
// MatchSeasonMgrSington.UpdateMatchSeasonLv(mc.p, -1, dirty)
|
||
// } else {
|
||
// MatchSeasonMgrSington.UpdateMatchSeasonLv(mc.p, 0, dirty)
|
||
// }
|
||
// })).StartByFixExecutor("SnId:" + strconv.Itoa(int(snid)))
|
||
// } else {
|
||
// dirty := false
|
||
// if ms.SeasonId < msid.SeasonId { //不同赛季段位继承
|
||
// num := msid.SeasonId - ms.SeasonId
|
||
// finalLv := ms.Lv
|
||
// for i := 0; i < int(num); i++ { //继承几次
|
||
// if i == int(num)-1 { //上个赛季
|
||
// ms.LastLv = finalLv
|
||
// }
|
||
// finalLv = MatchSeasonMgrSington.MatchSeasonInherit(finalLv)
|
||
// }
|
||
// ms.Lv = finalLv
|
||
// ms.SeasonId = msid.SeasonId
|
||
// ms.IsAward = false
|
||
// ms.UpdateTs = time.Now().Unix()
|
||
// ms.dirty = true
|
||
// dirty = true
|
||
// MatchSeasonMgrSington.SetMatchSeason(ms)
|
||
// }
|
||
// if rank <= upLine { //加分
|
||
// MatchSeasonMgrSington.UpdateMatchSeasonLv(mc.p, 1, dirty)
|
||
// } else if rank >= downLine && ms.Lv > 75 { //白银以上才触发减分
|
||
// MatchSeasonMgrSington.UpdateMatchSeasonLv(mc.p, -1, dirty)
|
||
// } else {
|
||
// MatchSeasonMgrSington.UpdateMatchSeasonLv(mc.p, 0, dirty)
|
||
// }
|
||
// }
|
||
//}
|
||
|
||
// GetSCTMInfosPack 发送比赛配置数据
|
||
func (this *Tournament) GetSCTMInfosPack(platform, channelName string) *tournament.SCTMInfos {
|
||
pack := &tournament.SCTMInfos{}
|
||
matchInfo := this.GetAllMatchInfo(platform)
|
||
if matchInfo != nil {
|
||
for id, info := range matchInfo {
|
||
if info.MatchSwitch == 1 && !this.IsOutTime(info) && common.InMatchChannel(info.OnChannelName, channelName) {
|
||
awardNum := this.GetMatchAwardNum(platform, info.Id)
|
||
tMInfo := &tournament.TMInfo{
|
||
Id: proto.Int32(id),
|
||
GameFreeId: info.GameFreeId,
|
||
MatchType: info.MatchType,
|
||
MatchName: info.MatchName,
|
||
MatchNumebr: info.MatchNumebr,
|
||
MatchSwitch: info.MatchSwitch,
|
||
SignupCostCoin: info.SignupCostCoin,
|
||
SignupCostDiamond: info.SignupCostDiamond,
|
||
MatchTimeType: info.MatchTimeType,
|
||
MatchTimeStartHMS: info.MatchTimeStartHMS,
|
||
MatchTimeEndHMS: info.MatchTimeEndHMS,
|
||
TitleURL: info.TitleURL,
|
||
AwardShow: info.AwardShow,
|
||
Rule: info.Rule,
|
||
SortId: info.SortId,
|
||
OnChannelName: info.OnChannelName,
|
||
ShowId: info.ShowId,
|
||
AwardNum: awardNum,
|
||
}
|
||
if info.MatchTimeWeek != nil && len(info.MatchTimeWeek) > 0 {
|
||
for _, week := range info.MatchTimeWeek {
|
||
tMInfo.MatchTimeWeek = append(tMInfo.MatchTimeWeek, week)
|
||
}
|
||
}
|
||
|
||
if info.MatchType == MatchTypeChampion {
|
||
week := this.getWeekDay()
|
||
for _, v := range info.MatchTimeWeek {
|
||
if v == int32(week) {
|
||
if info.MatchTimeStamp != nil && len(info.MatchTimeStamp) > 0 {
|
||
for _, stamp := range info.MatchTimeStamp {
|
||
tMInfo.MatchTimeStamp = append(tMInfo.MatchTimeStamp, stamp)
|
||
}
|
||
}
|
||
}
|
||
}
|
||
if len(tMInfo.MatchTimeStamp) == 0 {
|
||
tMInfo.MatchTimeStamp = []int64{time.Now().AddDate(0, 0, 2).Unix(), time.Now().AddDate(0, 0, 3).Unix()}
|
||
}
|
||
} else {
|
||
if info.MatchTimeStamp != nil && len(info.MatchTimeStamp) > 0 {
|
||
for _, stamp := range info.MatchTimeStamp {
|
||
tMInfo.MatchTimeStamp = append(tMInfo.MatchTimeStamp, stamp)
|
||
}
|
||
}
|
||
}
|
||
|
||
if info.MatchPromotion != nil {
|
||
for _, mp := range info.MatchPromotion {
|
||
tMInfo.MatchPromotion = append(tMInfo.MatchPromotion, mp)
|
||
}
|
||
}
|
||
if info.Award != nil {
|
||
for _, award := range info.Award {
|
||
miAward := &tournament.MatchInfoAward{
|
||
Coin: award.Coin,
|
||
Diamond: award.Diamond,
|
||
UpLimit: award.UpLimit,
|
||
DownLimit: award.DownLimit,
|
||
}
|
||
if award.ItemId != nil {
|
||
for _, itemInfo := range award.ItemId {
|
||
a := &tournament.ItemInfo{
|
||
ItemId: itemInfo.ItemId,
|
||
ItemNum: int32(itemInfo.ItemNum),
|
||
Name: itemInfo.Name,
|
||
}
|
||
miAward.ItemInfo = append(miAward.ItemInfo, a)
|
||
}
|
||
}
|
||
tMInfo.Award = append(tMInfo.Award, miAward)
|
||
}
|
||
}
|
||
if info.SignupCostItem != nil && info.SignupCostItem.ItemNum > 0 {
|
||
signupCost := &tournament.ItemInfo{
|
||
ItemId: info.SignupCostItem.ItemId,
|
||
ItemNum: int32(info.SignupCostItem.ItemNum),
|
||
Name: info.SignupCostItem.Name,
|
||
}
|
||
tMInfo.SignupCostItem = signupCost
|
||
}
|
||
pack.TMInfo = append(pack.TMInfo, tMInfo)
|
||
}
|
||
}
|
||
if l := this.TypeList[platform]; l != nil {
|
||
for _, v := range l.GetList() {
|
||
pack.TypeList = append(pack.TypeList, &tournament.MatchTypeInfo{
|
||
Name: v.GetName(),
|
||
SortId: v.GetSortId(),
|
||
On: v.GetOn(),
|
||
Id: v.GetId(),
|
||
})
|
||
}
|
||
}
|
||
}
|
||
return pack
|
||
}
|
||
|
||
// GetTmMatch 查询比赛中的比赛
|
||
func (this *Tournament) GetTmMatch(plt string, matchId int32, channelName string, audience bool, sortId int64) []*TmMatch {
|
||
matches := this.GetAllMatchInfo(plt)
|
||
if matches == nil {
|
||
return nil
|
||
}
|
||
|
||
var ids []int32
|
||
for id, info := range matches {
|
||
if info == nil || info.MatchSwitch != 1 {
|
||
continue
|
||
}
|
||
if matchId > 0 && id != matchId {
|
||
continue
|
||
}
|
||
if channelName != "" && !common.InMatchChannel(info.OnChannelName, channelName) {
|
||
continue
|
||
}
|
||
if info.GetAudienceSwitch() == 1 != audience {
|
||
continue
|
||
}
|
||
ids = append(ids, id)
|
||
}
|
||
|
||
var ret []*TmMatch
|
||
if sortId > 0 {
|
||
for _, v := range ids {
|
||
d := this.matches[v]
|
||
if d != nil {
|
||
r, ok := d[sortId]
|
||
if ok && r != nil {
|
||
return []*TmMatch{r}
|
||
}
|
||
}
|
||
}
|
||
return ret
|
||
}
|
||
|
||
for _, v := range ids {
|
||
for _, vv := range this.matches[v] {
|
||
ret = append(ret, vv)
|
||
}
|
||
}
|
||
|
||
return ret
|
||
}
|
||
|
||
func (this *Tournament) GetTmRoom(plt string, matchId int32, channelName string, audience bool, sortId int64) []*Scene {
|
||
tm := this.GetTmMatch(plt, matchId, channelName, audience, sortId)
|
||
|
||
sort.Slice(tm, func(i, j int) bool {
|
||
return tm[i].SortId < tm[j].SortId
|
||
})
|
||
|
||
var ret []*Scene
|
||
for _, v := range tm {
|
||
d := SceneMgrSingleton.GetMatchRoom(v.SortId)
|
||
sort.Slice(d, func(i, j int) bool {
|
||
return d[i].createTime.Before(d[j].createTime)
|
||
})
|
||
ret = append(ret, d...)
|
||
}
|
||
|
||
return ret
|
||
}
|
||
|
||
func (this *Tournament) MakeMatchLog(platform string, tmId int32, sortId int64) *model.MatchLog {
|
||
gameMatchDate := this.GetMatchInfo(platform, tmId, sortId)
|
||
if gameMatchDate == nil {
|
||
logger.Logger.Errorf("MakeMatchLog gameMatchDate == nil tmId:%d sortId:%d", tmId, sortId)
|
||
return nil
|
||
}
|
||
matchLog := model.NewMatchLog()
|
||
_, ok := this.roundPlayers[sortId]
|
||
if !ok {
|
||
return nil
|
||
}
|
||
info := this.roundPlayers[sortId][1]
|
||
if info == nil {
|
||
return nil
|
||
}
|
||
for _, v := range info.players {
|
||
if v == nil || v.p == nil || v.p.IsRob {
|
||
continue
|
||
}
|
||
|
||
var coin, diamond int64
|
||
items := make(map[int32]int64)
|
||
rankId := int32(-1)
|
||
perRankInfo := this.finalPerRank[sortId]
|
||
for _, info := range perRankInfo {
|
||
if info.SnId == v.p.SnId {
|
||
rankId = info.RankId
|
||
break
|
||
}
|
||
}
|
||
if gameMatchDate.Award != nil {
|
||
for _, award := range gameMatchDate.Award {
|
||
if rankId >= award.UpLimit && rankId <= award.DownLimit { //上下限是反的,我也是醉了
|
||
coin = award.Coin
|
||
diamond = award.Diamond
|
||
if award.ItemId != nil {
|
||
for _, info := range award.ItemId {
|
||
items[info.ItemId] = info.ItemNum
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
matchLog.Players = append(matchLog.Players, &model.MatchPlayer{
|
||
SnId: v.p.SnId,
|
||
CostCoin: this.matches[tmId][sortId].gmd.SignupCostCoin,
|
||
CostDiamond: this.matches[tmId][sortId].gmd.SignupCostDiamond,
|
||
Coin: coin,
|
||
Diamond: diamond,
|
||
Item: items,
|
||
Rank: rankId,
|
||
})
|
||
if rankId >= 1 && rankId <= 10 {
|
||
TaskSubjectSingleton.Touch(common.TaskTypeMatchRank10, &TaskData{
|
||
GameID: int(v.tm.dbGameFree.GetGameId()),
|
||
GameFreeID: v.tm.dbGameFree.GetId(),
|
||
SnId: v.p.SnId,
|
||
Num: 1,
|
||
})
|
||
}
|
||
}
|
||
matchLog.MatchId = tmId
|
||
matchLog.MatchName = gameMatchDate.MatchName
|
||
matchLog.Platform = platform
|
||
matchLog.GameFreeId = gameMatchDate.GameFreeId
|
||
matchLog.StartTime = this.matches[tmId][sortId].StartTime
|
||
matchLog.EndTime = time.Now()
|
||
matchLog.SortId = sortId
|
||
return matchLog
|
||
}
|
||
|
||
func (this *Tournament) saveMatchLog(matchLog *model.MatchLog) {
|
||
if matchLog == nil {
|
||
return
|
||
}
|
||
task.New(nil, task.CallableWrapper(func(o *basic.Object) interface{} {
|
||
err := model.InsertMatchLogs(matchLog)
|
||
if err != nil {
|
||
logger.Logger.Error("saveMatchLog error %v", err)
|
||
return err
|
||
}
|
||
return nil
|
||
}), task.CompleteNotifyWrapper(func(data interface{}, tt task.Task) {
|
||
})).StartByFixExecutor("saveMatchLogTask")
|
||
}
|
||
|
||
func (this *Tournament) SaveMatchAward() {
|
||
if this.MatchAwardNum == nil {
|
||
return
|
||
}
|
||
logger.Logger.Tracef("保存比赛场奖励领取次数")
|
||
for platform, v := range this.MatchAwardNum {
|
||
d := &model.MatchAward{
|
||
Platform: platform,
|
||
Award: make(map[int32]int32),
|
||
}
|
||
for k, vv := range v {
|
||
d.Award[k] = vv
|
||
}
|
||
err := model.UpsertMatchAward(d)
|
||
if err != nil {
|
||
logger.Logger.Errorf("SaveMatchAward error %v", err)
|
||
}
|
||
}
|
||
}
|
||
|
||
func (this *Tournament) getWeekDay() int {
|
||
getWeekNum := func(t time.Time) int {
|
||
strWeek := []string{"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"}
|
||
week := t.Weekday()
|
||
for i, s := range strWeek {
|
||
if week.String() == s {
|
||
return i
|
||
}
|
||
}
|
||
return 0
|
||
}
|
||
|
||
l := time.FixedZone("CST", model.GameParamData.BackendTimeLocal*3600)
|
||
bTs := time.Now().In(l)
|
||
week := getWeekNum(bTs)
|
||
return week
|
||
}
|
||
|
||
func (this *Tournament) FixMatchTimeStamp(d *webapiproto.GameMatchDate) {
|
||
// 更新比赛时间
|
||
if d == nil || d.MatchTimeType != 1 {
|
||
return
|
||
}
|
||
if len(d.MatchTimeStamp) != 2 {
|
||
return
|
||
}
|
||
|
||
l := time.FixedZone("CST", model.GameParamData.BackendTimeLocal*3600)
|
||
bTs := time.Now().In(l)
|
||
week := this.getWeekDay()
|
||
st := time.Unix(d.MatchTimeStamp[0], 0).In(l)
|
||
et := time.Unix(d.MatchTimeStamp[1], 0).In(l)
|
||
//logger.Logger.Tracef("FixMatchTimeStamp 1 id:%v now:%v week:%v start:%v end:%v", d.Id, bTs, bTs.Weekday(), st, et)
|
||
// 重复时间段比赛时间
|
||
for _, v := range d.MatchTimeWeek {
|
||
if v == int32(week) {
|
||
stSub := st.Unix() - nowtool.New(st).BeginningOfDay().Unix()
|
||
etSub := et.Unix() - nowtool.New(et).BeginningOfDay().Unix()
|
||
sub := etSub - stSub
|
||
d.MatchTimeStamp[0] = nowtool.New(bTs).BeginningOfDay().Add(time.Duration(stSub) * time.Second).Unix()
|
||
d.MatchTimeStamp[1] = d.MatchTimeStamp[0] + sub
|
||
|
||
st = time.Unix(d.MatchTimeStamp[0], 0).In(l)
|
||
et = time.Unix(d.MatchTimeStamp[1], 0).In(l)
|
||
//logger.Logger.Tracef("FixMatchTimeStamp 2 id:%v now:%v week:%v start:%v end:%v", d.Id, bTs, bTs.Weekday(), st, et)
|
||
break
|
||
}
|
||
}
|
||
}
|
||
|
||
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 {
|
||
has := false
|
||
for _, tm := range this.matches {
|
||
if _, ok := tm[sortId]; ok {
|
||
has = true
|
||
break
|
||
}
|
||
}
|
||
if !has {
|
||
logger.Logger.Errorf("比赛异常,比赛已经不存在了 %v", sortId)
|
||
delete(this.players, 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 剩余奖励数量
|
||
// id 比赛配置id
|
||
func (this *Tournament) GetMatchAwardNum(platform string, id int32) int32 {
|
||
var num int32
|
||
if this.MatchAwardNum != nil && this.MatchAwardNum[platform] != nil {
|
||
num = this.MatchAwardNum[platform][id]
|
||
}
|
||
matchInfo := this.GetAllMatchInfo(platform)
|
||
if matchInfo != nil {
|
||
for _, info := range matchInfo {
|
||
if info.Id == id {
|
||
if info.AwardNum == 9999 {
|
||
return 9999
|
||
} else {
|
||
num = info.AwardNum - num
|
||
if num < 0 {
|
||
num = 0
|
||
}
|
||
}
|
||
break
|
||
}
|
||
}
|
||
}
|
||
return num
|
||
}
|
||
|
||
// GetRound 获取当前轮次
|
||
func (this *Tournament) GetRound(sortId int64) int32 {
|
||
d, ok := this.roundPlayers[sortId]
|
||
if !ok || d == nil {
|
||
return 1
|
||
}
|
||
return int32(len(d))
|
||
}
|