Compare commits

..

23 Commits

Author SHA1 Message Date
sk 1235383c87 no message 2024-12-21 09:46:34 +08:00
sk 8177397b26 add 统计十三张自动手动摆牌时间 2024-12-21 09:13:01 +08:00
sk 694e8a5992 modify 十三张手动摆牌 2024-12-21 09:05:08 +08:00
sk b186967189 add 十三张记录分别自动手动摆牌时长 2024-12-20 16:09:26 +08:00
sk d82c5ed055 modify mq 2024-12-20 10:43:12 +08:00
sk e044a590d4 Merge branch 'develop' of git.pogorockgames.com:mango-games/server/game into develop 2024-12-20 09:21:40 +08:00
sk 39890efbfa add:破产记录添加游戏组id 2024-12-20 09:21:24 +08:00
by 09a609b1b3 Merge branch 'develop' of https://git.pogorockgames.com/mango-games/server/game into develop 2024-12-19 18:03:03 +08:00
by e2095d6878 后台补单 2024-12-19 18:02:51 +08:00
sk bb8af52a6b modify:平均游戏时长查询优化 2024-12-19 17:52:33 +08:00
sk 08023bcdea fix:游戏分组统计数据 2024-12-19 17:50:49 +08:00
sk 893bc4cbbb modify:房费扣除 2024-12-19 17:23:46 +08:00
sk a9efaed491 fix:tienlen调试发牌修改 2024-12-19 14:40:00 +08:00
sk 88b4c08740 fix:tienlen调试发牌修改 2024-12-19 14:36:42 +08:00
sk 167e1e9c10 add:tienlen调试发牌修改 2024-12-19 14:07:18 +08:00
sk 1ed0d5b4d7 Merge branch 'develop' of git.pogorockgames.com:mango-games/server/game into develop 2024-12-19 13:47:49 +08:00
sk 7a7baa9568 modify:十三张牌型预选
支持清空预选
空位随机补牌
2024-12-19 13:47:29 +08:00
sk 30d3ba1cc0 add:查询平均游戏时长 2024-12-19 11:48:56 +08:00
by 9b59039d4b 后台补单 2024-12-18 09:31:49 +08:00
by 7d0d5e9509 后台补单log 2024-12-18 09:19:57 +08:00
sk 93792b3e38 add:添加日志 2024-12-17 14:25:11 +08:00
sk f4964a57a2 fix:统计游戏组数据 2024-12-17 14:12:52 +08:00
sk 0c65af22ea add:对局中玩家人数上报 2024-12-17 13:29:50 +08:00
36 changed files with 917 additions and 522 deletions

View File

@ -250,6 +250,7 @@ func RegisterClockFunc(fs *ClockFunc) {
if fs == nil { if fs == nil {
return return
} }
if fs.OnSecTimerFunc != nil { if fs.OnSecTimerFunc != nil {
fs.event = fs.event | 1<<ClockEventSecond fs.event = fs.event | 1<<ClockEventSecond
} }
@ -272,5 +273,9 @@ func RegisterClockFunc(fs *ClockFunc) {
fs.event = fs.event | 1<<ClockEventShutdown fs.event = fs.event | 1<<ClockEventShutdown
} }
if fs.event == 0 {
return
}
ClockMgrSingleton.RegisterSinker(fs) ClockMgrSingleton.RegisterSinker(fs)
} }

View File

@ -899,6 +899,6 @@ var GuideIdToGainWay = map[int]int{
GuideIdCustom: GainWayGuide2, GuideIdCustom: GainWayGuide2,
} }
func GetGameDifKey(gamedif string) string { func GetKeyGameDif(gamedif string) string {
return fmt.Sprintf("gamedif-%v", gamedif) return fmt.Sprintf("gamedif-%v", gamedif)
} }

View File

