Compare commits

...

6 Commits

Author SHA1 Message Date
sk 622d622194 Merge branch 'develop' of git.pogorockgames.com:mango-games/server/game into develop 2024-09-29 11:22:12 +08:00
sk e07963720d 竞技馆奖励记录最新50条 2024-09-29 11:21:04 +08:00
sk e8c4f4489f no message 2024-09-29 10:16:57 +08:00
sk 025dbd8691 Merge branch 'release' into develop 2024-09-29 09:55:49 +08:00
sk bcdcc1cc47 修复比赛场id重复问题 2024-09-29 09:55:34 +08:00
sk f6804c4cd9 比赛场获奖记录 2024-09-28 15:36:31 +08:00
13 changed files with 431 additions and 411 deletions

9
common/id.go Normal file
View File

@ -0,0 +1,9 @@
package common
import "github.com/bwmarrin/snowflake"
var IdNode, _ = snowflake.NewNode(int64(GetSelfSrvId()))
func GetId() int64 {
return IdNode.Generate().Int64()
}

View File

@ -39,7 +39,7 @@ func (this *DBCustomLogAwardSvc) Find(req *model.CustomLogAwardFindReq, res *mod
return ErrCustomLogAwardNotFound return ErrCustomLogAwardNotFound
} }
if err := c.Find(bson.M{"startts": bson.M{"$gte": req.StartTs, "$lte": req.EndTs}}).Sort("startts").All(&res.List); err != nil { if err := c.Find(bson.M{"startts": bson.M{"$gte": req.StartTs, "$lte": req.EndTs}}).Sort("-startts").Limit(50).All(&res.List); err != nil {
return err return err
} }
return nil return nil

View File

