1016 lines
28 KiB
Go
1016 lines
28 KiB
Go
package game
|
||
|
||
import (
|
||
"fmt"
|
||
"maps"
|
||
"math"
|
||
|
||
avatarCfg "server/conf/avatar"
|
||
champshipCfg "server/conf/champship"
|
||
faceCfg "server/conf/face"
|
||
randnameCfg "server/conf/randname"
|
||
"server/db"
|
||
"server/game/mod/friend"
|
||
"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
|
||
Playroom map[int]int
|
||
DressSet map[int]int
|
||
FurSet int
|
||
ActLog *friend.ActLogInfo
|
||
PetName string
|
||
}
|
||
|
||
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()
|
||
} else {
|
||
c.mDispatr.AfterFunc(time.Duration(GoUtil.NextZeroTimestampDuration())*time.Second, func() {
|
||
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()
|
||
})
|
||
}
|
||
|
||
// 每天零点30分通知所有在线玩家领取奖励
|
||
func (c *ChampshipMgr) ZeroNotifyAll() (interface{}, error) {
|
||
NotifyAllPlayerMsg(&msg.Msg{
|
||
Type: msg.HANDLE_TYPE_CHAMPSHIP_NOTIFY,
|
||
HandleType: msg.HANDLE_MOD_PLAYER_MSG,
|
||
End: GoUtil.Now() + onehour,
|
||
})
|
||
c.mDispatr.AfterFunc(time.Duration(GoUtil.NextZeroTimestampDuration()+1800)*time.Second, func() {
|
||
c.ZeroNotifyAll()
|
||
})
|
||
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))
|
||
maps.Copy(oldRank, data.Rank)
|
||
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()
|
||
timeDuration := GoUtil.NextZeroTimestampDuration()
|
||
if timeDuration <= 0 {
|
||
log.Error("championship zero update error")
|
||
timeDuration = 24 * 3600
|
||
}
|
||
c.mDispatr.AfterFunc(time.Duration(timeDuration)*time.Second, func() {
|
||
c.ZeroUpdate()
|
||
})
|
||
c.mDispatr.AfterFunc(time.Duration(timeDuration+1800)*time.Second, func() {
|
||
c.ZeroNotifyAll()
|
||
})
|
||
// 在锁外通知玩家,避免在持有锁时调用外部函数
|
||
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
|
||
}
|
||
// 在锁外通知玩家,避免在持锁时启动 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
|
||
}
|
||
last := &proto.ActLog{}
|
||
if robot.ActLog != nil {
|
||
last = &proto.ActLog{
|
||
Type: int32(robot.ActLog.Type),
|
||
Time: robot.ActLog.Time,
|
||
Param: robot.ActLog.Param,
|
||
}
|
||
}
|
||
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),
|
||
Type: int32(v.Type),
|
||
PlayroomSet: GoUtil.MapIntToInt32(robot.Playroom),
|
||
DressSet: GoUtil.MapIntToInt32(robot.DressSet),
|
||
FurSet: int32(robot.FurSet),
|
||
PetName: robot.PetName,
|
||
Last: last,
|
||
}
|
||
} else {
|
||
simplePlayer := G_GameLogicPtr.GetSimplePlayerByUid(v.Uid)
|
||
if simplePlayer == nil {
|
||
continue
|
||
}
|
||
last := &proto.ActLog{}
|
||
if simplePlayer.ActLog != nil {
|
||
last = &proto.ActLog{
|
||
Type: int32(simplePlayer.ActLog.Type),
|
||
Time: simplePlayer.ActLog.Time,
|
||
Param: simplePlayer.ActLog.Param,
|
||
}
|
||
}
|
||
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),
|
||
PlayroomSet: GoUtil.MapIntToInt32(simplePlayer.Playroom),
|
||
DressSet: GoUtil.MapIntToInt32(simplePlayer.DressSet),
|
||
FurSet: int32(simplePlayer.PetFur),
|
||
PetName: simplePlayer.PetName,
|
||
Last: last,
|
||
}
|
||
}
|
||
}
|
||
|
||
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
|
||
}
|
||
last := &proto.ActLog{}
|
||
if robot.ActLog != nil {
|
||
last = &proto.ActLog{
|
||
Type: int32(robot.ActLog.Type),
|
||
Time: robot.ActLog.Time,
|
||
Param: robot.ActLog.Param,
|
||
}
|
||
}
|
||
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),
|
||
Type: int32(v.Type),
|
||
PlayroomSet: GoUtil.MapIntToInt32(robot.Playroom),
|
||
DressSet: GoUtil.MapIntToInt32(robot.DressSet),
|
||
FurSet: int32(robot.FurSet),
|
||
PetName: robot.PetName,
|
||
Last: last,
|
||
}
|
||
} else {
|
||
simplePlayer := G_GameLogicPtr.GetSimplePlayerByUid(v.Uid)
|
||
if simplePlayer == nil {
|
||
continue
|
||
}
|
||
last := &proto.ActLog{}
|
||
if simplePlayer.ActLog != nil {
|
||
last = &proto.ActLog{
|
||
Type: int32(simplePlayer.ActLog.Type),
|
||
Time: simplePlayer.ActLog.Time,
|
||
Param: simplePlayer.ActLog.Param,
|
||
}
|
||
}
|
||
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),
|
||
PlayroomSet: GoUtil.MapIntToInt32(simplePlayer.Playroom),
|
||
DressSet: GoUtil.MapIntToInt32(simplePlayer.DressSet),
|
||
FurSet: int32(simplePlayer.PetFur),
|
||
PetName: simplePlayer.PetName,
|
||
Last: last,
|
||
}
|
||
}
|
||
}
|
||
|
||
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
|
||
}
|
||
total, err := db.RedisZCard(RANK_USER)
|
||
if err != nil {
|
||
total = 10000
|
||
}
|
||
total = min(total, 10000)
|
||
g := make(map[int][]int, 0)
|
||
list, err := db.RedisZRevRangeWithScores(RANK_USER, 0, total)
|
||
if err != nil {
|
||
log.Debug("redis zrevrange failed, err:%v\n", err)
|
||
}
|
||
uids := make([]int, 0, len(list))
|
||
for _, v := range list {
|
||
uids = append(uids, GoUtil.Int(v.Member))
|
||
}
|
||
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
|
||
}
|
||
x = max(x, 1)
|
||
_, 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++ {
|
||
if len(ChampshipData.Rank[ChampshipData.AutoId]) >= 10 {
|
||
log.Error("championship error: more than 10 players in a group")
|
||
}
|
||
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,
|
||
})
|
||
//log.Debug("group AutoId:%d, Uid:%d, Score:%.2f, Time:%d", ChampshipData.AutoId, userData.Uid, userData.Score, userData.Time)
|
||
if len(ChampshipData.Rank[ChampshipData.AutoId]) >= 10 && j != len(g[i])-1 {
|
||
ChampshipData.AutoId++
|
||
}
|
||
}
|
||
for j := startId; j <= ChampshipData.AutoId; j++ { // 填充机器人
|
||
if len(ChampshipData.Rank[j]) >= 30 || len(ChampshipData.Rank[j]) == 0 {
|
||
log.Error("championship error: more than 30 players in a group or no player in a group")
|
||
continue
|
||
}
|
||
robotNum := 30 - len(ChampshipData.Rank[j])
|
||
//log.Debug("group AutoId:%d, player num:%d, need robot num:%d", j, len(ChampshipData.Rank[j]), robotNum)
|
||
robotList := CreateRobotList(i, robotNum, j)
|
||
for i := 0; i < robotNum; i++ {
|
||
go FormatRobotInfo(robotList[i], i+1, uids)
|
||
}
|
||
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
|
||
}
|
||
return false
|
||
})
|
||
}
|
||
}
|
||
|
||
// 收集需要通知的玩家
|
||
notifyList := make([]int, 0, len(ChampshipData.Pool))
|
||
for k := range ChampshipData.Pool {
|
||
go 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 {
|
||
rType := GoUtil.RandMap(map[int]int{1: 25, 2: 50, 3: 25})
|
||
score := M / 10
|
||
perScore := 0.0
|
||
if rType == 2 {
|
||
perScore = math.Round((M/10*0.34)/(float64(GoUtil.NextZeroTimestampDuration())/60)*100) / 100
|
||
score = M / 10 * 0.66
|
||
}
|
||
if rType == 3 {
|
||
perScore = math.Round((M/10*0.34)/(float64(GoUtil.NextZeroTimestampDuration())/1800)*100) / 100
|
||
score = 2
|
||
}
|
||
return &ChampshipRobot{
|
||
Max: M / 10,
|
||
Type: rType,
|
||
Name: randnameCfg.GetRandName(),
|
||
PetName: randnameCfg.GetRandName(),
|
||
Avatar: avatarCfg.GetRandInitId(),
|
||
Face: faceCfg.GetRandInitId(),
|
||
Level: GoUtil.RandNum(1, 10),
|
||
GroupId: groupId,
|
||
Time: GoUtil.Now(),
|
||
Score: score,
|
||
PerScore: perScore,
|
||
}
|
||
}
|
||
|
||
func FormatRobotInfo(robot *ChampshipRobot, index int, uids []int) {
|
||
x := int(len(uids)) / 30
|
||
if index > int(x) {
|
||
index = int(x)
|
||
}
|
||
start := max(int64((index-1)*x), 0)
|
||
end := max(int64(index*x-1), 0)
|
||
rindex := GoUtil.RandNum(int(start), int(end))
|
||
if rindex >= len(uids) {
|
||
rindex = len(uids) - 1
|
||
}
|
||
uid := uids[rindex]
|
||
playerSimpleData := G_GameLogicPtr.GetSimplePlayerByUid(uid)
|
||
if playerSimpleData == nil {
|
||
return
|
||
}
|
||
robot.Level = playerSimpleData.Level
|
||
robot.Avatar = playerSimpleData.Avatar
|
||
robot.Face = playerSimpleData.Face
|
||
robot.Playroom = playerSimpleData.Playroom
|
||
robot.DressSet = playerSimpleData.DressSet
|
||
robot.FurSet = playerSimpleData.PetFur
|
||
robot.ActLog = playerSimpleData.ActLog
|
||
robot.PetName = playerSimpleData.PetName
|
||
}
|
||
|
||
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 (c *ChampshipMgr) Debug() {
|
||
ChampshipData := c.getData()
|
||
ChampshipData.Pool = make(map[int]*GroupInfo)
|
||
ChampshipData.Rank = make(map[int][]*ChampshipRank)
|
||
for i := 1; i <= 1000; i++ {
|
||
ChampshipData.Pool[i+10000] = &GroupInfo{
|
||
Uid: i + 10000,
|
||
Score: float64(GoUtil.RandNum(20, 21680)),
|
||
Time: GoUtil.Now(),
|
||
N: GoUtil.RandNum(1, 99),
|
||
H: GoUtil.RandNum(1, 99),
|
||
}
|
||
}
|
||
c.group(true)
|
||
var i int
|
||
for _, v := range ChampshipData.Rank {
|
||
for _, v1 := range v {
|
||
if v1.Type == 0 {
|
||
i++
|
||
}
|
||
}
|
||
}
|
||
log.Debug("Debug player num:%d", i)
|
||
}
|
||
|
||
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
|
||
}
|