保存玩家游戏数据

This commit is contained in:
sk 2024-08-30 14:49:55 +08:00
parent a77cfa41dd
commit fa57f5e8e6
9 changed files with 328 additions and 22 deletions

View File

@ -452,6 +452,22 @@ func SliceValueWeight(sl []int, index int) float64 {
return float64(value) / float64(totle)
}
func GetMapKeys[K comparable, V any](data map[K]V) []K {
var ret []K
for k := range data {
ret = append(ret, k)
}
return ret
}
func GetMapValues[K comparable, V any](data map[K]V) []V {
var ret []V
for _, v := range data {
ret = append(ret, v)
}
return ret
}
type Int32Slice []int32
func (p Int32Slice) Len() int { return len(p) }

View File

@ -0,0 +1,71 @@
package svc
import (
"errors"
"net/rpc"
"github.com/globalsign/mgo"
"github.com/globalsign/mgo/bson"
"mongo.games.com/game/dbproxy/mongo"
"mongo.games.com/game/model"
)
var (
PlayerGameDataDBName = "user"
PlayerGameDataCollName = "user_gamedata"
PlayerGameDataColError = errors.New("PlayerGameData collection open failed")
PlayerGameDataSvcSingle = &PlayerGameDataSvc{}
)
func PlayerGameDataCollection(plt string) *mongo.Collection {
s := mongo.MgoSessionMgrSington.GetPltMgoSession(plt, PlayerGameDataDBName)
if s != nil {
c, first := s.DB().C(PlayerGameDataCollName)
if first {
c.EnsureIndex(mgo.Index{Key: []string{"snid", "id"}, Unique: true, Background: true, Sparse: true})
c.EnsureIndex(mgo.Index{Key: []string{"id"}, Background: true, Sparse: true})
}
return c
}
return nil
}
func init() {
rpc.Register(PlayerGameDataSvcSingle)
}
type PlayerGameDataSvc struct{}
func (p *PlayerGameDataSvc) Save(req *model.PlayerGameSaveReq, b *bool) error {
c := PlayerGameDataCollection(req.Platform)
if c == nil {
return PlayerGameDataColError
}
for _, v := range req.Data {
_, err := c.Upsert(bson.M{"snid": v.SnId, "id": v.Id}, v)
if err != nil {
return err
}
}
*b = true
return nil
}
func (p *PlayerGameDataSvc) Find(req *model.PlayerGameDataFindReq, res *model.PlayerGameDataFindRes) error {
c := PlayerGameDataCollection(req.Platform)
if c == nil {
return PlayerGameDataColError
}
var ret []*model.PlayerGameData
err := c.Find(bson.M{"snid": req.SnId}).All(&ret)
if err != nil {
return err
}
res.Data = ret
return nil
}

View File

