package items import ( "fmt" "go_dreamfactory/comm" "go_dreamfactory/lego/core" "go_dreamfactory/modules" "go_dreamfactory/pb" "go_dreamfactory/sys/configure" cfg "go_dreamfactory/sys/configure/structs" "go_dreamfactory/sys/db" "math" "time" "go.mongodb.org/mongo-driver/bson/primitive" "go.mongodb.org/mongo-driver/mongo" "go.mongodb.org/mongo-driver/x/bsonx" ) // /背包缓存数据管理组件 type ModelItemsComp struct { modules.MCompModel module *Items } // 组件初始化接口 func (this *ModelItemsComp) Init(service core.IService, module core.IModule, comp core.IModuleComp, opt core.IModuleOptions) (err error) { this.TableName = comm.TableItems this.MCompModel.Init(service, module, comp, opt) this.module = module.(*Items) //创建uid索引 this.DB.CreateIndex(core.SqlTable(this.TableName), mongo.IndexModel{ Keys: bsonx.Doc{{Key: "uid", Value: bsonx.Int32(1)}}, }) return } // /查询用户背包数据 func (this *ModelItemsComp) QueryUserPack(uId string) (itmes []*pb.DB_UserItemData, err error) { var ( model *db.DBModel ) itmes = make([]*pb.DB_UserItemData, 0) if this.module.IsCross() { if model, err = this.module.GetDBModelByUid(uId, this.TableName); err != nil { this.module.Errorln(err) } else { if err = model.GetList(uId, &itmes); err != nil { this.module.Errorf("err:%v", err) } } } else { if err = this.GetList(uId, &itmes); err != nil { this.module.Errorf("err:%v", err) } } return } // /查询用户指定格子的物品数据 func (this *ModelItemsComp) QueryUserPackByGridId(uId string, grid string) (itme *pb.DB_UserItemData, err error) { var ( model *db.DBModel ) itme = &pb.DB_UserItemData{} if this.module.IsCross() { if model, err = this.module.GetDBModelByUid(uId, this.TableName); err != nil { this.module.Errorln(err) } else { if err = model.GetListObj(uId, grid, itme); err != nil { this.module.Errorf("err:%v", err) } } } else { if err = this.GetListObj(uId, grid, itme); err != nil { this.module.Errorf("err:%v", err) } } return } // /查询用户指定格子的物品数据 func (this *ModelItemsComp) QueryUserPackByGridIds(uId string, grids []string) (itme []*pb.DB_UserItemData, err error) { var ( model *db.DBModel ) itme = make([]*pb.DB_UserItemData, len(grids)) if this.module.IsCross() { if model, err = this.module.GetDBModelByUid(uId, this.TableName); err != nil { this.module.Errorln(err) } else { if err = model.GetListObjs(uId, grids, &itme); err != nil { this.module.Errorf("err:%v", err) } } } else { if err = this.GetListObjs(uId, grids, &itme); err != nil { this.module.Errorf("err:%v", err) } } return } // 更新用户的背包信息 func (this *ModelItemsComp) AddUserPack(uId string, itmes ...*pb.DB_UserItemData) (err error) { data := make(map[string]*pb.DB_UserItemData) for _, v := range itmes { data[v.GridId] = v } var ( model *db.DBModel ) if this.module.IsCross() { if model, err = this.module.GetDBModelByUid(uId, this.TableName); err != nil { this.module.Errorln(err) } else { if err = model.AddLists(uId, data); err != nil { this.module.Errorf("err:%v", err) } } } else { if err = this.AddLists(uId, data); err != nil { this.module.Errorln(err) } } return } // 更新用户的背包信息 func (this *ModelItemsComp) UpdateUserPack(uid string, itmes ...*pb.DB_UserItemData) (err error) { var ( model *db.DBModel ) if this.module.IsCross() { if model, err = this.module.GetDBModelByUid(uid, this.TableName); err != nil { this.module.Errorln(err) } else { for _, v := range itmes { model.ChangeList(uid, v.GridId, map[string]interface{}{ "amount": v.Amount, "isNewItem": v.IsNewItem, "lastopt": configure.Now().Unix(), }) } } } else { for _, v := range itmes { this.ChangeList(uid, v.GridId, map[string]interface{}{ "amount": v.Amount, "isNewItem": v.IsNewItem, "lastopt": configure.Now().Unix(), }) } } return } // 更新用户的背包信息 func (this *ModelItemsComp) DeleteUserPack(uid string, itmes ...*pb.DB_UserItemData) (err error) { var ( model *db.DBModel ) gridIds := make([]string, len(itmes)) for i, v := range itmes { gridIds[i] = v.GridId } if this.module.IsCross() { if model, err = this.module.GetDBModelByUid(uid, this.TableName); err != nil { this.module.Errorln(err) } else { if err = model.DelListlds(uid, gridIds); err != nil { this.module.Errorf("err:%v", err) return } } } else { if len(gridIds) > 0 { if err = this.DelListlds(uid, gridIds); err != nil { this.module.Errorf("err:%v", err) return } } } return } // 查询用户背包物品数量 func (this *ModelItemsComp) QueryUserPackItemsAmount(uId string, itemid ...string) (result map[string]uint32) { var ( itmes []*pb.DB_UserItemData err error ) if itmes, err = this.QueryUserPack(uId); err != nil { this.module.Errorf("err:%v", err) return } result = map[string]uint32{} for _, v := range itmes { for _, v1 := range itemid { if v.ItemId == v1 { result[v1] += v.Amount } } } return } // /添加或则减少物品到用户背包 func (this *ModelItemsComp) AddItemToUserPack(uId string, itemId string, addnum int32) (change []*pb.DB_UserItemData, err error) { var ( itmes []*pb.DB_UserItemData add []*pb.DB_UserItemData del []*pb.DB_UserItemData update []*pb.DB_UserItemData leftnum int64 ) if addnum == 0 { return } if itmes, err = this.QueryUserPack(uId); err != nil { this.module.Errorf("err:%v", err) return } change = make([]*pb.DB_UserItemData, 0) if add, update, del, leftnum, err = this.addItemToUserPack(uId, itmes, itemId, addnum); err != nil { return } if leftnum < 0 { err = ItemNotEnoughError return } else if leftnum > 0 { err = PackGridNumUpper return } if len(add) > 0 { if err = this.AddUserPack(uId, add...); err != nil { this.module.Errorf("err:%v", err) return } change = append(change, add...) } if len(del) > 0 { if err = this.DeleteUserPack(uId, del...); err != nil { this.module.Errorf("err:%v", err) return } change = append(change, del...) } if len(update) > 0 { if err = this.UpdateUserPack(uId, update...); err != nil { this.module.Errorf("err:%v", err) return } change = append(change, update...) } return } // /添加或则减少多个物品到用户背包 func (this *ModelItemsComp) AddItemsToUserPack(uId string, items map[string]int32) (change []*pb.DB_UserItemData, err error) { var ( itmes []*pb.DB_UserItemData add []*pb.DB_UserItemData del []*pb.DB_UserItemData update []*pb.DB_UserItemData leftnum int64 ) if itmes, err = this.QueryUserPack(uId); err != nil { this.module.Errorf("err:%v", err) return } change = make([]*pb.DB_UserItemData, 0) for k, v := range items { if add, update, del, leftnum, err = this.addItemToUserPack(uId, itmes, k, v); err != nil { return } if leftnum < 0 { err = ItemNotEnoughError return } else if leftnum > 0 { err = PackGridNumUpper return } if len(add) > 0 { if err = this.AddUserPack(uId, add...); err != nil { this.module.Errorf("err:%v", err) return } change = append(change, add...) // } if len(del) > 0 { if err = this.DeleteUserPack(uId, del...); err != nil { this.module.Errorf("err:%v", err) return } change = append(change, del...) } if len(update) > 0 { if err = this.UpdateUserPack(uId, update...); err != nil { this.module.Errorf("err:%v", err) return } change = append(change, update...) } } return } // /修改指定格子的物品数量 func (this *ModelItemsComp) AddItemToUserPackByGrid(uId string, gridid string, addnum int32) (change []*pb.DB_UserItemData, err error) { var ( conf *cfg.GameItemData itme *pb.DB_UserItemData num int64 amount int64 ) if addnum == 0 { return } if itme, err = this.QueryUserPackByGridId(uId, gridid); err != nil { this.module.Errorf("err:%v", err) return } if conf, err = this.module.configure.GetItemConfigure(itme.ItemId); err != nil { this.module.Errorf("err:%v", err) return } amount = int64(itme.Amount) num = amount + int64(addnum) change = make([]*pb.DB_UserItemData, 0) if num < 0 { err = ItemNotEnoughError } else { if conf.UpperLimit > 0 && num > int64(conf.UpperLimit) { err = GirdAmountUpper return } else { itme.Amount = uint32(num) if itme.Amount > 0 { this.UpdateUserPack(uId, itme) } else { this.DeleteUserPack(uId, itme) } change = append(change, itme) } } return } // /添加移除物品到用户背包 func (this *ModelItemsComp) addItemToUserPack(uid string, items []*pb.DB_UserItemData, itemId string, addnum int32) (add, update, del []*pb.DB_UserItemData, leftnum int64, err error) { var ( conf *cfg.GameItemData num int64 isNew bool ) if addnum == 0 { return } if conf, err = this.module.configure.GetItemConfigure(itemId); err != nil { this.module.Errorln(err) err = NoFoundItemConfig return } // if conf.UpperLimit == 0 { // err = fmt.Errorf("item UpperLimit is 0") // return // } isNew = true leftnum = int64(addnum) add = make([]*pb.DB_UserItemData, 0) del = make([]*pb.DB_UserItemData, 0) update = make([]*pb.DB_UserItemData, 0) for _, v := range items { if v.ItemId == itemId { isNew = false num = int64(v.Amount) + int64(leftnum) if num < 0 { leftnum += int64(v.Amount) v.Change = -1 * int32(v.Amount) v.Amount = 0 del = append(del, v) } else if num > 0 && num < int64(v.Amount) { leftnum = 0 v.Change = int32(num) - int32(v.Amount) v.Amount = uint32(num) update = append(update, v) break } else if num > 0 && num > int64(v.Amount) { if conf.UpperLimit > 0 { if num <= int64(conf.UpperLimit) { leftnum = 0 v.Change = int32(num) - int32(v.Amount) v.Amount = uint32(num) update = append(update, v) break } else { if v.Amount < uint32(conf.UpperLimit) { leftnum = int64(num - int64(conf.UpperLimit)) v.Amount = uint32(conf.UpperLimit) update = append(update, v) } } } else { leftnum = 0 v.Change = int32(num) - int32(v.Amount) v.Amount = uint32(num) update = append(update, v) } } else if num == 0 { leftnum = 0 v.Amount = 0 del = append(del, v) } } } if leftnum < 0 { //背包物品不够 return } if leftnum > 0 { //还没有放完 寻找空的格子填充 index := int32(len(items)) for leftnum > 0 { //需要补充格子 if conf.UpperLimit == 0 || (conf.UpperLimit > 0 && leftnum <= int64(conf.UpperLimit)) { grid := &pb.DB_UserItemData{ GridId: primitive.NewObjectID().Hex(), UId: uid, ItemId: itemId, Change: int32(leftnum), Amount: uint32(leftnum), CTime: configure.Now().Unix(), IsNewItem: isNew, } if conf.Time > 0 { grid.ETime = configure.Now().Add(time.Minute * time.Duration(conf.Time)).Unix() } items = append(items, grid) add = append(add, grid) leftnum = 0 break } else { leftnum -= int64(conf.UpperLimit) grid := &pb.DB_UserItemData{ GridId: primitive.NewObjectID().Hex(), UId: uid, ItemId: itemId, Change: int32(conf.UpperLimit), Amount: uint32(conf.UpperLimit), CTime: configure.Now().Unix(), IsNewItem: isNew, } if conf.Time > 0 { grid.ETime = configure.Now().Add(time.Minute * time.Duration(conf.Time)).Unix() } items = append(items, grid) add = append(add, grid) index++ } if index > GridMaxNUm { //格子已达上限 break } } } return } // 购买门票 func (this *ModelItemsComp) buyTicket(session comm.IUserSession, buy int32) (info *pb.DBUserExpand, errdata *pb.ErrorData) { var ( need *cfg.Gameatn needs []*cfg.Gameatn maxbuy, vipbuy int err error ) if info, err = this.module.ModuleUser.GetUserExpand(session.GetUserId()); err != nil { errdata = &pb.ErrorData{ Code: pb.ErrorCode_CacheReadError, Title: pb.ErrorCode_CacheReadError.ToString(), } return } this.module.modelItems.recoverTicket(session) if maxbuy, err = this.module.configure.GetchallengeDataCount(); err != nil { errdata = &pb.ErrorData{ Code: pb.ErrorCode_ConfigNoFound, Title: pb.ErrorCode_ConfigNoFound.ToString(), Message: err.Error(), } return } vipbuy = int(this.module.privilege.GetCountByPrivilegeId(session.GetUserId(), comm.PrivilegeType3)) needs = make([]*cfg.Gameatn, 0) for i := int32(0); i < buy; i++ { if int(info.Buyunifiedticket+i+1) > maxbuy+vipbuy { errdata = &pb.ErrorData{ Code: pb.ErrorCode_ArenaTicketBuyUp, Title: pb.ErrorCode_ArenaTicketBuyUp.ToString(), } return } if need = this.module.configure.GetchallengeData(int(info.Buyunifiedticket + i + 1)); err != nil || need == nil { errdata = &pb.ErrorData{ Code: pb.ErrorCode_ConfigNoFound, Title: pb.ErrorCode_ConfigNoFound.ToString(), } return } needs = append(needs, need) } if errdata = this.module.ConsumeRes(session, needs, true); errdata != nil { return } atn := this.module.ModuleTools.GetGlobalConf().CopsBuyGet res := &cfg.Gameatn{ A: atn.A, T: atn.T, N: atn.N * buy, } info.Buyunifiedticket += buy if errdata = this.module.DispenseRes(session, []*cfg.Gameatn{res}, true); errdata != nil { return } this.module.ModuleUser.ChangeUserExpand(session.GetUserId(), map[string]interface{}{ "buyunifiedticket": info.Buyunifiedticket, "lasttimeunifiedticket": info.Lasttimeunifiedticket, "recovertimeunifiedticket": info.Recovertimeunifiedticket, }) return } // /回复门票 func (this *ModelItemsComp) recoverTicket(session comm.IUserSession) (errdata *pb.ErrorData) { var ( user *pb.DBUser info *pb.DBUserExpand duration time.Duration ticketitem *cfg.Gameatn ticket int32 ticketNum int32 err error ) if ticketitem = this.module.ModuleTools.GetGlobalConf().CopsBuyGet; ticketitem == nil { errdata = &pb.ErrorData{ Code: pb.ErrorCode_ConfigNoFound, Title: pb.ErrorCode_ConfigNoFound.ToString(), Message: comm.NewNotFoundConfErr(modelName, "global.json", "CopsBuyGet").Error(), } return } if user = this.module.ModuleUser.GetUser(session.GetUserId()); user == nil { errdata = &pb.ErrorData{ Code: pb.ErrorCode_CacheReadError, Title: pb.ErrorCode_CacheReadError.ToString(), } return } if info, err = this.module.ModuleUser.GetUserExpand(session.GetUserId()); err != nil { errdata = &pb.ErrorData{ Code: pb.ErrorCode_CacheReadError, Title: pb.ErrorCode_CacheReadError.ToString(), } return } if time.Unix(info.Lasttimeunifiedticket, 0).Day() < configure.Now().Day() { info.Lasttimeunifiedticket = configure.Now().Unix() info.Buyunifiedticket = 0 } global := this.module.ModuleTools.GetGlobalConf() playerlv := this.module.configure.GetPlayerlvConf(user.Lv) ticket = int32(this.module.ModuleItems.QueryItemAmount(session.GetUserId(), ticketitem.T)) if ticket < global.DreamlandFightnum && info.Recovertimeunifiedticket > 0 { duration = configure.Now().Sub(time.Unix(info.Recovertimeunifiedticket, 0)) ticketNum = int32(math.Floor(duration.Seconds() / float64(global.CopsRecoveryTime))) if ticketNum > 0 { if ticketNum+ticket > playerlv.CopsPsCeiling { ticketNum = playerlv.CopsPsCeiling - ticket } this.module.DispenseRes(session, []*cfg.Gameatn{{A: ticketitem.A, T: ticketitem.T, N: ticketNum}}, true) info.Recovertimeunifiedticket = time.Unix(info.Recovertimeunifiedticket, 0).Add(time.Duration(ticketNum) * time.Minute).Unix() } } this.module.ModuleUser.ChangeUserExpand(session.GetUserId(), map[string]interface{}{ "buyunifiedticket": info.Buyunifiedticket, "lasttimeunifiedticket": info.Lasttimeunifiedticket, "recovertimeunifiedticket": info.Recovertimeunifiedticket, }) return } // /使用道具 func (this *ModelItemsComp) useitem(session comm.IUserSession, gid string, amount int32, slt int32) (errdata *pb.ErrorData) { var ( item *pb.DB_UserItemData itemcf *cfg.GameItemData prop []*cfg.GameDropData err error ) if item, err = this.module.modelItems.QueryUserPackByGridId(session.GetUserId(), gid); err != nil { errdata = &pb.ErrorData{ Code: pb.ErrorCode_ReqParameterError, Title: pb.ErrorCode_ReqParameterError.ToString(), } return } if itemcf, err = this.module.configure.GetItemConfigure(item.ItemId); err != nil { errdata = &pb.ErrorData{ Code: pb.ErrorCode_ConfigurationException, Title: pb.ErrorCode_ConfigurationException.ToString(), } return } switch itemcf.Usetype { case itemuse_exchange: //合成/分解 if slt == 0 { // 合成 if itemcf.SynthetizeGet == nil || len(itemcf.SynthetizeGet) == 0 { errdata = &pb.ErrorData{ Code: pb.ErrorCode_ConfigNoFound, Title: pb.ErrorCode_ConfigNoFound.ToString(), Message: fmt.Sprintf("道具合成未配置! 道具id:%s ", itemcf.Id), } return } if itemcf.SynthetizeNum*int32(amount) > int32(item.Amount) { //碎片数量不够 errdata = &pb.ErrorData{ Code: pb.ErrorCode_ItemsNoEnough, Title: pb.ErrorCode_ItemsNoEnough.ToString(), Message: fmt.Sprintf("道具Id:%s", itemcf.Id), } return } sale := make([]*cfg.Gameatn, 0, len(itemcf.SynthetizeDeplete)) for _, v := range itemcf.SynthetizeDeplete { sale = append(sale, &cfg.Gameatn{ A: v.A, T: v.T, N: v.N * int32(amount), }) } if errdata = this.module.ConsumeRes(session, sale, true); errdata != nil { return } if errdata = this.module.AddItemforGrid(session, gid, -1*itemcf.SynthetizeNum*int32(amount), true); errdata != nil { return } sale = make([]*cfg.Gameatn, 0, len(itemcf.SynthetizeGet)) for _, v1 := range itemcf.SynthetizeGet { sale = append(sale, &cfg.Gameatn{ A: v1.A, T: v1.T, N: v1.N * int32(amount), }) } if errdata = this.module.DispenseRes(session, sale, true); errdata != nil { return } } else { if itemcf.DecomposeGet == nil || len(itemcf.DecomposeGet) == 0 { errdata = &pb.ErrorData{ Code: pb.ErrorCode_ConfigNoFound, Title: pb.ErrorCode_ConfigNoFound.ToString(), Message: fmt.Sprintf("道具分解未配置! 道具id:%s ", itemcf.Id), } return } if itemcf.SynthetizeNum*int32(amount) > int32(item.Amount) { //碎片数量不够 errdata = &pb.ErrorData{ Code: pb.ErrorCode_ItemsNoEnough, Title: pb.ErrorCode_ItemsNoEnough.ToString(), Message: fmt.Sprintf("道具Id:%s", itemcf.Id), } return } sale := make([]*cfg.Gameatn, 0, len(itemcf.DecomposeDeplete)) for _, v := range itemcf.DecomposeDeplete { sale = append(sale, &cfg.Gameatn{ A: v.A, T: v.T, N: v.N * int32(amount), }) } if errdata = this.module.ConsumeRes(session, sale, true); errdata != nil { return } if errdata = this.module.AddItemforGrid(session, gid, -1*int32(amount), true); errdata != nil { return } sale = make([]*cfg.Gameatn, len(itemcf.Sale)) for i, v := range itemcf.DecomposeGet { temp := *v sale[i] = &temp sale[i].N = v.N * int32(amount) } if errdata = this.module.DispenseRes(session, sale, true); errdata != nil { return } } case itemuse_optionalbox: //自选宝箱 if prop = this.module.configure.GetDropData(itemcf.BoxId); prop == nil { errdata = &pb.ErrorData{ Code: pb.ErrorCode_ConfigNoFound, Title: pb.ErrorCode_ConfigNoFound.ToString(), Message: fmt.Sprintf("掉落组未找到:%d", itemcf.BoxId), } return } if errdata = this.module.AddItemforGrid(session, gid, -1*int32(amount), true); errdata != nil { return } var sale []*cfg.Gameatn for _, v := range prop { if v.Id == slt { for _, v1 := range v.Prize { sale = append(sale, &cfg.Gameatn{ A: v1.A, T: v1.T, N: v1.N * int32(amount), }) } } } if sale == nil { this.module.Errorf("no found target sale:%v", slt) errdata = &pb.ErrorData{ Code: pb.ErrorCode_ReqParameterError, Title: pb.ErrorCode_ReqParameterError.ToString(), } return } if errdata = this.module.DispenseRes(session, sale, true); errdata != nil { return } case itemuse_randombox: //宝箱 user := this.module.ModuleUser.GetUser(session.GetUserId()) props := make([]*cfg.Gameatn, 0) for i := int32(0); i < amount; i++ { if prop := this.module.ModuleTools.GetGroupDataByLottery(itemcf.BoxId, user.Vip, user.Lv); len(prop) == 0 { //if prop = this.module.configure.GetDropData(itemcf.BoxId); prop == nil { errdata = &pb.ErrorData{ Code: pb.ErrorCode_ConfigNoFound, Title: pb.ErrorCode_ConfigNoFound.ToString(), Message: fmt.Sprintf("掉落组未找到:%d", itemcf.BoxId), } return } else { props = append(props, prop...) } } if errdata = this.module.AddItemforGrid(session, gid, -1*int32(amount), true); errdata != nil { return } if errdata = this.module.DispenseRes(session, props, true); errdata != nil { return } case itemuse_staminapotion: //体力药剂使用 if itemcf.DecomposeGet == nil || len(itemcf.DecomposeGet) == 0 { errdata = &pb.ErrorData{ Code: pb.ErrorCode_ConfigNoFound, Title: pb.ErrorCode_ConfigNoFound.ToString(), Message: fmt.Sprintf("道具分解未配置! 道具id:%s ", itemcf.Id), } return } if itemcf.SynthetizeNum*int32(amount) > int32(item.Amount) { //碎片数量不够 errdata = &pb.ErrorData{ Code: pb.ErrorCode_ItemsNoEnough, Title: pb.ErrorCode_ItemsNoEnough.ToString(), Message: fmt.Sprintf("道具Id:%s", itemcf.Id), } return } offps := this.module.ModuleUser.RemainingPS(session.GetUserId()) addps := itemcf.DecomposeGet[0].N * int32(amount) if addps > offps { //溢出 amount = int32(math.Floor(float64(offps) / float64(itemcf.DecomposeGet[0].N))) } sale := make([]*cfg.Gameatn, len(itemcf.Sale)) for i, v := range itemcf.DecomposeGet { temp := *v sale[i] = &temp sale[i].N = v.N * int32(amount) } if errdata = this.module.AddItemforGrid(session, gid, -1*int32(amount), true); errdata != nil { return } if errdata = this.module.DispenseRes(session, sale, true); errdata != nil { return } default: errdata = &pb.ErrorData{ Code: pb.ErrorCode_ItemsUseNotSupported, Title: pb.ErrorCode_ItemsUseNotSupported.ToString(), Message: fmt.Sprintf("道具使用类型:%d", itemcf.Usetype), } return } return }