game_sync/worldsrv/playermgr.go

1143 lines
29 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package main
import (
"math/rand"
"time"
"mongo.games.com/goserver/core/basic"
"mongo.games.com/goserver/core/logger"
"mongo.games.com/goserver/core/netlib"
"mongo.games.com/goserver/core/task"
"mongo.games.com/goserver/core/utils"
"mongo.games.com/goserver/srvlib"
srvproto "mongo.games.com/goserver/srvlib/protocol"
"mongo.games.com/game/common"
"mongo.games.com/game/model"
"mongo.games.com/game/proto"
playerproto "mongo.games.com/game/protocol/player"
serverproto "mongo.games.com/game/protocol/server"
"mongo.games.com/game/worldsrv/internal"
)
var PlayerMgrSington = &PlayerMgr{
sidMap: make(map[int64]*Player),
snidMap: make(map[int32]*Player),
accountMap: make(map[string]*Player),
tokenMap: make(map[string]*Player),
players: make([]*Player, 0, 1024),
playerOfPlatform: make(map[string]map[int32]*Player),
loading: make(map[string]*PlayerPendingData),
}
type PlayerPendingData struct {
sid int64 // 连接标识
ts int64 // 加载数据的开始时间
}
type PlayerMgr struct {
BaseClockSinker
sidMap map[int64]*Player // sid
snidMap map[int32]*Player // snid
accountMap map[string]*Player // accountid
tokenMap map[string]*Player // 客服token
players []*Player // 只有真实玩家
playerOfPlatform map[string]map[int32]*Player // platform:snid;只有真实玩家
loading map[string]*PlayerPendingData // accountid,控制访问频率
}
// PlayerStatics 在线统计
type PlayerStatics struct {
PlayerCnt int // 真人数量
RobotCnt int // 机器人数量
PlayerGamingCnt int // 游戏中的真人数量
RobotGamingCnt int // 游戏中的机器人数量
GamingCnt map[int]int // gameid:玩家人数(包含机器人)
}
// GetOnlineCount 在线人数统计
func (this *PlayerMgr) GetOnlineCount() *PlayerStatics {
ps := &PlayerStatics{
GamingCnt: make(map[int]int),
}
for _, player := range this.sidMap {
if player != nil && player.IsOnLine() {
if !player.IsRob {
ps.PlayerCnt++
if player.scene != nil {
ps.PlayerGamingCnt++
}
} else {
ps.RobotCnt++
if player.scene != nil {
ps.RobotGamingCnt++
}
}
if player.scene != nil {
ps.GamingCnt[player.scene.gameId] = ps.GamingCnt[player.scene.gameId] + 1
}
}
}
return ps
}
// IsOnline 判断玩家是否在线
func (this *PlayerMgr) IsOnline(snId int32) bool {
player, ok := this.snidMap[snId]
if ok {
return player.IsOnLine()
} else {
return false
}
}
// AddPlayer 缓存玩家数据,并添加到持久化管理器中
func (this *PlayerMgr) AddPlayer(sid int64, playerInfo *model.PlayerData, s *netlib.Session) bool {
player := NewPlayer(sid, playerInfo, s)
if player == nil {
return false
}
if sid == 0 {
logger.Logger.Warnf("(this *PlayerMgr) AddPlayer player sid == 0:")
return false
}
logger.Logger.Trace("(this *PlayerMgr) AddPlayer Set player ip:", player.Ip)
this.sidMap[sid] = player
var oldp *Player
if p, exist := this.snidMap[player.SnId]; exist {
oldp = p
}
this.snidMap[player.SnId] = player
this.accountMap[player.AccountId] = player
if player.customerToken != "" {
this.tokenMap[player.customerToken] = player
}
if !player.IsRob {
var found bool
for i, p := range this.players {
if p.SnId == player.SnId {
found = true
logger.Logger.Warnf("(this *PlayerMgr) AddPlayer [this.players] found player exist snid=%v", player.SnId)
this.players[i] = player
break
}
}
if !found {
this.players = append(this.players, player)
}
if player.HeadUrl == "" {
player.HeadUrl = niceIdMgr.GetRobHeadUrl(player.Head)
}
//平台玩家管理器
if pp, exist := this.playerOfPlatform[player.Platform]; exist {
pp[player.SnId] = player
} else {
pp = make(map[int32]*Player)
pp[player.SnId] = player
this.playerOfPlatform[player.Platform] = pp
}
logger.Logger.Tracef("###%v mount to DBSaver[AddPlayer]", player.Name)
if oldp != nil { //删除旧的玩家
DbSaver_Inst.UnregisteDbSaveTask(oldp)
}
DbSaver_Inst.RegisterDbSaverTask(player)
niceIdMgr.NiceIdCheck(player.SnId)
} else {
player.NiceId = niceIdMgr.PopNiceId(player.SnId)
player.HeadUrl = niceIdMgr.GetRobHeadUrlIdx()
}
return true
}
// DelPlayer 清除玩家缓存数据
// 一般真人是数据持久化后删除或数据没有修改,机器人不用持久化(机器人数据没有主动删除)
func (this *PlayerMgr) DelPlayer(snid int32) bool {
player, ok := this.snidMap[snid]
if !ok || player == nil {
return false
}
if player.sid != 0 {
delete(this.sidMap, player.sid)
}
delete(this.snidMap, player.SnId)
delete(this.accountMap, player.AccountId)
if player.customerToken != "" {
delete(this.tokenMap, player.customerToken)
}
if player != nil && !player.IsRob {
index := -1
for i, p := range this.players {
if p.SnId == snid {
index = i
break
}
}
if index != -1 {
this.players = append(this.players[:index], this.players[index+1:]...)
}
//平台玩家管理器
if pp, exist := this.playerOfPlatform[player.Platform]; exist {
delete(pp, player.SnId)
}
niceIdMgr.PushNiceId(player.NiceId)
}
for _, v := range internal.GetPlayerLoads() {
v.Release(player.Platform, player.SnId)
}
player.OnLogouted()
return true
}
// DroplinePlayer 玩家掉线或登出
// 1.玩家登出
// 2.玩家网络断开
// 3.被踢掉线
func (this *PlayerMgr) DroplinePlayer(p *Player) {
delete(this.sidMap, p.sid)
}
// ReholdPlayer 玩家重连
// 1.登录获取玩家数据
func (this *PlayerMgr) ReholdPlayer(p *Player, newSid int64, newSess *netlib.Session) {
if p.sid != 0 {
delete(this.sidMap, p.sid)
}
if newSid == 0 {
logger.Logger.Errorf("(this *PlayerMgr) ReholdPlayer(snid=%v, new=%v)", p.SnId, newSid)
}
p.sid = newSid
p.gateSess = newSess
p.SetOnline()
this.sidMap[newSid] = p
}
// GetPlayer 获取玩家数据(玩家在线)
func (this *PlayerMgr) GetPlayer(id int64) *Player {
if pi, ok := this.sidMap[id]; ok {
return pi
}
return nil
}
func (this *PlayerMgr) GetPlayerBySnId(id int32) *Player {
if p, ok := this.snidMap[id]; ok {
return p
}
return nil
}
func (this *PlayerMgr) GetPlatformPlayerBySnId(platform string, id int32) *Player {
if players, exit := this.playerOfPlatform[platform]; exit {
if p, ok := players[id]; ok {
return p
}
}
return nil
}
// GetPlayersBySnIds 批量取出玩家信息
func (this *PlayerMgr) GetPlayersBySnIds(ids []int32) []*Player {
var retPlayers []*Player
for _, v := range ids {
if p, ok := this.snidMap[v]; ok {
retPlayers = append(retPlayers, p)
}
}
return retPlayers
}
func (this *PlayerMgr) GetPlayerByAccount(acc string) *Player {
if p, ok := this.accountMap[acc]; ok {
return p
}
return nil
}
func (this *PlayerMgr) GetPlayerByToken(token string) *Player {
if p, ok := this.tokenMap[token]; ok {
return p
}
return nil
}
func (this *PlayerMgr) UpdatePlayerToken(p *Player, newToken string) {
oldToken := p.customerToken
if oldToken != newToken {
if oldToken != "" {
if _, ok := this.tokenMap[oldToken]; ok {
delete(this.tokenMap, oldToken)
}
}
if newToken != "" {
this.tokenMap[newToken] = p
p.customerToken = newToken
}
}
}
// BroadcastMessage 给所有玩家发消息
func (this *PlayerMgr) BroadcastMessage(packetid int, rawpack interface{}) bool {
sc := &srvproto.BCSessionUnion{
Bccs: &srvproto.BCClientSession{},
}
pack, err := common.CreateBroadcastPacket(sc, packetid, rawpack)
if err == nil && pack != nil {
srvlib.ServerSessionMgrSington.Broadcast(int(srvproto.SrvlibPacketID_PACKET_SS_BROADCAST), pack, common.GetSelfAreaId(), srvlib.GateServerType)
return true
}
return false
}
// BroadcastMessageToPlatform 给某个平台所有玩家发消息
func (this *PlayerMgr) BroadcastMessageToPlatform(platform string, packetid int, rawpack interface{}) {
if platform == "" {
this.BroadcastMessage(packetid, rawpack)
} else {
players := this.playerOfPlatform[platform]
mgs := make(map[*netlib.Session][]*srvproto.MCSessionUnion)
for _, p := range players {
if p != nil && p.gateSess != nil && p.IsOnLine() /*&& p.Platform == platform*/ {
mgs[p.gateSess] = append(mgs[p.gateSess], &srvproto.MCSessionUnion{
Mccs: &srvproto.MCClientSession{
SId: proto.Int64(p.sid),
},
})
}
}
for gateSess, v := range mgs {
if gateSess != nil && len(v) != 0 {
pack, err := common.CreateMulticastPacket(packetid, rawpack, v...)
if err == nil {
proto.SetDefaults(pack)
gateSess.Send(int(srvproto.SrvlibPacketID_PACKET_SS_MULTICAST), pack)
}
}
}
}
}
func (this *PlayerMgr) BroadcastDataConfigToPlatform(platform string, tp int) {
packetId := int(playerproto.PlayerPacketID_PACKET_SCDataConfig)
pack := &playerproto.SCDataConfig{}
f, ok := DataConfigFuncMap[tp]
if ok {
d := f(platform, nil)
if d != nil {
pack.Cfg = append(pack.Cfg, d)
}
}
if len(pack.Cfg) > 0 {
this.BroadcastMessageToPlatform(platform, packetId, pack)
}
}
func (this *PlayerMgr) BroadcastMessageToPlatformByFunc(platform string, packetid int, rawpack interface{}, f func(p *Player) bool) {
if platform == "" {
this.BroadcastMessage(packetid, rawpack)
} else {
players := this.playerOfPlatform[platform]
mgs := make(map[*netlib.Session][]*srvproto.MCSessionUnion)
for _, p := range players {
if p != nil && p.gateSess != nil && p.IsOnLine() && f(p) {
mgs[p.gateSess] = append(mgs[p.gateSess], &srvproto.MCSessionUnion{
Mccs: &srvproto.MCClientSession{
SId: proto.Int64(p.sid),
},
})
}
}
for gateSess, v := range mgs {
if gateSess != nil && len(v) != 0 {
pack, err := common.CreateMulticastPacket(packetid, rawpack, v...)
if err == nil {
proto.SetDefaults(pack)
gateSess.Send(int(srvproto.SrvlibPacketID_PACKET_SS_MULTICAST), pack)
}
}
}
}
}
// BroadcastMessageToPlatformWithHall 给某个平台所有在大厅中的玩家发消息
func (this *PlayerMgr) BroadcastMessageToPlatformWithHall(platform string, snid int32, packetid int, rawpack interface{}) {
if platform == "" {
this.BroadcastMessage(packetid, rawpack)
} else {
player := this.GetPlayerBySnId(snid)
if player != nil {
players := this.playerOfPlatform[platform]
mgs := make(map[*netlib.Session][]*srvproto.MCSessionUnion)
for _, p := range players {
if p != nil && p.gateSess != nil && p.IsOnLine() && p.scene == nil {
if FriendMgrSington.IsShield(p.Platform, p.SnId, snid) {
continue
}
mgs[p.gateSess] = append(mgs[p.gateSess], &srvproto.MCSessionUnion{
Mccs: &srvproto.MCClientSession{
SId: proto.Int64(p.sid),
},
})
}
}
for gateSess, v := range mgs {
if gateSess != nil && len(v) != 0 {
pack, err := common.CreateMulticastPacket(packetid, rawpack, v...)
if err == nil {
proto.SetDefaults(pack)
gateSess.Send(int(srvproto.SrvlibPacketID_PACKET_SS_MULTICAST), pack)
}
}
}
}
}
}
// BroadcastMessageToGroup 发送群组消息
func (this *PlayerMgr) BroadcastMessageToGroup(packetid int, rawpack interface{}, tags []string) bool {
pack := &serverproto.SSCustomTagMulticast{
Tags: tags,
}
if byteData, ok := rawpack.([]byte); ok {
pack.RawData = byteData
} else {
byteData, err := netlib.MarshalPacket(packetid, rawpack)
if err == nil {
pack.RawData = byteData
} else {
logger.Logger.Info("PlayerMgr.BroadcastMessageToGroup err:", err)
return false
}
}
srvlib.ServerSessionMgrSington.Broadcast(int(serverproto.SSPacketID_PACKET_SS_CUSTOMTAG_MULTICAST), pack, common.GetSelfAreaId(), srvlib.GateServerType)
return true
}
// BroadcastMessageToTarget 给某些玩家发消息
func (this *PlayerMgr) BroadcastMessageToTarget(target []int32, packetid int, rawpack interface{}) {
mgs := make(map[*netlib.Session][]*srvproto.MCSessionUnion)
for _, v := range target {
d := this.snidMap[v]
if d != nil && d.gateSess != nil && d.IsOnLine() {
mgs[d.gateSess] = append(mgs[d.gateSess], &srvproto.MCSessionUnion{
Mccs: &srvproto.MCClientSession{
SId: proto.Int64(d.sid),
},
})
}
}
for gateSess, v := range mgs {
if gateSess != nil && len(v) != 0 {
pack, err := common.CreateMulticastPacket(packetid, rawpack, v...)
if err == nil {
proto.SetDefaults(pack)
gateSess.Send(int(srvproto.SrvlibPacketID_PACKET_SS_MULTICAST), pack)
}
}
}
}
// 感兴趣所有clock event
func (this *PlayerMgr) InterestClockEvent() int {
return (1 << CLOCK_EVENT_MAX) - 1
}
func (this *PlayerMgr) OnSecTimer() {
for _, player := range this.players {
utils.CatchPanic(func() {
player.OnSecTimer()
})
}
}
func (this *PlayerMgr) OnMiniTimer() {
for _, player := range this.players {
utils.CatchPanic(func() {
player.OnMiniTimer()
})
}
}
func (this *PlayerMgr) OnHourTimer() {
for _, player := range this.players {
utils.CatchPanic(func() {
player.OnHourTimer()
})
}
}
func (this *PlayerMgr) OnDayTimer() {
for _, player := range this.players {
utils.CatchPanic(func() {
player.OnDayTimer(false, true, 1)
})
}
}
func (this *PlayerMgr) OnMonthTimer() {
for _, player := range this.players {
utils.CatchPanic(func() {
player.OnMonthTimer()
})
}
}
func (this *PlayerMgr) OnWeekTimer() {
for _, player := range this.players {
utils.CatchPanic(func() {
player.OnWeekTimer()
})
}
}
func (this *PlayerMgr) OnShutdown() {
this.SaveAll()
}
// SaveAll 保存所有数据dirty=true
func (this *PlayerMgr) SaveAll() {
count := len(this.players)
start := time.Now()
saveCnt := 0
failCnt := 0
nochangeCnt := 0
logger.Logger.Info("===@PlayerMgr.SaveAll BEG@=== TotalCount:", count)
for i, p := range this.players {
idx := i + 1
if p.dirty {
if model.SavePlayerData(p.PlayerData) {
logger.Logger.Infof("===@SavePlayerData %v/%v snid:%v coin:%v safebox:%v coinpayts:%v safeboxts:%v gamets:%v save [ok] @=", idx, count, p.SnId, p.Coin, p.SafeBoxCoin, p.CoinPayTs, p.SafeBoxCoinTs, p.GameCoinTs)
saveCnt++
} else {
logger.Logger.Warnf("===@SavePlayerData %v/%v snid:%v coin:%v safebox:%v coinpayts:%v safeboxts:%v gamets:%v save [error]@=", idx, count, p.SnId, p.Coin, p.SafeBoxCoin, p.CoinPayTs, p.SafeBoxCoinTs, p.GameCoinTs)
failCnt++
}
} else {
logger.Logger.Infof("nochange===@SavePlayerData %v/%v snid:%v coin:%v safebox:%v coinpayts:%v safeboxts:%v gamets:%v nochange [ok]@=", idx, count, p.SnId, p.Coin, p.SafeBoxCoin, p.CoinPayTs, p.SafeBoxCoinTs, p.GameCoinTs)
nochangeCnt++
}
for _, v := range internal.GetPlayerLoads() {
v.Save(p.Platform, p.SnId, true, true)
}
}
logger.Logger.Infof("===@PlayerMgr.SaveAll END@===, total:%v saveCnt:%v failCnt:%v nochangeCnt:%v take:%v", count, saveCnt, failCnt, nochangeCnt, time.Now().Sub(start))
}
// 黑名单事件
//func (this *PlayerMgr) OnAddBlackInfo(blackinfo *BlackInfo) {
// if blackinfo.Snid > 0 {
// if p := this.GetPlayerBySnId(blackinfo.Snid); p != nil {
// p.PlayerData.BlacklistType = int32(blackinfo.BlackType)
// p.dirty = true
// p.Time2Save()
// } else {
// task.New(nil, task.CallableWrapper(func(o *basic.Object) interface{} {
// model.UpdatePlayerBlacklistType(blackinfo.Platform, blackinfo.Snid, int32(blackinfo.BlackType))
// return nil
// }), nil, "PlayerMgrOnAddBlackInfo").Start()
// }
// }
//}
//func (this *PlayerMgr) OnEditBlackInfo(blackinfo *BlackInfo) {
// //nothing
// //if blackinfo.Snid > 0 {
// // if p := this.GetPlayerBySnId(blackinfo.Snid); p != nil {
// // p.PlayerData.BlacklistType = int32(blackinfo.BlackType)
// // p.dirty = true
// // p.Time2Save()
// // } else {
// // task.New(nil, task.CallableWrapper(func(o *basic.Object) interface{} {
// // model.UpdatePlayerBlacklistType(blackinfo.Platform, blackinfo.Snid, int32(blackinfo.BlackType))
// // return nil
// // }), nil, "PlayerMgrOnEditBlackInfo").Start()
// // }
// //}
//}
//func (this *PlayerMgr) OnRemoveBlackInfo(blackinfo *BlackInfo) {
// //nothing
// //if blackinfo.Snid > 0 {
// // if p := this.GetPlayerBySnId(blackinfo.Snid); p != nil {
// // p.PlayerData.BlacklistType = 0
// // p.dirty = true
// // p.Time2Save()
// // } else {
// // task.New(nil, task.CallableWrapper(func(o *basic.Object) interface{} {
// // model.UpdatePlayerBlacklistType(blackinfo.Platform, blackinfo.Snid, int32(0))
// // return nil
// // }), nil, "PlayerMgrOnRemoveBlackInfo").Start()
// // }
// //}
//}
func (this *PlayerMgr) KickoutByPlatform(name string) {
for _, p := range this.players {
if name == "" || p.Platform == name {
p.Kickout(common.KickReason_Disconnection)
}
}
}
// LoadRobots 预加载机器人数据
func (this *PlayerMgr) LoadRobots() {
if model.GameParamData.PreLoadRobotCount > 0 {
task.New(nil, task.CallableWrapper(func(o *basic.Object) interface{} {
tsBeg := time.Now()
robots := model.GetRobotPlayers(model.GameParamData.PreLoadRobotCount)
tsEnd := time.Now()
logger.Logger.Tracef("GetRobotPlayers take:%v total:%v", tsEnd.Sub(tsBeg), len(robots))
return robots
}), task.CompleteNotifyWrapper(func(data interface{}, t task.Task) {
if robots, ok := data.([]*model.PlayerData); ok {
if robots != nil {
for i := 0; i < len(robots); i++ {
if this.GetPlayerBySnId(robots[i].SnId) == nil {
player := NewPlayer(0, robots[i], nil)
if player != nil {
this.snidMap[player.SnId] = player
this.accountMap[player.AccountId] = player
if player.customerToken != "" {
this.tokenMap[player.customerToken] = player
}
}
}
}
}
}
}), "GetRobotPlayers").Start()
}
}
func (this *PlayerMgr) StartLoading(accid string, sid int64) bool {
ts := time.Now().Unix()
if d, exist := this.loading[accid]; exist {
d.sid = sid
if ts-d.ts > 300 {
d.ts = ts
return false
}
return true
}
this.loading[accid] = &PlayerPendingData{sid: sid, ts: ts}
return false
}
func (this *PlayerMgr) EndPlayerLoading(accid string) int64 {
if d, exist := this.loading[accid]; exist {
delete(this.loading, accid)
return d.sid
}
return 0
}
//func PlayerRankGe(p1, p2 *Player, n int) bool {
// switch n {
// case 0:
// if p1.TotalCoin == p2.TotalCoin {
// return p1.SnId < p2.SnId
// } else {
// return p1.TotalCoin > p2.TotalCoin
// }
// case 1:
// if p1.CoinPayTotal == p2.CoinPayTotal {
// return p1.SnId < p2.SnId
// } else {
// return p1.CoinPayTotal > p2.CoinPayTotal
// }
// case 2:
// if p1.CoinExchangeTotal == p2.CoinExchangeTotal {
// return p1.SnId < p2.SnId
// } else {
// return p1.CoinExchangeTotal > p2.CoinExchangeTotal
// }
// case 3:
// a := p1.Coin + p1.SafeBoxCoin - p1.CoinPayTotal
// b := p2.Coin + p2.SafeBoxCoin - p2.CoinPayTotal
// if a == b {
// return p1.SnId < p2.SnId
// } else {
// return a > b
// }
//
// }
// return false
//}
// func (this *PlayerMgr) GetRank() map[string][]*model.Rank {
// ret := make(map[string][]*model.Rank)
// ls := make(map[string]*list.List)
//
// platforms := PlatformMgrSingleton.Platforms
// for p := range platforms {
// ret[p] = make([]*model.Rank, 0)
// ls[p] = list.New()
// }
//
// for _, player := range this.players {
// if player.IsRob {
// continue
// }
//
// p := player.PlayerData.Platform
// if _, ok := platforms[p]; !ok {
// continue
// }
//
// l := ls[p]
// for n := l.Front(); n != nil; n = n.Next() {
// if np, ok := n.Value.(*Player); ok {
// if PlayerRankGe(player, np) {
// l.InsertBefore(player, n)
// goto CHECK
// }
// }
// //else {
// // logger.Logger.Warnf("PlayerMgr.GetRank n.Value.(*Player) fail")
// // continue
// //}
// }
//
// l.PushBack(player)
// CHECK:
// if l.Len() > model.MAX_RANK_COUNT {
// l.Remove(l.Back())
// }
// }
//
// for p := range platforms {
// l := ls[p]
// for n := l.Front(); n != nil; n = n.Next() {
// if np, ok := n.Value.(*Player); ok {
// ret[p] = append(ret[p], &model.Rank{
// SnId: np.PlayerData.SnId,
// Name: np.PlayerData.Name,
// Head: np.PlayerData.Head,
// VIP: np.PlayerData.VIP,
// TotalCoin: np.PlayerData.TotalCoin,
// })
// }
// }
// }
//
// return ret
// }
//func (this *PlayerMgr) GetAssetRank(platform string) []*model.Rank {
// ret := make([]*model.Rank, 0, model.MAX_RANK_COUNT)
// l := list.New()
//
// for _, player := range this.players {
// if player.IsRob {
// continue
// }
//
// if player.PlayerData.Platform != platform {
// continue
// }
//
// for n := l.Front(); n != nil; n = n.Next() {
// if np, ok := n.Value.(*Player); ok {
// if PlayerRankGe(player, np, 0) {
// l.InsertBefore(player, n)
// goto CHECK
// }
// }
// }
//
// l.PushBack(player)
// CHECK:
// if l.Len() > model.MAX_RANK_COUNT {
// l.Remove(l.Back())
// }
// }
//
// for n := l.Front(); n != nil; n = n.Next() {
// if np, ok := n.Value.(*Player); ok {
// ret = append(ret, &model.Rank{
// SnId: np.PlayerData.SnId,
// Name: np.PlayerData.Name,
// Head: np.PlayerData.Head,
// VIP: np.PlayerData.VIP,
// TotalCoin: np.PlayerData.TotalCoin,
// })
// }
// }
//
// return ret
//}
//func (this *PlayerMgr) GetRechargeLists(platform string) []*model.Rank {
// ret := make([]*model.Rank, 0, model.MAX_RANK_COUNT)
// l := list.New()
//
// for _, player := range this.players {
// if player.IsRob {
// continue
// }
//
// if player.PlayerData.Platform != platform {
// continue
// }
//
// for n := l.Front(); n != nil; n = n.Next() {
// if np, ok := n.Value.(*Player); ok {
// if PlayerRankGe(player, np, 1) {
// l.InsertBefore(player, n)
// goto CHECK
// }
// }
// }
//
// l.PushBack(player)
// CHECK:
// if l.Len() > model.MAX_RANK_COUNT {
// l.Remove(l.Back())
// }
// }
//
// for n := l.Front(); n != nil; n = n.Next() {
// if np, ok := n.Value.(*Player); ok {
// ret = append(ret, &model.Rank{
// SnId: np.PlayerData.SnId,
// Name: np.PlayerData.Name,
// Head: np.PlayerData.Head,
// VIP: np.PlayerData.VIP,
// TotalCoin: np.PlayerData.CoinPayTotal,
// })
// }
// }
//
// return ret
//}
//func (this *PlayerMgr) GetExchangeLists(platform string) []*model.Rank {
// ret := make([]*model.Rank, 0, model.MAX_RANK_COUNT)
// l := list.New()
//
// for _, player := range this.players {
// if player.IsRob {
// continue
// }
//
// if player.PlayerData.Platform != platform {
// continue
// }
//
// for n := l.Front(); n != nil; n = n.Next() {
// if np, ok := n.Value.(*Player); ok {
// if PlayerRankGe(player, np, 2) {
// l.InsertBefore(player, n)
// goto CHECK
// }
// }
// }
//
// l.PushBack(player)
// CHECK:
// if l.Len() > model.MAX_RANK_COUNT {
// l.Remove(l.Back())
// }
// }
//
// for n := l.Front(); n != nil; n = n.Next() {
// if np, ok := n.Value.(*Player); ok {
// ret = append(ret, &model.Rank{
// SnId: np.PlayerData.SnId,
// Name: np.PlayerData.Name,
// Head: np.PlayerData.Head,
// VIP: np.PlayerData.VIP,
// TotalCoin: np.PlayerData.CoinExchangeTotal,
// })
// }
// }
//
// return ret
//}
//func (this *PlayerMgr) GetProfitLists(platform string) []*model.Rank {
// ret := make([]*model.Rank, 0, model.MAX_RANK_COUNT)
// l := list.New()
//
// for _, player := range this.players {
// if player.IsRob {
// continue
// }
//
// if player.PlayerData.Platform != platform {
// continue
// }
//
// for n := l.Front(); n != nil; n = n.Next() {
// if np, ok := n.Value.(*Player); ok {
// if PlayerRankGe(player, np, 3) {
// l.InsertBefore(player, n)
// goto CHECK
// }
// }
// }
//
// l.PushBack(player)
// CHECK:
// if l.Len() > model.MAX_RANK_COUNT {
// l.Remove(l.Back())
// }
// }
//
// for n := l.Front(); n != nil; n = n.Next() {
// if np, ok := n.Value.(*Player); ok {
// ret = append(ret, &model.Rank{
// SnId: np.PlayerData.SnId,
// Name: np.PlayerData.Name,
// Head: np.PlayerData.Head,
// VIP: np.PlayerData.VIP,
// //TotalCoin: np.PlayerData.ProfitCoin,
// })
// }
// }
//
// return ret
//}
//func (this *PlayerMgr) DeletePlayerByPlatform(platform string) {
// var dels []*Player
// for _, p := range this.players {
// if p != nil && p.Platform == platform {
// p.Kickout(common.KickReason_Disconnection)
// dels = append(dels, p)
// }
// }
//
// for _, p := range dels {
// if p != nil {
// p.isDelete = true
// if p.scene == nil {
// this.DelPlayer(p.SnId)
// }
// }
// }
//}
func (this *PlayerMgr) StatsOnline() model.PlayerOLStats {
stats := model.PlayerOLStats{
PlatformStats: make(map[string]*model.PlayerStats),
RobotStats: model.PlayerStats{
InGameCnt: make(map[int32]map[int32]int32),
},
}
for _, p := range this.sidMap {
if p != nil {
if p.IsRob {
pps := &stats.RobotStats
if pps != nil {
if p.scene == nil {
pps.InHallCnt++
} else {
if g, exist := pps.InGameCnt[int32(p.scene.gameId)]; exist {
g[p.scene.dbGameFree.GetId()]++
} else {
g := make(map[int32]int32)
pps.InGameCnt[int32(p.scene.gameId)] = g
g[p.scene.dbGameFree.GetId()]++
}
}
}
} else {
var pps *model.PlayerStats
var exist bool
if pps, exist = stats.PlatformStats[p.Platform]; !exist {
pps = &model.PlayerStats{InGameCnt: make(map[int32]map[int32]int32)}
stats.PlatformStats[p.Platform] = pps
}
if pps != nil {
if p.scene == nil {
pps.InHallCnt++
} else {
if g, exist := pps.InGameCnt[int32(p.scene.gameId)]; exist {
g[p.scene.dbGameFree.GetId()]++
} else {
g := make(map[int32]int32)
pps.InGameCnt[int32(p.scene.gameId)] = g
g[p.scene.dbGameFree.GetId()]++
}
}
}
}
}
}
return stats
}
func (p *PlayerMgr) UpdateName(snId int32, name string) {
player := p.GetPlayerBySnId(snId)
if player == nil {
return
}
player.setName(name)
player.dirty = true
}
func (p *PlayerMgr) UpdateHead(snId, head int32) {
player := p.GetPlayerBySnId(snId)
if player == nil {
return
}
player.Head = head
//0:男 1:女
player.Sex = (player.Head%2 + 1) % 2
player.dirty = true
player.changeIconTime = time.Now()
}
func (p *PlayerMgr) UpdateHeadOutline(snId, outline int32) {
player := p.GetPlayerBySnId(snId)
if player == nil {
return
}
player.HeadOutLine = outline
player.dirty = true
}
func (p *PlayerMgr) UpdateHeadUrl(snId int32, url string) {
player := p.GetPlayerBySnId(snId)
if player == nil {
return
}
if player.HeadUrl != url {
player.HeadUrl = url
player.dirty = true
}
}
//func (p *PlayerMgr) ModifyActSwitchToPlayer(platform string, modify bool) {
// if modify { //活动开关修改了才去更新活动开关
// if players, ok := p.playerOfPlatform[platform]; ok {
// for _, p := range players {
// if p != nil && !p.IsRob {
// p.ModifyActSwitch()
// }
// }
// }
// }
//}
/*
推荐好友规则
1.优先判断在线玩家人数N
1N≥20每次刷新从在线玩家中随机6个
2N20则填充机器人保证N=20每次填充的机器人头像和昵称随机然后从N中随机6个
2.刷新有CD暂定20s刷新过后进入cd
*/
type RecommendFriend struct {
Snid int32
Name string
Head int32
HeadUrl string
RoleId int32
}
// RecommendFriendRule 推荐好友
func (this *PlayerMgr) RecommendFriendRule(platform string, snid int32) []RecommendFriend {
if platform == "" {
return nil
} else {
rets := []RecommendFriend{}
players := this.playerOfPlatform[platform]
for _, player := range players { //优先真人
if player.SnId != snid && !FriendMgrSington.IsFriend(platform, snid, player.SnId) {
roleId := common.DefaultRoleId
if player.Roles != nil {
roleId = int(player.Roles.ModId)
}
ret := RecommendFriend{
Snid: player.SnId,
Name: player.Name,
Head: player.Head,
HeadUrl: player.HeadUrl,
RoleId: int32(roleId),
}
rets = append(rets, ret)
if len(rets) >= 20 {
break
}
}
}
if len(rets) < 20 {
for _, player := range this.snidMap { //其次机器人
if player.IsRob {
roleId := common.DefaultRoleId
if player.Roles != nil {
roleId = int(player.Roles.ModId)
}
ret := RecommendFriend{
Snid: player.SnId,
Name: player.Name,
Head: player.Head,
HeadUrl: player.HeadUrl,
RoleId: int32(roleId),
}
rets = append(rets, ret)
if len(rets) >= 20 {
break
}
}
}
}
needIdxs := []int{}
if rets != nil {
if len(rets) >= 6 {
for {
if len(needIdxs) >= 6 {
break
}
randIdx := rand.Intn(len(rets))
if !common.InSliceInt(needIdxs, randIdx) {
needIdxs = append(needIdxs, randIdx)
}
}
} else {
for i := 0; i < len(rets); i++ {
needIdxs = append(needIdxs, i)
}
}
}
ret := []RecommendFriend{}
for _, idx := range needIdxs {
ret = append(ret, rets[idx])
}
return ret
}
}
func init() {
//BlackListMgrSington.RegisterObserver(PlayerMgrSington)
PlayerSubjectSign.AttachName(PlayerMgrSington)
PlayerSubjectSign.AttachHead(PlayerMgrSington)
PlayerSubjectSign.AttachHeadOutline(PlayerMgrSington)
PlayerSubjectSign.AttachHeadUrl(PlayerMgrSington)
PlayerSubjectSign.AttachName(FriendMgrSington)
PlayerSubjectSign.AttachHead(FriendMgrSington)
// 定时器
ClockMgrSington.RegisteSinker(PlayerMgrSington)
}