package main import ( "encoding/json" "errors" "fmt" "math/rand" "slices" "strconv" "time" "mongo.games.com/goserver/core/basic" "mongo.games.com/goserver/core/logger" "mongo.games.com/goserver/core/module" "mongo.games.com/goserver/core/task" "mongo.games.com/goserver/core/timer" "mongo.games.com/game/common" "mongo.games.com/game/model" "mongo.games.com/game/proto" hall_proto "mongo.games.com/game/protocol/gamehall" "mongo.games.com/game/protocol/shop" webapi_proto "mongo.games.com/game/protocol/webapi" "mongo.games.com/game/srvdata" "mongo.games.com/game/webapi" ) const ( BlindBox int32 = iota + 101 //盲盒 FirstPay //首冲 ContinuousPay //连充 Exchange // 兑换商品 ShopTypeStart int32 = 900000 //商品 ) // 消费类型 const ( ShopConsumeCoin = iota + 1 // 金币 ShopConsumeDiamond // 钻石 ShopConsumeMoney // 现金 ExchangeConsumeCash //兑换消耗现金 ShopConsumePhoneScore = 11 //手机积分 ) // page类型 const ( ShopPageCoin = iota + 1 //金币页面 ShopPageDiamond //钻石页面 ShopPageItem //道具页面 ShopPageVip //VIP页面 ShopPagePrivilege //VIP特权礼包 ShopPagePhoneScore = 61 //手机积分商城 ShopPagePhoneScore_google = 62 ShopPageGift = 7 //礼包页面 ) // 商品类型 const ( ShopTypeCoin = iota + 1 // 金币 ShopTypeDiamond // 钻石 ShopTypeItem // 道具 ) // 兑换商品状态 const ( Shop_Status_Keep = iota //0为待审核 Shop_Status_Pass // 1为审核通过 Shop_Status_Send // 2为已发货 Shop_Status_NotSend // 3为审核不通过 Shop_Status_Revoke // 4为撤单 ) const ( VCard int32 = 30001 JCard int32 = 30002 //金券 ) /* 1.兑换成功:兑换成功,请等待审核 2.今日兑换已达上限,请明日再来 3.该物品已被兑换完 */ const ( Err_ExShopNEnough string = "ExShopNotEnough" // 该物品已被兑换完 Err_ExShopLimit string = "ExShopIsLimit" // 今日兑换已达上限,请明日再来 Err_ExShopData string = "ExShopDataErr" // 收件人地址有误 ) var ShopMgrSington = &ShopMgr{ ConfigMgr: model.NewConfigMgr(), } type ShopMgr struct { *model.ConfigMgr } type ExchangeShopInfo struct { Id int32 //商品ID Picture string // 图片 Type int32 // 类型 1,话费2,实物 Name string // 名称 Rule string //规则说明 ExType []*shop.ExchangeType // 获得道具 OrderId string //兑换的订单Id ExchangeTypeId int32 //兑换类型的id ExchangeNum int32 //兑换数量 } func (this *ShopMgr) ModuleName() string { return "ShopMgr" } func (this *ShopMgr) Init() { } // UpExShop 更新兑换商品信息 func (this *ShopMgr) UpExShop(cfgs *webapi_proto.ExchangeShopList) { this.GetConfig(cfgs.Platform).ExchangeShopList = cfgs } func (this *ShopMgr) GetShopInfoProto(si *model.ShopInfo, p *Player, vipShopId int32) (shopInfo *shop.ShopInfo) { if si == nil { return nil } var itemInfo []*shop.ItemInfo for _, i2 := range si.AddItemInfo { itemInfo = append(itemInfo, &shop.ItemInfo{ ItemId: i2.ItemId, ItemNum: i2.ItemNum, }) } added := int32(rand.Intn(int(si.AddArea[1])-int(si.AddArea[0])+1) + int(si.AddArea[0])) consumptionAmount := int32(rand.Intn(int(si.CostArea[1])-int(si.CostArea[0])+1) + int(si.CostArea[0])) amount := int64(si.Amount) isBuy := false if si.Page == ShopPageVip { shopData := p.GetVipShopData(si.Id, vipShopId) if shopData == nil { logger.Logger.Errorf("Vip商城 没有当前物品 snid = %v,shopId = %v", p.SnId, si.Id) return nil } added = shopData.AddArea consumptionAmount = shopData.CostArea amount = si.Amount * int64(consumptionAmount) isBuy = shopData.IsBuy } shopInfo = &shop.ShopInfo{ Id: si.Id, AdLookedNum: si.AdLookedNum, AdReceiveNum: si.AdReceiveNum, LastLookTime: si.LastLookTime, RoleAdded: si.RoleAdded, PetAdded: si.PetAdded, ItemId: si.ItemId, Order: si.Order, Page: si.Page, Type: si.Type, Location: si.Location, Picture: si.Picture, Name: si.Name, Ad: si.Ad, AdTime: si.AdTime, RepeatTimes: si.RepeatTimes, CoolingTime: si.CoolingTime, Label: si.Label, Added: added, Amount: amount, Consume: si.ConstType, ConsumptionAmount: consumptionAmount, AddItemInfo: itemInfo, VipLevel: si.VipLevel, EndTime: si.EndTime, IsBuy: isBuy, RoleAddedId: si.RoleAddedId, AmountFinal: this.GetAmountFinal(p, si.Id, vipShopId), } return } // GetShopInfo 获取玩家某个商品信息(例如玩家看广告领取) func (this *ShopMgr) GetShopInfo(shopId int32, p *Player) *model.ShopInfo { if shopId == 0 { return nil } var shopInfo = this.ConfigMgr.GetShopInfo(p.Platform, shopId) if shopInfo != nil { // AdLookedNum 已看次数 // AdReceiveNum 已领次数 // remainingTime 商品设置的冷却时长 var AdLookedNum, AdReceiveNum, remainingTime int32 var lastLookTime int64 if shopInfo.Ad > 0 { shopTotal := p.ShopTotal[shopInfo.Id] if shopTotal != nil { AdLookedNum = shopTotal.AdLookedNum AdReceiveNum = shopTotal.AdReceiveNum } lastLookTime = p.ShopLastLookTime[shopInfo.Id] if AdLookedNum < int32(len(shopInfo.CoolingTime)) { remainingTime = shopInfo.CoolingTime[AdLookedNum] } if lastLookTime >= 0 { dif := int32(time.Now().Unix() - lastLookTime) if dif >= remainingTime { remainingTime = 0 } else { remainingTime = remainingTime - dif } } } award, roleId := PetMgrSington.GetShopAward(shopInfo, p) firstBuy := false if shopInfo.FirstSwitch { firstBuy = !slices.Contains(p.ShopID, int(shopInfo.Id)) } return &model.ShopInfo{ Id: shopInfo.Id, Ad: shopInfo.Ad, AdTime: shopInfo.AdTime, RepeatTimes: shopInfo.RepeatTimes, CoolingTime: shopInfo.CoolingTime, AdLookedNum: AdLookedNum, AdReceiveNum: AdReceiveNum, RemainingTime: remainingTime, LastLookTime: int32(lastLookTime), RoleAdded: award, ItemId: shopInfo.ItemId, Order: shopInfo.Order, Page: shopInfo.Page, Type: shopInfo.Type, Location: shopInfo.Location, Picture: shopInfo.Picture, Name: shopInfo.Name, Label: shopInfo.Label, AddArea: shopInfo.AddArea, Amount: shopInfo.Amount, ConstType: shopInfo.ConstType, CostArea: shopInfo.CostArea, RoleAddedId: roleId, AddItemInfo: shopInfo.AddItemInfo, VipLevel: shopInfo.VipLevel, EndTime: shopInfo.EndTime, Ratio: shopInfo.Ratio, FirstSwitch: firstBuy, AmountFinal: this.GetAmountFinal(p, shopId, 0), } } return nil } // GetShopInfos 获取玩家商品信息给客户端展示 func (this *ShopMgr) GetShopInfos(p *Player, nowLocation int) []*shop.ShopInfo { if p.ShopTotal == nil { p.ShopTotal = make(map[int32]*model.ShopTotal) } if p.ShopLastLookTime == nil { p.ShopLastLookTime = make(map[int32]int64) } var newShops = make([]*shop.ShopInfo, 0) if p.VipShopData == nil || len(p.VipShopData) == 0 { this.UpdateVipShopData(p) } shopInfos := this.GetConfig(p.Platform).ShopInfos for _, shopInfo := range shopInfos { if nowLocation == -1 || (nowLocation < len(shopInfo.Location) && shopInfo.Location[nowLocation] == 1) { if shopInfo.Page == ShopPageVip { continue } var AdLookedNum, AdReceiveNum, remainingTime int32 var lastLookTime int64 if shopInfo.Ad > 0 { shopTotal := p.ShopTotal[shopInfo.Id] if shopTotal != nil { AdLookedNum = shopTotal.AdLookedNum AdReceiveNum = shopTotal.AdReceiveNum } lastLookTime = p.ShopLastLookTime[shopInfo.Id] if AdLookedNum < int32(len(shopInfo.CoolingTime)) { remainingTime = shopInfo.CoolingTime[AdLookedNum] } dif := int32(time.Now().Unix() - lastLookTime) if dif >= remainingTime { remainingTime = 0 } else { remainingTime = remainingTime - dif } } added := int32(rand.Intn(int(shopInfo.AddArea[1])-int(shopInfo.AddArea[0])+1) + int(shopInfo.AddArea[0])) consumptionAmount := int32(rand.Intn(int(shopInfo.CostArea[1])-int(shopInfo.CostArea[0])+1) + int(shopInfo.CostArea[0])) var itemInfo []*shop.ItemInfo for _, i2 := range shopInfo.AddItemInfo { itemInfo = append(itemInfo, &shop.ItemInfo{ ItemId: i2.ItemId, ItemNum: i2.ItemNum, }) } award, roleId := PetMgrSington.GetShopAward(shopInfo, p) firstBuy := false if shopInfo.FirstSwitch { firstBuy = !slices.Contains(p.ShopID, int(shopInfo.Id)) } newShops = append(newShops, &shop.ShopInfo{ Id: shopInfo.Id, AdLookedNum: AdLookedNum, AdReceiveNum: AdReceiveNum, LastLookTime: int32(lastLookTime), RoleAdded: award, RoleAddedId: roleId, ItemId: shopInfo.ItemId, Order: shopInfo.Order, Page: shopInfo.Page, Type: shopInfo.Type, Location: shopInfo.Location, Picture: shopInfo.Picture, Name: shopInfo.Name, Ad: shopInfo.Ad, AdTime: shopInfo.AdTime, RepeatTimes: shopInfo.RepeatTimes, CoolingTime: shopInfo.CoolingTime, Label: shopInfo.Label, Added: added, Amount: int64(shopInfo.Amount), Consume: shopInfo.ConstType, ConsumptionAmount: consumptionAmount, AddItemInfo: itemInfo, VipLevel: shopInfo.VipLevel, EndTime: shopInfo.EndTime, IsBuy: false, FirstBuy: firstBuy, AmountFinal: this.GetAmountFinal(p, shopInfo.Id, 0), }) } } //VIP商城数据 if shopInfos == nil { return newShops } for i, data := range p.VipShopData { shopInfo := shopInfos[data.Id] if shopInfo == nil { continue } var AdLookedNum, AdReceiveNum, remainingTime int32 var lastLookTime int64 if shopInfo.Ad > 0 { shopTotal := p.ShopTotal[shopInfo.Id] if shopTotal != nil { AdLookedNum = shopTotal.AdLookedNum AdReceiveNum = shopTotal.AdReceiveNum } lastLookTime = p.ShopLastLookTime[shopInfo.Id] if AdLookedNum < int32(len(shopInfo.CoolingTime)) { remainingTime = shopInfo.CoolingTime[AdLookedNum] } dif := int32(time.Now().Unix() - lastLookTime) if dif >= remainingTime { remainingTime = 0 } else { remainingTime = remainingTime - dif } } var itemInfo []*shop.ItemInfo for _, i2 := range shopInfo.AddItemInfo { itemInfo = append(itemInfo, &shop.ItemInfo{ ItemId: i2.ItemId, ItemNum: i2.ItemNum, }) } award, roleId := PetMgrSington.GetShopAward(shopInfo, p) firstBuy := false if shopInfo.FirstSwitch { firstBuy = !slices.Contains(p.ShopID, int(shopInfo.Id)) } newShops = append(newShops, &shop.ShopInfo{ Id: shopInfo.Id, AdLookedNum: AdLookedNum, AdReceiveNum: AdReceiveNum, LastLookTime: int32(lastLookTime), RoleAdded: award, RoleAddedId: roleId, ItemId: shopInfo.ItemId, Order: shopInfo.Order, Page: shopInfo.Page, Type: shopInfo.Type, Location: shopInfo.Location, Picture: shopInfo.Picture, Name: shopInfo.Name, Ad: shopInfo.Ad, AdTime: shopInfo.AdTime, RepeatTimes: shopInfo.RepeatTimes, CoolingTime: shopInfo.CoolingTime, Label: shopInfo.Label, Added: data.AddArea, Amount: shopInfo.Amount * int64(data.CostArea), Consume: shopInfo.ConstType, ConsumptionAmount: data.CostArea, AddItemInfo: itemInfo, VipLevel: shopInfo.VipLevel, EndTime: shopInfo.EndTime, IsBuy: data.IsBuy, VipShopId: i, FirstBuy: firstBuy, AmountFinal: this.GetAmountFinal(p, shopInfo.Id, i), }) } return newShops } // 更新玩家vipShop数据 func (this *ShopMgr) UpdateVipShopData(p *Player) { if p.VIP == 0 { return } if p.VipShopData == nil { p.VipShopData = make(map[int32]*model.ShopData) } else { //购买过的不刷新 keysToDelete := []int32{} for id, data := range p.VipShopData { if !data.IsBuy { keysToDelete = append(keysToDelete, id) } } // 删除要删除的键 for _, id := range keysToDelete { delete(p.VipShopData, id) } } //获取vip商品刷新个数 vipConfig := VipMgrSington.GetVIPLevelCfg(p.Platform, p.VIP) if vipConfig == nil { return } count := int(vipConfig.Privilege3[1]) count -= len(p.VipShopData) logger.Logger.Trace("VIP商城刷新 刷新商品个数为:", count) if count <= 0 { logger.Logger.Error("VIP商城 暂时无法刷新!Snid = ", p.SnId) return } //获取对应VIP等级物品列表 vipShopInfoMap := make(map[int32]*model.ShopInfo) var sumRatio = 0 //权重 for _, shopInfo := range this.GetConfig(p.Platform).ShopInfos { if shopInfo.Page == ShopPageVip && shopInfo.VipLevel == p.VIP { vipShopInfoMap[shopInfo.Id] = shopInfo sumRatio += int(shopInfo.Ratio) } } if len(vipShopInfoMap) == 0 { return } for i := 1; i <= int(vipConfig.Privilege3[1]); i++ { if p.VipShopData[int32(i)] != nil { continue } //随机vip物品 random := rand.Intn(sumRatio + 1) logger.Logger.Tracef("Vip商城 随机到的值:%v,总权重:%v", random, sumRatio) ratio := 0 for id, shopInfo := range vipShopInfoMap { ratio += int(shopInfo.Ratio) if random <= ratio { //判断商品位置 p.VipShopData[int32(i)] = &model.ShopData{ Id: id, AddArea: int32(rand.Intn(int(shopInfo.AddArea[1]-shopInfo.AddArea[0]+1)) + int(shopInfo.AddArea[0])), CostArea: int32(rand.Intn(int(shopInfo.CostArea[1]-shopInfo.CostArea[0]+1)) + int(shopInfo.CostArea[0])), IsBuy: false, } logger.Logger.Tracef("Vip商城 随机到的物品id = %v,shopInfo = %v,random = %v,num = %v,商品位置:%v", id, shopInfo, random, ratio, i) break } } } } // LookAdReceive 看广告领取商品,校验领取次数 func (this *ShopMgr) LookAdReceive(shopId int32, p *Player, position int32) shop.OpResultCode { var shopInfo = this.ConfigMgr.GetShopInfo(p.Platform, shopId) if shopInfo == nil { logger.Logger.Errorf("this shop == nil shopId[%v] ", shopId) return shop.OpResultCode_OPRC_Error } //需要观看广告的 if shopInfo.Ad > 0 { if _, ok1 := p.ShopTotal[shopId]; !ok1 { p.ShopTotal[shopId] = &model.ShopTotal{} } shopTotal := p.ShopTotal[shopId] if shopTotal.AdReceiveNum < shopInfo.RepeatTimes { shopTotal.AdReceiveNum++ return this.ReceiveVCPayShop(shopInfo, p, 0, position) } } return shop.OpResultCode_OPRC_Error } // ReceiveVCPayShop 领取VC看广告商品 func (this *ShopMgr) ReceiveVCPayShop(shopInfo *model.ShopInfo, p *Player, vipShopId, position int32) shop.OpResultCode { if shopInfo == nil { logger.Logger.Errorf("this shop == nil") return shop.OpResultCode_OPRC_Error } //产生订单 this.PayAway(shopInfo, p, vipShopId, position) return shop.OpResultCode_OPRC_Sucess } // PayAway 商城 领取商品 func (this *ShopMgr) PayAway(shopInfo *model.ShopInfo, p *Player, vipShopId, position int32) { shopName := shopInfo.Name + "|" + strconv.Itoa(int(shopInfo.Id)) costNum := rand.Int31n(shopInfo.CostArea[1]-shopInfo.CostArea[0]+1) + shopInfo.CostArea[0] if shopInfo.Page == ShopPageVip { shopData := p.GetVipShopData(shopInfo.Id, vipShopId) if shopData != nil { costNum = shopData.CostArea } } if shopInfo.Ad <= 0 { //消耗 logger.Logger.Tracef("AddOrder Consume[%v],shopName[%v]", shopInfo.ConstType, shopName, costNum) switch shopInfo.ConstType { case ShopConsumeCoin: p.AddCoin(int64(-costNum), 0, common.GainWay_Shop_Buy, "sys", shopName) case ShopConsumeDiamond: p.AddDiamond(int64(-costNum), 0, common.GainWay_Shop_Buy, "sys", shopName) case ShopConsumePhoneScore: p.AddPhoneScore(int64(-costNum), 0, common.GainWay_Shop_Buy, "sys", shopName) case ShopConsumeMoney: //task.New(nil, task.CallableWrapper(func(o *basic.Object) interface{} { // return webapi.API_CreateOrder(common.GetAppId(),"", p.SnId, shopInfo.Id, p.Platform, p.PackageID, p.DeviceOS, // p.DeviceId, shopInfo.Name, shopInfo.Amount, shopInfo.ConsumptionAmount) //}), task.CompleteNotifyWrapper(func(data interface{}, t task.Task) { // if data != nil { // //失败 // } //}), "API_CreateOrder").Start() //p.AddMoneyPayTotal(int64(shopInfo.ConsumptionAmount)) return } } else { TaskSubjectSingleton.Touch(common.TaskTypeAdv, &TaskData{ SnId: p.SnId, Num: 1, Position: position, }) } amount := [3]int32{} // 获得 if shopInfo.Page == ShopPageVip { if p.VipShopData[vipShopId] == nil { return } p.VipShopData[vipShopId].IsBuy = true logger.Logger.Trace("玩家购买VIP商城物品成功,商品Id = ", shopInfo.Id) } addTotal := this.GetAmountFinal(p, shopInfo.Id, vipShopId) logger.Logger.Trace("addTotal ", addTotal, shopInfo.Amount) switch shopInfo.Type { case ShopTypeCoin: amount[shopInfo.Type-1] = int32(addTotal) p.AddCoin(addTotal, 0, common.GainWay_Shop_Buy, "system", shopName) if shopInfo.Ad > 0 { //观看广告 if !p.IsRob { LogChannelSingleton.WriteMQData(model.GenerateSystemFreeGive(p.SnId, p.Name, p.Platform, p.Channel, model.SystemFreeGive_GiveType_ShopAd, model.SystemFreeGive_CoinType_Coin, addTotal)) } } // 记录钻石兑换金币的金币数量,个人水池调控使用 if shopInfo.ConstType == ShopConsumeDiamond && shopInfo.Ad <= 0 && costNum > 0 { p.AddDiamondToCoin(addTotal) } if shopInfo.Ad <= 0 && costNum != 0 { TaskSubjectSingleton.Touch(common.TaskTypeBuyCoin, &TaskData{SnId: p.SnId, Num: 1, Position: position}) } case ShopTypeDiamond: //增加钻石 amount[shopInfo.Type-1] = int32(addTotal) p.AddDiamond(addTotal, 0, common.GainWay_Shop_Buy, "system", shopName) if shopInfo.Ad > 0 { //观看广告 if !p.IsRob { LogChannelSingleton.WriteMQData(model.GenerateSystemFreeGive(p.SnId, p.Name, p.Platform, p.Channel, model.SystemFreeGive_GiveType_ShopAd, model.SystemFreeGive_CoinType_Diamond, addTotal)) } } case ShopTypeItem: //增加道具 item := &Item{ItemId: shopInfo.ItemId, ItemNum: addTotal, ObtainTime: time.Now().Unix()} BagMgrSingleton.AddJybBagInfo(p, []*Item{item}, 0, common.GainWay_Shop_Buy, "system", shopName) data := srvdata.PBDB_GameItemMgr.GetData(item.ItemId) if data != nil { BagMgrSingleton.RecordItemLog(p.Platform, p.SnId, ItemObtain, shopInfo.ItemId, data.Name, addTotal, "商城购买") } PetMgrSington.CheckShowRed(p) } this.ShopAddItem(shopInfo, p) this.CreateVCOrder(shopInfo, p.SnId, costNum, p.Platform, amount) //抽奖兑换统计 if shopInfo.ConstType == ShopConsumePhoneScore { items := make([]*Item, 0) itemId := int32(0) if shopInfo.Type == ShopTypeCoin { itemId = common.ItemIDCoin } else if shopInfo.Type == ShopTypeDiamond { itemId = common.ItemIDDiamond } else { //道具 itemId = shopInfo.ItemId } items = append(items, &Item{ ItemId: itemId, // 物品id ItemNum: addTotal, // 数量 }) jsonData, err := json.Marshal(items) if err == nil { LogChannelSingleton.WriteMQData(model.GeneratePhoneLottery(p.SnId, p.Platform, string(jsonData), 2, 0, 0, int(costNum))) } } } // GetAmountFinal 计算商品实际获得数量 func (this *ShopMgr) GetAmountFinal(p *Player, shopId, vipShopId int32) int64 { if p == nil { return 0 } var shopInfo = this.ConfigMgr.GetShopInfo(p.Platform, shopId) if shopInfo == nil { return 0 } //默认加成 var addTotal = shopInfo.Amount added := rand.Int31n(shopInfo.AddArea[1]-shopInfo.AddArea[0]+1) + shopInfo.AddArea[0] if shopInfo.Page == ShopPageVip { if p.VipShopData[vipShopId] == nil { return 0 } addTotal = shopInfo.Amount * int64(p.VipShopData[vipShopId].CostArea) added = p.VipShopData[vipShopId].AddArea } var addNormal int64 if added > 0 { addNormal = int64(float64(addTotal) * float64(added) / 100.0) } vipAdded := int64(0) if shopInfo.Page == ShopPageDiamond { //vip加成 vipAdded = int64(VipMgrSington.GetVipDiamondExtra(p.Platform, p.VIP)) logger.Logger.Tracef("商城钻石购买,vip加成 vipAdded = %v", vipAdded) vipAdded = int64(float64(addTotal) * float64(vipAdded) / 100.0) } switch shopInfo.Type { case ShopTypeCoin: var addCoin int64 award, _ := PetMgrSington.GetShopAward(shopInfo, p) if award > 0 { addCoin = int64(float64(addTotal) * float64(award) / 100.0) } //增加金币 addTotal += addNormal + addCoin case ShopTypeDiamond: addTotal += addNormal + vipAdded // 首充翻倍 if shopInfo.FirstSwitch { if !slices.Contains(p.ShopID, int(shopInfo.Id)) { addTotal *= 2 } } } return addTotal } // 商城购买 额外增加道具 func (this *ShopMgr) ShopAddItem(shopInfo *model.ShopInfo, p *Player) { if shopInfo.AddItemInfo != nil { for _, info := range shopInfo.AddItemInfo { item := &Item{ItemId: info.ItemId, ItemNum: info.ItemNum, ObtainTime: time.Now().Unix()} BagMgrSingleton.AddJybBagInfo(p, []*Item{item}, 0, common.GainWay_Shop_Buy, "system", shopInfo.Name) data := srvdata.PBDB_GameItemMgr.GetData(item.ItemId) if data != nil { BagMgrSingleton.RecordItemLog(p.Platform, p.SnId, ItemObtain, shopInfo.ItemId, data.Name, shopInfo.Amount, "商城购买") } PetMgrSington.CheckShowRed(p) } } } // CreateVCOrder 产生VC订单,记录看广告获取商品的订单 func (this *ShopMgr) CreateVCOrder(shopInfo *model.ShopInfo, snid, costNum int32, platform string, amount [3]int32) { task.New(nil, task.CallableWrapper(func(o *basic.Object) interface{} { //获得类型 if shopInfo.Type < ShopTypeCoin && shopInfo.Type > ShopTypeItem { return errors.New("error type") } //道具 var item []model.ItemInfo if shopInfo.Type == ShopTypeItem { item = append(item, model.ItemInfo{ItemId: shopInfo.ItemId, ItemNum: shopInfo.Amount}) if shopInfo.AddItemInfo != nil { for _, info := range shopInfo.AddItemInfo { item = append(item, model.ItemInfo{ItemId: info.ItemId, ItemNum: int64(info.ItemNum)}) } } } dbShop := model.NewDbShop(platform, shopInfo.Page, amount[:], "sys", 0, shopInfo.ConstType, costNum, common.GainWay_ShopBuy, item, shopInfo.Id, shopInfo.Name, snid, 1, "shop_goods", []int32{}) return model.InsertDbShopLog(dbShop) }), task.CompleteNotifyWrapper(func(data interface{}, t task.Task) { if data != nil { logger.Logger.Errorf("err:", data.(error)) } }), "CreateVCOrder").Start() } func (this *ShopMgr) GetExchangeData(platform string, id int32) *ExchangeShopInfo { if exShops := this.GetConfig(platform).ExchangeShopList; exShops != nil { for _, data := range exShops.List { if data.Id == id { var exType []*shop.ExchangeType for _, info := range data.ExType { exType = append(exType, &shop.ExchangeType{ Price: info.Price, JPrice: info.JPrice, Cash: info.Cash, Id: info.Id, }) } return &ExchangeShopInfo{ Id: data.Id, Picture: data.Picture, Type: data.Type, Name: data.Name, Rule: data.Content, ExType: exType, } } } } return nil } // 兑换操作 // Exchange 生成兑换订单(v卡) id 兑换方式 0~2 func (this *ShopMgr) Exchange(p *Player, goodsId int32, username, mobile, comment string, id int32, num int32) (ret bool) { ret = true cdata := this.GetExchangeData(p.Platform, goodsId) pack := &shop.SCShopExchange{ RetCode: shop.OpResultCode_OPRC_VCoinNotEnough, } if cdata == nil { pack.RetCode = shop.OpResultCode_OPRC_ExchangeSoldOut p.SendToClient(int(shop.SPacketID_PACKET_SC_SHOP_EXCHANGE), pack) return false } var info *shop.ExchangeType for _, value := range cdata.ExType { if value.Id == id { info = value break } } if info == nil || (info.Price == 0 && info.JPrice == 0 && info.Cash == 0) { return false } var itemInfo []model.ItemInfo // TODO 服务器处理 减劵 成功后调后台生成订单 // 判断p.VCoin是否足够 不足返回错误 足够扣掉 另外需从后台操作回执成功生成扣除V卡的订单 回执失败 //扣除V卡 if info.Price > 0 { if isF := BagMgrSingleton.SaleItem(p, VCard, int64(info.Price*num)); !isF { // 扣掉V卡 p.SendToClient(int(shop.SPacketID_PACKET_SC_SHOP_EXCHANGE), pack) return false } itemInfo = append(itemInfo, model.ItemInfo{ ItemId: VCard, ItemNum: int64(info.Price * num), }) } //扣除金券 if info.JPrice > 0 { if isF := BagMgrSingleton.SaleItem(p, JCard, int64(info.JPrice*num)); !isF { // 扣掉金券 pack.RetCode = shop.OpResultCode_OPRC_JCoinNotEnough p.SendToClient(int(shop.SPacketID_PACKET_SC_SHOP_EXCHANGE), pack) return false } itemInfo = append(itemInfo, model.ItemInfo{ ItemId: JCard, ItemNum: int64(info.JPrice * num), }) } task.New(nil, task.CallableWrapper(func(o *basic.Object) interface{} { pack := &webapi_proto.ASCreateExchangeOrder{ Snid: p.SnId, Platform: p.Platform, Type: cdata.Type, GoodsId: cdata.Id, VCard: info.Price * num, GoodsName: cdata.Name, UserName: username, Mobile: mobile, Comment: comment, JPrice: info.JPrice * num, Cash: info.Cash * num, Amount: num, ExchangeType: id, } buff, err := webapi.API_CreateExchange(common.GetAppId(), pack) if err != nil { logger.Logger.Error("API_CreateExchange error:", err) } as := &webapi_proto.SACreateExchangeOrder{} if err := proto.Unmarshal(buff, as); err != nil { logger.Logger.Errorf("API_CreateExchange err: %v %v", err, as.Tag) } var amount [ShopTypeItem]int32 //保存db dbShop := this.NewDbShop(p, 0, amount[:], ExchangeConsumeCash, info.Cash*num, common.GainWay_ShopBuy, itemInfo, cdata.Id, cdata.Name, 0, "", []int32{}) err = model.InsertDbShopLog(dbShop) if err != nil { logger.Logger.Errorf("model.InsertDbShopLog err:", err) return nil } return as }), task.CompleteNotifyWrapper(func(data interface{}, t task.Task) { pack := &shop.SCShopExchange{ RetCode: shop.OpResultCode_OPRC_Error, } as := data.(*webapi_proto.SACreateExchangeOrder) // 必不为空 //dbShop if as.Tag == webapi_proto.TagCode_SUCCESS { pack.RetCode = shop.OpResultCode_OPRC_Sucess //p.SendVCoinDiffData() // 强推 if info.Price > 0 { name := "V卡" if item := BagMgrSingleton.GetItem(p.SnId, VCard); item != nil && item.Name != "" { name = item.Name } else { logger.Logger.Errorf("ExchangeList name err snid %v item %v ", p.SnId, VCard) } BagMgrSingleton.RecordItemLog(p.Platform, p.SnId, ItemConsume, VCard, name, int64(info.Price*num), fmt.Sprintf("兑换订单 %v-%v", cdata.Id, cdata.Name)) } if info.JPrice > 0 { name := "金券" if item := BagMgrSingleton.GetItem(p.SnId, JCard); item != nil && item.Name != "" { name = item.Name } else { logger.Logger.Errorf("ExchangeList name err snid %v item %v ", p.SnId, JCard) } BagMgrSingleton.RecordItemLog(p.Platform, p.SnId, ItemConsume, JCard, name, int64(info.JPrice*num), fmt.Sprintf("兑换订单 %v-%v", cdata.Id, cdata.Name)) } } else { if as.GetReturnCPO() != nil { switch as.ReturnCPO.Err { case Err_ExShopNEnough: pack.RetCode = shop.OpResultCode_OPRC_ExchangeNotEnough case Err_ExShopLimit: pack.RetCode = shop.OpResultCode_OPRC_ExchangeLimit case Err_ExShopData: pack.RetCode = shop.OpResultCode_OPRC_ExchangeDataRtt default: pack.RetCode = shop.OpResultCode_OPRC_ExchangeSoldOut } } logger.Logger.Trace("API_CreateExchange: ", as.Tag, as.GetReturnCPO()) var items = []*Item{} //返回V卡 if info.Price > 0 { item1 := &Item{ ItemId: VCard, // 物品id ItemNum: int64(info.Price * num), // 数量 } items = append(items, item1) } //返回金券 if info.JPrice > 0 { item := &Item{ ItemId: JCard, ItemNum: int64(info.JPrice * num), } items = append(items, item) } if len(items) > 0 { BagMgrSingleton.AddJybBagInfo(p, items, 0, common.GainWay_Exchange, "system", "返还物品") // 后台订单创建失败 返回物品 } } p.SendToClient(int(shop.SPacketID_PACKET_SC_SHOP_EXCHANGE), pack) }), "CreateExchange").Start() return } // 兑换列表 func (this *ShopMgr) ExchangeList(p *Player) (ret bool) { ret = true task.New(nil, task.CallableWrapper(func(o *basic.Object) interface{} { pack := &webapi_proto.ASGetExchangeShop{ Snid: p.SnId, Platform: p.Platform, } buff, err := webapi.API_ExchangeList(common.GetAppId(), pack) // spack := &shop.SCShopExchangeRecord{} as := &webapi_proto.SAGetExchangeShop{} logger.Logger.Trace("SCShopOrder:", pack) if err != nil { logger.Logger.Error("API_ExchangeList error:", err) return nil } else if err := proto.Unmarshal(buff, as); err != nil { // 有订单 logger.Logger.Errorf("ExchangeRecord: %v", err) return nil } return as }), task.CompleteNotifyWrapper(func(data interface{}, t task.Task) { pack := &shop.SCShopExchangeList{ RetCode: shop.OpResultCode_OPRC_Sucess, } if data != nil { if as := data.(*webapi_proto.SAGetExchangeShop); as != nil { for _, v := range as.List { var exChangeType []*shop.ExchangeType for _, info := range v.ExType { exChangeType = append(exChangeType, &shop.ExchangeType{ Price: info.Price, JPrice: info.JPrice, Id: info.Id, Cash: info.Cash, }) } pack.Infos = append(pack.Infos, &shop.ShopExchangeInfo{ Type: v.Type, Picture: v.Picture, Name: v.Name, Rule: v.Content, GoodsId: v.Id, ShopLimit: v.ShopLimit, DayMaxLimit: v.DayMaxLimit, DayPlayLimit: v.DayPlayLimit, ExType: exChangeType, TelCharge: v.TelCharge, }) } } } else { pack.RetCode = shop.OpResultCode_OPRC_Error } p.SendToClient(int(shop.SPacketID_PACKET_SC_SHOP_EXCHANGELIST), pack) }), "ExchangeList").Start() return } // 获取兑换记录 func (this *ShopMgr) GetExchangeRecord(p *Player, pageNo int32) { task.New(nil, task.CallableWrapper(func(o *basic.Object) interface{} { pack := &webapi_proto.ASGetExchangeOrder{ Snid: p.SnId, Platform: p.Platform, Page: pageNo, } buff, err := webapi.API_ExchangeRecord(common.GetAppId(), pack) // spack := &shop.SCShopExchangeRecord{} as := &webapi_proto.SAGetExchangeOrder{} logger.Logger.Trace("SCShopOrder:", pack) if err != nil { logger.Logger.Error("API_ExchangeRecord error:", err) return nil } else if err := proto.Unmarshal(buff, as); err != nil { // 有订单 logger.Logger.Errorf("ExchangeRecord: %v", err) return nil } return as }), task.CompleteNotifyWrapper(func(data interface{}, t task.Task) { pack := &shop.SCShopExchangeRecord{} if data != nil { if as := data.(*webapi_proto.SAGetExchangeOrder); as != nil { pack.PageNo = as.CurPage pack.PageSize = as.PageLimit pack.PageSum = as.PageTotal for _, v := range as.OrderList { record := &shop.ShopExchangeRecord{ CreateTs: v.CreateTime, OrderId: fmt.Sprintf("%v", v.Id), State: v.Status, Name: v.Name, Remark: v.Remark, PayState: v.PayStatus, ExchangeNum: v.ExchangeNum, EXchangeType: v.EXchangeType, GoodsId: v.GoodsId, } // remark pack.Infos = append(pack.Infos, record) } } } p.SendToClient(int(shop.SPacketID_PACKET_SC_SHOP_EXCHANGERECORD), pack) }), "ExchangeRecord").Start() } // ShopCheckShowRed 商城红点通知 func (this *ShopMgr) ShopCheckShowRed(p *Player) { if p == nil { return } for i := 0; i < 3; i++ { var isShow bool for _, shopInfo := range this.GetConfig(p.Platform).ShopInfos { if shopInfo == nil { continue } var AdLookedNum, remainingTime int32 var lastLookTime int64 if shopInfo.Ad > 0 && (i == -1 || (i < len(shopInfo.Location) && shopInfo.Location[i] == 1)) { shopTotal := p.ShopTotal[shopInfo.Id] if shopTotal != nil { AdLookedNum = shopTotal.AdLookedNum } lastLookTime = p.ShopLastLookTime[shopInfo.Id] if AdLookedNum < int32(len(shopInfo.CoolingTime)) { remainingTime = shopInfo.CoolingTime[AdLookedNum] } else { continue } dif := int32(time.Now().Unix() - lastLookTime) if dif >= remainingTime { remainingTime = 0 if i+1 <= len(shopInfo.Location) { isShow = true p.SendShowRed(hall_proto.ShowRedCode_Shop, int32(i+1), 1) } } } } if !isShow { p.SendShowRed(hall_proto.ShowRedCode_Shop, int32(i+1), 0) } } } // 现金订单 func (this *ShopMgr) NewDbShop(p *Player, pageId int32, amount []int32, consume, consumeNum, gainWay int32, itemInfo []model.ItemInfo, shopId int32, shopName string, state int32, remark string, other []int32) (dbShop *model.DbShop) { ct, cr := PlatformMgrSingleton.GetCurrencyByPackageTag(p.PackageID) dbShop = model.NewDbShop(p.Platform, pageId, amount[:], ct, consumeNum*cr, consume, consumeNum, gainWay, itemInfo, shopId, shopName, p.SnId, state, remark, other) return } // SendAPICreateOrder 创建订单 func (this *ShopMgr) SendAPICreateOrder(p *Player, ConfigPayId int32, data any, remark string) { //三方购买 task.New(nil, task.CallableWrapper(func(o *basic.Object) interface{} { var amount [ShopTypeItem]int32 var dbShop *model.DbShop if shopInfo, ok := data.(*model.ShopInfo); ok { // 目前现金只能买钻石 var addTotal = int64(shopInfo.Amount) added := rand.Int31n(shopInfo.AddArea[1]-shopInfo.AddArea[0]+1) + shopInfo.AddArea[0] costNum := rand.Int31n(shopInfo.CostArea[1]-shopInfo.CostArea[0]+1) + shopInfo.CostArea[0] /* if shopInfo.Page == ShopPageVip { //暂时这样修改 VIP礼包没有现金支付 shopData := p.GetVipShopData(shopInfo.Id, 0) if shopData != nil { added = shopData.AddArea costNum = shopData.CostArea } }*/ vipAdded := int32(0) if shopInfo.Page == ShopPageDiamond { //vip加成 vipAdded = VipMgrSington.GetVipDiamondExtra(p.Platform, p.VIP) logger.Logger.Tracef("商城钻石购买,vip加成 vipAdded = %v", vipAdded) } if added > 0 || vipAdded > 0 { addTotal = shopInfo.Amount + int64((float64(shopInfo.Amount)*float64(added+vipAdded))/100.0) } // 首充翻倍 if shopInfo.FirstSwitch { if !slices.Contains(p.ShopID, int(shopInfo.Id)) { addTotal *= 2 } } amount[ShopTypeDiamond-1] = int32(addTotal) var itemInfo []model.ItemInfo var webItemInfo []*webapi_proto.ItemInfo if shopInfo.AddItemInfo != nil { for _, info := range shopInfo.AddItemInfo { itemInfo = append(itemInfo, model.ItemInfo{ ItemId: info.ItemId, ItemNum: int64(info.ItemNum), }) webItemInfo = append(webItemInfo, &webapi_proto.ItemInfo{ ItemId: info.ItemId, ItemNum: info.ItemNum, }) } } dbShop = this.NewDbShop(p, shopInfo.Page, amount[:], ShopConsumeMoney, costNum, common.GainWay_ShopBuy, itemInfo, shopInfo.Id, shopInfo.Name, 0, remark, []int32{}) err := model.InsertDbShopLog(dbShop) if err != nil { logger.Logger.Errorf("model.InsertDbShopLog err:", err) return nil } return webapi.API_CreateOrder(common.GetAppId(), dbShop.LogId.Hex(), ConfigPayId, p.SnId, shopInfo.Id, p.Platform, p.PackageID, p.DeviceOS, p.DeviceId, shopInfo.Name, [ShopTypeItem]int32{0, int32(addTotal), 0}, costNum, webItemInfo, "") } else if cdata, ok := data.(*ExchangeShopInfo); ok { var info *shop.ExchangeType for _, value := range cdata.ExType { if value.Id == cdata.ExchangeTypeId { info = value break } } if info.Cash <= 0 { return nil } //保存到db dbShop = this.NewDbShop(p, 0, amount[:], ExchangeConsumeCash, info.Cash*cdata.ExchangeNum, common.GainWay_ShopBuy, nil, cdata.Id, cdata.Name, 0, remark, []int32{}) err := model.InsertDbShopLog(dbShop) if err != nil { logger.Logger.Errorf("model.InsertDbShopLog err:", err) return nil } orderId := cdata.OrderId //兑换 充值订单 logger.Logger.Infof("客户端请求兑换 创建支付订单!AppId = %v,SnId = %v,Id = %v,dbShop.LogId.Hex() = %v,cash = %v", common.GetAppId(), p.SnId, cdata.Id, dbShop.LogId.Hex(), info.Cash*cdata.ExchangeNum) return webapi.API_CreateOrder(common.GetAppId(), dbShop.LogId.Hex(), ConfigPayId, p.SnId, cdata.Id, p.Platform, p.PackageID, p.DeviceOS, p.DeviceId, cdata.Name, [ShopTypeItem]int32{0, 0, 0}, info.Cash*cdata.ExchangeNum, nil, orderId) } else if bbd, ok := data.(*webapi_proto.BlindBoxData); ok { if bbd.Type == 1 { //金币 amount[0] = bbd.Grade } else if bbd.Type == 2 { //钻石 amount[1] = bbd.Grade } dbShop = this.NewDbShop(p, 0, amount[:], ShopConsumeMoney, int32(bbd.Price2), common.GainWay_ActBlindBox, nil, 0, "", 0, remark, []int32{bbd.Id}) err := model.InsertDbShopLog(dbShop) if err != nil { logger.Logger.Errorf("model.InsertDbShopLog err:", err) return nil } return webapi.API_CreateOrder(common.GetAppId(), dbShop.LogId.Hex(), ConfigPayId, p.SnId, 0, p.Platform, p.PackageID, p.DeviceOS, p.DeviceId, bbd.Name, amount, int32(bbd.Price2), nil, "") } else if wfs, ok := data.(*webapi_proto.WelfareSpree); ok { for _, it := range wfs.Item { if it.Type == 1 { amount[0] = it.Grade } else if it.Type == 2 { amount[1] = it.Grade } } var gainWay int32 = common.GainWay_ActFirstPay if remark == "ContinuousPay" { gainWay = common.GainWay_ActContinuousPay } dbShop = this.NewDbShop(p, 0, amount[:], ShopConsumeMoney, int32(wfs.Price2), gainWay, nil, 0, "", 0, remark, []int32{wfs.Day}) err := model.InsertDbShopLog(dbShop) if err != nil { logger.Logger.Errorf("model.InsertDbShopLog err:", err) return nil } return webapi.API_CreateOrder(common.GetAppId(), dbShop.LogId.Hex(), ConfigPayId, p.SnId, 0, p.Platform, p.PackageID, p.DeviceOS, p.DeviceId, "FirstRecharge", amount, int32(wfs.Price2), nil, "") } return nil }), task.CompleteNotifyWrapper(func(retdata interface{}, t task.Task) { logger.Logger.Trace("API_CreateOrder:", retdata) pack := &shop.SCPayInfo{ RetCode: shop.OpResultCode_OPRC_Error, } if retdata == nil { p.SendToClient(int(shop.SPacketID_PACKET_SCPAYINFO), pack) return } info := retdata.(*webapi_proto.ASCreateOrder) if info == nil || info.Tag != 0 { logger.Logger.Errorf("SCPayInfo:Tag[%v] Msg[%v] Url[%v]", info.Tag, info.Msg, info.Url) //失败 p.SendToClient(int(shop.SPacketID_PACKET_SCPAYINFO), pack) } else { pack.RetCode = shop.OpResultCode_OPRC_Sucess pack.Url = info.Url logger.Logger.Trace("SCPayInfo:", pack) p.SendToClient(int(shop.SPacketID_PACKET_SCPAYINFO), pack) } }), "API_CreateOrder").Start() } func (this *ShopMgr) StartTimer(SnId int32, afterTs int32) { timer.StartTimer(timer.TimerActionWrapper(func(h timer.TimerHandle, ud interface{}) bool { p := PlayerMgrSington.GetPlayerBySnId(SnId) if p == nil || !p.IsOnLine() { return true } this.ShopCheckShowRed(p) return true }), nil, time.Duration(afterTs)*time.Second, 1) } func (this *ShopMgr) Update() { } func (this *ShopMgr) Shutdown() { module.UnregisteModule(this) } func init() { module.RegisteModule(ShopMgrSington, time.Second, 0) }