锦标赛优化

This commit is contained in:
hahwu 2026-02-04 15:00:04 +08:00
parent 00809c8484
commit 5da2f68a0c
3 changed files with 163 additions and 34 deletions

View File

@ -1,9 +1,11 @@
package game package game
import ( import (
"fmt"
"math" "math"
champshipCfg "server/conf/champship" champshipCfg "server/conf/champship"
randnameCfg "server/conf/randname" randnameCfg "server/conf/randname"
"server/db"
"server/game/mod/msg" "server/game/mod/msg"
GoUtil "server/game_util" GoUtil "server/game_util"
proto "server/msg" proto "server/msg"
@ -116,37 +118,72 @@ func (c *ChampshipMgr) ZeroUpdate() (interface{}, error) {
log.Debug("ChampshipMgr ZeroUpdate") log.Debug("ChampshipMgr ZeroUpdate")
data := c.getData() data := c.getData()
data.mu.Lock() data.mu.Lock()
defer data.mu.Unlock()
data.ZeroTime = GoUtil.ZeroTimestamp() data.ZeroTime = GoUtil.ZeroTimestamp()
data.PreRank = data.Rank // 深拷贝 map避免多个协程持有同一个 map 引用导致并发读写
data.PreRobot = data.Robot oldRank := make(map[int][]*ChampshipRank, len(data.Rank))
data.PreGroupInfo = data.GroupInfo 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.AutoId = 0
data.RobotId = 1 data.RobotId = 1
data.Robot = make(map[int]*ChampshipRobot, 0) data.Robot = make(map[int]*ChampshipRobot, 0)
data.Rank = make(map[int][]*ChampshipRank, 0) data.Rank = make(map[int][]*ChampshipRank, 0)
data.GroupInfo = make(map[int]int, 0) data.GroupInfo = make(map[int]int, 0)
c.update = true 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.mDispatr.AfterFunc(time.Duration(GoUtil.NextZeroTimestampDuration())*time.Second, func() {
c.ZeroUpdate() c.ZeroUpdate()
}) })
c.NotifyPlayer()
c.mDispatr.AfterFunc(time.Duration(1800)*time.Second, func() { c.mDispatr.AfterFunc(time.Duration(1800)*time.Second, func() {
c.NotifyAll() c.NotifyAll()
}) })
// 在锁外通知玩家,避免在持有锁时调用外部函数
go c.NotifyPlayer()
return nil, nil return nil, nil
} }
func (c *ChampshipMgr) NotifyPlayer() { func (c *ChampshipMgr) NotifyPlayer() {
List := c.getData().PreRank data := c.getData()
for _, v := range List { data.mu.RLock()
for i := 0; i < 3; i++ { // 深拷贝需要通知的数据,避免在锁外访问 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 { if v[i].Type == RANK_PLAYER_ROBOT {
continue continue
} }
NotifyChampshipResult(v[i].Uid, i+1) 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) { func (c *ChampshipMgr) ai() (interface{}, error) {
@ -154,6 +191,7 @@ func (c *ChampshipMgr) ai() (interface{}, error) {
ChampshipData.mu.Lock() ChampshipData.mu.Lock()
defer ChampshipData.mu.Unlock() defer ChampshipData.mu.Unlock()
Now := GoUtil.Now() Now := GoUtil.Now()
uids := make(map[int]struct{})
for k, v := range ChampshipData.Rank { for k, v := range ChampshipData.Rank {
Notify := make(map[int]int) Notify := make(map[int]int)
for e, r := range v { for e, r := range v {
@ -190,18 +228,26 @@ func (c *ChampshipMgr) ai() (interface{}, error) {
continue continue
} }
if Notify[r.Uid] != e { if Notify[r.Uid] != e {
NotifyPlayer(r.Uid, &msg.Msg{ c.SetRankCache(r.Uid)
Type: msg.HANDLE_TYPE_CHAMPSHIP_NOTIFY, uids[r.Uid] = struct{}{}
})
} }
} }
ChampshipData.Rank[k] = v ChampshipData.Rank[k] = v
} }
// 在锁外通知玩家,避免在持锁时启动 goroutine 访问可能被并发修改的数据
for uid := range uids {
go NotifyPlayer(uid, &msg.Msg{
Type: msg.HANDLE_TYPE_CHAMPSHIP_NOTIFY,
})
}
c.mDispatr.AfterFunc(time.Duration(60)*time.Second, func() { c.mDispatr.AfterFunc(time.Duration(60)*time.Second, func() {
c.ai() c.ai()
}) })
return nil, nil return nil, nil
} }
func (c *ChampshipMgr) GetPreRankMsg(Uid int) *proto.ResChampshipPreRank { func (c *ChampshipMgr) GetPreRankMsg(Uid int) *proto.ResChampshipPreRank {
ChampshipData := c.getData() ChampshipData := c.getData()
ChampshipData.mu.RLock() ChampshipData.mu.RLock()
@ -403,12 +449,20 @@ func (c *ChampshipMgr) group() (interface{}, error) {
} }
} }
for k := range ChampshipData.Pool { // 分组完成通知 // 收集需要通知的玩家
NotifyPlayer(k, &msg.Msg{ 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, Type: msg.HANDLE_TYPE_CHAMPSHIP_NOTIFY,
}) })
} }
c.getData().Pool = make(map[int]*GroupInfo) // 清空未分配池
return nil, nil return nil, nil
} }
@ -427,11 +481,19 @@ func (c *ChampshipMgr) getGroupId(Uid int) int {
// 进去榜单 // 进去榜单
func (c *ChampshipMgr) inRank(m *msg.Msg) (interface{}, error) { func (c *ChampshipMgr) inRank(m *msg.Msg) (interface{}, error) {
data := m.Extra.(CRank)
// 在加锁前获取 GroupId避免在持有写锁时调用会获取读锁的 getGroupId 导致死锁
GroupId := c.getGroupId(data.Uid)
ChampshipData := c.getData() ChampshipData := c.getData()
ChampshipData.mu.Lock() ChampshipData.mu.Lock()
defer ChampshipData.mu.Unlock() defer ChampshipData.mu.Unlock()
data := m.Extra.(CRank)
GroupId := c.getGroupId(data.Uid) // 再次检查 GroupId因为可能在等待锁期间被其他协程修改
if currentGroupId, ok := ChampshipData.GroupInfo[data.Uid]; ok {
GroupId = currentGroupId
}
if GroupId == 0 { if GroupId == 0 {
ChampshipData.Pool[data.Uid] = &GroupInfo{ ChampshipData.Pool[data.Uid] = &GroupInfo{
Uid: data.Uid, Uid: data.Uid,
@ -475,15 +537,23 @@ func (c *ChampshipMgr) inRank(m *msg.Msg) (interface{}, error) {
} }
return false return false
}) })
// 收集需要通知的玩家
notifyList := make([]int, 0)
for k, v := range RankList { for k, v := range RankList {
if Notify[v.Uid] != k { if Notify[v.Uid] != k {
NotifyPlayer(v.Uid, &msg.Msg{ c.SetRankCache(v.Uid)
Type: msg.HANDLE_TYPE_CHAMPSHIP_NOTIFY, notifyList = append(notifyList, v.Uid)
})
} }
} }
ChampshipData.Rank[GroupId] = RankList ChampshipData.Rank[GroupId] = RankList
// 在锁外通知玩家
for _, uid := range notifyList {
go NotifyPlayer(uid, &msg.Msg{
Type: msg.HANDLE_TYPE_CHAMPSHIP_NOTIFY,
})
}
return nil, nil return nil, nil
} }
@ -507,7 +577,44 @@ func (c *ChampshipMgr) getMyRank(Uid int) int {
return 0 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 { 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() ChampshipData := c.getData()
GroupId := ChampshipData.PreGroupInfo[Uid] GroupId := ChampshipData.PreGroupInfo[Uid]
if GroupId == 0 { if GroupId == 0 {
@ -736,3 +843,23 @@ func CreateRobot(M float64, GroupId int) *ChampshipRobot {
PerScore: PerScore, 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)
db.RedisSetKey(key, fmt.Sprintf("%d_%d_%d_%d", PreRank, Rank, PreGroupId, GroupId), 86400*2)
}
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
}

View File

@ -5,7 +5,6 @@ import (
playroomCfg "server/conf/playroom" playroomCfg "server/conf/playroom"
"server/game/mod/item" "server/game/mod/item"
limitedTimeEvent "server/game/mod/limited_time_event" limitedTimeEvent "server/game/mod/limited_time_event"
"server/game/mod/msg"
GoUtil "server/game_util" GoUtil "server/game_util"
proto "server/msg" proto "server/msg"
) )
@ -295,22 +294,14 @@ func (p *Player) ChargeBackData() {
func (p *Player) BackChampship() { func (p *Player) BackChampship() {
ChampshipMod := p.PlayMod.getChampshipMod() ChampshipMod := p.PlayMod.getChampshipMod()
MyRank, MyPreRank := p.GetChampshipRank() rank, preRank := p.GetChampshipRank()
p.PushClientRes(ChampshipMod.BackData(MyRank, MyPreRank)) p.PushClientRes(ChampshipMod.BackData(preRank, rank))
} }
// 获取冠军赛排名 redis缓存
func (p *Player) GetChampshipRank() (int, int) { func (p *Player) GetChampshipRank() (int, int) {
MyRank := 0 preRank, rank, _, _ := GetRankCache(int(p.M_DwUin))
MyPreRank := 0 return rank, preRank
res, _ := SendMsgToCenterSync(&msg.Msg{
From: int(p.M_DwUin),
HandleType: msg.HANDLE_MOD_CHAMPSHIP_RANK_INFO,
})
if res != nil {
MyRank = res.Extra.([]int)[0]
MyPreRank = res.Extra.([]int)[1]
}
return MyRank, MyPreRank
} }
// 返回好友信息 // 返回好友信息

View File

@ -95,3 +95,14 @@ func DiffMap(a, b map[int]int) map[int]int {
} }
return diff return diff
} }
func GetMapIntValueByKey(m interface{}, key string) int {
mi, ok := m.(map[string]interface{})
if !ok {
return 0
}
if v, ok := mi[key]; ok {
return Int(v)
}
return 0
}