578 lines
16 KiB
Go
578 lines
16 KiB
Go
package main
|
||
|
||
import (
|
||
"mongo.games.com/game/worldsrv/internal"
|
||
"strconv"
|
||
"time"
|
||
|
||
"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"
|
||
"mongo.games.com/game/srvdata"
|
||
)
|
||
|
||
const (
|
||
BagItemMax int32 = 200
|
||
)
|
||
|
||
// 道具功能 Function
|
||
const (
|
||
ItemCanUse = iota //可以使用
|
||
ItemCanGive //可以赠送
|
||
ItemCanSell //可以出售
|
||
ItemMax
|
||
)
|
||
|
||
type Item struct {
|
||
ItemId int32 // 物品ID
|
||
ItemNum int64 // 物品数量
|
||
////数据表数据
|
||
Name string // 名称
|
||
//ShowLocation []int32 // 显示位置
|
||
//Classify []int32 // 分页类型 1,道具类 2,资源类 3,兑换类
|
||
//Type int32 // 道具种类 1,宠物碎片 2,角色碎片
|
||
Effect0 []int32 // 竖版道具功能 1,使用 2,赠送 3,出售
|
||
Effect []int32 // 横版道具功能 1,使用 2,赠送 3,出售
|
||
SaleType int32 // 出售类型
|
||
SaleGold int32 // 出售金额
|
||
//Composition int32 // 能否叠加 1,能 2,不能
|
||
//CompositionMax int32 // 叠加上限
|
||
//Time int32 // 道具时效 0为永久
|
||
//Location string // 跳转页面
|
||
//Describe string // 道具描述
|
||
//数据库数据
|
||
ObtainTime int64 //获取的时间
|
||
}
|
||
|
||
type BagInfo struct {
|
||
SnId int32 //玩家账号直接在这里生成
|
||
Platform string //平台
|
||
BagItem map[int32]*Item //背包数据 key为itemId
|
||
dirty bool
|
||
}
|
||
|
||
// BagMgrSingleton 背包管理器
|
||
var BagMgrSingleton = &BagMgr{
|
||
PlayerBag: make(map[int32]*BagInfo),
|
||
}
|
||
|
||
type BagMgr struct {
|
||
PlayerBag map[int32]*BagInfo // snid:背包
|
||
}
|
||
|
||
func (this *BagMgr) ModuleName() string {
|
||
return "BagMgr"
|
||
}
|
||
|
||
func (this *BagMgr) Init() {
|
||
}
|
||
|
||
func (this *BagMgr) GetBagInfo(snid int32) *BagInfo {
|
||
if v, exist := this.PlayerBag[snid]; exist {
|
||
return v
|
||
}
|
||
return nil
|
||
}
|
||
|
||
// 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.PBDB_GameItemMgr.GetData(itemId)
|
||
if itemX != nil {
|
||
item.Name = itemX.Name
|
||
//item.ShowLocation = itemX.ShowLocation
|
||
//item.Classify = itemX.Classify
|
||
//item.Type = itemX.Type
|
||
item.Effect0 = itemX.Effect
|
||
item.Effect = itemX.Effect
|
||
item.SaleType = itemX.SaleType
|
||
item.SaleGold = itemX.SaleGold
|
||
//item.Composition = itemX.Composition
|
||
//item.CompositionMax = itemX.CompositionMax
|
||
//item.Time = itemX.Time
|
||
//item.Location = itemX.Location
|
||
//item.Describe = itemX.Describe
|
||
}
|
||
}
|
||
|
||
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
|
||
}
|
||
|
||
// AddJybBagInfo 给玩家背包添加道具
|
||
// add 加成数量
|
||
// gainWay 记录类型
|
||
// oper 操作人
|
||
// remark 备注
|
||
func (this *BagMgr) AddJybBagInfo(p *Player, addItems []*Item, add int64, gainWay int32, oper, remark string) (*BagInfo, bag.OpResultCode) {
|
||
var items []*Item
|
||
for _, v := range addItems {
|
||
if v == nil || v.ItemNum == 0 {
|
||
continue
|
||
}
|
||
item := srvdata.PBDB_GameItemMgr.GetData(v.ItemId)
|
||
switch item.Type {
|
||
case common.ItemTypeCoin:
|
||
//增加金币
|
||
if item.Id == common.ItemIDCoin {
|
||
p.AddCoin(v.ItemNum, 0, gainWay, oper, remark)
|
||
}
|
||
case common.ItemTypeDiamond:
|
||
//增加钻石
|
||
if item.Id == common.ItemIDDiamond {
|
||
p.AddDiamond(v.ItemNum, 0, gainWay, oper, 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, gainWay, oper, remark)
|
||
}
|
||
default:
|
||
// 道具变化
|
||
items = append(items, v)
|
||
}
|
||
}
|
||
|
||
// 添加道具到背包
|
||
|
||
var changeItems []int32
|
||
var newBagInfo *BagInfo
|
||
if _, exist := this.PlayerBag[p.SnId]; !exist {
|
||
newBagInfo = &BagInfo{
|
||
SnId: p.SnId,
|
||
Platform: p.Platform,
|
||
BagItem: make(map[int32]*Item),
|
||
}
|
||
} else {
|
||
newBagInfo = this.PlayerBag[p.SnId]
|
||
}
|
||
|
||
if len(items) == 0 {
|
||
return newBagInfo, bag.OpResultCode_OPRC_Sucess
|
||
}
|
||
|
||
var code = bag.OpResultCode_OPRC_Sucess
|
||
for _, v := range items {
|
||
if v == nil || v.ItemNum == 0 {
|
||
continue
|
||
}
|
||
item := srvdata.PBDB_GameItemMgr.GetData(v.ItemId)
|
||
if item == nil {
|
||
code = bag.OpResultCode_OPRC_IdErr
|
||
continue
|
||
}
|
||
|
||
changeItems = append(changeItems, v.ItemId)
|
||
if itm, exist := newBagInfo.BagItem[v.ItemId]; exist {
|
||
itm.ItemNum += v.ItemNum
|
||
} else {
|
||
newBagInfo.BagItem[v.ItemId] = &Item{
|
||
ItemId: item.Id, // 物品id
|
||
ItemNum: v.ItemNum, // 数量
|
||
ObtainTime: time.Now().Unix(),
|
||
}
|
||
}
|
||
if v.ItemId == common.ItemIDWeekScore && v.ItemNum != 0 {
|
||
TaskSubjectSingleton.Touch(common.TaskTypeActivityScore, &TaskData{
|
||
SnId: p.SnId,
|
||
Num: v.ItemNum,
|
||
})
|
||
}
|
||
}
|
||
if len(changeItems) > 0 {
|
||
newBagInfo.dirty = true
|
||
p.dirty = true
|
||
this.PlayerBag[p.SnId] = newBagInfo
|
||
this.SyncBagData(p.SnId, changeItems...)
|
||
}
|
||
|
||
return newBagInfo, code
|
||
}
|
||
|
||
// SaleItem 出售道具,减少玩家道具数量
|
||
func (this *BagMgr) SaleItem(p *Player, itemId int32, num int64) bool {
|
||
item := this.GetItem(p.SnId, itemId)
|
||
if item != nil && item.ItemNum >= num {
|
||
return this.SalePlayerItem(p, item, num)
|
||
}
|
||
return false
|
||
}
|
||
|
||
// SalePlayerItem 出售道具,减少玩家道具数量
|
||
func (this *BagMgr) SalePlayerItem(p *Player, item *Item, num int64) bool {
|
||
item.ItemNum -= num
|
||
p.dirty = true
|
||
this.SyncBagData(p.SnId, item.ItemId)
|
||
return true
|
||
}
|
||
|
||
func (this *BagMgr) SaleItemV2(p *Player, itemId int32, num int64, gain int32, oper string, remark string) bool {
|
||
item := this.GetItem(p.SnId, itemId)
|
||
if item != nil && item.ItemNum >= num {
|
||
switch item.ItemId {
|
||
case common.ItemIDCoin:
|
||
p.AddCoin(-num, 0, gain, oper, remark)
|
||
return true
|
||
case common.ItemIDDiamond:
|
||
p.AddDiamond(-num, 0, gain, oper, remark)
|
||
return true
|
||
default:
|
||
return this.SalePlayerItem(p, item, num)
|
||
}
|
||
}
|
||
return false
|
||
}
|
||
|
||
// RecordItemLog 道具操作记录(获得,消耗)
|
||
func (this *BagMgr) RecordItemLog(platform string, snid, logType, itemId int32, itemName string, count int64, remark string) {
|
||
//logger.Logger.Trace("RecordItemLog:", platform, snid, logType, itemId, itemName, count, remark)
|
||
switch itemId {
|
||
case common.ItemIDCoin, common.ItemIDDiamond:
|
||
return
|
||
}
|
||
log := model.NewItemLogEx(platform, snid, logType, itemId, itemName, count, remark)
|
||
if log != nil {
|
||
LogChannelSingleton.WriteLog(log)
|
||
}
|
||
}
|
||
|
||
// AddMailByItem 赠送道具到邮件
|
||
// srcId 发送人 srcName发送人名字
|
||
// 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([]*Item, 0)
|
||
for _, v := range jyb.Award.Item {
|
||
items = append(items, &Item{
|
||
ItemId: v.ItemId, // 物品id
|
||
ItemNum: v.ItemNum, // 数量
|
||
ObtainTime: time.Now().Unix(),
|
||
})
|
||
}
|
||
if _, code := this.AddJybBagInfo(p, items, 0, common.GainWay_ActJybAward, "system", "礼包码兑换"); code != bag.OpResultCode_OPRC_Sucess { //TODO 添加失败 要回退礼包
|
||
logger.Logger.Errorf("CSPlayerSettingHandler AddJybBagInfo err", code)
|
||
pack.OpRetCode = playerproto.OpResultCode_OPRC_Error
|
||
proto.SetDefaults(pack)
|
||
p.SendToClient(int(playerproto.PlayerPacketID_PACKET_ALL_SETTING), pack)
|
||
} else {
|
||
for _, v := range items {
|
||
itemData := srvdata.PBDB_GameItemMgr.GetData(v.ItemId)
|
||
if itemData != nil {
|
||
BagMgrSingleton.RecordItemLog(p.Platform, p.SnId, ItemObtain, v.ItemId, itemData.Name, int64(v.ItemNum), "礼包领取")
|
||
}
|
||
}
|
||
PetMgrSington.CheckShowRed(p)
|
||
}
|
||
p.dirty = true
|
||
}
|
||
}
|
||
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,
|
||
})
|
||
}
|
||
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, model.SystemFreeGive_GiveType_ActJybAward, model.SystemFreeGive_CoinType_Coin, int64(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, model.SystemFreeGive_GiveType_ActJybAward, model.SystemFreeGive_CoinType_Diamond, int64(jyb.Award.Diamond)))
|
||
}
|
||
}
|
||
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()
|
||
// 先检查玩家背包是否足够
|
||
|
||
}
|
||
|
||
// SyncBagData 通知玩家背包数据变化
|
||
func (this *BagMgr) SyncBagData(snid int32, changeItemIds ...int32) {
|
||
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,
|
||
//Name: itemInfo.Name,
|
||
//Classify: itemInfo.Classify,
|
||
//Type: itemInfo.Type,
|
||
//Effect0: itemInfo.Effect0,
|
||
//Effect: itemInfo.Effect,
|
||
//SaleType: itemInfo.SaleType,
|
||
//SaleGold: itemInfo.SaleGold,
|
||
//Composition: itemInfo.Composition,
|
||
//CompositionMax: itemInfo.CompositionMax,
|
||
//Time: itemInfo.Time,
|
||
//Location: itemInfo.Location,
|
||
//Describe: itemInfo.Describe,
|
||
ObtainTime: itemInfo.ObtainTime,
|
||
})
|
||
if itemInfo.ItemId == VCard {
|
||
FriendMgrSington.UpdateInfo(p.Platform, p.SnId)
|
||
}
|
||
}
|
||
}
|
||
p.SyncBagData(itemInfos)
|
||
}
|
||
|
||
func (this *BagMgr) Update() {
|
||
}
|
||
|
||
func (this *BagMgr) Shutdown() {
|
||
module.UnregisteModule(this)
|
||
}
|
||
|
||
//========================implement IPlayerLoad ==============================
|
||
|
||
func (this *BagMgr) Load(platform string, snid int32, player any) *internal.PlayerLoadReplay {
|
||
data := model.GetBagInfo(snid, platform)
|
||
return &internal.PlayerLoadReplay{
|
||
Platform: platform,
|
||
Snid: snid,
|
||
Err: nil,
|
||
Data: data,
|
||
}
|
||
}
|
||
|
||
func (this *BagMgr) Callback(player any, ret *internal.PlayerLoadReplay) {
|
||
if ret == nil || ret.Data == nil {
|
||
return
|
||
}
|
||
|
||
bagInfo, ok := ret.Data.(*model.BagInfo)
|
||
if !ok || bagInfo == nil {
|
||
return
|
||
}
|
||
|
||
//数据表 数据库数据相结合
|
||
newBagInfo := &BagInfo{
|
||
SnId: ret.Snid,
|
||
Platform: ret.Platform,
|
||
BagItem: make(map[int32]*Item),
|
||
}
|
||
for k, bi := range bagInfo.BagItem {
|
||
item := srvdata.PBDB_GameItemMgr.GetData(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
|
||
}
|
||
|
||
func (this *BagMgr) LoadAfter(platform string, snid int32) *internal.PlayerLoadReplay {
|
||
// 查询最近游戏
|
||
gameID := model.GetRecentGame(platform, snid)
|
||
return &internal.PlayerLoadReplay{
|
||
Platform: platform,
|
||
Snid: snid,
|
||
Err: nil,
|
||
Data: gameID,
|
||
}
|
||
}
|
||
|
||
func (this *BagMgr) CallbackAfter(ret *internal.PlayerLoadReplay) {
|
||
if ret == nil {
|
||
return
|
||
}
|
||
if ret.Err != nil {
|
||
logger.Logger.Error("BagMgr LoadAfter err:", ret.Err)
|
||
return
|
||
}
|
||
p := PlayerMgrSington.GetPlayerBySnId(ret.Snid)
|
||
if p != nil {
|
||
p.GameID = ret.Data.([]int32)
|
||
}
|
||
}
|
||
|
||
func (this *BagMgr) Save(platform string, snid int32, isSync, force bool) {
|
||
bagInfo := this.PlayerBag[snid]
|
||
logger.Logger.Trace("SaveBagData:", bagInfo)
|
||
|
||
if bagInfo == nil || (!bagInfo.dirty && !force) {
|
||
return
|
||
}
|
||
|
||
type BagInfoMap struct {
|
||
SnId int32 //玩家账号直接在这里生成
|
||
Platform string //平台
|
||
BagItem []*Item //背包数据 key为itemId
|
||
}
|
||
// biMap 数据拷贝
|
||
var biMap = BagInfoMap{
|
||
SnId: bagInfo.SnId,
|
||
Platform: bagInfo.Platform,
|
||
}
|
||
for _, v := range bagInfo.BagItem {
|
||
biMap.BagItem = append(biMap.BagItem, &Item{ItemId: v.ItemId, ItemNum: v.ItemNum, ObtainTime: v.ObtainTime})
|
||
}
|
||
|
||
var err error
|
||
f := func() {
|
||
newBagInfo := &model.BagInfo{
|
||
SnId: biMap.SnId,
|
||
Platform: biMap.Platform,
|
||
BagItem: make(map[int32]*model.Item),
|
||
}
|
||
for _, v := range biMap.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 {
|
||
bagInfo.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()
|
||
}), "SaveBagData").StartByFixExecutor("SnId:" + strconv.Itoa(int(snid)))
|
||
}
|
||
|
||
func (this *BagMgr) Release(platform string, snid int32) {
|
||
delete(this.PlayerBag, snid)
|
||
}
|
||
|
||
func init() {
|
||
module.RegisteModule(BagMgrSingleton, time.Second, 0)
|
||
internal.RegisterPlayerLoad(BagMgrSingleton)
|
||
}
|