package game import ( "fmt" "math" champshipCfg "server/conf/champship" randnameCfg "server/conf/randname" "server/db" "server/game/mod/msg" GoUtil "server/game_util" proto "server/msg" "server/pkg/github.com/name5566/leaf/log" "sort" "sync" "time" ) const ( RANK_PLAYER_ROBOT = 2 ) type ChampshipMgr struct { *ServerMod } type ChampshipData struct { mu sync.RWMutex AutoId int RobotId int Rank map[int][]*ChampshipRank // 锦标赛排行榜 PreRank map[int][]*ChampshipRank // 锦标赛排行榜 备份 Pool map[int]*GroupInfo // 锦标赛未分配玩家 GroupInfo map[int]int // 锦标赛分组信息 PreGroupInfo map[int]int // 锦标赛分组信息 备份 Robot map[int]*ChampshipRobot // 机器人 PreRobot map[int]*ChampshipRobot // 机器人 备份 ZeroTime int64 } type ChampshipRank struct { Uid int Score float64 Time int64 Type int } type ChampshipRobot struct { Max float64 Type int Name string Avatar int Face int Level int GroupId int Time int64 Score float64 PerScore float64 } type GroupInfo struct { Uid int Score float64 Time int64 N int H int } type CRank struct { Uid int Score float64 N int H int } func (c *ChampshipMgr) Init() { c.key = CHAMPSHIP_MGR_KEY c.data = &ChampshipData{ Rank: make(map[int][]*ChampshipRank, 0), PreRank: make(map[int][]*ChampshipRank, 0), Pool: make(map[int]*GroupInfo, 0), GroupInfo: make(map[int]int), PreGroupInfo: make(map[int]int), Robot: make(map[int]*ChampshipRobot, 0), PreRobot: make(map[int]*ChampshipRobot, 0), } // 注册处理函数 c.init() Now := GoUtil.Now() ZeroTime := GoUtil.ZeroTimestamp() if c.getData().ZeroTime != ZeroTime { c.ZeroUpdate() } Remain := Now - ZeroTime Remain1 := 1800 - Remain%1800 c.mDispatr.AfterFunc(time.Duration(Remain1)*time.Second, func() { // 30分钟后重新分组 c.group(false) }) c.mDispatr.AfterFunc(time.Duration(60)*time.Second, func() { c.ai() }) c.mDispatr.AfterFunc(time.Duration(GoUtil.NextZeroTimestampDuration())*time.Second, func() { c.ZeroUpdate() }) } func (c *ChampshipMgr) NotifyAll() (interface{}, error) { NotifyAllPlayerMsg(&msg.Msg{ Type: msg.HANDLE_TYPE_CHAMPSHIP_NOTIFY, HandleType: msg.HANDLE_MOD_PLAYER_MSG, End: GoUtil.Now() + onehour, }) return nil, nil } func (c *ChampshipMgr) ZeroUpdate() (interface{}, error) { c.group(true) log.Debug("ChampshipMgr ZeroUpdate") data := c.getData() data.mu.Lock() data.ZeroTime = GoUtil.ZeroTimestamp() // 深拷贝 map,避免多个协程持有同一个 map 引用导致并发读写 oldRank := make(map[int][]*ChampshipRank, len(data.Rank)) for k, v := range data.Rank { oldRank[k] = v } oldRobot := make(map[int]*ChampshipRobot, len(data.Robot)) for k, v := range data.Robot { oldRobot[k] = v } oldGroupInfo := make(map[int]int, len(data.GroupInfo)) for k, v := range data.GroupInfo { oldGroupInfo[k] = v } data.PreRank = oldRank data.PreRobot = oldRobot data.PreGroupInfo = oldGroupInfo data.AutoId = 0 data.RobotId = 1 data.Robot = make(map[int]*ChampshipRobot, 0) data.Rank = make(map[int][]*ChampshipRank, 0) data.GroupInfo = make(map[int]int, 0) c.update = true // 0点更新排行榜缓存 for k := range data.PreGroupInfo { c.SetRankCache(k) } data.mu.Unlock() c.mDispatr.AfterFunc(time.Duration(GoUtil.NextZeroTimestampDuration())*time.Second, func() { c.ZeroUpdate() }) c.mDispatr.AfterFunc(time.Duration(1800)*time.Second, func() { c.NotifyAll() }) // 在锁外通知玩家,避免在持有锁时调用外部函数 go c.NotifyPlayer() return nil, nil } func (c *ChampshipMgr) NotifyPlayer() { data := c.getData() data.mu.RLock() // 深拷贝需要通知的数据,避免在锁外访问 map notifyList := make([]struct { Uid int Rank int }, 0) for _, v := range data.PreRank { for i := 0; i < 3 && i < len(v); i++ { if v[i].Type == RANK_PLAYER_ROBOT { continue } notifyList = append(notifyList, struct { Uid int Rank int }{Uid: v[i].Uid, Rank: i + 1}) } } data.mu.RUnlock() // 在锁外通知,避免持锁时间过长 for _, item := range notifyList { NotifyChampshipResult(item.Uid, item.Rank) } } func (c *ChampshipMgr) ai() (interface{}, error) { ChampshipData := c.getData() ChampshipData.mu.Lock() defer ChampshipData.mu.Unlock() Now := GoUtil.Now() uids := make(map[int]struct{}) for k, v := range ChampshipData.Rank { Notify := make(map[int]int) for e, r := range v { if r.Type == RANK_PLAYER_ROBOT { AddScore := 0.0 Robot := ChampshipData.Robot[r.Uid] if Robot == nil { continue } if Robot.Type == 2 && Robot.Time+60 < Now { AddScore = Robot.PerScore Robot.Time = Now } if Robot.Type == 3 && Robot.Time+1800 < Now { AddScore = Robot.PerScore Robot.Time = Now } r.Score += AddScore } else { Notify[r.Uid] = e } } sort.Slice(v, func(i, j int) bool { // 排序 从大到小 数值相等按时间排序 if v[i].Score > v[j].Score { return true } else if v[i].Score == v[j].Score { return v[i].Time < v[j].Time } return false }) for e, r := range v { if r.Type == RANK_PLAYER_ROBOT { continue } if Notify[r.Uid] != e { c.SetRankCache(r.Uid) uids[r.Uid] = struct{}{} } } ChampshipData.Rank[k] = v } now := GoUtil.Now() // 在锁外通知玩家,避免在持锁时启动 goroutine 访问可能被并发修改的数据 for uid := range uids { go NotifyPlayer(uid, &msg.Msg{ Type: msg.HANDLE_TYPE_CHAMPSHIP_NOTIFY, End: now + onehour, }) } c.mDispatr.AfterFunc(time.Duration(60)*time.Second, func() { c.ai() }) return nil, nil } func (c *ChampshipMgr) GetPreRankMsg(Uid int) *proto.ResChampshipPreRank { ChampshipData := c.getData() ChampshipData.mu.RLock() defer ChampshipData.mu.RUnlock() GroupId := ChampshipData.PreGroupInfo[Uid] if GroupId == 0 { return &proto.ResChampshipPreRank{} } RankList, ok := ChampshipData.PreRank[GroupId] if !ok { return &proto.ResChampshipPreRank{} } MyRank := 0 MyScore := 0.0 RL := make(map[int32]*proto.ResPlayerRank, 0) for k, v := range RankList { if v.Uid == Uid { MyRank = k + 1 MyScore = v.Score } if v.Type == RANK_PLAYER_ROBOT { Robot := ChampshipData.PreRobot[v.Uid] if Robot == nil { continue } RL[int32(k+1)] = &proto.ResPlayerRank{ Uid: int64(v.Uid), Score: float32(v.Score), Name: Robot.Name, Avatar: int32(Robot.Avatar), Face: int32(Robot.Face), Level: int32(Robot.Level), } } else { SimplePlayer := G_GameLogicPtr.GetResSimplePlayerByUid(v.Uid) if SimplePlayer == nil { continue } RL[int32(k+1)] = &proto.ResPlayerRank{ Uid: int64(v.Uid), Score: float32(v.Score), Name: SimplePlayer.Name, Avatar: int32(SimplePlayer.Avatar), Face: int32(SimplePlayer.Face), Level: int32(SimplePlayer.Level), Type: int32(v.Type), } } } return &proto.ResChampshipPreRank{ MyRank: int32(MyRank), MyScore: float32(MyScore), RankList: RL, } } // TODO 待优化 func (c *ChampshipMgr) GetRankMsg(Uid int) *proto.ResChampshipRank { ChampshipData := c.getData() ChampshipData.mu.RLock() defer ChampshipData.mu.RUnlock() GroupId := ChampshipData.GroupInfo[Uid] if GroupId == 0 { return &proto.ResChampshipRank{} } RankList, ok := ChampshipData.Rank[GroupId] if !ok { return &proto.ResChampshipRank{} } MyRank := 0 MyScore := 0.0 RL := make(map[int32]*proto.ResPlayerRank, 0) for k, v := range RankList { if v.Uid == Uid { MyRank = k + 1 MyScore = v.Score } if v.Type == RANK_PLAYER_ROBOT { Robot := ChampshipData.Robot[v.Uid] if Robot == nil { continue } RL[int32(k+1)] = &proto.ResPlayerRank{ Uid: int64(v.Uid), Score: float32(v.Score), Name: Robot.Name, Avatar: int32(Robot.Avatar), Face: int32(Robot.Face), Level: int32(Robot.Level), } } else { SimplePlayer := G_GameLogicPtr.GetResSimplePlayerByUid(v.Uid) if SimplePlayer == nil { continue } RL[int32(k+1)] = &proto.ResPlayerRank{ Uid: int64(v.Uid), Score: float32(v.Score), Name: SimplePlayer.Name, Avatar: int32(SimplePlayer.Avatar), Face: int32(SimplePlayer.Face), Level: int32(SimplePlayer.Level), } } } return &proto.ResChampshipRank{ MyRank: int32(MyRank), MyScore: float32(MyScore), RankList: RL, } } // 分组 func (c *ChampshipMgr) group(iszero bool) (interface{}, error) { Now := GoUtil.Now() Zero := GoUtil.ZeroTimestamp() if Now-Zero < 1800 && !iszero { // 0点30分钟内不分组 return nil, nil } c.mDispatr.AfterFunc(time.Duration(1800)*time.Second, func() { // 30分钟后重新分组 c.group(false) }) ChampshipData := c.getData() ChampshipData.mu.Lock() defer ChampshipData.mu.Unlock() log.Debug("ChampshipMgr group, player num:%d", len(ChampshipData.Pool)) if len(ChampshipData.Pool) == 0 { // 未分配玩家池为空 return nil, nil } g := make(map[int][]int, 0) for k, v := range ChampshipData.Pool { // step 1:根据数值分配玩家 x := 0 n := champshipCfg.GetGroupId(v.N) h := champshipCfg.GetGroupId(v.H) if n < h { x = min(max(n-1, h-2), 1) } else { x = n } _, ok := g[x] if !ok { g[x] = make([]int, 0) } g[x] = append(g[x], k) } for i := 11; i > 0; i-- { if len(g[i]) == 0 { continue } // 少于10个的元素合并到下一组 if len(g[i]) < 10 && i > 1 { g[i-1] = append(g[i-1], g[i]...) continue } // 不被10整除的元素分到下一组 if len(g[i])%10 != 0 && i > 1 { remainder := len(g[i]) % 10 g[i-1] = append(g[i-1], g[i][len(g[i])-remainder:]...) g[i] = g[i][:len(g[i])-remainder] } ChampshipData.AutoId++ StartId := ChampshipData.AutoId for j := 0; j < len(g[i]); j++ { ChampshipData.GroupInfo[g[i][j]] = ChampshipData.AutoId UserData := ChampshipData.Pool[g[i][j]] ChampshipData.Rank[ChampshipData.AutoId] = append(ChampshipData.Rank[ChampshipData.AutoId], &ChampshipRank{ Uid: UserData.Uid, Score: UserData.Score, Time: UserData.Time, }) if len(ChampshipData.Rank[ChampshipData.AutoId]) == 10 { ChampshipData.AutoId++ } } for j := StartId; j <= ChampshipData.AutoId; j++ { // 填充机器人 RobotNum := 30 - len(ChampshipData.Rank[j]) RobotList := CreateRobotList(i, RobotNum, j) for _, v := range RobotList { ChampshipData.Robot[ChampshipData.RobotId] = v ChampshipData.Rank[j] = append(ChampshipData.Rank[j], &ChampshipRank{ Uid: ChampshipData.RobotId, Score: v.Score, Time: v.Time, Type: RANK_PLAYER_ROBOT, }) ChampshipData.RobotId++ } sort.Slice(ChampshipData.Rank[j], func(x, y int) bool { // 排序 从大到小 数值相等按时间排序 if ChampshipData.Rank[j][x].Score > ChampshipData.Rank[j][y].Score { return true } else if ChampshipData.Rank[j][x].Score == ChampshipData.Rank[j][y].Score { return ChampshipData.Rank[j][x].Time < ChampshipData.Rank[j][y].Time } return false }) } } // 收集需要通知的玩家 notifyList := make([]int, 0, len(ChampshipData.Pool)) for k := range ChampshipData.Pool { c.SetRankCache(k) // SetRankCache 使用 unsafe 方法,在持有锁时是安全的 notifyList = append(notifyList, k) } c.getData().Pool = make(map[int]*GroupInfo) // 清空未分配池 // 在锁外通知玩家,避免在持有锁时调用外部函数 for _, uid := range notifyList { go NotifyPlayer(uid, &msg.Msg{ Type: msg.HANDLE_TYPE_CHAMPSHIP_NOTIFY, End: GoUtil.Now() + onehour, }) } return nil, nil } // 获取分组ID func (c *ChampshipMgr) getGroupId(Uid int) int { ChampshipData := c.getData() ChampshipData.mu.RLock() defer ChampshipData.mu.RUnlock() GroupId, ok := ChampshipData.GroupInfo[Uid] if ok { return GroupId } return 0 } // 进去榜单 func (c *ChampshipMgr) inRank(m *msg.Msg) (interface{}, error) { data := m.Extra.(CRank) // 在加锁前获取 GroupId,避免在持有写锁时调用会获取读锁的 getGroupId 导致死锁 GroupId := c.getGroupId(data.Uid) ChampshipData := c.getData() ChampshipData.mu.Lock() defer ChampshipData.mu.Unlock() // 再次检查 GroupId,因为可能在等待锁期间被其他协程修改 if currentGroupId, ok := ChampshipData.GroupInfo[data.Uid]; ok { GroupId = currentGroupId } if GroupId == 0 { ChampshipData.Pool[data.Uid] = &GroupInfo{ Uid: data.Uid, Score: data.Score, Time: GoUtil.Now(), N: data.N, H: data.H, } return nil, nil } RankList, ok := ChampshipData.Rank[GroupId] if !ok { ChampshipData.Rank[GroupId] = make([]*ChampshipRank, 0) } inRank := false Notify := make(map[int]int) for k, v := range RankList { if v.Uid == data.Uid { if v.Score < data.Score { v.Score = data.Score v.Time = GoUtil.Now() inRank = true break } return nil, nil } Notify[v.Uid] = k } if !inRank { RankList = append(RankList, &ChampshipRank{ Uid: data.Uid, Score: data.Score, Time: GoUtil.Now(), }) } sort.Slice(RankList, func(i, j int) bool { // 排序 从大到小 数值相等按时间排序 if RankList[i].Score > RankList[j].Score { return true } else if RankList[i].Score == RankList[j].Score { return RankList[i].Time < RankList[j].Time } return false }) ChampshipData.Rank[GroupId] = RankList // 收集需要通知的玩家 notifyList := make([]int, 0) for k, v := range RankList { if Notify[v.Uid] != k && v.Type != RANK_PLAYER_ROBOT { c.SetRankCache(v.Uid) notifyList = append(notifyList, v.Uid) } } // 在锁外通知玩家 for _, uid := range notifyList { go NotifyPlayer(uid, &msg.Msg{ Type: msg.HANDLE_TYPE_CHAMPSHIP_NOTIFY, End: GoUtil.Now() + onehour, }) } return nil, nil } func (c *ChampshipMgr) getMyRank(Uid int) int { ChampshipData := c.getData() ChampshipData.mu.RLock() defer ChampshipData.mu.RUnlock() GroupId := ChampshipData.GroupInfo[Uid] if GroupId == 0 { return 0 } RankList, ok := ChampshipData.Rank[GroupId] if !ok { return 0 } for k, v := range RankList { if v.Uid == Uid { return k + 1 } } return 0 } func (c *ChampshipMgr) unsafe_getMyRank(Uid int) int { ChampshipData := c.getData() GroupId := ChampshipData.GroupInfo[Uid] if GroupId == 0 { return 0 } RankList, ok := ChampshipData.Rank[GroupId] if !ok { return 0 } for k, v := range RankList { if v.Uid == Uid { return k + 1 } } return 0 } func (c *ChampshipMgr) getLastMyRank(Uid int) int { ChampshipData := c.getData() ChampshipData.mu.RLock() defer ChampshipData.mu.RUnlock() GroupId := ChampshipData.PreGroupInfo[Uid] if GroupId == 0 { return 0 } RankList, ok := ChampshipData.PreRank[GroupId] if !ok { return 0 } for k, v := range RankList { if v.Uid == Uid { return k + 1 } } return 0 } func (c *ChampshipMgr) unsafe_getLastMyRank(Uid int) int { ChampshipData := c.getData() GroupId := ChampshipData.PreGroupInfo[Uid] if GroupId == 0 { return 0 } RankList, ok := ChampshipData.PreRank[GroupId] if !ok { return 0 } for k, v := range RankList { if v.Uid == Uid { return k + 1 } } return 0 } func (c *ChampshipMgr) getData() *ChampshipData { return c.data.(*ChampshipData) } func CreateRobotList(G, Num, GroupId int) []*ChampshipRobot { r := make([]*ChampshipRobot, 0) switch G { case 1: r = append(r, CreateRobot(float64(GoUtil.RandNum(12181, 21680)), GroupId)) r = append(r, CreateRobot(float64(GoUtil.RandNum(7531, 12180)), GroupId)) r = append(r, CreateRobot(float64(GoUtil.RandNum(4631, 7530)), GroupId)) r = append(r, CreateRobot(float64(GoUtil.RandNum(2781, 4630)), GroupId)) for i := 0; i < 6; i++ { r = append(r, CreateRobot(float64(GoUtil.RandNum(1731, 2780)), GroupId)) } for i := 0; i < 5; i++ { r = append(r, CreateRobot(float64(GoUtil.RandNum(241, 580)), GroupId)) } Last := Num - len(r) for i := 0; i < Last; i++ { r = append(r, CreateRobot(float64(GoUtil.RandNum(20, 240)), GroupId)) } case 2: r = append(r, CreateRobot(float64(GoUtil.RandNum(12181, 21680)), GroupId)) r = append(r, CreateRobot(float64(GoUtil.RandNum(7531, 12180)), GroupId)) r = append(r, CreateRobot(float64(GoUtil.RandNum(4631, 7530)), GroupId)) r = append(r, CreateRobot(float64(GoUtil.RandNum(2781, 4630)), GroupId)) for i := 0; i < 6; i++ { r = append(r, CreateRobot(float64(GoUtil.RandNum(1731, 2780)), GroupId)) } n := Num - 10 for i := 0; i < int(float64(n)*0.1); i++ { r = append(r, CreateRobot(float64(GoUtil.RandNum(241, 580)), GroupId)) } Last := Num - len(r) for i := 0; i < Last; i++ { r = append(r, CreateRobot(float64(GoUtil.RandNum(20, 240)), GroupId)) } case 3: r = append(r, CreateRobot(float64(GoUtil.RandNum(12181, 21680)), GroupId)) r = append(r, CreateRobot(float64(GoUtil.RandNum(7531, 12180)), GroupId)) r = append(r, CreateRobot(float64(GoUtil.RandNum(4631, 7530)), GroupId)) r = append(r, CreateRobot(float64(GoUtil.RandNum(2781, 4630)), GroupId)) for i := 0; i < 6; i++ { r = append(r, CreateRobot(float64(GoUtil.RandNum(1731, 2780)), GroupId)) } n := Num - 10 for i := 0; i < int(float64(n)*0.05); i++ { r = append(r, CreateRobot(float64(GoUtil.RandNum(581, 1730)), GroupId)) } for i := 0; i < int(float64(n)*0.15); i++ { r = append(r, CreateRobot(float64(GoUtil.RandNum(241, 580)), GroupId)) } Last := Num - len(r) for i := 0; i < Last; i++ { r = append(r, CreateRobot(float64(GoUtil.RandNum(20, 240)), GroupId)) } case 4: r = append(r, CreateRobot(float64(GoUtil.RandNum(12181, 21680)), GroupId)) r = append(r, CreateRobot(float64(GoUtil.RandNum(7531, 12180)), GroupId)) r = append(r, CreateRobot(float64(GoUtil.RandNum(4631, 7530)), GroupId)) r = append(r, CreateRobot(float64(GoUtil.RandNum(2781, 4630)), GroupId)) n := Num - 4 for i := 0; i < int(float64(n)*0.35); i++ { r = append(r, CreateRobot(float64(GoUtil.RandNum(1731, 2780)), GroupId)) } for i := 0; i < int(float64(n)*0.1); i++ { r = append(r, CreateRobot(float64(GoUtil.RandNum(581, 1730)), GroupId)) } for i := 0; i < int(float64(n)*0.1); i++ { r = append(r, CreateRobot(float64(GoUtil.RandNum(241, 580)), GroupId)) } Last := Num - len(r) for i := 0; i < Last; i++ { r = append(r, CreateRobot(float64(GoUtil.RandNum(20, 240)), GroupId)) } case 5: r = append(r, CreateRobot(float64(GoUtil.RandNum(12181, 21680)), GroupId)) r = append(r, CreateRobot(float64(GoUtil.RandNum(7531, 12180)), GroupId)) r = append(r, CreateRobot(float64(GoUtil.RandNum(4631, 7530)), GroupId)) n := Num - 3 for i := 0; i < int(float64(n)*0.05); i++ { r = append(r, CreateRobot(float64(GoUtil.RandNum(2781, 4630)), GroupId)) } for i := 0; i < int(float64(n)*0.3); i++ { r = append(r, CreateRobot(float64(GoUtil.RandNum(1731, 2780)), GroupId)) } for i := 0; i < int(float64(n)*0.1); i++ { r = append(r, CreateRobot(float64(GoUtil.RandNum(581, 1730)), GroupId)) } for i := 0; i < int(float64(n)*0.2); i++ { r = append(r, CreateRobot(float64(GoUtil.RandNum(241, 580)), GroupId)) } Last := Num - len(r) for i := 0; i < Last; i++ { r = append(r, CreateRobot(float64(GoUtil.RandNum(20, 240)), GroupId)) } case 6: r = append(r, CreateRobot(float64(GoUtil.RandNum(12181, 21680)), GroupId)) r = append(r, CreateRobot(float64(GoUtil.RandNum(7531, 12180)), GroupId)) n := Num - 2 for i := 0; i < int(float64(n)*0.05); i++ { r = append(r, CreateRobot(float64(GoUtil.RandNum(4631, 7530)), GroupId)) } for i := 0; i < int(float64(n)*0.05); i++ { r = append(r, CreateRobot(float64(GoUtil.RandNum(2781, 4630)), GroupId)) } for i := 0; i < int(float64(n)*0.3); i++ { r = append(r, CreateRobot(float64(GoUtil.RandNum(1731, 2780)), GroupId)) } for i := 0; i < int(float64(n)*0.1); i++ { r = append(r, CreateRobot(float64(GoUtil.RandNum(581, 1730)), GroupId)) } for i := 0; i < int(float64(n)*0.25); i++ { r = append(r, CreateRobot(float64(GoUtil.RandNum(241, 580)), GroupId)) } Last := Num - len(r) for i := 0; i < Last; i++ { r = append(r, CreateRobot(float64(GoUtil.RandNum(20, 240)), GroupId)) } case 7: r = append(r, CreateRobot(float64(GoUtil.RandNum(12181, 21680)), GroupId)) n := Num - 1 for i := 0; i < int(float64(n)*0.05); i++ { r = append(r, CreateRobot(float64(GoUtil.RandNum(7531, 12180)), GroupId)) } for i := 0; i < int(float64(n)*0.05); i++ { r = append(r, CreateRobot(float64(GoUtil.RandNum(4631, 7530)), GroupId)) } for i := 0; i < int(float64(n)*0.1); i++ { r = append(r, CreateRobot(float64(GoUtil.RandNum(2781, 4630)), GroupId)) } for i := 0; i < int(float64(n)*0.3); i++ { r = append(r, CreateRobot(float64(GoUtil.RandNum(1731, 2780)), GroupId)) } for i := 0; i < int(float64(n)*0.1); i++ { r = append(r, CreateRobot(float64(GoUtil.RandNum(581, 1730)), GroupId)) } for i := 0; i < int(float64(n)*0.2); i++ { r = append(r, CreateRobot(float64(GoUtil.RandNum(241, 580)), GroupId)) } Last := Num - len(r) for i := 0; i < Last; i++ { r = append(r, CreateRobot(float64(GoUtil.RandNum(20, 240)), GroupId)) } case 8, 9, 10, 11: M10 := GoUtil.RandMap(map[int]int{0: 98, 1: 2}) if M10 == 1 { r = append(r, CreateRobot(float64(GoUtil.RandNum(35131, 64980)), GroupId)) } n := Num for i := 0; i < int(float64(n)*0.05); i++ { r = append(r, CreateRobot(float64(GoUtil.RandNum(12181, 21680)), GroupId)) } for i := 0; i < int(float64(n)*0.05); i++ { r = append(r, CreateRobot(float64(GoUtil.RandNum(7531, 12180)), GroupId)) } for i := 0; i < int(float64(n)*0.05); i++ { r = append(r, CreateRobot(float64(GoUtil.RandNum(4631, 7530)), GroupId)) } for i := 0; i < int(float64(n)*0.1); i++ { r = append(r, CreateRobot(float64(GoUtil.RandNum(2781, 4630)), GroupId)) } for i := 0; i < int(float64(n)*0.3); i++ { r = append(r, CreateRobot(float64(GoUtil.RandNum(1731, 2780)), GroupId)) } for i := 0; i < int(float64(n)*0.15); i++ { r = append(r, CreateRobot(float64(GoUtil.RandNum(581, 1730)), GroupId)) } for i := 0; i < int(float64(n)*0.2); i++ { r = append(r, CreateRobot(float64(GoUtil.RandNum(241, 580)), GroupId)) } Last := Num - len(r) for i := 0; i < Last; i++ { r = append(r, CreateRobot(float64(GoUtil.RandNum(20, 240)), GroupId)) } } return r } func CreateRobot(M float64, GroupId int) *ChampshipRobot { Type := GoUtil.RandMap(map[int]int{1: 25, 2: 50, 3: 25}) Score := M / 10 PerScore := 0.0 if Type == 2 { PerScore = math.Round((M/10*0.34)/(float64(GoUtil.NextZeroTimestampDuration())/60)*100) / 100 Score = M / 10 * 0.66 } if Type == 3 { PerScore = math.Round((M/10*0.34)/(float64(GoUtil.NextZeroTimestampDuration())/1800)*100) / 100 Score = 2 } return &ChampshipRobot{ Max: M / 10, Type: Type, Name: randnameCfg.GetRandName(), Avatar: GoUtil.RandNum(1, 10), Face: GoUtil.RandNum(1, 10), Level: GoUtil.RandNum(1, 10), GroupId: GroupId, Time: GoUtil.Now(), Score: Score, PerScore: PerScore, } } func (c *ChampshipMgr) SetRankCache(Uid int) { PreRank := c.unsafe_getLastMyRank(Uid) Rank := c.unsafe_getMyRank(Uid) PreGroupId := c.getData().PreGroupInfo[Uid] GroupId := c.getData().GroupInfo[Uid] key := fmt.Sprintf("champship_rank_cache_%d", Uid) log.Debug("SetRankCache key:%s; data:%s", key, fmt.Sprintf("%d_%d_%d_%d", PreRank, Rank, PreGroupId, GroupId)) db.RedisSetKey(key, fmt.Sprintf("%d_%d_%d_%d", PreRank, Rank, PreGroupId, GroupId), time.Second*172800) } func GetRankCache(Uid int) (int, int, int, int) { key := fmt.Sprintf("champship_rank_cache_%d", Uid) data, err := db.RedisGetKey(key) if err != nil || data == "" { return 0, 0, 0, 0 } var PreRank, Rank, PreGroupId, GroupId int fmt.Sscanf(data, "%d_%d_%d_%d", &PreRank, &Rank, &PreGroupId, &GroupId) return PreRank, Rank, PreGroupId, GroupId }