1025 lines
27 KiB
Go
1025 lines
27 KiB
Go
package main
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"time"
|
|
|
|
"github.com/globalsign/mgo/bson"
|
|
"golang.org/x/exp/maps"
|
|
"mongo.games.com/goserver/core/basic"
|
|
"mongo.games.com/goserver/core/i18n"
|
|
"mongo.games.com/goserver/core/logger"
|
|
"mongo.games.com/goserver/core/module"
|
|
"mongo.games.com/goserver/core/task"
|
|
|
|
"mongo.games.com/game/common"
|
|
"mongo.games.com/game/model"
|
|
"mongo.games.com/game/proto"
|
|
"mongo.games.com/game/protocol/bag"
|
|
playerproto "mongo.games.com/game/protocol/player"
|
|
webapiproto "mongo.games.com/game/protocol/webapi"
|
|
"mongo.games.com/game/srvdata"
|
|
"mongo.games.com/game/webapi"
|
|
"mongo.games.com/game/worldsrv/internal"
|
|
)
|
|
|
|
func init() {
|
|
module.RegisteModule(BagMgrSingleton, time.Second, 0)
|
|
internal.RegisterPlayerLoad(BagMgrSingleton)
|
|
|
|
BagMgrSingleton.AddOnChangeFuncs(func(param *model.ChangeItemParam) {
|
|
p := PlayerMgrSington.GetPlayerBySnId(param.SnId)
|
|
if p == nil {
|
|
return
|
|
}
|
|
itemData := srvdata.GameItemMgr.Get(p.Platform, param.ItemId)
|
|
if itemData == nil {
|
|
return
|
|
}
|
|
|
|
logType := ItemObtain
|
|
if param.ItemNum < 0 {
|
|
logType = ItemConsume
|
|
}
|
|
//获奖记录log
|
|
if logType == ItemObtain && param.ItemNum > 0 {
|
|
awardLogType := 0
|
|
if itemData.Type == common.ItemTypeChange {
|
|
//话费
|
|
awardLogType = 1
|
|
} else if itemData.Type == common.ItemTypeObjective {
|
|
//实物
|
|
awardLogType = 2
|
|
AwardLogMgr.UpdateAwardLog(p.Platform, itemData.Id, param.ItemNum)
|
|
}
|
|
if awardLogType != 0 {
|
|
data := model.AnnouncerLog{
|
|
Platform: p.Platform,
|
|
Snid: p.SnId,
|
|
Name: p.Name,
|
|
Phone: p.Tel,
|
|
ItemId: param.ItemId, //获得物品ID
|
|
TypeId: int32(awardLogType),
|
|
}
|
|
AwardLogMgr.UpdateAnnouncerLog(data)
|
|
}
|
|
}
|
|
|
|
// 皮肤自动解锁
|
|
if p != nil && itemData.GetType() == 21 && param.ItemNum > 0 {
|
|
p.AutoSkinUnlock()
|
|
}
|
|
|
|
if param.ItemNum > 0 {
|
|
switch param.ItemId {
|
|
case common.ItemIDWeekScore:
|
|
TaskSubjectSingleton.Touch(common.TaskTypeActivityScore, &TaskData{
|
|
SnId: p.SnId,
|
|
Num: param.ItemNum,
|
|
})
|
|
case common.ItemIDPetSkill:
|
|
PetMgrSington.CheckShowRed(p)
|
|
|
|
case common.ItemIDPermit, common.ItemIDLong:
|
|
var permitScore, long int64
|
|
if param.ItemId == common.ItemIDLong {
|
|
long = param.ItemNum
|
|
} else {
|
|
permitScore = param.ItemNum
|
|
}
|
|
LogChannelSingleton.WriteLog(&model.BackendPermitJoin{
|
|
Platform: p.Platform,
|
|
StartTs: PlatformMgrSingleton.GetConfig(p.Platform).PermitStartTs,
|
|
SnId: p.SnId,
|
|
Score: permitScore,
|
|
Long: long,
|
|
Ts: time.Now().Unix(),
|
|
})
|
|
|
|
}
|
|
|
|
switch itemData.GetType() {
|
|
case common.ItemTypeSkinChip:
|
|
PetMgrSington.CheckSkinRed(p)
|
|
}
|
|
}
|
|
|
|
// 统计 v卡兑换消耗数量
|
|
if p != nil && param.ItemId == common.ItemIDVCard && param.GainWay == common.GainWay_Exchange {
|
|
p.VCardCost += -param.ItemNum
|
|
if p.VCardCost < 0 {
|
|
p.VCardCost = 0
|
|
}
|
|
}
|
|
|
|
// 更新通行证赛季积分排行榜
|
|
if param.ItemId == common.ItemIDPermit {
|
|
item := BagMgrSingleton.GetItem(p.SnId, param.ItemId)
|
|
startTs := PlatformMgrSingleton.GetConfig(p.Platform).PermitStartTs
|
|
if item != nil && item.ItemNum > 0 && startTs > 0 {
|
|
// 赛季积分排行榜
|
|
LogChannelSingleton.WriteLog(&model.PermitScore{
|
|
Platform: p.Platform,
|
|
SnId: p.SnId,
|
|
Name: p.Name,
|
|
Exp: item.ItemNum,
|
|
ModId: p.Roles.ModId,
|
|
StartTs: startTs,
|
|
Ts: time.Now().Unix(),
|
|
})
|
|
}
|
|
}
|
|
|
|
// 更新好友信息
|
|
if param.ItemId == common.ItemIDVCard {
|
|
FriendMgrSington.UpdateInfo(p.Platform, p.SnId)
|
|
}
|
|
})
|
|
}
|
|
|
|
const (
|
|
BagItemMax int32 = 200
|
|
)
|
|
|
|
// 道具功能 Function
|
|
const (
|
|
ItemCanUse = iota //可以使用
|
|
ItemCanGive //可以赠送
|
|
ItemCanSell //可以出售
|
|
ItemCanExchange //可以兑换
|
|
ItemCanFen //可以分解
|
|
ItemMax
|
|
)
|
|
|
|
type Item struct {
|
|
ItemId int32 // 物品ID
|
|
ItemNum int64 // 物品数量
|
|
ObtainTime int64 //获取的时间
|
|
//数据表数据
|
|
Name string // 名称
|
|
Effect0 []int32 // 竖版道具功能 ItemCanUse ...
|
|
Effect []int32 // 横版道具功能 ItemCanUse ...
|
|
SaleType int32 // 出售类型
|
|
SaleGold int32 // 出售金额
|
|
}
|
|
|
|
type BagInfo struct {
|
|
SnId int32 //玩家id
|
|
Platform string //平台id
|
|
BagItem map[int32]*Item //背包数据 key为itemId
|
|
Ts int64 //更新时间戳
|
|
|
|
// 临时携带参数
|
|
dirty bool `bson:"-"` //是否需要更新数据库
|
|
LogId string `bson:"-"` //最后一次保存的日志id
|
|
}
|
|
|
|
func NewBagInfo(platform string, snid int32) *BagInfo {
|
|
return &BagInfo{
|
|
SnId: snid,
|
|
Platform: platform,
|
|
BagItem: make(map[int32]*Item),
|
|
Ts: time.Now().Unix(),
|
|
dirty: true,
|
|
LogId: "",
|
|
}
|
|
}
|
|
|
|
// BagMgrSingleton 背包管理器
|
|
var BagMgrSingleton = &BagMgr{
|
|
PlayerBag: make(map[int32]*BagInfo),
|
|
}
|
|
|
|
type BagMgr struct {
|
|
PlayerBag map[int32]*BagInfo // snid:背包
|
|
|
|
// 道具变更监听,玩家离线时道具变更会在登录时根据道具日志执行一遍
|
|
onChangeFuncs []func(param *model.ChangeItemParam)
|
|
}
|
|
|
|
func (this *BagMgr) ModuleName() string {
|
|
return "BagMgr"
|
|
}
|
|
|
|
func (this *BagMgr) Init() {
|
|
}
|
|
|
|
func (this *BagMgr) Update() {
|
|
}
|
|
|
|
func (this *BagMgr) Shutdown() {
|
|
module.UnregisteModule(this)
|
|
}
|
|
|
|
func (this *BagMgr) AddOnChangeFuncs(f ...func(param *model.ChangeItemParam)) {
|
|
this.onChangeFuncs = append(this.onChangeFuncs, f...)
|
|
}
|
|
|
|
func (this *BagMgr) OnChangeFuncs(param *model.ChangeItemParam) {
|
|
logger.Logger.Tracef("OnChangeFuncs %+v", *param)
|
|
for _, v := range this.onChangeFuncs {
|
|
v(param)
|
|
}
|
|
}
|
|
|
|
// GetItem 获取个人的指定道具信息
|
|
func (this *BagMgr) GetItem(snid, itemId int32) *Item {
|
|
p := PlayerMgrSington.GetPlayerBySnId(snid)
|
|
if p == nil {
|
|
return nil
|
|
}
|
|
|
|
item := &Item{
|
|
ItemId: itemId,
|
|
}
|
|
f := func() {
|
|
itemX := srvdata.GameItemMgr.Get(p.Platform, itemId)
|
|
if itemX != nil {
|
|
item.Name = itemX.Name
|
|
item.Effect0 = itemX.Effect
|
|
item.Effect = itemX.Effect
|
|
item.SaleType = itemX.SaleType
|
|
item.SaleGold = itemX.SaleGold
|
|
}
|
|
}
|
|
|
|
switch itemId {
|
|
case common.ItemIDCoin:
|
|
item.ItemNum = p.Coin
|
|
f()
|
|
case common.ItemIDDiamond:
|
|
item.ItemNum = p.Diamond
|
|
f()
|
|
default:
|
|
if bagItem, ok := this.PlayerBag[snid]; ok {
|
|
if bagItem != nil {
|
|
item = bagItem.BagItem[itemId]
|
|
if item != nil {
|
|
f()
|
|
return item
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return item
|
|
}
|
|
|
|
// Range 遍历背包
|
|
func (this *BagMgr) Range(snid int32, fn func(item *Item) bool) {
|
|
if v, exist := this.PlayerBag[snid]; exist {
|
|
for k := range v.BagItem {
|
|
e := this.GetItem(snid, k)
|
|
if e == nil {
|
|
continue
|
|
}
|
|
if !fn(e) {
|
|
return
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// GetBagInfo 获取背包信息
|
|
// 是复制的一份数据
|
|
func (this *BagMgr) GetBagInfo(snid int32) *BagInfo {
|
|
p := PlayerMgrSington.GetPlayerBySnId(snid)
|
|
if p == nil {
|
|
return nil
|
|
}
|
|
ret := NewBagInfo(p.Platform, p.SnId)
|
|
if v, exist := this.PlayerBag[snid]; exist {
|
|
ret.Ts = v.Ts
|
|
ret.dirty = v.dirty
|
|
ret.LogId = v.LogId
|
|
for k := range v.BagItem {
|
|
ret.BagItem[k] = this.GetItem(snid, k)
|
|
}
|
|
} else {
|
|
this.PlayerBag[snid] = NewBagInfo(p.Platform, p.SnId)
|
|
}
|
|
return ret
|
|
}
|
|
|
|
// SyncBagData 通知玩家背包数据变化
|
|
func (this *BagMgr) SyncBagData(snid int32, changeItemIds ...int32) {
|
|
if len(changeItemIds) == 0 {
|
|
return
|
|
}
|
|
p := PlayerMgrSington.GetPlayerBySnId(snid)
|
|
if p == nil || p.IsRob {
|
|
return
|
|
}
|
|
|
|
var itemInfos []*bag.ItemInfo
|
|
for _, itemId := range changeItemIds {
|
|
itemInfo := this.GetItem(snid, itemId)
|
|
if itemInfo != nil {
|
|
itemInfos = append(itemInfos, &bag.ItemInfo{
|
|
ItemId: itemInfo.ItemId,
|
|
ItemNum: itemInfo.ItemNum,
|
|
ObtainTime: itemInfo.ObtainTime,
|
|
})
|
|
}
|
|
}
|
|
pack := &bag.SCSyncBagData{
|
|
Infos: itemInfos,
|
|
}
|
|
p.SendToClient(int(bag.SPacketID_PACKET_SC_SYNCBAGDATA), pack)
|
|
logger.Logger.Tracef("背包数据变更(%v): %v", p.SnId, pack)
|
|
}
|
|
|
|
// AddItemCheck 校验道具是否充足
|
|
// 返回道具变化,操作结果,是否成功
|
|
func (this *BagMgr) AddItemCheck(param *model.AddItemParam) ([]*model.Item, bag.OpResultCode, bool) {
|
|
var items []*model.Item // 道具变化
|
|
p := PlayerMgrSington.GetPlayerBySnId(param.SnId)
|
|
if p == nil {
|
|
return items, bag.OpResultCode_OPRC_NotPlayer, false
|
|
}
|
|
|
|
// 获取背包
|
|
var newBagInfo *BagInfo
|
|
if _, exist := this.PlayerBag[p.SnId]; !exist {
|
|
newBagInfo = NewBagInfo(p.Platform, p.SnId)
|
|
this.PlayerBag[p.SnId] = newBagInfo
|
|
} else {
|
|
newBagInfo = this.PlayerBag[p.SnId]
|
|
}
|
|
|
|
// 参数校验
|
|
for _, v := range param.Change {
|
|
if v == nil || v.ItemNum == 0 {
|
|
continue
|
|
}
|
|
item := srvdata.GameItemMgr.Get(p.Platform, v.ItemId)
|
|
if item == nil {
|
|
return items, bag.OpResultCode_OPRC_IdErr, false
|
|
}
|
|
if itm, exist := newBagInfo.BagItem[v.ItemId]; exist {
|
|
if v.ItemNum < 0 && itm.ItemNum < -v.ItemNum {
|
|
return items, bag.OpResultCode_OPRC_UseUp, false
|
|
}
|
|
} else {
|
|
if v.ItemNum < 0 {
|
|
return items, bag.OpResultCode_OPRC_UseUp, false
|
|
}
|
|
}
|
|
items = append(items, &model.Item{
|
|
ItemId: v.ItemId,
|
|
ItemNum: v.ItemNum,
|
|
ObtainTime: v.ObtainTime,
|
|
})
|
|
}
|
|
return items, bag.OpResultCode_OPRC_Sucess, true
|
|
}
|
|
|
|
// AddItems 修改道具,玩家需在线
|
|
func (this *BagMgr) AddItems(param *model.AddItemParam) (*BagInfo, bag.OpResultCode, bool) {
|
|
p := PlayerMgrSington.GetPlayerBySnId(param.SnId)
|
|
if p == nil {
|
|
return nil, bag.OpResultCode_OPRC_NotPlayer, false
|
|
}
|
|
|
|
// 非道具
|
|
var realItems []*model.Item
|
|
for _, v := range param.Change {
|
|
if v == nil || v.ItemNum == 0 {
|
|
continue
|
|
}
|
|
item := srvdata.GameItemMgr.Get(p.Platform, v.ItemId)
|
|
if item == nil {
|
|
continue
|
|
}
|
|
switch item.Type {
|
|
case common.ItemTypeCoin:
|
|
//增加金币
|
|
if item.Id == common.ItemIDCoin {
|
|
p.AddCoin(v.ItemNum, param.Add, param.GainWay, param.Operator, param.Remark)
|
|
}
|
|
case common.ItemTypeDiamond:
|
|
//增加钻石
|
|
if item.Id == common.ItemIDDiamond {
|
|
p.AddDiamond(v.ItemNum, param.Add, param.GainWay, param.Operator, param.Remark)
|
|
}
|
|
case common.ItemTypeFishPower:
|
|
//增加炮台
|
|
//p.ItemUnPlayerPowerListEx(v.ItemId)
|
|
case common.ItemTypeMoneyPond:
|
|
//增加个人金币池
|
|
//if v.ItemId == common.ItemIDMoneyPond {
|
|
// p.MoneyPond += v.ItemNum
|
|
//}
|
|
case common.ItemTypeVipExp:
|
|
//增加玩家VIP经验
|
|
if v.ItemId == common.ItemIDVipExp {
|
|
p.AddMoneyPayTotal(v.ItemNum)
|
|
}
|
|
case common.ItemTypeShopScore:
|
|
if v.ItemId == common.ItemIDPhoneScore {
|
|
p.AddPhoneScore(v.ItemNum, 0, param.GainWay, param.Operator, param.Remark)
|
|
}
|
|
case common.ItemTypeExpireTime:
|
|
p.AddItemRecExpireTime(v.ItemId, v.ItemNum, 0, param.GainWay, param.Operator, param.Remark)
|
|
default:
|
|
// 道具变化
|
|
realItems = append(realItems, v)
|
|
}
|
|
}
|
|
param.Change = realItems
|
|
if len(realItems) == 0 {
|
|
return nil, bag.OpResultCode_OPRC_Sucess, true
|
|
}
|
|
// 非道具
|
|
|
|
items, code, ok := this.AddItemCheck(param)
|
|
if !ok {
|
|
return nil, code, ok
|
|
}
|
|
|
|
if len(items) == 0 {
|
|
return nil, bag.OpResultCode_OPRC_Sucess, true
|
|
}
|
|
|
|
newBagInfo, ok := this.PlayerBag[param.SnId]
|
|
if !ok {
|
|
newBagInfo = NewBagInfo(p.Platform, p.SnId)
|
|
this.PlayerBag[param.SnId] = newBagInfo
|
|
}
|
|
|
|
// 更新背包
|
|
var ts int64 // 最新日志纳秒时间戳
|
|
var itemInfos []int32
|
|
for _, v := range items {
|
|
itemData := srvdata.GameItemMgr.Get(p.Platform, v.ItemId)
|
|
if itemData == nil {
|
|
continue
|
|
}
|
|
if itm, exist := newBagInfo.BagItem[v.ItemId]; exist {
|
|
itm.ItemNum += v.ItemNum
|
|
} else {
|
|
newBagInfo.BagItem[v.ItemId] = &Item{
|
|
ItemId: v.ItemId, // 物品id
|
|
ItemNum: v.ItemNum, // 数量
|
|
ObtainTime: time.Now().Unix(),
|
|
}
|
|
}
|
|
|
|
num := v.ItemNum
|
|
logType := ItemObtain
|
|
if v.ItemNum < 0 {
|
|
logType = ItemConsume
|
|
num = -v.ItemNum
|
|
}
|
|
// 日志
|
|
log := model.NewItemLogEx(model.ItemParam{
|
|
Platform: p.Platform,
|
|
SnId: p.SnId,
|
|
LogType: int32(logType),
|
|
ItemId: v.ItemId,
|
|
ItemName: itemData.Name,
|
|
Count: num,
|
|
Remark: param.Remark,
|
|
TypeId: param.GainWay,
|
|
GameId: param.GameId,
|
|
GameFreeId: param.GameFreeId,
|
|
Cost: param.Cost,
|
|
LogId: param.LogId,
|
|
RoomConfigId: param.RoomConfigId,
|
|
})
|
|
if log != nil {
|
|
LogChannelSingleton.WriteLog(log)
|
|
ts = log.Ts
|
|
newBagInfo.LogId = log.LogId.Hex()
|
|
}
|
|
// 监听道具变化
|
|
this.OnChangeFuncs(&model.ChangeItemParam{
|
|
SnId: p.SnId,
|
|
ItemId: v.ItemId,
|
|
ItemNum: num,
|
|
GainWay: param.GainWay,
|
|
RoomConfigId: param.RoomConfigId,
|
|
GameId: param.GameId,
|
|
GameFreeId: param.GameFreeId,
|
|
Cost: param.Cost,
|
|
})
|
|
|
|
itemInfo := this.GetItem(p.SnId, v.ItemId)
|
|
if itemInfo != nil {
|
|
itemInfos = append(itemInfos, v.ItemId)
|
|
}
|
|
}
|
|
newBagInfo.dirty = true
|
|
if ts > newBagInfo.Ts {
|
|
newBagInfo.Ts = ts
|
|
}
|
|
this.PlayerBag[p.SnId] = newBagInfo
|
|
p.SendDiffData()
|
|
this.SyncBagData(p.SnId, itemInfos...)
|
|
return newBagInfo, bag.OpResultCode_OPRC_Sucess, true
|
|
}
|
|
|
|
// AddItemsOffline 修改道具,玩家离线
|
|
func (this *BagMgr) AddItemsOffline(param *model.AddItemParam, callback func(err error)) {
|
|
// 玩家在线时
|
|
p := PlayerMgrSington.GetPlayerBySnId(param.SnId)
|
|
if p != nil {
|
|
this.AddItems(param)
|
|
callback(nil)
|
|
return
|
|
}
|
|
|
|
// 玩家离线时
|
|
var findPlayer *model.PlayerBaseInfo
|
|
task.New(nil, task.CallableWrapper(func(o *basic.Object) interface{} {
|
|
findPlayer = model.GetPlayerBaseInfo(param.Platform, param.SnId)
|
|
if findPlayer == nil {
|
|
return nil
|
|
}
|
|
newBagInfo := &model.BagInfo{
|
|
SnId: findPlayer.SnId,
|
|
Platform: findPlayer.Platform,
|
|
BagItem: make(map[int32]*model.Item),
|
|
GainWay: param.GainWay,
|
|
}
|
|
for _, v := range param.Change {
|
|
if v == nil || v.ItemNum == 0 {
|
|
continue
|
|
}
|
|
itemData := srvdata.GameItemMgr.Get(param.Platform, v.ItemId)
|
|
if itemData == nil {
|
|
continue
|
|
}
|
|
newBagInfo.BagItem[v.ItemId] = &model.Item{ItemId: v.ItemId, ItemNum: v.ItemNum}
|
|
}
|
|
if err := model.SaveDBBagItem(newBagInfo); err != nil {
|
|
logger.Logger.Errorf("离线保存道具变更错误 %v", err)
|
|
return err
|
|
}
|
|
// 保存日志
|
|
if err := model.InsertItemLog(srvdata.GameItemMgr.GetItems(param.Platform), param, true); err != nil {
|
|
logger.Logger.Errorf("离线保存道具变更日志错误 %v", err)
|
|
return err
|
|
}
|
|
return nil
|
|
}), task.CompleteNotifyWrapper(func(data interface{}, t task.Task) {
|
|
logger.Logger.Tracef("AddItemsOffline error(%v) Player:%+v", data, *findPlayer)
|
|
if data != nil || findPlayer == nil {
|
|
logger.Logger.Errorf("AddItemsOffline Error %v", data)
|
|
callback(errors.New("AddItemsOffline failed"))
|
|
return
|
|
}
|
|
callback(nil)
|
|
})).StartByExecutor(fmt.Sprintf("Player%v", param.SnId))
|
|
}
|
|
|
|
// AddMailByItem 赠送道具到邮件
|
|
// srcId 发送人 srcName发送人名字
|
|
// showId 显示位置
|
|
// items[0]:道具id items[1]:道具数量 items[2]:道具id items[3]:道具数量
|
|
func (this *BagMgr) AddMailByItem(platform string, srcId int32, srcName string, snid int32, showId int64, items []int32) {
|
|
logger.Logger.Trace("AddMailByItem:", srcId, srcName, items)
|
|
var newMsg *model.Message
|
|
task.New(nil, task.CallableWrapper(func(o *basic.Object) interface{} {
|
|
content := i18n.Tr("languages", "GiftMail", srcName, srcName, srcName, srcName)
|
|
title := i18n.Tr("languages", "GiftMailTitle")
|
|
newMsg = model.NewMessageByPlayer("", 1, srcId, srcName, snid, model.MSGTYPE_ITEM, title, content,
|
|
0, 0, model.MSGSTATE_UNREAD, time.Now().Unix(), 0, "", items, platform, showId)
|
|
return model.InsertMessage(platform, newMsg)
|
|
}), task.CompleteNotifyWrapper(func(data interface{}, t task.Task) {
|
|
if data == nil {
|
|
p := PlayerMgrSington.GetPlayerBySnId(snid)
|
|
if p != nil {
|
|
p.AddMessage(newMsg)
|
|
}
|
|
}
|
|
}), "AddMailByItem").Start()
|
|
}
|
|
|
|
// VerifyUpJybInfo 兑换礼包
|
|
func (this *BagMgr) VerifyUpJybInfo(p *Player, args *model.VerifyUpJybInfoArgs) {
|
|
|
|
type VerifyInfo struct {
|
|
jyb *model.JybInfo
|
|
err error
|
|
}
|
|
pack := &playerproto.SCPlayerSetting{
|
|
OpRetCode: playerproto.OpResultCode_OPRC_Sucess,
|
|
}
|
|
task.New(nil, task.CallableWrapper(func(o *basic.Object) interface{} {
|
|
jyb, err := model.VerifyUpJybInfo(args)
|
|
info := &VerifyInfo{
|
|
jyb: jyb,
|
|
err: err,
|
|
}
|
|
return info
|
|
}), task.CompleteNotifyWrapper(func(data interface{}, t task.Task) {
|
|
if data != nil && data.(*VerifyInfo) != nil {
|
|
jyb := data.(*VerifyInfo).jyb
|
|
err := data.(*VerifyInfo).err
|
|
if jyb != nil && jyb.Award != nil { // 领取到礼包
|
|
pack.GainItem = &playerproto.JybInfoAward{}
|
|
if jyb.Award.Item != nil {
|
|
if len(jyb.Award.Item) > 0 {
|
|
items := make([]*model.Item, 0)
|
|
for _, v := range jyb.Award.Item {
|
|
items = append(items, &model.Item{
|
|
ItemId: v.ItemId, // 物品id
|
|
ItemNum: v.ItemNum, // 数量
|
|
ObtainTime: time.Now().Unix(),
|
|
})
|
|
}
|
|
BagMgrSingleton.AddItems(&model.AddItemParam{
|
|
Platform: p.Platform,
|
|
SnId: p.SnId,
|
|
Change: items,
|
|
GainWay: common.GainWay_ActJybAward,
|
|
Operator: "system",
|
|
Remark: "礼包码兑换",
|
|
})
|
|
p.dirty = true
|
|
}
|
|
}
|
|
jybLog := &model.JybLog{
|
|
Platform: p.Platform,
|
|
Id: jyb.JybId.Hex(),
|
|
Ts: time.Now().Unix(),
|
|
SnId: p.SnId,
|
|
Tp: jyb.CodeType,
|
|
Name: jyb.Name,
|
|
}
|
|
for _, v := range jyb.Award.Item {
|
|
//if _, code := BagMgrSingleton.UpBagInfo(p.SnId, p.Platform, v.ItemId, v.ItemNum); code == bag.OpResultCode_OPRC_Sucess { // 需修改
|
|
pack.GainItem.ItemId = append(pack.GainItem.ItemId, &playerproto.ItemInfo{
|
|
ItemId: v.ItemId,
|
|
ItemNum: v.ItemNum,
|
|
})
|
|
jybLog.Award = append(jybLog.Award, &model.JybItem{
|
|
Id: v.ItemId,
|
|
Num: int32(v.ItemNum),
|
|
})
|
|
}
|
|
if jyb.Award.Coin > 0 {
|
|
p.AddCoin(jyb.Award.Coin, 0, common.GainWay_ActJybAward, "system", "礼包码兑换")
|
|
if !p.IsRob {
|
|
LogChannelSingleton.WriteMQData(model.GenerateSystemFreeGive(p.SnId, p.Name, p.Platform, p.Channel, model.SystemFreeGive_GiveType_ActJybAward, model.SystemFreeGive_CoinType_Coin, int64(jyb.Award.Coin)))
|
|
}
|
|
jybLog.Award = append(jybLog.Award, &model.JybItem{
|
|
Id: common.ItemIDCoin,
|
|
Num: int32(jyb.Award.Coin),
|
|
})
|
|
}
|
|
if jyb.Award.Diamond > 0 {
|
|
p.AddDiamond(jyb.Award.Diamond, 0, common.GainWay_ActJybAward, "system", "礼包码兑换")
|
|
if !p.IsRob {
|
|
LogChannelSingleton.WriteMQData(model.GenerateSystemFreeGive(p.SnId, p.Name, p.Platform, p.Channel, model.SystemFreeGive_GiveType_ActJybAward, model.SystemFreeGive_CoinType_Diamond, int64(jyb.Award.Diamond)))
|
|
}
|
|
jybLog.Award = append(jybLog.Award, &model.JybItem{
|
|
Id: common.ItemIDDiamond,
|
|
Num: int32(jyb.Award.Coin),
|
|
})
|
|
}
|
|
// 领取日志
|
|
LogChannelSingleton.WriteLog(jybLog)
|
|
p.dirty = true
|
|
pack.GainItem.Coin = jyb.Award.Coin
|
|
pack.GainItem.Diamond = jyb.Award.Diamond
|
|
} else {
|
|
switch err.Error() {
|
|
case model.ErrJybISReceive.Error():
|
|
pack.OpRetCode = playerproto.OpResultCode_OPRC_Jyb_Receive
|
|
case model.ErrJYBPlCode.Error():
|
|
pack.OpRetCode = playerproto.OpResultCode_OPRC_Jyb_CodeExist
|
|
case model.ErrJybTsTimeErr.Error():
|
|
pack.OpRetCode = playerproto.OpResultCode_OPRC_Jyb_TimeErr
|
|
default:
|
|
pack.OpRetCode = playerproto.OpResultCode_OPRC_Jyb_CodeErr
|
|
}
|
|
}
|
|
} else {
|
|
proto.SetDefaults(pack)
|
|
p.SendToClient(int(playerproto.PlayerPacketID_PACKET_ALL_SETTING), pack)
|
|
}
|
|
proto.SetDefaults(pack)
|
|
p.SendToClient(int(playerproto.PlayerPacketID_PACKET_ALL_SETTING), pack)
|
|
}), "VerifyUpJybInfo").Start()
|
|
}
|
|
|
|
// 兑换话费卡
|
|
func (this *BagMgr) ItemExchangeCard(p *Player, itemId int32, money, cardType int32, logId string) bool {
|
|
// 兑换码奖品
|
|
var err error
|
|
var newMsg *model.Message
|
|
res := &webapiproto.SAGetMatchAwardCode{}
|
|
pack := &bag.SCItemExChangeRes{RetCode: bag.OpResultCode_OPRC_Sucess}
|
|
task.New(nil, task.CallableWrapper(func(o *basic.Object) interface{} {
|
|
// 获取兑换码
|
|
pack := &webapiproto.ASGetMatchAwardCode{
|
|
Platform: p.Platform,
|
|
Snid: p.SnId,
|
|
ItemID: itemId,
|
|
Money: int64(money),
|
|
Tel: p.Tel,
|
|
CardType: cardType,
|
|
Remark: "背包内使用兑换",
|
|
}
|
|
logger.Logger.Trace("ItemChangeCode ", pack)
|
|
var buff []byte
|
|
buff, err = webapi.APIGetMatchAwardCode(common.GetAppId(), pack)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if err = proto.Unmarshal(buff, res); err != nil {
|
|
return err
|
|
}
|
|
|
|
if res.GetCode() == "" || res.GetTag() != webapiproto.TagCode_SUCCESS {
|
|
return nil
|
|
}
|
|
|
|
var params []string
|
|
for range []string{"zh", "vi", "en", "kh"} {
|
|
params = append(params, res.GetMoney(), res.GetCode()) // 金额,兑换码
|
|
}
|
|
// 发送邮件
|
|
title := i18n.Tr("languages", "MatchAwardTitle")
|
|
content := i18n.Tr("languages", "MatchAward", params)
|
|
newMsg = model.NewMessage("", 0, "", p.SnId, model.MSGTYPE_ITEM_CHANGE,
|
|
title, content, 0, 0, model.MSGSTATE_UNREAD, time.Now().Unix(), 0, "", nil, p.Platform, model.HallTienlen, nil)
|
|
err := model.InsertMessage(p.Platform, newMsg)
|
|
if err != nil {
|
|
logger.Logger.Errorf("发送邮件失败 snid:%v itemID:%v err:%v", p.SnId, itemId, err)
|
|
return err
|
|
}
|
|
return nil
|
|
}), task.CompleteNotifyWrapper(func(i interface{}, t task.Task) {
|
|
if err != nil || res.GetCode() == "" || res.GetTag() != webapiproto.TagCode_SUCCESS {
|
|
//返回道具
|
|
items := make([]*model.Item, 0)
|
|
items = append(items, &model.Item{
|
|
ItemId: itemId, // 物品id
|
|
ItemNum: 1, // 数量
|
|
ObtainTime: time.Now().Unix(),
|
|
})
|
|
this.AddItems(&model.AddItemParam{
|
|
Platform: p.Platform,
|
|
SnId: p.SnId,
|
|
Change: items,
|
|
Add: 0,
|
|
GainWay: common.GainWayItemChange,
|
|
Operator: "system",
|
|
Remark: "背包内使用兑换失败",
|
|
GameId: 0,
|
|
GameFreeId: 0,
|
|
LogId: logId,
|
|
})
|
|
logger.Logger.Errorf("获取兑换码失败 snid:%v itemID:%v res:%v err:%v", p.SnId, itemId, res, err)
|
|
pack.RetCode = bag.OpResultCode_OPRC_Error
|
|
p.SendToClient(int(bag.SPacketID_PACKET_SC_ITEM_EXCHANGE_RES), pack)
|
|
// 标记兑换失败
|
|
task.New(nil, task.CallableWrapper(func(o *basic.Object) interface{} {
|
|
model.UpdateItemState(&model.UpdateParam{
|
|
Platform: p.Platform,
|
|
LogId: bson.ObjectIdHex(logId),
|
|
State: 1,
|
|
})
|
|
return nil
|
|
}), nil).Start()
|
|
return
|
|
}
|
|
p := PlayerMgrSington.GetPlayerBySnId(p.SnId)
|
|
if p != nil {
|
|
p.AddMessage(newMsg)
|
|
//已兑换log
|
|
itemData := srvdata.GameItemMgr.Get(p.Platform, itemId)
|
|
AwardLogMgr.UpdateAwardLog(p.Platform, itemData.Id, int64(1))
|
|
}
|
|
p.SendToClient(int(bag.SPacketID_PACKET_SC_ITEM_EXCHANGE_RES), pack)
|
|
}), fmt.Sprintf("ItemExChange%d", p.SnId)).Start()
|
|
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)
|
|
}
|