@ -68,8 +68,8 @@ const (
)
type Player struct {
model.PlayerData //po 持久化对象
ExtraData interface{} //扩展接口
model.WGPlayerInfo
ExtraData interface{} //具体游戏对局中的玩家扩展信息
gateSess *netlib.Session //所在GateServer的session
worldSess *netlib.Session //所在WorldServer的session
scene *Scene //当前所在个Scene
@ -141,13 +141,15 @@ func NewPlayer(sid int64, data []byte, ws, gs *netlib.Session) *Player {
RankScore: make(map[int32]int64),
}
// 需要make的统一在这里初始化默认值,别的地方就不用再初始化了
p.PlayerData = model.PlayerData{
//TotalGameData: make(map[int][]*model.PlayerGameTotal),
//todo 初始化
p.WGPlayerInfo = model.WGPlayerInfo{
PlayerData: &model.PlayerData{
GDatas: make(map[string]*model.PlayerGameInfo),
ShopTotal: make(map[int32]*model.ShopTotal),
ShopLastLookTime: make(map[int32]int64),
IsFoolPlayer: make(map[string]bool),
},
GameData: make(map[int32]*model.PlayerGameData),
}
if p.init(data) {
@ -373,7 +375,20 @@ func (this *Player) OnAudienceLeave(reason int) {
}
func (this *Player) MarshalData(gameid int) (d []byte, e error) {
d, e = netlib.Gob.Marshal(&this.PlayerData)
// 防止参数遗漏
for k, v := range this.GameData {
if v.SnId == 0 {
v.SnId = this.SnId
}
if v.Platform == "" {
v.Platform = this.Platform
}
if v.Id == 0 {
v.Id = k
}
}
d, e = netlib.Gob.Marshal(&this.WGPlayerInfo)
logger.Logger.Trace("(this *Player) MarshalData(gameid int)")
return
}
@ -382,7 +397,7 @@ func (this *Player) UnmarshalData(data []byte) bool {
if len(data) == 0 {
return true
}
err := netlib.Gob.Unmarshal(data, &this.PlayerData)
err := netlib.Gob.Unmarshal(data, &this.WGPlayerInfo)
if err == nil {
this.dirty = true
return true

View File

@ -1984,7 +1984,7 @@ func (this *Scene) TryBillExGameDrop(p *Player) {
itemData := srvdata.GameItemMgr.Get(p.Platform, id)
if itemData != nil {
p.AddItems(&model.AddItemParam{
P: &p.PlayerData,
P: p.PlayerData,
Change: nil,
GainWay: common.GainWay_Game,
Operator: "system",
@ -2021,7 +2021,7 @@ func (this *Scene) DropCollectBox(p *Player) {
if itemData != nil {
pack.Items = map[int32]int32{itemData.Id: 1}
p.AddItems(&model.AddItemParam{
P: &p.PlayerData,
P: p.PlayerData,
Change: []*model.Item{
{
ItemId: itemData.Id,

View File

@ -1803,7 +1803,7 @@ func (this *SceneBilledStateTienLen) OnEnter(s *base.Scene) {
// vip加成分
vipScore = int64(math.Ceil(float64(rankScore) * float64(losePlayer.VipExtra) / 100.0))
// 角色加成分
_, roleAdd = srvdata.RolePetMgrSington.GetRoleAdd(&losePlayer.PlayerData, common.RoleAddRankScore)
_, roleAdd = srvdata.RolePetMgrSington.GetRoleAdd(losePlayer.PlayerData, common.RoleAddRankScore)
roleScore = int64(math.Ceil(float64(rankScore) * float64(roleAdd) / 100.0))
//周卡加成
if losePlayer.GetWeekCardPrivilege(2) {
@ -1945,7 +1945,7 @@ func (this *SceneBilledStateTienLen) OnEnter(s *base.Scene) {
// vip加成分
vipScore = int64(math.Ceil(float64(rankScore) * float64(lastWinPlayer.VipExtra) / 100.0))
// 角色加成分
_, roleAdd = srvdata.RolePetMgrSington.GetRoleAdd(&lastWinPlayer.PlayerData, common.RoleAddRankScore)
_, roleAdd = srvdata.RolePetMgrSington.GetRoleAdd(lastWinPlayer.PlayerData, common.RoleAddRankScore)
roleScore = int64(math.Ceil(float64(rankScore) * float64(roleAdd) / 100.0))
//周卡加成
if lastWinPlayer.GetWeekCardPrivilege(2) {
@ -2056,7 +2056,7 @@ func (this *SceneBilledStateTienLen) OnEnter(s *base.Scene) {
// vip加成分
vipScore = int64(math.Ceil(float64(rankScore) * float64(playerEx.VipExtra) / 100.0))
// 角色加成分
_, roleAdd = srvdata.RolePetMgrSington.GetRoleAdd(&playerEx.PlayerData, common.RoleAddRankScore)
_, roleAdd = srvdata.RolePetMgrSington.GetRoleAdd(playerEx.PlayerData, common.RoleAddRankScore)
roleScore = int64(math.Ceil(float64(rankScore) * float64(roleAdd) / 100.0))
//周卡加成
if playerEx.GetWeekCardPrivilege(2) {
@ -2161,7 +2161,7 @@ func (this *SceneBilledStateTienLen) OnEnter(s *base.Scene) {
// vip加成分
vipScore = int64(math.Ceil(float64(rankScore) * float64(playerEx.VipExtra) / 100.0))
// 角色加成分
_, roleAdd = srvdata.RolePetMgrSington.GetRoleAdd(&playerEx.PlayerData, common.RoleAddRankScore)
_, roleAdd = srvdata.RolePetMgrSington.GetRoleAdd(playerEx.PlayerData, common.RoleAddRankScore)
roleScore = int64(math.Ceil(float64(rankScore) * float64(roleAdd) / 100.0))
//周卡加成
if playerEx.GetWeekCardPrivilege(2) {
@ -2310,7 +2310,7 @@ func (this *SceneBilledStateTienLen) OnEnter(s *base.Scene) {
// vip加成分
vipScore = int64(math.Ceil(float64(rankScore) * float64(playerEx.VipExtra) / 100.0))
// 角色加成分
_, roleAdd = srvdata.RolePetMgrSington.GetRoleAdd(&playerEx.PlayerData, common.RoleAddRankScore)
_, roleAdd = srvdata.RolePetMgrSington.GetRoleAdd(playerEx.PlayerData, common.RoleAddRankScore)
roleScore = int64(math.Ceil(float64(rankScore) * float64(roleAdd) / 100.0))
//周卡加成
if playerEx.GetWeekCardPrivilege(2) {
@ -2442,7 +2442,7 @@ func (this *SceneBilledStateTienLen) OnEnter(s *base.Scene) {
// vip加成分
vipScore = int64(math.Ceil(float64(rankScore) * float64(playerEx.VipExtra) / 100.0))
// 角色加成分
_, roleAdd = srvdata.RolePetMgrSington.GetRoleAdd(&playerEx.PlayerData, common.RoleAddRankScore)
_, roleAdd = srvdata.RolePetMgrSington.GetRoleAdd(playerEx.PlayerData, common.RoleAddRankScore)
roleScore = int64(math.Ceil(float64(rankScore) * float64(roleAdd) / 100.0))
//周卡加成
if playerEx.GetWeekCardPrivilege(2) {
@ -2613,7 +2613,7 @@ func (this *SceneBilledStateTienLen) OnEnter(s *base.Scene) {
}
}
p.AddItems(&model.AddItemParam{
P: &p.PlayerData,
P: p.PlayerData,
Change: items,
GainWay: common.GainWayRoomGain,
Operator: "system",

View File

@ -344,6 +344,13 @@ type MatchFreeSignupRec struct {
UseTimes int32 //累计使用免费次数
}
// WGPlayerInfo 游戏服玩家信息
// 大厅玩家信息发送给游戏服
type WGPlayerInfo struct {
*PlayerData
GameData map[int32]*PlayerGameData // 游戏数据,只允许存储玩家对应某个游戏需要持久化的数据
}
type PlayerData struct {
Id bson.ObjectId `bson:"_id"`
AccountId string //账号id

56
model/playergamedata.go Normal file
View File

@ -0,0 +1,56 @@
package model
import (
"time"
"mongo.games.com/goserver/core/logger"
)
type PlayerGameData struct {
Platform string `bson:"-"`
SnId int32
Id int32 // 游戏id或场次id
Data interface{} // 数据
}
type PlayerGameSaveReq struct {
Platform string
Data []*PlayerGameData
}
func SavePlayerGameData(platform string, data []*PlayerGameData) error {
if rpcCli == nil {
logger.Logger.Error("model.SavePlayerGameData rpcCli == nil")
return nil
}
b := false
err := rpcCli.CallWithTimeout("PlayerGameDataSvc.Save", &PlayerGameSaveReq{Platform: platform, Data: data}, &b, time.Second*30)
if err != nil {
logger.Logger.Error("model.SavePlayerGameData err:%v", err)
return err
}
return nil
}
type PlayerGameDataFindReq struct {
Platform string
SnId int32
}
type PlayerGameDataFindRes struct {
Data []*PlayerGameData
}
func GetPlayerGameData(platform string, snid int32) ([]*PlayerGameData, error) {
if rpcCli == nil {
logger.Logger.Error("model.GetPlayerGameData rpcCli == nil")
return nil, nil
}
res := &PlayerGameDataFindRes{}
err := rpcCli.CallWithTimeout("PlayerGameDataSvc.Find", &PlayerGameDataFindReq{Platform: platform, SnId: snid}, res, time.Second*30)
if err != nil {
logger.Logger.Error("model.GetPlayerGameData err:%v", err)
return nil, err
}
return res.Data, nil
}

View File

@ -1663,14 +1663,21 @@ func (this *Player) OnLogouted() {
}
func (this *Player) MarshalData() (d []byte, e error) {
d, e = netlib.Gob.Marshal(this.PlayerData)
data := &model.WGPlayerInfo{
PlayerData: this.PlayerData,
}
info := PlayerInfoMgrSingle.Players[this.SnId]
if info != nil {
data.GameData = info.GameData
}
d, e = netlib.Gob.Marshal(data)
return
}
// UnmarshalData 更新玩家数据
// 例如游戏服数据同步
func (this *Player) UnmarshalData(data []byte, scene *Scene) {
pd := &model.PlayerData{}
pd := &model.WGPlayerInfo{}
if err := netlib.Gob.Unmarshal(data, pd); err != nil {
logger.Logger.Warn("Player.SyncData err:", err)
return
@ -1687,6 +1694,12 @@ func (this *Player) UnmarshalData(data []byte, scene *Scene) {
this.GDatas[v] = d
}
}
// PlayerInfo 同步
info := PlayerInfoMgrSingle.Players[this.SnId]
if info == nil {
PlayerInfoMgrSingle.Players[this.SnId] = &PlayerInfo{}
}
info.GameData = pd.GameData
this.LastRechargeWinCoin = pd.LastRechargeWinCoin
oldRecharge := int64(0)

128
worldsrv/playerinfo.go Normal file
View File

@ -0,0 +1,128 @@
package main
import (
"strconv"
"mongo.games.com/goserver/core/basic"
"mongo.games.com/goserver/core/logger"
"mongo.games.com/goserver/core/task"
"mongo.games.com/game/common"
"mongo.games.com/game/model"
"mongo.games.com/game/worldsrv/internal"
)
/*
玩家信息加载缓存持久化缓存释放
*/
func init() {
internal.RegisterPlayerLoad(PlayerInfoMgrSingle)
}
var PlayerInfoMgrSingle = &PlayerInfoMgr{
Players: make(map[int32]*PlayerInfo),
}
type AllPlayerInfo struct {
GameData []*model.PlayerGameData
}
// PlayerInfo 玩家信息
type PlayerInfo struct {
GameData map[int32]*model.PlayerGameData // 游戏数据
}
type PlayerInfoMgr struct {
Players map[int32]*PlayerInfo
}
func (p *PlayerInfoMgr) Load(platform string, snid int32, player any) *internal.PlayerLoadReplay {
var err error
allPlayerInfo := &AllPlayerInfo{
GameData: make([]*model.PlayerGameData, 0),
}
// 游戏数据
gameData, err := model.GetPlayerGameData(platform, snid)
if err != nil {
logger.Logger.Errorf("GetPlayerGameData snid:%v error: %v", snid, err)
goto here
}
allPlayerInfo.GameData = gameData
// ...
here:
return &internal.PlayerLoadReplay{
Platform: platform,
Snid: snid,
Err: err,
Data: allPlayerInfo,
}
}
func (p *PlayerInfoMgr) Callback(player any, ret *internal.PlayerLoadReplay) {
if ret.Err != nil {
return
}
data, ok := ret.Data.(*AllPlayerInfo)
if !ok {
return
}
info := &PlayerInfo{
GameData: make(map[int32]*model.PlayerGameData),
}
// 游戏数据
for _, v := range data.GameData {
info.GameData[v.Id] = v
}
// ...
p.Players[ret.Snid] = info
}
func (p *PlayerInfoMgr) LoadAfter(platform string, snid int32) *internal.PlayerLoadReplay {
return nil
}
func (p *PlayerInfoMgr) CallbackAfter(ret *internal.PlayerLoadReplay) {
}
func (p *PlayerInfoMgr) Save(platform string, snid int32, isSync, force bool) {
var err error
f := func() {
data, ok := p.Players[snid]
if !ok {
return
}
// 游戏数据
err = model.SavePlayerGameData(platform, common.GetMapValues(data.GameData))
if err != nil {
logger.Logger.Errorf("SavePlayerGameData snid:%v error: %v", snid, err)
}
// ...
}
cf := func() {
}
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()
}), "SavePlayerInfo").StartByFixExecutor("SnId:" + strconv.Itoa(int(snid)))
}
func (p *PlayerInfoMgr) Release(platform string, snid int32) {
delete(p.Players, snid)
}