@ -35,6 +35,7 @@ const (
ThirteenWaterPlayerOpReset = 4 // 重新选牌 ThirteenWaterPlayerOpReset = 4 // 重新选牌
ThirteenWaterPlayerJoin = 5 // 加入游戏 ThirteenWaterPlayerJoin = 5 // 加入游戏
ThirteenWaterPlayerOpSelect = 6 // 预选牌 ThirteenWaterPlayerOpSelect = 6 // 预选牌
ThirteenWaterPlayerOpAuto = 7 // 自动摆牌 1自动 2手动
) )
const ( const (
ThirteenWaterSceneWaitTimeout = time.Second * 2 //等待倒计时 ThirteenWaterSceneWaitTimeout = time.Second * 2 //等待倒计时

View File

@ -653,6 +653,12 @@ func (this *Player) ReportGameEvent(param *ReportGameEventParam) *ReportGameEven
gameTimes = dataGame.Statics.GameTimes gameTimes = dataGame.Statics.GameTimes
} }
dataGameDif, ok := this.GDatas[common.GetKeyGameDif(this.scene.GetDBGameFree().GetGameDif())]
if ok {
gamedifFirstTime = dataGameDif.FirstTime
gamedifTimes = dataGameDif.Statics.GameTimes
}
isNew := int32(0) isNew := int32(0)
tCreateDay := now.New(this.CreateTime.Local()).BeginningOfDay() tCreateDay := now.New(this.CreateTime.Local()).BeginningOfDay()
if now.BeginningOfDay().Equal(tCreateDay) { if now.BeginningOfDay().Equal(tCreateDay) {

View File

@ -2111,7 +2111,7 @@ func (this *Scene) Statistics(param *StaticParam) {
var statics []*model.PlayerGameStatics var statics []*model.PlayerGameStatics
keyGameId := strconv.Itoa(this.GetGameId()) keyGameId := strconv.Itoa(this.GetGameId())
keyGameFreeId := strconv.Itoa(int(this.GetGameFreeId())) keyGameFreeId := strconv.Itoa(int(this.GetGameFreeId()))
keyGameDif := common.GetGameDifKey(this.GetDBGameFree().GetGameDif()) keyGameDif := common.GetKeyGameDif(this.GetDBGameFree().GetGameDif())
// 当天数据统计 // 当天数据统计
// 按场次分 // 按场次分
if data, ok := p.TodayGameData.CtrlData[keyGameFreeId]; ok { if data, ok := p.TodayGameData.CtrlData[keyGameFreeId]; ok {
@ -2350,7 +2350,7 @@ func (this *Scene) StaticsLaba(param *StaticLabaParam) {
var statics []*model.PlayerGameStatics var statics []*model.PlayerGameStatics
keyGameId := strconv.Itoa(this.GetGameId()) keyGameId := strconv.Itoa(this.GetGameId())
keyGameFreeId := strconv.Itoa(int(this.GetGameFreeId())) keyGameFreeId := strconv.Itoa(int(this.GetGameFreeId()))
keyGameDif := common.GetGameDifKey(this.GetDBGameFree().GetGameDif()) keyGameDif := common.GetKeyGameDif(this.GetDBGameFree().GetGameDif())
// 当天数据统计 // 当天数据统计
// 按场次分 // 按场次分
if data, ok := p.TodayGameData.CtrlData[keyGameFreeId]; ok { if data, ok := p.TodayGameData.CtrlData[keyGameFreeId]; ok {

View File

@ -1,6 +1,8 @@
package thirteen package thirteen
import ( import (
"time"
"mongo.games.com/goserver/core/logger" "mongo.games.com/goserver/core/logger"
"mongo.games.com/game/gamerule/thirteen" "mongo.games.com/game/gamerule/thirteen"
@ -25,7 +27,10 @@ type PlayerEx struct {
odds int32 odds int32
totalScore int64 totalScore int64
defGroup *thirteen.Group defGroup *thirteen.Group
playerPool int // 个人水池分 playerPool int // 个人水池分
AutoState int // 是否自动模式
AutoMill time.Duration // 自动时长
HandMill time.Duration // 手动时长
} }
func (this *PlayerEx) Clear() { func (this *PlayerEx) Clear() {
@ -42,6 +47,9 @@ func (this *PlayerEx) Clear() {
this.gainCoin = 0 this.gainCoin = 0
this.taxCoin = 0 this.taxCoin = 0
this.deterMine = false this.deterMine = false
this.AutoState = 0
this.AutoMill = time.Duration(0)
this.HandMill = time.Duration(0)
this.score = [7]int64{0, 0, 0, 0, 0, 0, 0} this.score = [7]int64{0, 0, 0, 0, 0, 0, 0}
this.tableScore = [6]int64{} this.tableScore = [6]int64{}
this.winThreePos = make(map[int]int64) this.winThreePos = make(map[int]int64)

View File

@ -86,6 +86,7 @@ type SceneEx struct {
ctrlType int // 1控赢 2控输 0不控 ctrlType int // 1控赢 2控输 0不控
cardsArr [][13]int cardsArr [][13]int
cardsGroup []map[int]*rule.Group cardsGroup []map[int]*rule.Group
timestamp time.Time
} }
func NewThirteenWaterSceneData(s *base.Scene) *SceneEx { func NewThirteenWaterSceneData(s *base.Scene) *SceneEx {

View File

@ -4,6 +4,7 @@ import (
"strconv" "strconv"
"time" "time"
"go.mongodb.org/mongo-driver/bson/primitive"
"mongo.games.com/goserver/core" "mongo.games.com/goserver/core"
"mongo.games.com/goserver/core/logger" "mongo.games.com/goserver/core/logger"
@ -11,6 +12,7 @@ import (
rule "mongo.games.com/game/gamerule/thirteen" rule "mongo.games.com/game/gamerule/thirteen"
"mongo.games.com/game/gamesrv/base" "mongo.games.com/game/gamesrv/base"
"mongo.games.com/game/model" "mongo.games.com/game/model"
"mongo.games.com/game/mq"
"mongo.games.com/game/proto" "mongo.games.com/game/proto"
"mongo.games.com/game/protocol/thirteen" "mongo.games.com/game/protocol/thirteen"
) )
@ -808,6 +810,11 @@ func (this *StateOp) OnEnter(s *base.Scene) {
logger.Logger.Tracef("(this *StateOp) OnEnter, sceneid=%v", s.GetSceneId()) logger.Logger.Tracef("(this *StateOp) OnEnter, sceneid=%v", s.GetSceneId())
this.BaseState.OnEnter(s) this.BaseState.OnEnter(s)
ThirteenWaterBroadcastRoomState(s) ThirteenWaterBroadcastRoomState(s)
sceneEx, ok := s.ExtraData.(*SceneEx)
if !ok {
return
}
sceneEx.timestamp = time.Now()
} }
// 玩家操作 // 玩家操作
@ -826,38 +833,34 @@ func (this *StateOp) OnPlayerOp(s *base.Scene, p *base.Player, opcode int, param
return false return false
} }
returnFunc := func(code thirteen.OpResultCode) { returnFunc := func(code thirteen.OpResultCode, broadcast bool) {
pack := &thirteen.SCThirteenPlayerOp{ pack := &thirteen.SCThirteenPlayerOp{
OpRetCode: code, OpRetCode: code,
OpCode: int32(opcode), OpCode: int32(opcode),
OpParam: params, OpParam: params,
Pos: int32(playerEx.GetPos()), Pos: int32(playerEx.GetPos()),
} }
if code == thirteen.OpResultCode_OPRC_Error { if broadcast {
proto.SetDefaults(pack) playerEx.Broadcast(int(thirteen.TWMmoPacketID_PACKET_SCThirteenPlayerOp), pack, 0)
logger.Logger.Trace("SCThirteenPlayerOp:", pack) } else {
playerEx.SendToClient(int(thirteen.TWMmoPacketID_PACKET_SCThirteenPlayerOp), pack) playerEx.SendToClient(int(thirteen.TWMmoPacketID_PACKET_SCThirteenPlayerOp), pack)
return
} }
logger.Logger.Trace("SCThirteenPlayerOp:", pack)
} }
if !playerEx.IsGameing() { if !playerEx.IsGameing() {
returnFunc(thirteen.OpResultCode_OPRC_Error) returnFunc(thirteen.OpResultCode_OPRC_Error, false)
return true return true
} }
switch opcode { switch opcode {
case rule.ThirteenWaterPlayerOpMS: //确定牌 case rule.ThirteenWaterPlayerOpMS: //确定牌
//if playerEx.deterMine { // 确认牌型
// returnFunc(thirteen.OpResultCode_OPRC_Error)
// return false
//}
if len(params) == 13 { if len(params) == 13 {
//校验牌 //校验牌
a := rule.DelCards(playerEx.cards[:], common.Int64Toint(params)) a := rule.DelCards(playerEx.cards[:], common.Int64Toint(params))
if len(a) != 0 { if len(a) != 0 {
logger.Logger.Error("the cards is error.") logger.Logger.Error("the cards is error.")
returnFunc(thirteen.OpResultCode_OPRC_Error) returnFunc(thirteen.OpResultCode_OPRC_Error, false)
return true return true
} }
//牌赋值 //牌赋值
@ -873,6 +876,7 @@ func (this *StateOp) OnPlayerOp(s *base.Scene, p *base.Player, opcode int, param
playerEx.Trusteeship = 0 playerEx.Trusteeship = 0
playerEx.UnmarkFlag(base.PlayerState_Auto) playerEx.UnmarkFlag(base.PlayerState_Auto)
playerEx.deterMine = true playerEx.deterMine = true
playerEx.AutoState = 0
//如果所有玩家都确认牌之后 可以直接开始下一阶段 //如果所有玩家都确认牌之后 可以直接开始下一阶段
a := true a := true
for _, v := range sceneEx.players { for _, v := range sceneEx.players {
@ -892,38 +896,70 @@ func (this *StateOp) OnPlayerOp(s *base.Scene, p *base.Player, opcode int, param
playerEx.cardsO = &rule.Group{Head: [3]int{-1, -1, -1}, Mid: [5]int{-1, -1, -1, -1, -1}, End: [5]int{-1, -1, -1, -1, -1}, PokerType: -1} playerEx.cardsO = &rule.Group{Head: [3]int{-1, -1, -1}, Mid: [5]int{-1, -1, -1, -1, -1}, End: [5]int{-1, -1, -1, -1, -1}, PokerType: -1}
playerEx.Trusteeship = 0 playerEx.Trusteeship = 0
playerEx.UnmarkFlag(base.PlayerState_Auto) playerEx.UnmarkFlag(base.PlayerState_Auto)
pack := &thirteen.SCThirteenPlayerOp{
OpRetCode: thirteen.OpResultCode_OPRC_Sucess,
OpCode: int32(opcode),
OpParam: params,
Pos: int32(playerEx.GetPos()),
}
if len(params) == 13 { if len(params) == 13 {
//校验牌 //校验牌
a := rule.DelCards(playerEx.cards[:], common.Int64Toint(params)) remain := len(playerEx.cards)
if len(a) != 0 { remainCards := make([]int, remain)
logger.Logger.Error("the cards is error.") copy(remainCards, playerEx.cards[:])
returnFunc(thirteen.OpResultCode_OPRC_Error) for _, v := range params {
return true if v >= 0 {
a := rule.DelCards(remainCards, []int{int(v)})
if len(a) == remain {
logger.Logger.Error("the cards is error.")
returnFunc(thirteen.OpResultCode_OPRC_Error, false)
return true
}
remain = len(a)
remainCards = a
}
} }
//牌赋值 //牌赋值
copy(playerEx.preCardsO.Head[:], common.Int64Toint(params[:3])) copy(playerEx.preCardsO.Head[:], common.Int64Toint(params[:3]))
copy(playerEx.preCardsO.Mid[:], common.Int64Toint(params[3:8])) copy(playerEx.preCardsO.Mid[:], common.Int64Toint(params[3:8]))
copy(playerEx.preCardsO.End[:], common.Int64Toint(params[8:])) copy(playerEx.preCardsO.End[:], common.Int64Toint(params[8:]))
playerEx.preCardsO.PokerType = 0 playerEx.preCardsO.PokerType = 0
for k, v := range playerEx.preCardsO.Head {
if v < 0 {
playerEx.preCardsO.Head[k] = remainCards[0]
remainCards = remainCards[1:]
}
}
for k, v := range playerEx.preCardsO.Mid {
if v < 0 {
playerEx.preCardsO.Mid[k] = remainCards[0]
remainCards = remainCards[1:]
}
}
for k, v := range playerEx.preCardsO.End {
if v < 0 {
playerEx.preCardsO.End[k] = remainCards[0]
remainCards = remainCards[1:]
}
}
} }
playerEx.SendToClient(int(thirteen.TWMmoPacketID_PACKET_SCThirteenPlayerOp), pack)
if len(params) == 1 {
sceneEx.SelectCards(playerEx, int(params[0]))
}
if len(params) == 0 {
playerEx.preCardsO = &rule.Group{Head: [3]int{-1, -1, -1}, Mid: [5]int{-1, -1, -1, -1, -1}, End: [5]int{-1, -1, -1, -1, -1}, PokerType: -1}
}
returnFunc(thirteen.OpResultCode_OPRC_Sucess, true)
case rule.ThirteenWaterPlayerOpReset: case rule.ThirteenWaterPlayerOpReset:
// 取消确认 // 取消确认
playerEx.deterMine = false playerEx.deterMine = false
pack := &thirteen.SCThirteenPlayerOp{ returnFunc(thirteen.OpResultCode_OPRC_Sucess, true)
OpRetCode: thirteen.OpResultCode_OPRC_Sucess,
OpCode: int32(opcode), case rule.ThirteenWaterPlayerOpAuto:
OpParam: params, if len(params) == 0 {
Pos: int32(playerEx.GetPos()), return true
} }
playerEx.Broadcast(int(thirteen.TWMmoPacketID_PACKET_SCThirteenPlayerOp), pack, 0)
playerEx.AutoState = int(params[0])
default: default:
return false return false
@ -941,6 +977,19 @@ func (this *StateOp) OnLeave(s *base.Scene) {
for _, player := range sceneEx.players { for _, player := range sceneEx.players {
if player != nil && player.IsGameing() { if player != nil && player.IsGameing() {
if !player.IsRobot() {
mq.Write(model.ThirteenAutoLog{
Id: primitive.NewObjectID().Hex(),
Platform: player.Platform,
LogId: sceneEx.logid,
SnId: player.SnId,
AutoTime: player.AutoMill.Milliseconds(),
HandTime: player.HandMill.Milliseconds(),
Ts: time.Now().Unix(),
}, mq.BackThirteenAutoLog)
}
// 使用预选牌 // 使用预选牌
if player.preCardsO != nil && player.preCardsO.PokerType != -1 && (player.cardsO == nil || player.cardsO.PokerType == -1) { if player.preCardsO != nil && player.preCardsO.PokerType != -1 && (player.cardsO == nil || player.cardsO.PokerType == -1) {
player.cardsO = player.preCardsO player.cardsO = player.preCardsO
@ -1120,7 +1169,23 @@ func (this *StateOp) OnLeave(s *base.Scene) {
func (this *StateOp) OnTick(s *base.Scene) { func (this *StateOp) OnTick(s *base.Scene) {
this.BaseState.OnTick(s) this.BaseState.OnTick(s)
if sceneEx, ok := s.ExtraData.(*SceneEx); ok { if sceneEx, ok := s.ExtraData.(*SceneEx); ok {
if time.Now().Sub(sceneEx.StateStartTime) > sceneEx.GetBaiPai() { now := time.Now()
addTime := now.Sub(sceneEx.timestamp)
for _, v := range sceneEx.seats {
if v != nil && v.IsGameing() {
switch v.AutoState {
case 2:
v.AutoMill += addTime
case 1:
v.HandMill += addTime
default:
}
}
}
sceneEx.timestamp = now
if now.Sub(sceneEx.StateStartTime) > sceneEx.GetBaiPai() {
s.ChangeSceneState(rule.ThirteenWaterSceneStateShowCards) s.ChangeSceneState(rule.ThirteenWaterSceneStateShowCards)
} }
} }

View File

@ -1298,24 +1298,20 @@ func (this *TienLenSceneData) SendHandCardOdds() {
allcs[i], allcs[j] = allcs[j], allcs[i] allcs[i], allcs[j] = allcs[j], allcs[i]
}) })
if len(this.testPokers) > 14 {
this.testPokers = this.testPokers[:14]
}
if len(this.testPokers) < 14 {
allcs = common.DelSliceIn32s(allcs, this.testPokers[1:])
this.testPokers = append(this.testPokers, allcs[:14-len(this.testPokers)]...)
allcs = allcs[14-len(this.testPokers):]
}
allcs = common.DelSliceIn32s(allcs, this.testPokers[1:]) allcs = common.DelSliceIn32s(allcs, this.testPokers[1:])
this.testPokers = append(this.testPokers, allcs...)
for _, seat := range this.seats { for _, seat := range this.seats {
if seat != nil && seat.IsGameing() { if seat != nil && seat.IsGameing() && seat.SnId == this.testPokers[0] {
if seat.SnId == this.testPokers[0] { f1(seat, this.testPokers[1:14])
f1(seat, this.testPokers[1:]) this.testPokers = this.testPokers[14:]
} else { break
f1(seat, allcs[:13]) }
allcs = allcs[13:] }
} for _, seat := range this.seats {
if seat != nil && seat.IsGameing() && seat.cards[0] == rule.InvalideCard {
f1(seat, this.testPokers[:13])
this.testPokers = this.testPokers[13:]
} }
} }
this.testPokers = nil this.testPokers = nil

View File

@ -8,9 +8,11 @@ type BankruptLog struct {
LogId bson.ObjectId `bson:"_id"` LogId bson.ObjectId `bson:"_id"`
SnId int32 //玩家id SnId int32 //玩家id
Channel string // 渠道 Channel string // 渠道
ChannelId string // 推广渠道
Platform string //平台名称 Platform string //平台名称
GameId int //游戏id GameId int //游戏id
GameFreeID int32 //房间id GameFreeID int32 //房间id
GameDif string // 游戏分组
CreateTime int64 // 注册时间 CreateTime int64 // 注册时间
UseCoin int64 // 消耗金币 UseCoin int64 // 消耗金币
@ -22,12 +24,14 @@ func NewBankruptLog() *BankruptLog {
return log return log
} }
func NewBankruptLogEx(snid int32, gamefreeid int32, createtime, usecoin int64, platform, channel string, gameId int) *BankruptLog { func NewBankruptLogEx(snid int32, gamefreeid int32, createtime, usecoin int64, platform, channel, channelId, gamedif string, gameId int) *BankruptLog {
cl := NewBankruptLog() cl := NewBankruptLog()
cl.SnId = snid cl.SnId = snid
cl.Platform = platform cl.Platform = platform
cl.Channel = channel cl.Channel = channel
cl.ChannelId = channelId
cl.GameId = gameId cl.GameId = gameId
cl.GameDif = gamedif
cl.GameFreeID = gamefreeid cl.GameFreeID = gamefreeid
cl.CreateTime = createtime cl.CreateTime = createtime

View File

@ -1262,9 +1262,11 @@ func SavePlayerData(pd *PlayerData) bool {
} }
if pd != nil { if pd != nil {
var ret bool var ret bool
t1 := time.Now()
err := rpcCli.CallWithTimeout("PlayerDataSvc.SavePlayerData", pd, &ret, time.Second*30) err := rpcCli.CallWithTimeout("PlayerDataSvc.SavePlayerData", pd, &ret, time.Second*30)
if err != nil { if err != nil {
logger.Logger.Errorf("SavePlayerData %v err:%v", pd.SnId, err) logger.Logger.Errorf("SavePlayerData %v cost:%v fail err:%v PlayerData:%+v",
pd.SnId, time.Now().Sub(t1), err, *pd)
return false return false
} }
return ret return ret

View File

@ -15,6 +15,13 @@ func GenerateOnline(online map[string]map[string]int) *mq.RabbitMQData {
return NewRabbitMQData(mq.BackOnline, params) return NewRabbitMQData(mq.BackOnline, params)
} }
func GenerateOnlineGame(online map[string]map[string]map[string]map[int]map[int]int) *mq.RabbitMQData {
params := make(map[string]interface{})
params["Online"] = online
params["Time"] = time.Now().Unix()
return NewRabbitMQData(mq.BackOnlineGame, params)
}
// GenerateLogin 玩家登陆事件 // GenerateLogin 玩家登陆事件
func GenerateLogin(o *PlayerLoginEvent) *mq.RabbitMQData { func GenerateLogin(o *PlayerLoginEvent) *mq.RabbitMQData {
return NewRabbitMQData(mq.BackLogin, o) return NewRabbitMQData(mq.BackLogin, o)

11
model/thirteen.go Normal file
View File

@ -0,0 +1,11 @@
package model
type ThirteenAutoLog struct {
Id string `gorm:"primaryKey"`
Platform string `gorm:"-"`
LogId string `gorm:"index;column:logid"`
SnId int32 `gorm:"index;column:snid"`
AutoTime int64 // 自动时长,毫秒
HandTime int64 // 手动时长,毫秒
Ts int64
}

View File

@ -55,18 +55,18 @@ type RabbitMQData struct {
Data interface{} Data interface{}
} }
func (c *MessageMgr) Send(data interface{}, name ...string) error { func (c *MessageMgr) Send(data interface{}, name string, options ...broker.PublishOption) error {
if msg, ok := data.(*RabbitMQData); ok { if msg, ok := data.(*RabbitMQData); ok {
return Send(msg.MQName, msg.Data) return Send(msg.MQName, msg.Data, options...)
} }
if len(name) > 0 && name[0] != "" { if len(name) > 0 {
return Send(name[0], data) return Send(name, data, options...)
} }
key := c.getName(data) key := c.getName(data)
if key == "" { if key == "" {
key = "_null_" key = "_null_"
} }
return Send(key, data) return Send(key, data, options...)
} }
type RegisterHandlerParam struct { type RegisterHandlerParam struct {
@ -132,7 +132,14 @@ func RegisterMessage(param *RegisterMessageParam) {
// Write 发送消息 // Write 发送消息
// 默认队列名称规则队列前缀_消息结构体名称 // 默认队列名称规则队列前缀_消息结构体名称
func Write(data interface{}, name ...string) error { func Write(data interface{}, name ...string) error {
return MessageMgrSingle.Send(data, name...) if len(name) > 0 && name[0] != "" {
return MessageMgrSingle.Send(data, name[0])
}
return MessageMgrSingle.Send(data, "")
}
func WriteWithOptions(data interface{}, name string, opts ...broker.PublishOption) error {
return MessageMgrSingle.Send(data, name, opts...)
} }
// RegisterHandler 注册消息处理函数 // RegisterHandler 注册消息处理函数

View File

@ -18,11 +18,14 @@ const (
BackSystemPermitTask = "back_permittask" BackSystemPermitTask = "back_permittask"
BackSystemJyb = "back_jyblog" BackSystemJyb = "back_jyblog"
BackActivityLog = "back_activitylog" BackActivityLog = "back_activitylog"
BackOnlineGame = "back_onlinegame"
) )
// mgrsrv // go后端
const () const (
BackThirteenAutoLog = "b_thirteenautolog"
)
// worldsrv 消息 // worldsrv 消息

View File

@ -386,7 +386,7 @@ type CSThirteenPlayerOp struct {
sizeCache protoimpl.SizeCache sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields unknownFields protoimpl.UnknownFields
OpCode int32 `protobuf:"varint,1,opt,name=OpCode,proto3" json:"OpCode,omitempty"` // 1:确定牌 2站起状态 3test 4重新选牌 5加入游戏 6预选 OpCode int32 `protobuf:"varint,1,opt,name=OpCode,proto3" json:"OpCode,omitempty"` // 1:确定牌 2站起状态 3test 4重新选牌 5加入游戏 6预选 7自动手动切换(1自动2手动)
// 确定牌时,两种参数规则,都可以 // 确定牌时,两种参数规则,都可以
// 第一种玩家从推荐牌型中选择一个把Poker.IndexType发过来减少数据传输 // 第一种玩家从推荐牌型中选择一个把Poker.IndexType发过来减少数据传输
// 第二种:按头墩中墩尾墩顺序把牌发过来 // 第二种:按头墩中墩尾墩顺序把牌发过来

View File

@ -73,7 +73,7 @@ message SCThirteenPlayerCards {
// //
//PACKET_CSThirteenPlayerOp //PACKET_CSThirteenPlayerOp
message CSThirteenPlayerOp { message CSThirteenPlayerOp {
int32 OpCode = 1; // 1: 2 3test 4 5 6 int32 OpCode = 1; // 1: 2 3test 4 5 6 7(12)
// , // ,
// Poker.IndexType发过来 // Poker.IndexType发过来

View File

@ -24,4 +24,9 @@ update_invite_num: 30
# 几秒读取一次道具日志 # 几秒读取一次道具日志
update_second_item: 10 update_second_item: 10
# 一次最多读取多少道具日志 # 一次最多读取多少道具日志
update_item_num: 100 update_item_num: 100
# rabbitmq配置
rabbitmq:
url: amqp://win88:123456@127.0.0.1:5672/win99
exchange: win99

View File

@ -15,9 +15,10 @@ import (
"mongo.games.com/goserver/core/utils" "mongo.games.com/goserver/core/utils"
"mongo.games.com/goserver/core/viperx" "mongo.games.com/goserver/core/viperx"
"mongo.games.com/game/mq"
mongomodel "mongo.games.com/game/statistics/modelmongo" mongomodel "mongo.games.com/game/statistics/modelmongo"
mysqlmodel "mongo.games.com/game/statistics/modelmysql" mysqlmodel "mongo.games.com/game/statistics/modelmysql"
"mongo.games.com/game/statistics/static" _ "mongo.games.com/game/statistics/mq"
"mongo.games.com/game/statistics/syn" "mongo.games.com/game/statistics/syn"
) )
@ -92,26 +93,32 @@ func main() {
mysqlx.SetAutoMigrateTables(mysqlmodel.Tables) mysqlx.SetAutoMigrateTables(mysqlmodel.Tables)
// mq
mq.StartConsumer(VP.GetString("rabbitmq.url"), VP.GetString("rabbitmq.exchange"), true)
wg := &sync.WaitGroup{} wg := &sync.WaitGroup{}
ctx, cancel := context.WithCancel(context.Background()) ctx, cancel := context.WithCancel(context.Background())
// 同步注册和登录日志
DoTick(ctx, wg, time.Duration(VP.GetInt64("update_second"))*time.Second, SyncSnId) DoTick(ctx, wg, time.Duration(VP.GetInt64("update_second"))*time.Second, SyncSnId)
DoTick(ctx, wg, time.Duration(VP.GetInt64("update_second_snid"))*time.Second, func(ctx context.Context) { //DoTick(ctx, wg, time.Duration(VP.GetInt64("update_second_snid"))*time.Second, func(ctx context.Context) {
wg := new(sync.WaitGroup) // wg := new(sync.WaitGroup)
for _, v := range VP.GetStringSlice("platforms") { // for _, v := range VP.GetStringSlice("platforms") {
platform := v // platform := v
wg.Add(1) // wg.Add(1)
go func() { // go func() {
defer wg.Done() // defer wg.Done()
Static(platform) // Static(platform)
}() // }()
} // }
wg.Wait() // wg.Wait()
}) //})
// 同步邀请数据
DoTick(ctx, wg, time.Duration(VP.GetInt64("update_second_invite"))*time.Second, SyncInvite) DoTick(ctx, wg, time.Duration(VP.GetInt64("update_second_invite"))*time.Second, SyncInvite)
// 同步道具日志数据
DoTickPlatform(ctx, wg, time.Duration(VP.GetInt64("update_second_item"))*time.Second, VP.GetInt("update_item_num"), DoTickPlatform(ctx, wg, time.Duration(VP.GetInt64("update_second_item"))*time.Second, VP.GetInt("update_item_num"),
func(ctx context.Context, platform string, batchSize int) { func(ctx context.Context, platform string, batchSize int) {
err := syn.ItemGainDone(&syn.Data[mongomodel.ItemLog]{ err := syn.ItemGainDone(&syn.Data[mongomodel.ItemLog]{
@ -123,7 +130,7 @@ func main() {
} }
}) })
logger.Logger.Info("start") logger.Logger.Info("start success")
c := make(chan os.Signal, 1) c := make(chan os.Signal, 1)
signal.Notify(c, os.Interrupt, os.Kill) signal.Notify(c, os.Interrupt, os.Kill)
@ -162,36 +169,36 @@ func SyncSnId(ctx context.Context) {
} }
// Static 玩家id触发数据统计 // Static 玩家id触发数据统计
func Static(platform string) { //func Static(platform string) {
// 查询需要更新的玩家id // // 查询需要更新的玩家id
var ids []*mysqlmodel.UserID // var ids []*mysqlmodel.UserID
db, err := mysqlx.GetDatabase(platform) // db, err := mysqlx.GetDatabase(platform)
if err != nil { // if err != nil {
logger.Logger.Errorf("GetDatabase error: %v", err) // logger.Logger.Errorf("GetDatabase error: %v", err)
return // return
} // }
if err := db.Limit(VP.GetInt("update_snid_num")).Find(&ids).Error; err != nil { // if err := db.Limit(VP.GetInt("update_snid_num")).Find(&ids).Error; err != nil {
logger.Logger.Warnf("Get UserID error: %v", err) // logger.Logger.Warnf("Get UserID error: %v", err)
return // return
} // }
//
if len(ids) == 0 { // if len(ids) == 0 {
logger.Logger.Tracef("Static: no need to update") // logger.Logger.Tracef("Static: no need to update")
return // return
} // }
//
// 统计玩家跳出记录 // // 统计玩家跳出记录
if err := static.UserLogin(platform, ids); err != nil { // //if err := static.UserLogin(platform, ids); err != nil {
logger.Logger.Errorf("StaticUserLogin error: %v", err) // // logger.Logger.Errorf("StaticUserLogin error: %v", err)
return // // return
} // //}
//
// 删除更新过的玩家id // // 删除更新过的玩家id
if err := db.Delete(ids).Error; err != nil { // if err := db.Delete(ids).Error; err != nil {
logger.Logger.Errorf("Delete error: %v", err) // logger.Logger.Errorf("Delete error: %v", err)
return // return
} // }
} //}
// SyncInvite 同步邀请数据 // SyncInvite 同步邀请数据
func SyncInvite(ctx context.Context) { func SyncInvite(ctx context.Context) {

View File

@ -1,5 +1,7 @@
package modelmysql package modelmysql
import "mongo.games.com/game/model"
// 需要自动迁移的表添加在这里 Tables // 需要自动迁移的表添加在这里 Tables
var Tables = []interface{}{ var Tables = []interface{}{
@ -14,4 +16,5 @@ var Tables = []interface{}{
&LogMid{}, &LogMid{},
&ItemGain{}, &ItemGain{},
&ItemTotalGain{}, &ItemTotalGain{},
&model.ThirteenAutoLog{},
} }

View File

@ -1 +1,35 @@
package mq package mq
import (
"mongo.games.com/goserver/core/logger"
"mongo.games.com/goserver/core/mysqlx"
"mongo.games.com/game/model"
"mongo.games.com/game/mq"
)
func init() {
mq.RegisterHandler(&mq.RegisterHandlerParam{
Name: mq.BackThirteenAutoLog,
Data: &model.ThirteenAutoLog{},
Handler: func(data interface{}) (err error) {
d, ok := data.(*model.ThirteenAutoLog)
if !ok {
return nil
}
db, err := mysqlx.GetDatabase(d.Platform)
if err != nil {
logger.Logger.Errorf("mysql: SyncThirteenAutoLog failed to get database: %v", err)
return err
}
if err = db.Create(d).Error; err != nil {
logger.Logger.Errorf("mysql: SyncThirteenAutoLog failed to create thirteen_auto_log: %v", err)
return err
}
return nil
},
})
}

View File

@ -1,371 +1,355 @@
package static package static
import ( //func getAccountTel(platform string, id int) (string, error) {
"context" // acc := &mongomodel.Account{}
"errors" // cc, err := mymongo.GetUserCollection(platform, mongomodel.UserAccount)
// if err != nil {
"go.mongodb.org/mongo-driver/bson" // logger.Logger.Errorf("get collection %s error %v", mongomodel.UserAccount, err)
"go.mongodb.org/mongo-driver/mongo" // return "", err
"go.mongodb.org/mongo-driver/mongo/options" // }
"mongo.games.com/goserver/core/logger" // dd := cc.FindOne(context.TODO(), bson.M{"snid": id}, options.FindOne().SetProjection(bson.M{"tel": 1}))
// err = dd.Err()
mymongo "mongo.games.com/goserver/core/mongox" // if err != nil {
mymysql "mongo.games.com/goserver/core/mysqlx" // if errors.Is(err, mongo.ErrNoDocuments) {
// logger.Logger.Tracef("getAccountTel %v not found in user_account", id)
mongomodel "mongo.games.com/game/statistics/modelmongo" // return "", nil
mysqlmodel "mongo.games.com/game/statistics/modelmysql" // }
) // logger.Logger.Errorf("getAccountTel %v get user_account err: %v", id, err)
// return "", err
func getAccountTel(platform string, id int) (string, error) { // }
acc := &mongomodel.Account{} // if err := dd.Decode(acc); err != nil {
cc, err := mymongo.GetUserCollection(platform, mongomodel.UserAccount) // logger.Logger.Errorf("getAccountTel %v decode user_account err: %v", id, err)
if err != nil { // return "", err
logger.Logger.Errorf("get collection %s error %v", mongomodel.UserAccount, err) // }
return "", err // return acc.Tel, nil
} //}
dd := cc.FindOne(context.TODO(), bson.M{"snid": id}, options.FindOne().SetProjection(bson.M{"tel": 1})) //
err = dd.Err() //// 游戏结束离开
if err != nil { //func checkGameOver(db *mymysql.Database, login *mysqlmodel.UserLogin, platform string, id int) (bool, error) {
if errors.Is(err, mongo.ErrNoDocuments) { // // 最早的一条掉线记录并且是游戏结束离开
logger.Logger.Tracef("getAccountTel %v not found in user_account", id) // a := &mongomodel.LoginLog{}
return "", nil // c, err := mymongo.GetLogCollection(platform, mongomodel.LogLogin)
} // if err != nil {
logger.Logger.Errorf("getAccountTel %v get user_account err: %v", id, err) // logger.Logger.Errorf("get collection %s error %v", mongomodel.LogLogin, err)
return "", err // return false, err
} // }
if err := dd.Decode(acc); err != nil { // d := c.FindOne(context.TODO(), bson.M{"snid": id, "logtype": mongomodel.LogTypeDrop, "gameid": 0, "lastgameid": bson.D{{"$gt", 0}}},
logger.Logger.Errorf("getAccountTel %v decode user_account err: %v", id, err) // options.FindOne().SetSort(bson.D{{"time", 1}}))
return "", err // err = d.Err()
} // if err != nil {
return acc.Tel, nil // if errors.Is(err, mongo.ErrNoDocuments) {
} // logger.Logger.Tracef("checkGameOver %v not found in log_login", id)
// return false, nil
// 游戏结束离开 // }
func checkGameOver(db *mymysql.Database, login *mysqlmodel.UserLogin, platform string, id int) (bool, error) { // logger.Logger.Errorf("checkGameOver %v get log_login err: %v", id, err)
// 最早的一条掉线记录并且是游戏结束离开 // return false, err
a := &mongomodel.LoginLog{} // }
c, err := mymongo.GetLogCollection(platform, mongomodel.LogLogin) // if err := d.Decode(a); err != nil {
if err != nil { // logger.Logger.Errorf("checkGameOver %v decode log_login err: %v", id, err)
logger.Logger.Errorf("get collection %s error %v", mongomodel.LogLogin, err) // return false, err
return false, err // }
} //
d := c.FindOne(context.TODO(), bson.M{"snid": id, "logtype": mongomodel.LogTypeDrop, "gameid": 0, "lastgameid": bson.D{{"$gt", 0}}}, // // account tel
options.FindOne().SetSort(bson.D{{"time", 1}})) // tel, err := getAccountTel(platform, id)
err = d.Err() // if err != nil {
if err != nil { // logger.Logger.Warnf("get account tel %v err: %v", id, err)
if errors.Is(err, mongo.ErrNoDocuments) { // }
logger.Logger.Tracef("checkGameOver %v not found in log_login", id) //
return false, nil // update := &mysqlmodel.UserLogin{
} // //OfflineTs: int(a.Ts),
logger.Logger.Errorf("checkGameOver %v get log_login err: %v", id, err) // OfflineTime: a.Time,
return false, err // OutType: mysqlmodel.OutTypeGameOver,
} // GameID: a.LastGameID,
if err := d.Decode(a); err != nil { // Tel: tel,
logger.Logger.Errorf("checkGameOver %v decode log_login err: %v", id, err) // DeviceName: a.DeviceName,
return false, err // AppVersion: a.AppVersion,
} // BuildVersion: a.BuildVersion,
// AppChannel: a.AppChannel,
// account tel // ChannelId: a.ChannelId,
tel, err := getAccountTel(platform, id) // }
if err != nil { //
logger.Logger.Warnf("get account tel %v err: %v", id, err) // if err := db.Model(login).Select(
} // "OfflineTime", "OutType", "GameID", "DeviceName", "AppVersion", "BuildVersion", "AppChannel", "Tel",
// ).Updates(update).Error; err != nil {
update := &mysqlmodel.UserLogin{ // logger.Logger.Errorf("checkLogin %v update user_login err: %v", id, err)
//OfflineTs: int(a.Ts), // return false, err
OfflineTime: a.Time, // }
OutType: mysqlmodel.OutTypeGameOver, //
GameID: a.LastGameID, // return true, nil
Tel: tel, //}
DeviceName: a.DeviceName, //
AppVersion: a.AppVersion, //// 游戏中离开
BuildVersion: a.BuildVersion, //func checkGaming(db *mymysql.Database, login *mysqlmodel.UserLogin, platform string, id int) (bool, error) {
AppChannel: a.AppChannel, // // 最早的一条掉线记录并且是游戏中掉线
ChannelId: a.ChannelId, // a := &mongomodel.LoginLog{}
} // c, err := mymongo.GetLogCollection(platform, mongomodel.LogLogin)
// if err != nil {
if err := db.Model(login).Select( // logger.Logger.Errorf("get collection %s error %v", mongomodel.LogLogin, err)
"OfflineTime", "OutType", "GameID", "DeviceName", "AppVersion", "BuildVersion", "AppChannel", "Tel", // return false, err
).Updates(update).Error; err != nil { // }
logger.Logger.Errorf("checkLogin %v update user_login err: %v", id, err) // d := c.FindOne(context.TODO(), bson.M{"snid": id, "logtype": mongomodel.LogTypeDrop, "gameid": bson.D{{"$gt", 0}}},
return false, err // options.FindOne().SetSort(bson.D{{"time", 1}}))
} // err = d.Err()
// if err != nil {
return true, nil // if errors.Is(err, mongo.ErrNoDocuments) {
} // logger.Logger.Tracef("checkGaming %v not found in log_login", id)
// return false, nil
// 游戏中离开 // }
func checkGaming(db *mymysql.Database, login *mysqlmodel.UserLogin, platform string, id int) (bool, error) { // logger.Logger.Errorf("checkGaming %v get log_login err: %v", id, err)
// 最早的一条掉线记录并且是游戏中掉线 // return false, err
a := &mongomodel.LoginLog{} // }
c, err := mymongo.GetLogCollection(platform, mongomodel.LogLogin) // if err := d.Decode(a); err != nil {
if err != nil { // logger.Logger.Errorf("checkGaming %v decode log_login err: %v", id, err)
logger.Logger.Errorf("get collection %s error %v", mongomodel.LogLogin, err) // return false, err
return false, err // }
} //
d := c.FindOne(context.TODO(), bson.M{"snid": id, "logtype": mongomodel.LogTypeDrop, "gameid": bson.D{{"$gt", 0}}}, // // account tel
options.FindOne().SetSort(bson.D{{"time", 1}})) // tel, err := getAccountTel(platform, id)
err = d.Err() // if err != nil {
if err != nil { // logger.Logger.Warnf("get account tel %v err: %v", id, err)
if errors.Is(err, mongo.ErrNoDocuments) { // }
logger.Logger.Tracef("checkGaming %v not found in log_login", id) //
return false, nil // update := &mysqlmodel.UserLogin{
} // //OfflineTs: int(a.Ts),
logger.Logger.Errorf("checkGaming %v get log_login err: %v", id, err) // OfflineTime: a.Time,
return false, err // OutType: mysqlmodel.OutTypeGaming,
} // GameID: a.GameId,
if err := d.Decode(a); err != nil { // Tel: tel,
logger.Logger.Errorf("checkGaming %v decode log_login err: %v", id, err) // DeviceName: a.DeviceName,
return false, err // AppVersion: a.AppVersion,
} // BuildVersion: a.BuildVersion,
// AppChannel: a.AppChannel,
// account tel // ChannelId: a.ChannelId,
tel, err := getAccountTel(platform, id) // }
if err != nil { //
logger.Logger.Warnf("get account tel %v err: %v", id, err) // if err := db.Model(login).Select(
} // "OfflineTime", "OutType", "GameID", "DeviceName", "AppVersion", "BuildVersion", "AppChannel", "Tel",
// ).Updates(update).Error; err != nil {
update := &mysqlmodel.UserLogin{ // logger.Logger.Errorf("checkLogin %v update user_login err: %v", id, err)
//OfflineTs: int(a.Ts), // return false, err
OfflineTime: a.Time, // }
OutType: mysqlmodel.OutTypeGaming, //
GameID: a.GameId, // return true, nil
Tel: tel, //}
DeviceName: a.DeviceName, //
AppVersion: a.AppVersion, //// 登录后离开
BuildVersion: a.BuildVersion, //func checkLogin(db *mymysql.Database, login *mysqlmodel.UserLogin, platform string, id int) (bool, error) {
AppChannel: a.AppChannel, // // 最早的一条掉线记录
ChannelId: a.ChannelId, // a := &mongomodel.LoginLog{}
} // c, err := mymongo.GetLogCollection(platform, mongomodel.LogLogin)
// if err != nil {
if err := db.Model(login).Select( // logger.Logger.Errorf("get collection %s error %v", mongomodel.LogLogin, err)
"OfflineTime", "OutType", "GameID", "DeviceName", "AppVersion", "BuildVersion", "AppChannel", "Tel", // return false, err
).Updates(update).Error; err != nil { // }
logger.Logger.Errorf("checkLogin %v update user_login err: %v", id, err) // d := c.FindOne(context.TODO(), bson.M{"snid": id, "logtype": mongomodel.LogTypeDrop}, options.FindOne().SetSort(bson.D{{"time", 1}}))
return false, err // err = d.Err()
} // if err != nil {
// if errors.Is(err, mongo.ErrNoDocuments) {
return true, nil // logger.Logger.Tracef("checkLogin %v not found in log_login", id)
} // return false, nil
// }
// 登录后离开 // logger.Logger.Errorf("checkLogin %v get log_login err: %v", id, err)
func checkLogin(db *mymysql.Database, login *mysqlmodel.UserLogin, platform string, id int) (bool, error) { // return false, err
// 最早的一条掉线记录 // }
a := &mongomodel.LoginLog{} // if err := d.Decode(a); err != nil {
c, err := mymongo.GetLogCollection(platform, mongomodel.LogLogin) // logger.Logger.Errorf("checkLogin %v decode log_login err: %v", id, err)
if err != nil { // return false, err
logger.Logger.Errorf("get collection %s error %v", mongomodel.LogLogin, err) // }
return false, err //
} // // account tel
d := c.FindOne(context.TODO(), bson.M{"snid": id, "logtype": mongomodel.LogTypeDrop}, options.FindOne().SetSort(bson.D{{"time", 1}})) // tel, err := getAccountTel(platform, id)
err = d.Err() // if err != nil {
if err != nil { // logger.Logger.Warnf("get account tel %v err: %v", id, err)
if errors.Is(err, mongo.ErrNoDocuments) { // }
logger.Logger.Tracef("checkLogin %v not found in log_login", id) //
return false, nil // update := &mysqlmodel.UserLogin{
} // //OfflineTs: int(a.Ts),
logger.Logger.Errorf("checkLogin %v get log_login err: %v", id, err) // OfflineTime: a.Time,
return false, err // OutType: mysqlmodel.OutTypeLogin,
} // Tel: tel,
if err := d.Decode(a); err != nil { // DeviceName: a.DeviceName,
logger.Logger.Errorf("checkLogin %v decode log_login err: %v", id, err) // AppVersion: a.AppVersion,
return false, err // BuildVersion: a.BuildVersion,
} // AppChannel: a.AppChannel,
// ChannelId: a.ChannelId,
// account tel // }
tel, err := getAccountTel(platform, id) //
if err != nil { // if err := db.Model(login).Select(
logger.Logger.Warnf("get account tel %v err: %v", id, err) // "OfflineTime", "OutType", "DeviceName", "AppVersion", "BuildVersion", "AppChannel", "Tel",
} // ).Updates(update).Error; err != nil {
// logger.Logger.Errorf("checkLogin %v update user_login err: %v", id, err)
update := &mysqlmodel.UserLogin{ // return false, err
//OfflineTs: int(a.Ts), // }
OfflineTime: a.Time, //
OutType: mysqlmodel.OutTypeLogin, // return true, nil
Tel: tel, //}
DeviceName: a.DeviceName, //
AppVersion: a.AppVersion, //// 注册后离开
BuildVersion: a.BuildVersion, //func checkRegister(db *mymysql.Database, login *mysqlmodel.UserLogin, platform string, id int) (bool, error) {
AppChannel: a.AppChannel, // a := &mongomodel.Account{}
ChannelId: a.ChannelId, // c, err := mymongo.GetUserCollection(platform, mongomodel.UserAccount)
} // if err != nil {
// logger.Logger.Errorf("get collection %s error %v", mongomodel.UserAccount, err)
if err := db.Model(login).Select( // return false, err
"OfflineTime", "OutType", "DeviceName", "AppVersion", "BuildVersion", "AppChannel", "Tel", // }
).Updates(update).Error; err != nil { // d := c.FindOne(context.TODO(), bson.M{"snid": id})
logger.Logger.Errorf("checkLogin %v update user_login err: %v", id, err) // err = d.Err()
return false, err // if err != nil {
} // if errors.Is(err, mongo.ErrNoDocuments) {
// logger.Logger.Warnf("checkRegister %v not found in user_account", id)
return true, nil // return false, nil
} // }
// logger.Logger.Errorf("checkRegister %v get user_account err: %v", id, err)
// 注册后离开 // return false, err
func checkRegister(db *mymysql.Database, login *mysqlmodel.UserLogin, platform string, id int) (bool, error) { // }
a := &mongomodel.Account{} // if err := d.Decode(a); err != nil {
c, err := mymongo.GetUserCollection(platform, mongomodel.UserAccount) // logger.Logger.Errorf("checkRegister %v decode user_account err: %v", id, err)
if err != nil { // return false, err
logger.Logger.Errorf("get collection %s error %v", mongomodel.UserAccount, err) // }
return false, err //
} // // account tel
d := c.FindOne(context.TODO(), bson.M{"snid": id}) // tel, err := getAccountTel(platform, id)
err = d.Err() // if err != nil {
if err != nil { // logger.Logger.Warnf("get account tel %v err: %v", id, err)
if errors.Is(err, mongo.ErrNoDocuments) { // }
logger.Logger.Warnf("checkRegister %v not found in user_account", id) //
return false, nil // login.Snid = id
} // //login.OnlineTs = int(a.RegisterTs)
logger.Logger.Errorf("checkRegister %v get user_account err: %v", id, err) // login.OnlineTime = a.RegisteTime
return false, err // //login.OfflineTs = int(a.RegisterTs)
} // login.OfflineTime = a.RegisteTime
if err := d.Decode(a); err != nil { // login.OutType = mysqlmodel.OutTypRegister
logger.Logger.Errorf("checkRegister %v decode user_account err: %v", id, err) // login.Tel = tel
return false, err // login.DeviceName = a.DeviceName
} // login.AppVersion = a.AppVersion
// login.BuildVersion = a.BuildVersion
// account tel // login.AppChannel = a.AppChannel
tel, err := getAccountTel(platform, id) // login.ChannelId = a.ChannelId
if err != nil { //
logger.Logger.Warnf("get account tel %v err: %v", id, err) // if err := db.Create(login).Error; err != nil {
} // logger.Logger.Errorf("checkRegister create err: %v", err)
// return false, err
login.Snid = id // }
//login.OnlineTs = int(a.RegisterTs) // return true, nil
login.OnlineTime = a.RegisteTime //}
//login.OfflineTs = int(a.RegisterTs)
login.OfflineTime = a.RegisteTime
login.OutType = mysqlmodel.OutTypRegister
login.Tel = tel
login.DeviceName = a.DeviceName
login.AppVersion = a.AppVersion
login.BuildVersion = a.BuildVersion
login.AppChannel = a.AppChannel
login.ChannelId = a.ChannelId
if err := db.Create(login).Error; err != nil {
logger.Logger.Errorf("checkRegister create err: %v", err)
return false, err
}
return true, nil
}
// UserLogin 玩家跳出统计 // UserLogin 玩家跳出统计
func UserLogin(platform string, ids []*mysqlmodel.UserID) error { //func UserLogin(platform string, ids []*mysqlmodel.UserID) error {
f := func(id int) error { // f := func(id int) error {
// 玩家是否已经统计结束,已经是游戏结束状态 // // 玩家是否已经统计结束,已经是游戏结束状态
login := &mysqlmodel.UserLogin{} // login := &mysqlmodel.UserLogin{}
db, err := mymysql.GetDatabase(platform) // db, err := mymysql.GetDatabase(platform)
if err != nil { // if err != nil {
logger.Logger.Errorf("UserLogin get db err: %v", err) // logger.Logger.Errorf("UserLogin get db err: %v", err)
return err // return err
} // }
if err = db.Where("snid = ?", id).Find(login).Error; err != nil { // if err = db.Where("snid = ?", id).Find(login).Error; err != nil {
logger.Logger.Errorf("UserLogin find %v err: %v", id, err) // logger.Logger.Errorf("UserLogin find %v err: %v", id, err)
return err // return err
} // }
//
switch login.OutType { // switch login.OutType {
case mysqlmodel.OutTypeGameOver: // case mysqlmodel.OutTypeGameOver:
return nil // return nil
//
case mysqlmodel.OutTypeGaming: // case mysqlmodel.OutTypeGaming:
_, err := checkGameOver(db, login, platform, id) // _, err := checkGameOver(db, login, platform, id)
if err != nil { // if err != nil {
logger.Logger.Errorf("UserLogin checkGameOver %v err: %v", id, err) // logger.Logger.Errorf("UserLogin checkGameOver %v err: %v", id, err)
return err // return err
} // }
return nil // return nil
//
case mysqlmodel.OutTypeLogin: // case mysqlmodel.OutTypeLogin:
ret, err := checkGameOver(db, login, platform, id) // ret, err := checkGameOver(db, login, platform, id)
if err != nil { // if err != nil {
logger.Logger.Errorf("UserLogin checkGameOver %v err: %v", id, err) // logger.Logger.Errorf("UserLogin checkGameOver %v err: %v", id, err)
return err // return err
} // }
if ret { // if ret {
return nil // return nil
} // }
ret, err = checkGaming(db, login, platform, id) // ret, err = checkGaming(db, login, platform, id)
if err != nil { // if err != nil {
logger.Logger.Errorf("UserLogin checkGaming %v err: %v", id, err) // logger.Logger.Errorf("UserLogin checkGaming %v err: %v", id, err)
return err // return err
} // }
if ret { // if ret {
return nil // return nil
} // }
//
case mysqlmodel.OutTypRegister: // case mysqlmodel.OutTypRegister:
ret, err := checkGameOver(db, login, platform, id) // ret, err := checkGameOver(db, login, platform, id)
if err != nil { // if err != nil {
logger.Logger.Errorf("UserLogin checkGameOver %v err: %v", id, err) // logger.Logger.Errorf("UserLogin checkGameOver %v err: %v", id, err)
return err // return err
} // }
if ret { // if ret {
return nil // return nil
} // }
ret, err = checkGaming(db, login, platform, id) // ret, err = checkGaming(db, login, platform, id)
if err != nil { // if err != nil {
logger.Logger.Errorf("UserLogin checkGaming %v err: %v", id, err) // logger.Logger.Errorf("UserLogin checkGaming %v err: %v", id, err)
return err // return err
} // }
if ret { // if ret {
return nil // return nil
} // }
ret, err = checkLogin(db, login, platform, id) // ret, err = checkLogin(db, login, platform, id)
if err != nil { // if err != nil {
logger.Logger.Errorf("UserLogin checkLogin %v err: %v", id, err) // logger.Logger.Errorf("UserLogin checkLogin %v err: %v", id, err)
return err // return err
} // }
if ret { // if ret {
return nil // return nil
} // }
//
default: // default:
ret, err := checkRegister(db, login, platform, id) // ret, err := checkRegister(db, login, platform, id)
if err != nil { // if err != nil {
logger.Logger.Errorf("UserLogin checkRegister %v err: %v", id, err) // logger.Logger.Errorf("UserLogin checkRegister %v err: %v", id, err)
return err // return err
} // }
if !ret { // if !ret {
logger.Logger.Warnf("UserLogin not found user_account checkRegister %v err: %v", id, err) // logger.Logger.Warnf("UserLogin not found user_account checkRegister %v err: %v", id, err)
return nil // return nil
} // }
//
ret, err = checkGameOver(db, login, platform, id) // ret, err = checkGameOver(db, login, platform, id)
if err != nil { // if err != nil {
logger.Logger.Errorf("UserLogin checkGameOver %v err: %v", id, err) // logger.Logger.Errorf("UserLogin checkGameOver %v err: %v", id, err)
return err // return err
} // }
if ret { // if ret {
return nil // return nil
} // }
ret, err = checkGaming(db, login, platform, id) // ret, err = checkGaming(db, login, platform, id)
if err != nil { // if err != nil {
logger.Logger.Errorf("UserLogin checkGaming %v err: %v", id, err) // logger.Logger.Errorf("UserLogin checkGaming %v err: %v", id, err)
return err // return err
} // }
if ret { // if ret {
return nil // return nil
} // }
ret, err = checkLogin(db, login, platform, id) // ret, err = checkLogin(db, login, platform, id)
if err != nil { // if err != nil {
logger.Logger.Errorf("UserLogin checkLogin %v err: %v", id, err) // logger.Logger.Errorf("UserLogin checkLogin %v err: %v", id, err)
return err // return err
} // }
if ret { // if ret {
return nil // return nil
} // }
return nil // return nil
} // }
//
return nil // return nil
} // }
//
for _, v := range ids { // for _, v := range ids {
if err := f(v.Snid); err != nil { // if err := f(v.Snid); err != nil {
return err // return err
} // }
} // }
//
return nil // return nil
} //}

View File

@ -9,12 +9,12 @@ import (
"go.mongodb.org/mongo-driver/mongo" "go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options" "go.mongodb.org/mongo-driver/mongo/options"
"gorm.io/gorm" "gorm.io/gorm"
mongomodel "mongo.games.com/game/statistics/modelmongo"
mysqlmodel "mongo.games.com/game/statistics/modelmysql"
"mongo.games.com/goserver/core/logger" "mongo.games.com/goserver/core/logger"
mymongo "mongo.games.com/goserver/core/mongox" mymongo "mongo.games.com/goserver/core/mongox"
mymysql "mongo.games.com/goserver/core/mysqlx" mymysql "mongo.games.com/goserver/core/mysqlx"
mongomodel "mongo.games.com/game/statistics/modelmongo"
mysqlmodel "mongo.games.com/game/statistics/modelmysql"
) )
/* /*
@ -155,19 +155,19 @@ func LogLogin(platform string, batchSize int) ([]*mysqlmodel.LogLogin, error) {
return err return err
} }
for _, v := range ls { //for _, v := range ls {
if err = tx.First(&mysqlmodel.UserID{}, "snid = ?", v.Snid).Error; err != nil && !errors.Is(err, gorm.ErrRecordNotFound) { // if err = tx.First(&mysqlmodel.UserID{}, "snid = ?", v.Snid).Error; err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
logger.Logger.Errorf("mysql: SyncLogLogin failed to find user_id: %v", err) // logger.Logger.Errorf("mysql: SyncLogLogin failed to find user_id: %v", err)
return err // return err
} // }
//
if errors.Is(err, gorm.ErrRecordNotFound) { // if errors.Is(err, gorm.ErrRecordNotFound) {
if err = tx.Create(&mysqlmodel.UserID{Snid: v.Snid}).Error; err != nil { // if err = tx.Create(&mysqlmodel.UserID{Snid: v.Snid}).Error; err != nil {
logger.Logger.Errorf("mysql: SyncLogLogin failed to create user_id: %v", err) // logger.Logger.Errorf("mysql: SyncLogLogin failed to create user_id: %v", err)
return err // return err
} // }
} // }
} //}
return nil return nil
}) })

View File

@ -1 +1,3 @@
游戏服mongodb同步到mysql 游戏服mongodb同步到mysql
datasync.go 同步模型

View File

@ -1,17 +1,18 @@
StartTime: "2024-11-26T00:00:00+08:00" StartTime: "2024-12-19T00:00:00+08:00"
EndTime: "2024-11-27T00:00:00+08:00" EndTime: "2024-12-20T00:00:00+08:00"
Switch: # 1: open, 0: close Switch: # 1: open, 0: close
- 0 # 新用户游戏破产率 - 0 # 新用户游戏破产率
- 0 # 新用户平均游戏时长 - 0 # 新用户平均游戏时长
- 1 # 用户平均游戏时长
- 0 # 新用户平均局数 - 0 # 新用户平均局数
- 0 # 平均倍数 - 0 # 平均倍数
- 1 # 活跃破产率 - 0 # 活跃破产率
- 1 # 控输赢胜率 - 0 # 控输赢胜率
- 1 # 机器人胜率 - 0 # 机器人胜率
- 1 # 人均获得金币 - 0 # 人均获得金币
- 1 # 破产后离线 - 0 # 破产后离线
- 1 # 充值玩家金币余额 - 0 # 充值玩家金币余额
Gamefreeids: Gamefreeids:
- 2070001 - 2070001

View File

@ -18,6 +18,7 @@ import (
const ( const (
ExcelTypeNewPlayerBankrupt = iota // 新用户游戏破产率 ExcelTypeNewPlayerBankrupt = iota // 新用户游戏破产率
ExcelTypeGameTimeAvg // 新用户平均游戏时长 ExcelTypeGameTimeAvg // 新用户平均游戏时长
ExcelTypeGameTimeAllAvg // 用户平均游戏时长
ExcelTypeGameCountAvg // 新用户平均局数 ExcelTypeGameCountAvg // 新用户平均局数
ExcelTypeGameRate // 平均倍数 ExcelTypeGameRate // 平均倍数
ExcelTypeActiveRate // 活跃破产率 ExcelTypeActiveRate // 活跃破产率
@ -71,6 +72,7 @@ func main() {
mgr := NewExcelMgr() mgr := NewExcelMgr()
mgr.Register(ExcelTypeNewPlayerBankrupt, []string{"日期", "场次id", "破产人数", "参与人数", "破产率"}) mgr.Register(ExcelTypeNewPlayerBankrupt, []string{"日期", "场次id", "破产人数", "参与人数", "破产率"})
mgr.Register(ExcelTypeGameTimeAvg, []string{"日期", "场次id", "参与人数", "平均游戏时长"}) mgr.Register(ExcelTypeGameTimeAvg, []string{"日期", "场次id", "参与人数", "平均游戏时长"})
mgr.Register(ExcelTypeGameTimeAllAvg, []string{"日期", "场次id", "参与人数", "平均游戏时长"})
mgr.Register(ExcelTypeGameCountAvg, []string{"日期", "场次id", "参与人数", "平均局数"}) mgr.Register(ExcelTypeGameCountAvg, []string{"日期", "场次id", "参与人数", "平均局数"})
mgr.Register(ExcelTypeGameRate, []string{"日期", "场次id", "总局数", "平均倍数", "有炸弹分局数", "炸弹分平均倍数", "2留在手里的局数"}) mgr.Register(ExcelTypeGameRate, []string{"日期", "场次id", "总局数", "平均倍数", "有炸弹分局数", "炸弹分平均倍数", "2留在手里的局数"})
mgr.Register(ExcelTypeActiveRate, []string{"日期", "场次id", "破产人数", "参与人数", "破产率"}) mgr.Register(ExcelTypeActiveRate, []string{"日期", "场次id", "破产人数", "参与人数", "破产率"})
@ -99,6 +101,10 @@ func main() {
// 新用户平均游戏时长 // 新用户平均游戏时长
mgr.GenNewPlayerGameTimeAvgExcel("1", startTimeStr, endTimeStr) mgr.GenNewPlayerGameTimeAvgExcel("1", startTimeStr, endTimeStr)
} }
if switchArr[ExcelTypeGameTimeAllAvg] == 1 {
// 用户平均游戏时长
mgr.GenPlayerGameTimeAvgExcel("1", startTimeStr, endTimeStr)
}
if switchArr[ExcelTypeGameCountAvg] == 1 { if switchArr[ExcelTypeGameCountAvg] == 1 {
// 新用户平均局数 // 新用户平均局数
mgr.GenGameCountExcel("1", startTimeStr, endTimeStr) mgr.GenGameCountExcel("1", startTimeStr, endTimeStr)
@ -144,7 +150,10 @@ func (e *ExcelMgr) SaveAll(startTime, endTime string) {
e.Save(ExcelTypeNewPlayerBankrupt, fmt.Sprintf("新用户破产率_%s_%s.xlsx", startTime, endTime)) e.Save(ExcelTypeNewPlayerBankrupt, fmt.Sprintf("新用户破产率_%s_%s.xlsx", startTime, endTime))
} }
if switchArr[ExcelTypeGameTimeAvg] == 1 { if switchArr[ExcelTypeGameTimeAvg] == 1 {
e.Save(ExcelTypeGameTimeAvg, fmt.Sprintf("新用户平局游戏时长_%s_%s.xlsx", startTime, endTime)) e.Save(ExcelTypeGameTimeAvg, fmt.Sprintf("新用户平均游戏时长_%s_%s.xlsx", startTime, endTime))
}
if switchArr[ExcelTypeGameTimeAllAvg] == 1 {
e.Save(ExcelTypeGameTimeAllAvg, fmt.Sprintf("用户平均游戏时长_%s_%s.xlsx", startTime, endTime))
} }
if switchArr[ExcelTypeGameCountAvg] == 1 { if switchArr[ExcelTypeGameCountAvg] == 1 {
e.Save(ExcelTypeGameCountAvg, fmt.Sprintf("新用户平均局数_%s_%s.xlsx", startTime, endTime)) e.Save(ExcelTypeGameCountAvg, fmt.Sprintf("新用户平均局数_%s_%s.xlsx", startTime, endTime))
@ -223,6 +232,29 @@ func (e *ExcelMgr) GenNewPlayerGameTimeAvgExcel(plt string, startTime, endTime s
} }
} }
func (e *ExcelMgr) GenPlayerGameTimeAvgExcel(plt string, startTime, endTime string) {
for _, v := range VP.GetIntSlice("Gamefreeids") {
a, b, err := task.PlayerGameTimeAvg(plt, startTime, endTime, v)
if err != nil {
logger.Logger.Errorf("PlayerGameTimeAvg get StartTime:%v EndTime:%v GameFreeId:%v err: %v", startTime, endTime, v, err)
continue
}
ex := e.Get(ExcelTypeGameTimeAllAvg)
ex.NewLine()
ex.SetCell(startTime[:10])
ex.SetCell(GetGameFreeName(v))
ex.SetCell(a)
if a > 0 {
avg := float64(b) / float64(a)
show := fmt.Sprintf("%v", time.Second*time.Duration(avg))
ex.SetCell(show)
} else {
ex.SetCell(0)
}
logger.Logger.Tracef("PlayerGameTimeAvg GameFreeId: %v avg: %v", v, float64(b)/float64(a))
}
}
func (e *ExcelMgr) GenGameCountExcel(plt string, startTime, endTime string) { func (e *ExcelMgr) GenGameCountExcel(plt string, startTime, endTime string) {
for _, v := range VP.GetIntSlice("Gamefreeids") { for _, v := range VP.GetIntSlice("Gamefreeids") {
a, b, err := task.NewPlayerGameCountAvg(plt, startTime, endTime, v) a, b, err := task.NewPlayerGameCountAvg(plt, startTime, endTime, v)

View File

@ -45,6 +45,37 @@ func GetNewPayerIds(plt string, startTime, endTime string) ([]int, error) {
return ret, nil return ret, nil
} }
func GetPayerIds(plt string, startTime, endTime string, gamefreeid int) ([]int, error) {
s, e := common.StrRFC3339TimeToTime(startTime), common.StrRFC3339TimeToTime(endTime)
c, err := mymongo.GetLogCollection(plt, mongomodel.LogGamePlayerListLog)
if err != nil {
return nil, err
}
var res []struct{ Snid int }
dd, err := c.Aggregate(context.TODO(), bson.A{
bson.M{"$match": bson.M{"time": bson.M{"$gte": s, "$lt": e}, "gamefreeid": gamefreeid}},
bson.M{"$group": bson.M{"_id": "$snid", "snid": bson.M{"$first": "$snid"}}},
})
if err != nil {
if errors.Is(err, mongo.ErrNoDocuments) {
return nil, nil
}
logger.Logger.Errorf("find game player snid get err: %v", err)
return nil, err
}
if err := dd.All(context.TODO(), &res); err != nil {
logger.Logger.Errorf("find game player snid decode err: %v", err)
return nil, err
}
var ret []int
for _, v := range res {
ret = append(ret, v.Snid)
}
logger.Logger.Tracef("find game player snid: %v", ret)
return ret, nil
}
// 场次破产总人数 // 场次破产总人数
func GameFreeIdBankruptPlayerCount(plt string, ids []int, startTime, endTime string, gamefreeid int) (int, error) { func GameFreeIdBankruptPlayerCount(plt string, ids []int, startTime, endTime string, gamefreeid int) (int, error) {
s, e := common.StrRFC3339TimeToTime(startTime), common.StrRFC3339TimeToTime(endTime) s, e := common.StrRFC3339TimeToTime(startTime), common.StrRFC3339TimeToTime(endTime)

View File

@ -36,7 +36,10 @@ func NewPlayerGameTime(plt string, ids []int, startTime, endTime string, gamefre
if gamefreeid > 0 { if gamefreeid > 0 {
where["gamefreeid"] = gamefreeid where["gamefreeid"] = gamefreeid
} }
cur, err := c.Find(context.TODO(), where, options.Find().SetProjection(bson.M{"gamedetailedlogid": 1})) cur, err := c.Aggregate(context.Background(), bson.A{
bson.M{"$match": where},
bson.M{"$group": bson.M{"_id": "$gamedetailedlogid", "gamedetailedlogid": bson.M{"$first": "$gamedetailedlogid"}}},
})
if err != nil { if err != nil {
logger.Logger.Errorf("find player gamedetailedlogid get err: %v", err) logger.Logger.Errorf("find player gamedetailedlogid get err: %v", err)
return 0, 0, err return 0, 0, err
@ -102,3 +105,26 @@ func NewPlayerGameTimeAvg(plt string, startTime, endTime string, gamefreeid int)
} }
return b, a, err return b, a, err
} }
func PlayerGameTimeAvg(plt string, startTime, endTime string, gamefreeid int) (int, int, error) {
s, e := common.StrRFC3339TimeToTime(startTime), common.StrRFC3339TimeToTime(endTime)
if s.IsZero() || e.IsZero() {
return 0, 0, fmt.Errorf("time format error")
}
ids, err := GetPayerIds(plt, startTime, endTime, gamefreeid)
if err != nil {
return 0, 0, err
}
if len(ids) == 0 {
return 0, 0, nil
}
a, _, err := NewPlayerGameTime(plt, ids, startTime, endTime, gamefreeid)
if err != nil {
return 0, 0, err
}
if len(ids) == 0 {
return 0, 0, nil
}
return len(ids), a, err
}

View File

@ -180,6 +180,11 @@ func (this *CSEnterRoomHandler) Process(s *netlib.Session, packetid int, data in
p.matchCtx = mc p.matchCtx = mc
} }
} }
if scene.IsCustom() {
if scene.CustomParam.GetCostType() == 1 {
sp.CostPayment(scene, p.SnId)
}
}
if !scene.PlayerEnter(p, -1, true) { if !scene.PlayerEnter(p, -1, true) {
code = gamehall.OpResultCode_Game_OPRC_Error_Game code = gamehall.OpResultCode_Game_OPRC_Error_Game
@ -1342,15 +1347,13 @@ func CSCreatePrivateRoomHandler(s *netlib.Session, packetId int, data interface{
csp.AddScene(scene) csp.AddScene(scene)
sp.CostPayment(scene, p.SnId)
if !scene.PlayerEnter(p, -1, true) { if !scene.PlayerEnter(p, -1, true) {
send() send()
return nil return nil
} }
if costType == 2 {
sp.CostPayment(scene, p.SnId)
}
code = gamehall.OpResultCode_Game_OPRC_Sucess_Game code = gamehall.OpResultCode_Game_OPRC_Sucess_Game
pack = &gamehall.SCCreatePrivateRoom{ pack = &gamehall.SCCreatePrivateRoom{
GameFreeId: msg.GetGameFreeId(), GameFreeId: msg.GetGameFreeId(),

View File

@ -134,7 +134,8 @@ func init() {
CostCoin := p.takeCoin - msg.GetReturnCoin() CostCoin := p.takeCoin - msg.GetReturnCoin()
logger.Logger.Infof("NewBankruptLogEx: snid:%v GetReturnCoin:%v coin:%v CostCoin:%v", p.SnId, msg.GetReturnCoin(), p.takeCoin, CostCoin) logger.Logger.Infof("NewBankruptLogEx: snid:%v GetReturnCoin:%v coin:%v CostCoin:%v", p.SnId, msg.GetReturnCoin(), p.takeCoin, CostCoin)
log := model.NewBankruptLogEx(p.SnId, scene.dbGameFree.GetId(), p.CreateTime.Unix(), CostCoin, p.Platform, p.Channel, scene.gameId) log := model.NewBankruptLogEx(p.SnId, scene.dbGameFree.GetId(), p.CreateTime.Unix(), CostCoin,
p.Platform, p.Channel, p.ChannelId, scene.dbGameFree.GetGameDif(), scene.gameId)
if log != nil { if log != nil {
mq.Write(log) mq.Write(log)
} }

View File

@ -324,8 +324,6 @@ func (this *Player) OnLogined() {
this.DealShopLog() this.DealShopLog()
PlayerOnlineSington.Check = true
this.LoadMessage(tLastLogout.Unix(), isFirstLogin, !inSameWeek) this.LoadMessage(tLastLogout.Unix(), isFirstLogin, !inSameWeek)
//登录次数 //登录次数
@ -401,7 +399,6 @@ func (this *Player) OnRehold() {
if !this.IsRob { if !this.IsRob {
TournamentMgr.Quit(this.Platform, this.SnId) // 比赛没有开始,退赛 TournamentMgr.Quit(this.Platform, this.SnId) // 比赛没有开始,退赛
this.SendJackPotInit() this.SendJackPotInit()
PlayerOnlineSington.Check = true
this.DealShopLog() this.DealShopLog()
@ -1188,7 +1185,6 @@ func (this *Player) DropLine() {
this.SendPlayerCoin() this.SendPlayerCoin()
this.OnlineLogDrop() this.OnlineLogDrop()
PlayerOnlineSington.Check = true
} }
if this.scene != nil && this.scene.gameSess != nil { if this.scene != nil && this.scene.gameSess != nil {
@ -1222,7 +1218,6 @@ func (this *Player) OnLogoutFinish() {
if !this.IsRobot() { if !this.IsRobot() {
FriendUnreadMgrSington.SaveFriendUnreadData(this.Platform, this.SnId) FriendUnreadMgrSington.SaveFriendUnreadData(this.Platform, this.SnId)
PlayerOnlineSington.Check = true
//登录日志 //登录日志
logState := LoginStateMgrSington.GetLoginStateBySid(this.sid) logState := LoginStateMgrSington.GetLoginStateBySid(this.sid)
@ -1265,6 +1260,7 @@ func (this *Player) UnmarshalData(data []byte, scene *Scene) {
strconv.Itoa(int(scene.dbGameFree.GetGameId())), strconv.Itoa(int(scene.dbGameFree.GetGameId())),
common.GetKeyNoviceGameId(int(scene.dbGameFree.GetGameId())), common.GetKeyNoviceGameId(int(scene.dbGameFree.GetGameId())),
common.GetKeyGameType(int(scene.dbGameFree.GetGameType())), common.GetKeyGameType(int(scene.dbGameFree.GetGameType())),
common.GetKeyGameDif(scene.dbGameFree.GetGameDif()),
} { } {
if d, ok := pd.GDatas[v]; ok { if d, ok := pd.GDatas[v]; ok {
this.GDatas[v] = d this.GDatas[v] = d

View File

@ -8,8 +8,40 @@ import (
"mongo.games.com/game/common" "mongo.games.com/game/common"
"mongo.games.com/game/model" "mongo.games.com/game/model"
"mongo.games.com/game/mq" "mongo.games.com/game/mq"
"mongo.games.com/game/worldsrv/internal"
) )
func init() {
module.RegisteModule(PlayerOnlineSington, 5*time.Second, 0)
internal.RegisterPlayerListenerFunc(&internal.PlayerListenerFunc[*Player, *Scene]{
OnPlayerLoginedFunc: func(p *Player) {
if p == nil || p.IsRob {
return
}
PlayerOnlineSington.Check = true
},
OnPlayerLogoutedFunc: func(p *Player) {
if p == nil || p.IsRob {
return
}
PlayerOnlineSington.Check = true
},
OnPlayerDropLineFunc: func(p *Player) {
if p == nil || p.IsRob {
return
}
PlayerOnlineSington.Check = true
},
OnPlayerReholdFunc: func(p *Player) {
if p == nil || p.IsRob {
return
}
PlayerOnlineSington.Check = true
},
})
}
var PlayerOnlineSington = &PlayerOnlineEvent{ var PlayerOnlineSington = &PlayerOnlineEvent{
OnlineCh: make(map[string]map[string]int), OnlineCh: make(map[string]map[string]int),
} }
@ -66,7 +98,3 @@ here:
func (p *PlayerOnlineEvent) Shutdown() { func (p *PlayerOnlineEvent) Shutdown() {
module.UnregisteModule(p) module.UnregisteModule(p)
} }
func init() {
module.RegisteModule(PlayerOnlineSington, 5*time.Second, 0)
}

View File

@ -0,0 +1,125 @@
package main
import (
"slices"
"time"
"golang.org/x/exp/maps"
"mongo.games.com/goserver/core/logger"
"mongo.games.com/goserver/core/module"
"mongo.games.com/game/common"
"mongo.games.com/game/model"
"mongo.games.com/game/mq"
"mongo.games.com/game/worldsrv/internal"
)
func init() {
module.RegisteModule(PlayerOnlineGameSingleton, 10*time.Second, 0)
internal.RegisterPlayerListenerFunc(&internal.PlayerListenerFunc[*Player, *Scene]{
OnPlayerEnterSceneAfterFunc: func(p *Player, s *Scene) {
if p == nil || p.IsRob {
return
}
PlayerOnlineGameSingleton.Check = true
},
OnPlayerLeaveSceneAfterFunc: func(p *Player, s *Scene) {
if p == nil || p.IsRob {
return
}
PlayerOnlineGameSingleton.Check = true
},
})
}
var PlayerOnlineGameSingleton = &PlayerOnlineGameEvent{
Online: make(map[string]map[string]map[string]map[int]map[int]int),
}
type PlayerOnlineGameEvent struct {
Online map[string]map[string]map[string]map[int]map[int]int // 平台推广渠道游戏组游戏id场次id在线人数
Check bool
}
func (p *PlayerOnlineGameEvent) ModuleName() string {
return "PlayerOnlineGameEvent"
}
func (p *PlayerOnlineGameEvent) Init() {
}
func (p *PlayerOnlineGameEvent) Update() {
if !p.Check {
return
}
p.Check = false
onlineCh := make(map[string]map[string]map[string]map[int]map[int]int)
for _, v := range SceneMgrSingleton.scenes {
if v == nil {
continue
}
plt := SceneMgrSingleton.GetPlatformBySceneId(v.sceneId)
// 平台
if _, ok := onlineCh[plt]; !ok {
onlineCh[plt] = map[string]map[string]map[int]map[int]int{}
}
for _, player := range v.players {
if player == nil || player.IsRob || player.Platform == common.Platform_Rob && player.Channel == common.Channel_Rob {
continue
}
// 渠道
if _, ok := onlineCh[plt][player.ChannelId]; !ok {
onlineCh[plt][player.ChannelId] = map[string]map[int]map[int]int{}
}
// 游戏组
if _, ok := onlineCh[plt][player.ChannelId][v.dbGameFree.GetGameDif()]; !ok {
onlineCh[plt][player.ChannelId][v.dbGameFree.GetGameDif()] = map[int]map[int]int{}
}
// 游戏id
if _, ok := onlineCh[plt][player.ChannelId][v.dbGameFree.GetGameDif()][int(v.dbGameFree.GetGameId())]; !ok {
onlineCh[plt][player.ChannelId][v.dbGameFree.GetGameDif()][int(v.dbGameFree.GetGameId())] = map[int]int{}
}
onlineCh[plt][player.ChannelId][v.dbGameFree.GetGameDif()][int(v.dbGameFree.GetGameId())][int(v.dbGameFree.GetId())] += 1
}
}
// 判断差异
if !slices.Equal(maps.Keys(p.Online), maps.Keys(onlineCh)) {
goto here
}
for k, v := range p.Online {
if !slices.Equal(maps.Keys(v), maps.Keys(onlineCh[k])) {
goto here
}
for k1, v1 := range v {
if !slices.Equal(maps.Keys(v1), maps.Keys(onlineCh[k][k1])) {
goto here
}
for k2, v2 := range v1 {
if !slices.Equal(maps.Keys(v2), maps.Keys(onlineCh[k][k1][k2])) {
goto here
}
for k3, v3 := range v2 {
if !slices.Equal(maps.Keys(v3), maps.Keys(onlineCh[k][k1][k2][k3])) {
goto here
}
}
}
}
}
here:
p.Online = onlineCh
mq.Write(model.GenerateOnlineGame(p.Online))
logger.Logger.Trace("PlayerOnlineGameEvent", p.Online)
}
func (p *PlayerOnlineGameEvent) Shutdown() {
module.UnregisteModule(p)
}

View File

@ -162,6 +162,10 @@ func NewScene(args *CreateSceneParam) *Scene {
return s return s
} }
func (this *Scene) GetPlatform() *Platform {
return this.platform
}
func (this *Scene) RobotIsLimit() bool { func (this *Scene) RobotIsLimit() bool {
if this.robotLimit != 0 { if this.robotLimit != 0 {
if this.robotNum >= this.robotLimit { if this.robotNum >= this.robotLimit {

View File

@ -57,11 +57,6 @@ func (spd *ScenePolicyData) OnTick(s *Scene) {
func (spd *ScenePolicyData) OnPlayerEnter(s *Scene, snid int32) { func (spd *ScenePolicyData) OnPlayerEnter(s *Scene, snid int32) {
s.NotifyPrivateRoom(common.ListModify) s.NotifyPrivateRoom(common.ListModify)
if s.IsCustom() {
if s.CustomParam.GetCostType() == 1 { // AA
spd.CostPayment(s, snid)
}
}
} }
func (spd *ScenePolicyData) OnPlayerLeave(s *Scene, snid int32) { func (spd *ScenePolicyData) OnPlayerLeave(s *Scene, snid int32) {

View File

@ -2257,11 +2257,13 @@ func init() {
state = msg.GetState() state = msg.GetState()
player := PlayerMgrSington.GetPlayerBySnId(info.SnId) player := PlayerMgrSington.GetPlayerBySnId(info.SnId)
if player == nil { logger.Logger.Info("CallbackPayment player", player)
if player == nil || (player != nil && player.IsOffline()) {
if msg.State == 1 { if msg.State == 1 {
state = 3 state = 3
} }
} }
logger.Logger.Info("------------CallbackPayment state----------", state)
task.New(nil, task.CallableWrapper(func(o *basic.Object) interface{} { task.New(nil, task.CallableWrapper(func(o *basic.Object) interface{} {
err := model.UpdateDbShopState(msg.Platform, msg.OrderId, state) err := model.UpdateDbShopState(msg.Platform, msg.OrderId, state)
if err != nil { if err != nil {
@ -2274,7 +2276,7 @@ func init() {
retFail("购买记录状态修改失败") retFail("购买记录状态修改失败")
return return
} }
if player != nil { if player != nil || (player != nil && player.IsOffline()) {
player.DoShopInfo(info, false) player.DoShopInfo(info, false)
// 邀请积分 // 邀请积分
InviteTask(msg.Platform, player.PSnId, info.SnId, common.InviteScoreTypePay, int64(info.ConsumeNum)) InviteTask(msg.Platform, player.PSnId, info.SnId, common.InviteScoreTypePay, int64(info.ConsumeNum))