@ -75,8 +75,9 @@ func (svc *MatchAwardSvc) GetMatchAward(plt string, ret *model.MatchAward) (err
err = c.Find(nil).One(ret) err = c.Find(nil).One(ret)
if err != nil && err != mgo.ErrNotFound { if err != nil && err != mgo.ErrNotFound {
logger.Logger.Errorf("GetMatchAward err:%v", err) logger.Logger.Errorf("GetMatchAward err:%v", err)
}
return err return err
}
return nil
} }
func init() { func init() {

View File

@ -8,6 +8,12 @@ import (
"mongo.games.com/goserver/core/logger" "mongo.games.com/goserver/core/logger"
) )
type Item struct {
ItemId int32 // 物品ID
ItemNum int64 // 物品数量
ObtainTime int64 //获取的时间
}
type BagInfo struct { type BagInfo struct {
BagId bson.ObjectId `bson:"_id"` BagId bson.ObjectId `bson:"_id"`
SnId int32 //玩家账号直接在这里生成 SnId int32 //玩家账号直接在这里生成
@ -19,20 +25,11 @@ type BagInfo struct {
GainWay int32 `bson:"-"` GainWay int32 `bson:"-"`
} }
type Item struct {
ItemId int32 // 物品ID
ItemNum int64 // 物品数量
ObtainTime int64 //获取的时间
}
type GetBagInfoArgs struct { type GetBagInfoArgs struct {
Plt string Plt string
SnId int32 SnId int32
} }
func NewBagInfo(sid int32, plt string) *BagInfo {
return &BagInfo{BagId: bson.NewObjectId(), SnId: sid, Platform: plt, BagItem: make(map[int32]*Item)}
}
func GetBagInfo(sid int32, plt string) (*BagInfo, error) { func GetBagInfo(sid int32, plt string) (*BagInfo, error) {
if rpcCli == nil { if rpcCli == nil {
return nil, ErrRPClientNoConn return nil, ErrRPClientNoConn
@ -76,18 +73,6 @@ func SaveDBBagItem(args *BagInfo) error {
return nil return nil
} }
func SaveToDelBackupBagItem(args *BagInfo) error {
if rpcCli == nil {
return ErrRPClientNoConn
}
ret := false
err := rpcCli.CallWithTimeout("BagSvc.UpdateBag", args, &ret, time.Second*30)
if err != nil {
return err
}
return nil
}
type AddItemParam struct { type AddItemParam struct {
Platform string Platform string
SnId int32 SnId int32

View File

@ -92,6 +92,7 @@ func (r *ListMgr[T]) Take(platform string, index int32, f func([]T, error)) {
} }
// UpdateCache 更新缓存 // UpdateCache 更新缓存
// 重新获取数据
func (r *ListMgr[T]) UpdateCache(platform string, index int32) { func (r *ListMgr[T]) UpdateCache(platform string, index int32) {
tp := r.platform[platform] tp := r.platform[platform]
if tp == nil { if tp == nil {

View File

@ -7,6 +7,7 @@ import (
"github.com/jinzhu/now" "github.com/jinzhu/now"
"mongo.games.com/goserver/core/logger" "mongo.games.com/goserver/core/logger"
"mongo.games.com/goserver/core/module" "mongo.games.com/goserver/core/module"
"mongo.games.com/goserver/core/timer"
"mongo.games.com/goserver/srvlib" "mongo.games.com/goserver/srvlib"
"mongo.games.com/goserver/srvlib/action" "mongo.games.com/goserver/srvlib/action"
@ -84,6 +85,10 @@ func (c *CustomAwardMgr) Update() {
StartTs: nowTime.Add(-time.Minute * 8).Unix(), StartTs: nowTime.Add(-time.Minute * 8).Unix(),
EndTs: nowTime.Unix(), EndTs: nowTime.Unix(),
}) })
timer.AfterTimer(func(h timer.TimerHandle, ud interface{}) bool {
CustomAwardMgrInstance.UpdateCache(k, 0)
return true
}, nil, time.Second*2)
// 通知获奖 // 通知获奖
pack := &rank.UserAward{ pack := &rank.UserAward{
Snid: int32(id), Snid: int32(id),

View File

@ -216,7 +216,7 @@ func (this *CSLoginHandler) Process(s *netlib.Session, packetid int, data interf
if player != nil { if player != nil {
waitMatch, _ = TournamentMgr.IsMatchWaiting(player.Platform, player.SnId) waitMatch, _ = TournamentMgr.IsMatchWaiting(player.Platform, player.SnId)
} }
if len(lss) > 0 && (player != nil && (player.scene != nil || player.thrscene != 0 || waitMatch || TournamentMgr.IsMatching(player.SnId))) { if len(lss) > 0 && (player != nil && (player.scene != nil || player.thrscene != 0 || waitMatch || TournamentMgr.IsGaming(player.SnId))) {
sendSCLogin(login_proto.OpResultCode_OPRC_LoginOtherPlace) sendSCLogin(login_proto.OpResultCode_OPRC_LoginOtherPlace)
sendSCDisconnect(common.KickReason_Logining) sendSCDisconnect(common.KickReason_Logining)
return nil return nil

View File

@ -82,8 +82,8 @@ func CSSignRace(s *netlib.Session, packetid int, data interface{}, sid int64) er
} }
default: // 取消报名 default: // 取消报名
if TournamentMgr.IsMatching(p.SnId) { if TournamentMgr.IsGaming(p.SnId) {
logger.Logger.Warnf("player(%v) IsMatching.", p.SnId) logger.Logger.Warnf("player(%v) IsGaming.", p.SnId)
} else { } else {
//取消报名 //取消报名
TournamentMgr.CancelSignUp(platform, tmId, p.SnId) TournamentMgr.CancelSignUp(platform, tmId, p.SnId)
@ -115,7 +115,7 @@ func CSMatchList(s *netlib.Session, packetId int, data interface{}, sid int64) e
// 开始时间排序 // 开始时间排序
sort.Slice(list, func(i, j int) bool { sort.Slice(list, func(i, j int) bool {
return list[i].StartTime < list[j].StartTime return list[i].StartTime.Compare(list[j].StartTime) == -1
}) })
for _, v := range list { for _, v := range list {

View File

@ -10,7 +10,6 @@ import (
"mongo.games.com/goserver/core/basic" "mongo.games.com/goserver/core/basic"
"mongo.games.com/goserver/core/i18n" "mongo.games.com/goserver/core/i18n"
"mongo.games.com/goserver/core/logger" "mongo.games.com/goserver/core/logger"
"mongo.games.com/goserver/core/module"
"mongo.games.com/goserver/core/task" "mongo.games.com/goserver/core/task"
"mongo.games.com/game/common" "mongo.games.com/game/common"
@ -24,10 +23,22 @@ import (
"mongo.games.com/game/worldsrv/internal" "mongo.games.com/game/worldsrv/internal"
) )
func init() { const (
module.RegisteModule(BagMgrSingleton, time.Second, 0) BagItemMax int32 = 200
internal.RegisterPlayerLoad(BagMgrSingleton) )
// 道具功能 Function
const (
ItemCanUse = iota //可以使用
ItemCanGive //可以赠送
ItemCanSell //可以出售
ItemCanExchange //可以兑换
ItemCanFen //可以分解
ItemMax
)
func init() {
internal.RegisterPlayerLoad(BagMgrSingleton)
BagMgrSingleton.AddOnChangeFuncs(func(param *model.ChangeItemParam) { BagMgrSingleton.AddOnChangeFuncs(func(param *model.ChangeItemParam) {
p := PlayerMgrSington.GetPlayerBySnId(param.SnId) p := PlayerMgrSington.GetPlayerBySnId(param.SnId)
if p == nil { if p == nil {
@ -138,20 +149,6 @@ func init() {
}) })
} }
const (
BagItemMax int32 = 200
)
// 道具功能 Function
const (
ItemCanUse = iota //可以使用
ItemCanGive //可以赠送
ItemCanSell //可以出售
ItemCanExchange //可以兑换
ItemCanFen //可以分解
ItemMax
)
type Item struct { type Item struct {
ItemId int32 // 物品ID ItemId int32 // 物品ID
ItemNum int64 // 物品数量 ItemNum int64 // 物品数量
@ -186,11 +183,7 @@ func NewBagInfo(platform string, snid int32) *BagInfo {
} }
} }
// BagMgrSingleton 背包管理器 // BagMgr 玩家背包
var BagMgrSingleton = &BagMgr{
PlayerBag: make(map[int32]*BagInfo),
}
type BagMgr struct { type BagMgr struct {
PlayerBag map[int32]*BagInfo // snid:背包 PlayerBag map[int32]*BagInfo // snid:背包
@ -198,20 +191,241 @@ type BagMgr struct {
onChangeFuncs []func(param *model.ChangeItemParam) onChangeFuncs []func(param *model.ChangeItemParam)
} }
func (this *BagMgr) ModuleName() string { // BagMgrSingleton 背包管理器
return "BagMgr" var BagMgrSingleton = &BagMgr{
PlayerBag: make(map[int32]*BagInfo),
} }
func (this *BagMgr) Init() { // ============================================================================
// implement IPlayerLoad
//=============================================================================
type LoadData struct {
BagInfo *model.BagInfo
} }
func (this *BagMgr) Update() { func (this *BagMgr) Load(platform string, snid int32, player any) *internal.PlayerLoadReplay {
// 加载道具
bagInfo, err := model.GetBagInfo(snid, platform)
if err != nil {
return &internal.PlayerLoadReplay{
Platform: platform,
Snid: snid,
Err: err,
Data: nil,
}
}
// 对账时间戳初始化
if bagInfo.Ts == 0 {
bagInfo.Ts = time.Now().UnixNano()
}
return &internal.PlayerLoadReplay{
Platform: platform,
Snid: snid,
Err: err,
Data: &LoadData{
BagInfo: bagInfo,
},
}
} }
func (this *BagMgr) Shutdown() { func (this *BagMgr) Callback(player any, ret *internal.PlayerLoadReplay) {
module.UnregisteModule(this) if ret == nil || ret.Data == nil {
return
}
data, ok := ret.Data.(*LoadData)
if !ok || data == nil || data.BagInfo == nil {
return
}
// 背包数据
newBagInfo := NewBagInfo(ret.Platform, ret.Snid)
newBagInfo.Ts = data.BagInfo.Ts
for k, bi := range data.BagInfo.BagItem {
item := srvdata.GameItemMgr.Get(ret.Platform, bi.ItemId)
if item != nil {
if bi.ItemNum > 0 {
newBagInfo.BagItem[k] = &Item{
ItemId: bi.ItemId,
ItemNum: bi.ItemNum,
ObtainTime: bi.ObtainTime,
}
}
} else {
logger.Logger.Error("InitBagInfo err: item is nil. ItemId:", bi.ItemId)
}
}
this.PlayerBag[ret.Snid] = newBagInfo
} }
type LoadAfterData struct {
GameID []int32
ItemLogs []*model.ItemLog
StarTs, EndTs int64
}
func (this *BagMgr) LoadAfter(platform string, snid int32) *internal.PlayerLoadReplay {
var err error
// 查询最近游戏
gameID := model.GetRecentGame(platform, snid)
// 道具变更记录
endTs := time.Now().UnixNano()
var itemLogs []*model.ItemLog
itemLogs, err = model.GetItemLog(platform, snid, this.PlayerBag[snid].Ts)
if err != nil {
logger.Logger.Errorf("LoadAfter GetItemLog err: %v", err)
return &internal.PlayerLoadReplay{
Platform: platform,
Snid: snid,
Err: err,
Data: nil,
}
}
return &internal.PlayerLoadReplay{
Platform: platform,
Snid: snid,
Err: nil,
Data: &LoadAfterData{
GameID: gameID,
ItemLogs: itemLogs,
StarTs: this.PlayerBag[snid].Ts,
EndTs: endTs,
},
}
}
func (this *BagMgr) CallbackAfter(ret *internal.PlayerLoadReplay) {
if ret == nil {
return
}
if ret.Err != nil {
logger.Logger.Error("BagMgr LoadAfter err:", ret.Err)
return
}
param, ok := ret.Data.(*LoadAfterData)
if !ok {
logger.Logger.Errorf("BagMgr LoadAfter BUGE 1")
return
}
p := PlayerMgrSington.GetPlayerBySnId(ret.Snid)
if p == nil {
logger.Logger.Errorf("BagMgr LoadAfter BUGE 2")
return
}
// 最近游戏
p.GameID = param.GameID
// 道具变更记录
bagInfo := this.PlayerBag[p.SnId]
if bagInfo != nil {
changeItems := make(map[int32]struct{})
for _, v := range param.ItemLogs {
if v == nil {
continue
}
if v.Ts > param.StarTs && v.Ts <= param.EndTs {
bagInfo.dirty = true
num := v.Count
if v.LogType == 1 {
num = -num
}
if v.Ts > bagInfo.Ts {
bagInfo.Ts = v.Ts
}
if v.Offline == 0 {
// 在线数据恢复
logger.Logger.Tracef("道具恢复 SnId:%v Item:%+v", p.SnId, *v)
if _, ok := bagInfo.BagItem[v.ItemId]; !ok {
bagInfo.BagItem[v.ItemId] = &Item{
ItemId: v.ItemId,
ItemNum: 0,
ObtainTime: v.CreateTs,
}
}
bagInfo.BagItem[v.ItemId].ItemNum += num
changeItems[v.ItemId] = struct{}{}
} else {
// 离线时的变更
logger.Logger.Tracef("处理离线道具变化 SnId:%v Item:%v", p.SnId, *v)
this.OnChangeFuncs(&model.ChangeItemParam{
SnId: p.SnId,
ItemId: v.ItemId,
ItemNum: num,
GainWay: v.TypeId,
RoomConfigId: v.RoomConfigId,
GameId: v.GameId,
GameFreeId: v.GameFreeId,
Cost: v.Cost,
})
}
}
}
this.SyncBagData(p.SnId, maps.Keys(changeItems)...)
}
}
func (this *BagMgr) Save(platform string, snid int32, isSync, force bool) {
bagInfo := this.GetBagInfo(snid)
if bagInfo == nil {
return
}
if !bagInfo.dirty && !force {
return
}
logger.Logger.Tracef("SaveBagData: %+v", *bagInfo)
var err error
f := func() {
newBagInfo := &model.BagInfo{
SnId: bagInfo.SnId,
Platform: bagInfo.Platform,
Ts: bagInfo.Ts,
BagItem: make(map[int32]*model.Item),
}
for _, v := range bagInfo.BagItem {
newBagInfo.BagItem[v.ItemId] = &model.Item{ItemId: v.ItemId, ItemNum: v.ItemNum, ObtainTime: v.ObtainTime}
}
err = model.UpBagItem(newBagInfo)
}
cf := func() {
if err == nil && this.PlayerBag[snid] != nil {
this.PlayerBag[snid].dirty = false
}
}
if isSync {
f()
cf()
return
}
task.New(nil, task.CallableWrapper(func(o *basic.Object) interface{} {
f()
return nil
}), task.CompleteNotifyWrapper(func(i interface{}, t task.Task) {
cf()
})).StartByExecutor(fmt.Sprintf("Player%v", snid))
}
func (this *BagMgr) Release(platform string, snid int32) {
delete(this.PlayerBag, snid)
}
// ===========================================================================
// other functions
//============================================================================
// AddOnChangeFuncs 添加道具变更监听
func (this *BagMgr) AddOnChangeFuncs(f ...func(param *model.ChangeItemParam)) { func (this *BagMgr) AddOnChangeFuncs(f ...func(param *model.ChangeItemParam)) {
this.onChangeFuncs = append(this.onChangeFuncs, f...) this.onChangeFuncs = append(this.onChangeFuncs, f...)
} }
@ -706,7 +920,7 @@ func (this *BagMgr) VerifyUpJybInfo(p *Player, args *model.VerifyUpJybInfoArgs)
}), "VerifyUpJybInfo").Start() }), "VerifyUpJybInfo").Start()
} }
// 兑换话费卡 // ItemExchangeCard 兑换话费卡
func (this *BagMgr) ItemExchangeCard(p *Player, itemId int32, money, cardType int32, logId string) bool { func (this *BagMgr) ItemExchangeCard(p *Player, itemId int32, money, cardType int32, logId string) bool {
// 兑换码奖品 // 兑换码奖品
var err error var err error
@ -799,226 +1013,3 @@ func (this *BagMgr) ItemExchangeCard(p *Player, itemId int32, money, cardType in
}), fmt.Sprintf("ItemExChange%d", p.SnId)).Start() }), fmt.Sprintf("ItemExChange%d", p.SnId)).Start()
return true return true
} }
// ========================implement IPlayerLoad ==============================
type LoadData struct {
BagInfo *model.BagInfo
}
func (this *BagMgr) Load(platform string, snid int32, player any) *internal.PlayerLoadReplay {
// 加载道具
bagInfo, err := model.GetBagInfo(snid, platform)
if err != nil {
return &internal.PlayerLoadReplay{
Platform: platform,
Snid: snid,
Err: err,
Data: nil,
}
}
// 对账时间戳初始化
if bagInfo.Ts == 0 {
bagInfo.Ts = time.Now().UnixNano()
}
return &internal.PlayerLoadReplay{
Platform: platform,
Snid: snid,
Err: err,
Data: &LoadData{
BagInfo: bagInfo,
},
}
}
func (this *BagMgr) Callback(player any, ret *internal.PlayerLoadReplay) {
if ret == nil || ret.Data == nil {
return
}
data, ok := ret.Data.(*LoadData)
if !ok || data == nil || data.BagInfo == nil {
return
}
// 背包数据
newBagInfo := NewBagInfo(ret.Platform, ret.Snid)
newBagInfo.Ts = data.BagInfo.Ts
for k, bi := range data.BagInfo.BagItem {
item := srvdata.GameItemMgr.Get(ret.Platform, bi.ItemId)
if item != nil {
if bi.ItemNum > 0 {
newBagInfo.BagItem[k] = &Item{
ItemId: bi.ItemId,
ItemNum: bi.ItemNum,
ObtainTime: bi.ObtainTime,
}
}
} else {
logger.Logger.Error("InitBagInfo err: item is nil. ItemId:", bi.ItemId)
}
}
this.PlayerBag[ret.Snid] = newBagInfo
}
type LoadAfterData struct {
GameID []int32
ItemLogs []*model.ItemLog
StarTs, EndTs int64
}
func (this *BagMgr) LoadAfter(platform string, snid int32) *internal.PlayerLoadReplay {
var err error
// 查询最近游戏
gameID := model.GetRecentGame(platform, snid)
// 道具变更记录
endTs := time.Now().UnixNano()
var itemLogs []*model.ItemLog
itemLogs, err = model.GetItemLog(platform, snid, this.PlayerBag[snid].Ts)
if err != nil {
logger.Logger.Errorf("LoadAfter GetItemLog err: %v", err)
return &internal.PlayerLoadReplay{
Platform: platform,
Snid: snid,
Err: err,
Data: nil,
}
}
return &internal.PlayerLoadReplay{
Platform: platform,
Snid: snid,
Err: nil,
Data: &LoadAfterData{
GameID: gameID,
ItemLogs: itemLogs,
StarTs: this.PlayerBag[snid].Ts,
EndTs: endTs,
},
}
}
func (this *BagMgr) CallbackAfter(ret *internal.PlayerLoadReplay) {
if ret == nil {
return
}
if ret.Err != nil {
logger.Logger.Error("BagMgr LoadAfter err:", ret.Err)
return
}
param, ok := ret.Data.(*LoadAfterData)
if !ok {
logger.Logger.Errorf("BagMgr LoadAfter BUGE 1")
return
}
p := PlayerMgrSington.GetPlayerBySnId(ret.Snid)
if p == nil {
logger.Logger.Errorf("BagMgr LoadAfter BUGE 2")
return
}
// 最近游戏
p.GameID = param.GameID
// 道具变更记录
bagInfo := this.PlayerBag[p.SnId]
if bagInfo != nil {
changeItems := make(map[int32]struct{})
for _, v := range param.ItemLogs {
if v == nil {
continue
}
if v.Ts > param.StarTs && v.Ts <= param.EndTs {
bagInfo.dirty = true
num := v.Count
if v.LogType == 1 {
num = -num
}
if v.Ts > bagInfo.Ts {
bagInfo.Ts = v.Ts
}
if v.Offline == 0 {
// 在线数据恢复
logger.Logger.Tracef("道具恢复 SnId:%v Item:%+v", p.SnId, *v)
if _, ok := bagInfo.BagItem[v.ItemId]; !ok {
bagInfo.BagItem[v.ItemId] = &Item{
ItemId: v.ItemId,
ItemNum: 0,
ObtainTime: v.CreateTs,
}
}
bagInfo.BagItem[v.ItemId].ItemNum += num
changeItems[v.ItemId] = struct{}{}
} else {
// 离线时的变更
logger.Logger.Tracef("处理离线道具变化 SnId:%v Item:%v", p.SnId, *v)
this.OnChangeFuncs(&model.ChangeItemParam{
SnId: p.SnId,
ItemId: v.ItemId,
ItemNum: num,
GainWay: v.TypeId,
RoomConfigId: v.RoomConfigId,
GameId: v.GameId,
GameFreeId: v.GameFreeId,
Cost: v.Cost,
})
}
}
}
this.SyncBagData(p.SnId, maps.Keys(changeItems)...)
}
}
func (this *BagMgr) Save(platform string, snid int32, isSync, force bool) {
bagInfo := this.GetBagInfo(snid)
if bagInfo == nil {
return
}
if !bagInfo.dirty && !force {
return
}
logger.Logger.Tracef("SaveBagData: %+v", *bagInfo)
var err error
f := func() {
newBagInfo := &model.BagInfo{
SnId: bagInfo.SnId,
Platform: bagInfo.Platform,
Ts: bagInfo.Ts,
BagItem: make(map[int32]*model.Item),
}
for _, v := range bagInfo.BagItem {
newBagInfo.BagItem[v.ItemId] = &model.Item{ItemId: v.ItemId, ItemNum: v.ItemNum, ObtainTime: v.ObtainTime}
}
err = model.UpBagItem(newBagInfo)
}
cf := func() {
if err == nil && this.PlayerBag[snid] != nil {
this.PlayerBag[snid].dirty = false
}
}
if isSync {
f()
cf()
return
}
task.New(nil, task.CallableWrapper(func(o *basic.Object) interface{} {
f()
return nil
}), task.CompleteNotifyWrapper(func(i interface{}, t task.Task) {
cf()
})).StartByExecutor(fmt.Sprintf("Player%v", snid))
}
func (this *BagMgr) Release(platform string, snid int32) {
delete(this.PlayerBag, snid)
}

View File

@ -1,12 +1,14 @@
package main package main
import ( import (
"mongo.games.com/game/srvdata" "time"
"mongo.games.com/goserver/core/logger" "mongo.games.com/goserver/core/logger"
"mongo.games.com/game/common" "mongo.games.com/game/common"
"mongo.games.com/game/proto" "mongo.games.com/game/proto"
"mongo.games.com/game/protocol/server" "mongo.games.com/game/protocol/server"
"mongo.games.com/game/srvdata"
) )
var MatchSceneMgrSingleton = &MatchSceneMgr{} var MatchSceneMgrSingleton = &MatchSceneMgr{}
@ -119,6 +121,7 @@ func (ms *MatchSceneMgr) MatchStart(tm *TmMatch) {
// NewRoundStart 开始非首轮比赛 // NewRoundStart 开始非首轮比赛
func (ms *MatchSceneMgr) NewRoundStart(tm *TmMatch, mct []*PlayerMatchContext, finals bool, round int32) { func (ms *MatchSceneMgr) NewRoundStart(tm *TmMatch, mct []*PlayerMatchContext, finals bool, round int32) {
tm.RoundTime = time.Now()
var scene *Scene var scene *Scene
csp := CoinSceneMgrSingleton.GetCoinScenePool(tm.Platform, tm.dbGameFree.GetId()) csp := CoinSceneMgrSingleton.GetCoinScenePool(tm.Platform, tm.dbGameFree.GetId())
if csp == nil { if csp == nil {

View File

@ -899,7 +899,7 @@ func (this *Scene) TryForceDeleteMatchInfo() {
if players, exist := TournamentMgr.players[this.MatchSortId]; exist { if players, exist := TournamentMgr.players[this.MatchSortId]; exist {
for _, player := range this.players { for _, player := range this.players {
if player != nil && !player.IsRob { if player != nil && !player.IsRob {
if TournamentMgr.IsMatching(player.SnId) { if TournamentMgr.IsGaming(player.SnId) {
delete(players, player.SnId) delete(players, player.SnId)
} }
} }

View File

@ -1,6 +1,7 @@
package main package main
import ( import (
"fmt"
"math" "math"
"math/rand" "math/rand"
"sort" "sort"
@ -21,7 +22,7 @@ import (
) )
func getSortId() int64 { func getSortId() int64 {
return time.Now().UnixMilli() return common.GetId()
} }
type TmPlayer struct { type TmPlayer struct {
@ -49,10 +50,17 @@ type TmMatch struct {
robotGrades map[int][]*TmGradeInfo // 第几轮:玩家积分 robotGrades map[int][]*TmGradeInfo // 第几轮:玩家积分
copyRobotGrades []*TmGradeInfo // 最近一轮的机器人积分备份 copyRobotGrades []*TmGradeInfo // 最近一轮的机器人积分备份
useRobot int32 // 是否使用机器人 useRobot int32 // 是否使用机器人
StartTime int64 // 本场比赛开始时间 StartTime time.Time // 本场比赛开始时间
RoundTime time.Time // 本轮开始时间
}
func (tm *TmMatch) String() string {
return fmt.Sprintf("比赛配置id: %v 比赛id:%v 开启机器人:%v 比赛开始时间: %v 本轮开始时间:%v 比赛玩家: %v",
tm.TMId, tm.SortId, tm.useRobot, tm.StartTime, tm.RoundTime, tm.TmPlayer)
} }
func NewTmMatch(platform string, match *webapi_proto.GameMatchDate, players map[int32]*TmPlayer) *TmMatch { func NewTmMatch(platform string, match *webapi_proto.GameMatchDate, players map[int32]*TmPlayer) *TmMatch {
now := time.Now()
ret := &TmMatch{ ret := &TmMatch{
SortId: getSortId(), SortId: getSortId(),
TMId: match.Id, TMId: match.Id,
@ -63,7 +71,8 @@ func NewTmMatch(platform string, match *webapi_proto.GameMatchDate, players map[
dbGameFree: srvdata.PBDB_GameFreeMgr.GetData(match.GameFreeId), dbGameFree: srvdata.PBDB_GameFreeMgr.GetData(match.GameFreeId),
robotGrades: make(map[int][]*TmGradeInfo), robotGrades: make(map[int][]*TmGradeInfo),
useRobot: match.UseRobot, useRobot: match.UseRobot,
StartTime: time.Now().Unix(), StartTime: now,
RoundTime: now,
} }
ret.copyPlayers(players) ret.copyPlayers(players)

View File

@ -84,16 +84,18 @@ type PlayerRoundInfo struct {
type Tournament struct { type Tournament struct {
common.BaseClockSinker common.BaseClockSinker
TypeList map[string]*webapiproto.GameMatchType // 比赛类型列表 平台id比赛类型列表 TypeList map[string]*webapiproto.GameMatchType // 平台id:比赛类型列表
GameMatchDateList map[string]map[int32]*webapiproto.GameMatchDate // 比赛配置platform:比赛场配置id:比赛配置 GameMatchDateList map[string]map[int32]*webapiproto.GameMatchDate // 平台id:比赛场配置id:比赛配置
singleSignupPlayers map[int32]*SignupInfo // 开启机器人时报名的玩家玩家Id:报名信息
signupPlayers map[string]map[int32]*SignInfo // 报名的玩家 platform:比赛配置id:报名人 singleSignupPlayers map[int32]*SignupInfo // 玩家Id:报名信息; 使用机器人时的报名信息
playerWaitStart map[int32]int64 // 等待时间 玩家Id:等待时长秒 signupPlayers map[string]map[int32]*SignInfo // 平台id:比赛配置id:报名信息; 不使用机器人时的报名信息
matches map[int32]map[int64]*TmMatch // 开始比赛的数据比赛配置Id:比赛顺序序号:一场开始的比赛数据 MatchAwardNum map[string]map[int32]int32 // 平台id:比赛配置Id:发第一名奖励次数
players map[int64]map[int32]*PlayerMatchContext // 比赛中玩家 比赛顺序序号:玩家id:玩家信息
roundPlayers map[int64]map[int32]*PlayerRoundInfo // 每轮比赛数据备份 比赛顺序序号:第几轮 playerWaitStart map[int32]int64 // 玩家Id:等待时长秒; 玩家报名后等待比赛开始
finalPerRank map[int64][]*PerRankInfo // 本场比赛排名,每淘汰一位记录一位,最后记录决赛玩家 比赛顺序序号 matches map[int32]map[int64]*TmMatch // 比赛配置Id:比赛顺序序号:开始的比赛数据
MatchAwardNum map[string]map[int32]int32 // 比赛配置Id:比赛奖励次數 players map[int64]map[int32]*PlayerMatchContext // 比赛顺序序号:玩家id:玩家信息
roundPlayers map[int64]map[int32]*PlayerRoundInfo // 比赛顺序序号:第几轮:结算记录
finalPerRank map[int64][]*PerRankInfo // 比赛顺序序号:本场比赛排名,每淘汰一位记录一位,最后记录决赛玩家
} }
func NewTournament() *Tournament { func NewTournament() *Tournament {
@ -111,6 +113,61 @@ func NewTournament() *Tournament {
return ret return ret
} }
func (this *Tournament) ModuleName() string {
return "Tournament"
}
func (this *Tournament) Init() {
logger.Logger.Trace("Tournament Init")
for _, v := range PlatformMgrSingleton.GetPlatforms() {
if v == nil || v.IdStr == "0" {
continue
}
ret, err := model.GetMatchAward(v.IdStr)
if err != nil {
logger.Logger.Warnf("GetMatchAward error %v", err)
continue
}
if this.MatchAwardNum == nil {
this.MatchAwardNum = make(map[string]map[int32]int32)
}
this.MatchAwardNum[v.IdStr] = ret.Award
}
}
func (this *Tournament) Update() {
// 使用机器人的情况
for snId, info := range this.singleSignupPlayers {
if info == nil || info.Ts <= 0 {
continue
}
matchInfo := this.GetMatchInfo(info.Platform, info.TmId, 0)
if this.IsMatchOn(matchInfo) && !this.IsOutTime(matchInfo) && this.IsRobotOn(matchInfo) {
needTime := this.playerWaitStart[snId]
if time.Now().Unix()-info.Ts > needTime {
signInfo := &SignInfo{
signup: make(map[int32]*TmPlayer),
Platform: info.Platform,
MaxCnt: int(matchInfo.MatchNumebr),
}
seq := rand.Intn(int(matchInfo.MatchNumebr)) + 1
signInfo.signup[snId] = &TmPlayer{SnId: snId, seq: seq}
this.signupPlayers[info.Platform][info.TmId] = signInfo
//倒计时结束 开始比赛
this.Start(info.Platform, info.TmId)
}
} else {
this.CancelSignUpAll(info.Platform, info.TmId)
}
}
}
func (this *Tournament) Shutdown() {
this.SaveMatchAward()
module.UnregisteModule(this)
}
// 检查下数据是否合法(主要检查报名人数和晋级方式) n n|...|4|1 // 检查下数据是否合法(主要检查报名人数和晋级方式) n n|...|4|1
func (this *Tournament) checkData(cfg *webapiproto.GameMatchDate) bool { func (this *Tournament) checkData(cfg *webapiproto.GameMatchDate) bool {
if cfg == nil { if cfg == nil {
@ -486,8 +543,8 @@ func (this *Tournament) GetAllMatchInfo(platform string) map[int32]*webapiproto.
return nil return nil
} }
// IsMatching 判断是否在比赛中 // IsGaming 判断是否在比赛中
func (this *Tournament) IsMatching(snId int32) bool { func (this *Tournament) IsGaming(snId int32) bool {
if this.players != nil { if this.players != nil {
for _, v := range this.players { for _, v := range this.players {
if v != nil { if v != nil {
@ -666,7 +723,7 @@ func (this *Tournament) SignUp(tmId int32, p *Player) (bool, int32) {
} }
// 已报名 // 已报名
isWaiting, _ := this.IsMatchWaiting(p.Platform, p.SnId) isWaiting, _ := this.IsMatchWaiting(p.Platform, p.SnId)
if this.IsMatching(p.SnId) || isWaiting { if this.IsGaming(p.SnId) || isWaiting {
return false, int32(tournament.SignRaceCode_OPRC_Repeat) return false, int32(tournament.SignRaceCode_OPRC_Repeat)
} }
if this.GetMatchAwardNum(p.Platform, tmId) <= 0 { if this.GetMatchAwardNum(p.Platform, tmId) <= 0 {
@ -783,7 +840,7 @@ func (this *Tournament) CancelSignUpAll(platform string, tmId int32) {
func (this *Tournament) Quit(platform string, snid int32) { func (this *Tournament) Quit(platform string, snid int32) {
logger.Logger.Tracef("TournamentMgr.Quit: snId:%d", snid) logger.Logger.Tracef("TournamentMgr.Quit: snId:%d", snid)
isWaiting, tmid := this.IsMatchWaiting(platform, snid) isWaiting, tmid := this.IsMatchWaiting(platform, snid)
if isWaiting && !this.IsMatching(snid) { if isWaiting && !this.IsGaming(snid) {
this.CancelSignUp(platform, tmid, snid) this.CancelSignUp(platform, tmid, snid)
} }
} }
@ -861,6 +918,7 @@ func (this *Tournament) Start(platform string, tmId int32) {
// 开始比赛,清除报名数据 // 开始比赛,清除报名数据
for _, v := range signInfo.signup { for _, v := range signInfo.signup {
delete(this.singleSignupPlayers, v.SnId) delete(this.singleSignupPlayers, v.SnId)
delete(this.playerWaitStart, v.SnId)
TaskSubjectSingleton.Touch(common.TaskTypeJoinMatch, &TaskData{ TaskSubjectSingleton.Touch(common.TaskTypeJoinMatch, &TaskData{
SnId: v.SnId, SnId: v.SnId,
GameID: int(tm.dbGameFree.GetGameId()), GameID: int(tm.dbGameFree.GetGameId()),
@ -880,9 +938,10 @@ func (this *Tournament) Start(platform string, tmId int32) {
// StopMatch 比赛结束 // StopMatch 比赛结束
func (this *Tournament) StopMatch(tmId int32, sortId int64) { func (this *Tournament) StopMatch(tmId int32, sortId int64) {
logger.Logger.Tracef("StopMatch%v, %v", tmId, sortId) logger.Logger.Tracef("StopMatch%v, %v", tmId, sortId)
var tm *TmMatch
//房间清理 //房间清理
if this.matches[tmId] != nil && this.matches[tmId][sortId] != nil { if this.matches[tmId] != nil && this.matches[tmId][sortId] != nil {
tm := this.matches[tmId][sortId] tm = this.matches[tmId][sortId]
matchLog := this.MakeMatchLog(tm.Platform, tmId, sortId) matchLog := this.MakeMatchLog(tm.Platform, tmId, sortId)
this.saveMatchLog(matchLog) this.saveMatchLog(matchLog)
tm.Stop() tm.Stop()
@ -1030,6 +1089,25 @@ func (this *Tournament) GetRank(sortId int64, snid int32) int32 {
} }
} }
func (this *Tournament) stopMatch(matchId int32, sortId int64) (isOver bool) {
if this.players[sortId] != nil {
hasReal := false
for snId, context := range this.players[sortId] {
if !context.p.IsRob && !this.isOut(sortId, snId) { // 有真人没有淘汰
hasReal = true
break
}
}
//没有真人比赛解散
if !hasReal {
isOver = true
logger.Logger.Trace("没有真人比赛解散")
this.StopMatch(matchId, sortId)
}
}
return
}
// UpdateMatchInfo 玩家比赛结束 更新积分 // UpdateMatchInfo 玩家比赛结束 更新积分
func (this *Tournament) UpdateMatchInfo(p *Player, sortId int64, grade, isWin int32, matchRobotGrades map[int32]int32) { func (this *Tournament) UpdateMatchInfo(p *Player, sortId int64, grade, isWin int32, matchRobotGrades map[int32]int32) {
logger.Logger.Tracef("UpdateMatchInfo: sortId:%v, grade:%v, isWin: %v, matchRobotGrades:%v", sortId, grade, isWin, matchRobotGrades) logger.Logger.Tracef("UpdateMatchInfo: sortId:%v, grade:%v, isWin: %v, matchRobotGrades:%v", sortId, grade, isWin, matchRobotGrades)
@ -1083,25 +1161,6 @@ func (this *Tournament) UpdateMatchInfo(p *Player, sortId int64, grade, isWin in
} }
} }
func (this *Tournament) stopMatch(matchId int32, sortId int64) (isOver bool) {
if this.players[sortId] != nil {
hasReal := false
for snId, context := range this.players[sortId] {
if !context.p.IsRob && !this.isOut(sortId, snId) { // 有真人没有淘汰
hasReal = true
break
}
}
//没有真人比赛解散
if !hasReal {
isOver = true
logger.Logger.Trace("没有真人比赛解散")
this.StopMatch(matchId, sortId)
}
}
return
}
// NextRoundStartSingle 下一轮是否开始 // NextRoundStartSingle 下一轮是否开始
// 开启机器人时使用 // 开启机器人时使用
func (this *Tournament) NextRoundStartSingle(sortId int64, playerCtx *PlayerMatchContext, matchRobotGrades map[int32]int32) { func (this *Tournament) NextRoundStartSingle(sortId int64, playerCtx *PlayerMatchContext, matchRobotGrades map[int32]int32) {
@ -1283,6 +1342,7 @@ func (this *Tournament) NextRoundStart(sortId int64, playerCtx *PlayerMatchConte
willOut = true willOut = true
} else { } else {
if !meIn { //自己暂时没晋级 if !meIn { //自己暂时没晋级
logger.Logger.Tracef("待定 %+v", info.players)
this.sendPromotionInfo(playerCtx, sortId, DaiDing, false, false) //待定 this.sendPromotionInfo(playerCtx, sortId, DaiDing, false, false) //待定
} }
} }
@ -1307,10 +1367,11 @@ func (this *Tournament) NextRoundStart(sortId int64, playerCtx *PlayerMatchConte
}), nil, time.Second*7, 1) }), nil, time.Second*7, 1)
} }
} else { } else {
this.sendPromotionInfo(playerCtx, sortId, DaiDing, false, false) //待定 // 待定
logger.Logger.Tracef("待定 %+v", info.players)
this.sendPromotionInfo(playerCtx, sortId, DaiDing, false, false)
} }
} else { } else {
if len(info.players) == 4 {
MatchContextSlice(info.players).Sort(true) MatchContextSlice(info.players).Sort(true)
for _, mc := range info.players { for _, mc := range info.players {
outCode := TaoTai outCode := TaoTai
@ -1324,7 +1385,6 @@ func (this *Tournament) NextRoundStart(sortId int64, playerCtx *PlayerMatchConte
// 比赛结束 // 比赛结束
this.StopMatch(playerCtx.tm.TMId, sortId) this.StopMatch(playerCtx.tm.TMId, sortId)
} }
}
} }
// 发送晋级信息 // 发送晋级信息
@ -1877,7 +1937,7 @@ func (this *Tournament) MakeMatchLog(platform string, tmId int32, sortId int64)
matchLog.MatchName = gameMatchDate.MatchName matchLog.MatchName = gameMatchDate.MatchName
matchLog.Platform = platform matchLog.Platform = platform
matchLog.GameFreeId = gameMatchDate.GameFreeId matchLog.GameFreeId = gameMatchDate.GameFreeId
matchLog.StartTime = time.Unix(this.matches[tmId][sortId].StartTime, 0) matchLog.StartTime = this.matches[tmId][sortId].StartTime
matchLog.EndTime = time.Now() matchLog.EndTime = time.Now()
matchLog.SortId = sortId matchLog.SortId = sortId
return matchLog return matchLog
@ -1898,84 +1958,6 @@ func (this *Tournament) saveMatchLog(matchLog *model.MatchLog) {
})).StartByFixExecutor("saveMatchLogTask") })).StartByFixExecutor("saveMatchLogTask")
} }
func (this *Tournament) ModuleName() string {
return "Tournament"
}
func (this *Tournament) Init() {
logger.Logger.Trace("Tournament Init")
for _, v := range PlatformMgrSingleton.GetPlatforms() {
if v == nil || v.IdStr == "0" {
continue
}
ret, err := model.GetMatchAward(v.IdStr)
if err != nil {
logger.Logger.Warnf("GetMatchAward error %v", err)
continue
}
if this.MatchAwardNum == nil {
this.MatchAwardNum = make(map[string]map[int32]int32)
}
this.MatchAwardNum[v.IdStr] = ret.Award
}
}
func (this *Tournament) Update() {
// 使用机器人的情况
for snId, info := range this.singleSignupPlayers {
if info == nil || info.Ts <= 0 {
continue
}
matchInfo := this.GetMatchInfo(info.Platform, info.TmId, 0)
if this.IsMatchOn(matchInfo) && !this.IsOutTime(matchInfo) && this.IsRobotOn(matchInfo) {
needTime := this.playerWaitStart[snId]
if time.Now().Unix()-info.Ts > needTime {
signInfo := &SignInfo{
signup: make(map[int32]*TmPlayer),
Platform: info.Platform,
MaxCnt: int(matchInfo.MatchNumebr),
}
seq := rand.Intn(int(matchInfo.MatchNumebr)) + 1
signInfo.signup[snId] = &TmPlayer{SnId: snId, seq: seq}
this.signupPlayers[info.Platform][info.TmId] = signInfo
//倒计时结束 开始比赛
this.Start(info.Platform, info.TmId)
}
} else {
this.CancelSignUpAll(info.Platform, info.TmId)
}
}
// 防止内存泄露
now := time.Now().Unix()
for _, v := range this.matches {
for _, vv := range v {
if vv != nil && now-vv.StartTime > int64(time.Hour.Seconds()*5) {
for _, p := range vv.TmPlayer {
this.ForceQuit(vv.Platform, p.SnId)
break
}
}
}
}
}
func (this *Tournament) OnDayTimer() {
for k := range this.MatchAwardNum {
this.MatchAwardNum[k] = make(map[int32]int32)
}
task.New(nil, task.CallableWrapper(func(o *basic.Object) interface{} {
this.SaveMatchAward()
return nil
}), nil, "save_match_award_times").Start()
}
func (this *Tournament) Shutdown() {
this.SaveMatchAward()
module.UnregisteModule(this)
}
func (this *Tournament) SaveMatchAward() { func (this *Tournament) SaveMatchAward() {
if this.MatchAwardNum == nil { if this.MatchAwardNum == nil {
return return
@ -2047,11 +2029,44 @@ func (this *Tournament) FixMatchTimeStamp(d *webapiproto.GameMatchDate) {
} }
func (this *Tournament) OnHourTimer() { func (this *Tournament) OnHourTimer() {
now := time.Now()
for _, v := range this.GameMatchDateList { for _, v := range this.GameMatchDateList {
for _, vv := range v { for _, vv := range v {
this.FixMatchTimeStamp(vv) this.FixMatchTimeStamp(vv)
} }
} }
// 防止异常情况卡房间
for _, v := range this.matches {
for _, vv := range v {
if vv != nil && (now.Sub(vv.RoundTime).Hours() >= 1 || now.Sub(vv.StartTime).Hours() > 5) {
logger.Logger.Errorf("比赛异常 %v", vv)
this.StopMatch(vv.TMId, vv.SortId)
}
}
}
for sortId := range this.players {
for _, tm := range this.matches {
if _, ok := tm[sortId]; !ok {
for _, v := range this.players[sortId] {
if v != nil {
logger.Logger.Errorf("比赛异常 %v", v.tm)
}
break
}
this.StopMatch(0, sortId)
}
}
}
}
func (this *Tournament) OnDayTimer() {
for k := range this.MatchAwardNum {
this.MatchAwardNum[k] = make(map[int32]int32)
}
task.New(nil, task.CallableWrapper(func(o *basic.Object) interface{} {
this.SaveMatchAward()
return nil
}), nil, "save_match_award_times").Start()
} }
// GetMatchAwardNum 剩余奖励数量 // GetMatchAwardNum 剩余奖励数量
@ -2080,6 +2095,7 @@ func (this *Tournament) GetMatchAwardNum(platform string, id int32) int32 {
return num return num
} }
// GetRound 获取当前轮次
func (this *Tournament) GetRound(sortId int64) int32 { func (this *Tournament) GetRound(sortId int64) int32 {
d, ok := this.roundPlayers[sortId] d, ok := this.roundPlayers[sortId]
if !ok || d == nil { if !ok || d == nil {