From 2c35fc0df429f9043174eebe429028ab673a6059 Mon Sep 17 00:00:00 2001 From: flswld Date: Tue, 14 Mar 2023 15:29:18 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- gs/dao/player_mongo.go | 7 + gs/game/player_avatar.go | 611 ++++++++++++++++++++++------------- gs/game/player_base.go | 6 +- gs/game/player_costume.go | 94 ------ gs/game/player_fight_sync.go | 16 +- gs/game/player_flycloak.go | 83 ----- gs/game/player_gacha.go | 13 +- gs/game/player_item.go | 201 ++++++------ gs/game/player_shop.go | 24 +- gs/game/player_weapon.go | 53 +-- gs/game/user_manager.go | 3 +- gs/model/db_item.go | 35 +- 12 files changed, 559 insertions(+), 587 deletions(-) delete mode 100644 gs/game/player_costume.go delete mode 100644 gs/game/player_flycloak.go diff --git a/gs/dao/player_mongo.go b/gs/dao/player_mongo.go index 0014876e..4fb361de 100644 --- a/gs/dao/player_mongo.go +++ b/gs/dao/player_mongo.go @@ -8,6 +8,11 @@ import ( "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson/primitive" "go.mongodb.org/mongo-driver/mongo" + "go.mongodb.org/mongo-driver/mongo/options" +) + +const ( + MaxQueryChatMsgLen = 1000 // 最大可查询聊天记录条数 ) func (d *Dao) InsertPlayer(player *model.Player) error { @@ -250,6 +255,8 @@ func (d *Dao) QueryChatMsgListByUid(uid uint32) ([]*model.ChatMsg, error) { find, err := db.Find( context.TODO(), bson.D{{"$or", []bson.D{{{"ToUid", uid}}, {{"Uid", uid}}}}}, + options.Find().SetLimit(MaxQueryChatMsgLen), + options.Find().SetSort(bson.M{"Time": -1}), ) if err != nil { return nil, err diff --git a/gs/game/player_avatar.go b/gs/game/player_avatar.go index 205f4c86..b824b8f5 100644 --- a/gs/game/player_avatar.go +++ b/gs/game/player_avatar.go @@ -14,105 +14,86 @@ import ( pb "google.golang.org/protobuf/proto" ) -func (g *GameManager) GetAllAvatarDataConfig() map[int32]*gdconf.AvatarData { - allAvatarDataConfig := make(map[int32]*gdconf.AvatarData) - for avatarId, avatarData := range gdconf.GetAvatarDataMap() { - if avatarId <= 10000001 || avatarId >= 11000000 { - // 跳过无效角色 - continue - } - if avatarId == 10000005 || avatarId == 10000007 { - // 跳过主角 - continue - } - allAvatarDataConfig[avatarId] = avatarData - } - return allAvatarDataConfig -} - -func (g *GameManager) AddUserAvatar(userId uint32, avatarId uint32) { - player := USER_MANAGER.GetOnlineUser(userId) - if player == nil { - logger.Error("player is nil, uid: %v", userId) - return - } - // 判断玩家是否已有该角色 - dbAvatar := player.GetDbAvatar() - _, ok := dbAvatar.AvatarMap[avatarId] - if ok { - // TODO 如果已有转换命座材料 - return - } - dbAvatar.AddAvatar(player, avatarId) - - // 添加初始武器 - avatarDataConfig := gdconf.GetAvatarDataById(int32(avatarId)) - if avatarDataConfig == nil { - logger.Error("config is nil, itemId: %v", avatarId) - return - } - weaponId := g.AddUserWeapon(player.PlayerID, uint32(avatarDataConfig.InitialWeapon)) - - // 角色装上初始武器 - g.WearUserAvatarWeapon(player.PlayerID, avatarId, weaponId) - - g.UpdateUserAvatarFightProp(player.PlayerID, avatarId) - - avatarAddNotify := &proto.AvatarAddNotify{ - Avatar: g.PacketAvatarInfo(dbAvatar.AvatarMap[avatarId]), - IsInTeam: false, - } - g.SendMsg(cmd.AvatarAddNotify, userId, player.ClientSeq, avatarAddNotify) -} - -// AvatarPromoteGetRewardReq 角色突破获取奖励请求 -func (g *GameManager) AvatarPromoteGetRewardReq(player *model.Player, payloadMsg pb.Message) { - req := payloadMsg.(*proto.AvatarPromoteGetRewardReq) +// AvatarUpgradeReq 角色升级请求 +func (g *GameManager) AvatarUpgradeReq(player *model.Player, payloadMsg pb.Message) { + req := payloadMsg.(*proto.AvatarUpgradeReq) // 是否拥有角色 avatar, ok := player.GameObjectGuidMap[req.AvatarGuid].(*model.Avatar) if !ok { logger.Error("avatar error, avatarGuid: %v", req.AvatarGuid) - g.SendError(cmd.AvatarPromoteGetRewardRsp, player, &proto.AvatarPromoteGetRewardRsp{}, proto.Retcode_RET_CAN_NOT_FIND_AVATAR) + g.SendError(cmd.AvatarUpgradeRsp, player, &proto.AvatarUpgradeRsp{}, proto.Retcode_RET_CAN_NOT_FIND_AVATAR) + return + } + // 获取经验书物品配置表 + itemDataConfig := gdconf.GetItemDataById(int32(req.ItemId)) + if itemDataConfig == nil { + logger.Error("item data config error, itemId: %v", constant.ITEM_ID_SCOIN) + g.SendError(cmd.AvatarUpgradeRsp, player, &proto.AvatarUpgradeRsp{}, proto.Retcode_RET_ITEM_NOT_EXIST) + return + } + // 经验书将给予的经验数 + itemParam, err := strconv.Atoi(itemDataConfig.Use1Param1) + if err != nil { + logger.Error("parse item param error: %v", err) + g.SendError(cmd.AvatarUpgradeRsp, player, &proto.AvatarUpgradeRsp{}) + return + } + // 角色获得的经验 + expCount := uint32(itemParam) * req.Count + // 摩拉数量是否足够 + if g.GetPlayerItemCount(player.PlayerID, constant.ITEM_ID_SCOIN) < expCount/5 { + logger.Error("item count not enough, itemId: %v", constant.ITEM_ID_SCOIN) + g.SendError(cmd.AvatarUpgradeRsp, player, &proto.AvatarUpgradeRsp{}, proto.Retcode_RET_SCOIN_NOT_ENOUGH) return } // 获取角色配置表 avatarDataConfig := gdconf.GetAvatarDataById(int32(avatar.AvatarId)) if avatarDataConfig == nil { logger.Error("avatar config error, avatarId: %v", avatar.AvatarId) - g.SendError(cmd.AvatarPromoteGetRewardRsp, player, &proto.AvatarPromoteGetRewardRsp{}) + g.SendError(cmd.AvatarUpgradeRsp, player, &proto.AvatarUpgradeRsp{}) return } - // 角色是否获取过该突破等级的奖励 - if avatar.PromoteRewardMap[req.PromoteLevel] { - logger.Error("avatar config error, avatarId: %v", avatar.AvatarId) - g.SendError(cmd.AvatarPromoteGetRewardRsp, player, &proto.AvatarPromoteGetRewardRsp{}, proto.Retcode_RET_REWARD_HAS_TAKEN) + // 获取角色突破配置表 + avatarPromoteConfig := gdconf.GetAvatarPromoteDataByIdAndLevel(avatarDataConfig.PromoteId, int32(avatar.Promote)) + if avatarPromoteConfig == nil { + logger.Error("avatar promote config error, promoteLevel: %v", avatar.Promote) + g.SendError(cmd.AvatarUpgradeRsp, player, &proto.AvatarUpgradeRsp{}) return } - // 获取奖励配置表 - rewardConfig := gdconf.GetRewardDataById(int32(avatarDataConfig.PromoteRewardMap[req.PromoteLevel])) - if rewardConfig == nil { - logger.Error("reward config error, rewardId: %v", avatarDataConfig.PromoteRewardMap[req.PromoteLevel]) - g.SendError(cmd.AvatarPromoteGetRewardRsp, player, &proto.AvatarPromoteGetRewardRsp{}) + // 角色等级是否达到限制 + if avatar.Level >= uint8(avatarPromoteConfig.LevelLimit) { + logger.Error("avatar level ge level limit, level: %v", avatar.Level) + g.SendError(cmd.AvatarUpgradeRsp, player, &proto.AvatarUpgradeRsp{}, proto.Retcode_RET_AVATAR_BREAK_LEVEL_LESS_THAN) return } - // 设置该奖励为已被获取状态 - avatar.PromoteRewardMap[req.PromoteLevel] = true - // 给予突破奖励 - rewardItemList := make([]*ChangeItem, 0, len(rewardConfig.RewardItemMap)) - for itemId, count := range rewardConfig.RewardItemMap { - rewardItemList = append(rewardItemList, &ChangeItem{ - ItemId: itemId, - ChangeCount: count, - }) + // 消耗升级材料以及摩拉 + ok = g.CostUserItem(player.PlayerID, []*ChangeItem{ + {ItemId: req.ItemId, ChangeCount: req.Count}, + {ItemId: constant.ITEM_ID_SCOIN, ChangeCount: expCount / 5}, + }) + if !ok { + logger.Error("item count not enough, uid: %v", player.PlayerID) + g.SendError(cmd.AvatarUpgradeRsp, player, &proto.AvatarUpgradeRsp{}, proto.Retcode_RET_ITEM_COUNT_NOT_ENOUGH) + return + } + // 角色升级前的信息 + oldLevel := avatar.Level + oldFightPropMap := make(map[uint32]float32, len(avatar.FightPropMap)) + for propType, propValue := range avatar.FightPropMap { + oldFightPropMap[propType] = propValue } - g.AddUserItem(player.PlayerID, rewardItemList, false, 0) - avatarPromoteGetRewardRsp := &proto.AvatarPromoteGetRewardRsp{ - RewardId: uint32(rewardConfig.RewardID), - AvatarGuid: req.AvatarGuid, - PromoteLevel: req.PromoteLevel, + // 角色添加经验 + g.UpgradePlayerAvatar(player, avatar, expCount) + + avatarUpgradeRsp := &proto.AvatarUpgradeRsp{ + CurLevel: uint32(avatar.Level), + OldLevel: uint32(oldLevel), + OldFightPropMap: oldFightPropMap, + CurFightPropMap: avatar.FightPropMap, + AvatarGuid: req.AvatarGuid, } - g.SendMsg(cmd.AvatarPromoteGetRewardRsp, player.PlayerID, player.ClientSeq, avatarPromoteGetRewardRsp) + g.SendMsg(cmd.AvatarUpgradeRsp, player.PlayerID, player.ClientSeq, avatarUpgradeRsp) } // AvatarPromoteReq 角色突破请求 @@ -167,9 +148,8 @@ func (g *GameManager) AvatarPromoteReq(player *model.Player, payloadMsg pb.Messa ChangeCount: uint32(avatarPromoteConfig.CostCoin), }) // 突破材料以及摩拉是否足够 - dbItem := player.GetDbItem() for _, item := range costItemList { - if dbItem.GetItemCount(player, item.ItemId) < item.ChangeCount { + if g.GetPlayerItemCount(player.PlayerID, item.ItemId) < item.ChangeCount { logger.Error("item count not enough, itemId: %v", item.ItemId) // 摩拉的错误提示与材料不同 if item.ItemId == constant.ITEM_ID_SCOIN { @@ -186,7 +166,12 @@ func (g *GameManager) AvatarPromoteReq(player *model.Player, payloadMsg pb.Messa return } // 消耗突破材料和摩拉 - g.CostUserItem(player.PlayerID, costItemList) + ok = g.CostUserItem(player.PlayerID, costItemList) + if !ok { + logger.Error("item count not enough, uid: %v", player.PlayerID) + g.SendError(cmd.AvatarPromoteRsp, player, &proto.AvatarPromoteRsp{}, proto.Retcode_RET_ITEM_COUNT_NOT_ENOUGH) + return + } // 角色突破等级+1 avatar.Promote++ @@ -201,180 +186,167 @@ func (g *GameManager) AvatarPromoteReq(player *model.Player, payloadMsg pb.Messa g.SendMsg(cmd.AvatarPromoteRsp, player.PlayerID, player.ClientSeq, avatarPromoteRsp) } -// AvatarUpgradeReq 角色升级请求 -func (g *GameManager) AvatarUpgradeReq(player *model.Player, payloadMsg pb.Message) { - req := payloadMsg.(*proto.AvatarUpgradeReq) +// AvatarPromoteGetRewardReq 角色突破获取奖励请求 +func (g *GameManager) AvatarPromoteGetRewardReq(player *model.Player, payloadMsg pb.Message) { + req := payloadMsg.(*proto.AvatarPromoteGetRewardReq) // 是否拥有角色 avatar, ok := player.GameObjectGuidMap[req.AvatarGuid].(*model.Avatar) if !ok { logger.Error("avatar error, avatarGuid: %v", req.AvatarGuid) - g.SendError(cmd.AvatarUpgradeRsp, player, &proto.AvatarUpgradeRsp{}, proto.Retcode_RET_CAN_NOT_FIND_AVATAR) - return - } - // 经验书数量是否足够 - dbItem := player.GetDbItem() - if dbItem.GetItemCount(player, req.ItemId) < req.Count { - logger.Error("item count not enough, itemId: %v", req.ItemId) - g.SendError(cmd.AvatarUpgradeRsp, player, &proto.AvatarUpgradeRsp{}, proto.Retcode_RET_ITEM_COUNT_NOT_ENOUGH) - return - } - // 获取经验书物品配置表 - itemDataConfig := gdconf.GetItemDataById(int32(req.ItemId)) - if itemDataConfig == nil { - logger.Error("item data config error, itemId: %v", constant.ITEM_ID_SCOIN) - g.SendError(cmd.AvatarUpgradeRsp, player, &proto.AvatarUpgradeRsp{}, proto.Retcode_RET_ITEM_NOT_EXIST) - return - } - // 经验书将给予的经验数 - itemParam, err := strconv.Atoi(itemDataConfig.Use1Param1) - if err != nil { - logger.Error("parse item param error: %v", err) - g.SendError(cmd.AvatarUpgradeRsp, player, &proto.AvatarUpgradeRsp{}) - return - } - // 角色获得的经验 - expCount := uint32(itemParam) * req.Count - // 摩拉数量是否足够 - if dbItem.GetItemCount(player, constant.ITEM_ID_SCOIN) < expCount/5 { - logger.Error("item count not enough, itemId: %v", constant.ITEM_ID_SCOIN) - g.SendError(cmd.AvatarUpgradeRsp, player, &proto.AvatarUpgradeRsp{}, proto.Retcode_RET_SCOIN_NOT_ENOUGH) + g.SendError(cmd.AvatarPromoteGetRewardRsp, player, &proto.AvatarPromoteGetRewardRsp{}, proto.Retcode_RET_CAN_NOT_FIND_AVATAR) return } // 获取角色配置表 avatarDataConfig := gdconf.GetAvatarDataById(int32(avatar.AvatarId)) if avatarDataConfig == nil { logger.Error("avatar config error, avatarId: %v", avatar.AvatarId) - g.SendError(cmd.AvatarUpgradeRsp, player, &proto.AvatarUpgradeRsp{}) + g.SendError(cmd.AvatarPromoteGetRewardRsp, player, &proto.AvatarPromoteGetRewardRsp{}) return } - // 获取角色突破配置表 - avatarPromoteConfig := gdconf.GetAvatarPromoteDataByIdAndLevel(avatarDataConfig.PromoteId, int32(avatar.Promote)) - if avatarPromoteConfig == nil { - logger.Error("avatar promote config error, promoteLevel: %v", avatar.Promote) - g.SendError(cmd.AvatarUpgradeRsp, player, &proto.AvatarUpgradeRsp{}) - return - } - // 角色等级是否达到限制 - if avatar.Level >= uint8(avatarPromoteConfig.LevelLimit) { - logger.Error("avatar level ge level limit, level: %v", avatar.Level) - g.SendError(cmd.AvatarUpgradeRsp, player, &proto.AvatarUpgradeRsp{}, proto.Retcode_RET_AVATAR_BREAK_LEVEL_LESS_THAN) - return - } - // 消耗升级材料以及摩拉 - g.CostUserItem(player.PlayerID, []*ChangeItem{ - { - ItemId: req.ItemId, - ChangeCount: req.Count, - }, - { - ItemId: constant.ITEM_ID_SCOIN, - ChangeCount: expCount / 5, - }, - }) - // 角色升级前的信息 - oldLevel := avatar.Level - oldFightPropMap := make(map[uint32]float32, len(avatar.FightPropMap)) - for propType, propValue := range avatar.FightPropMap { - oldFightPropMap[propType] = propValue - } - - // 角色添加经验 - g.UpgradePlayerAvatar(player, avatar, expCount) - - avatarUpgradeRsp := &proto.AvatarUpgradeRsp{ - CurLevel: uint32(avatar.Level), - OldLevel: uint32(oldLevel), - OldFightPropMap: oldFightPropMap, - CurFightPropMap: avatar.FightPropMap, - AvatarGuid: req.AvatarGuid, - } - g.SendMsg(cmd.AvatarUpgradeRsp, player.PlayerID, player.ClientSeq, avatarUpgradeRsp) -} - -// UpgradePlayerAvatar 玩家角色升级 -func (g *GameManager) UpgradePlayerAvatar(player *model.Player, avatar *model.Avatar, expCount uint32) { - // 获取角色配置表 - avatarDataConfig := gdconf.GetAvatarDataById(int32(avatar.AvatarId)) - if avatarDataConfig == nil { + // 角色是否获取过该突破等级的奖励 + if avatar.PromoteRewardMap[req.PromoteLevel] { logger.Error("avatar config error, avatarId: %v", avatar.AvatarId) + g.SendError(cmd.AvatarPromoteGetRewardRsp, player, &proto.AvatarPromoteGetRewardRsp{}, proto.Retcode_RET_REWARD_HAS_TAKEN) return } - // 获取角色突破配置表 - avatarPromoteConfig := gdconf.GetAvatarPromoteDataByIdAndLevel(avatarDataConfig.PromoteId, int32(avatar.Promote)) - if avatarPromoteConfig == nil { - logger.Error("avatar promote config error, promoteLevel: %v", avatar.Promote) + // 获取奖励配置表 + rewardConfig := gdconf.GetRewardDataById(int32(avatarDataConfig.PromoteRewardMap[req.PromoteLevel])) + if rewardConfig == nil { + logger.Error("reward config error, rewardId: %v", avatarDataConfig.PromoteRewardMap[req.PromoteLevel]) + g.SendError(cmd.AvatarPromoteGetRewardRsp, player, &proto.AvatarPromoteGetRewardRsp{}) return } - // 角色增加经验 - avatar.Exp += expCount - // 角色升级 - for { - // 获取角色等级配置表 - avatarLevelConfig := gdconf.GetAvatarLevelDataByLevel(int32(avatar.Level)) - if avatarLevelConfig == nil { - // 获取不到代表已经到达最大等级 - break - } - // 角色当前等级未突破则跳出循环 - if avatar.Level >= uint8(avatarPromoteConfig.LevelLimit) { - // 角色未突破溢出的经验处理 - avatar.Exp = 0 - break - } - // 角色经验小于升级所需的经验则跳出循环 - if avatar.Exp < uint32(avatarLevelConfig.Exp) { - break - } - // 角色等级提升 - avatar.Exp -= uint32(avatarLevelConfig.Exp) - avatar.Level++ + // 设置该奖励为已被获取状态 + avatar.PromoteRewardMap[req.PromoteLevel] = true + // 给予突破奖励 + rewardItemList := make([]*ChangeItem, 0, len(rewardConfig.RewardItemMap)) + for itemId, count := range rewardConfig.RewardItemMap { + rewardItemList = append(rewardItemList, &ChangeItem{ + ItemId: itemId, + ChangeCount: count, + }) } - // 角色更新面板 - g.UpdateUserAvatarFightProp(player.PlayerID, avatar.AvatarId) - // 角色属性表更新通知 - g.SendMsg(cmd.AvatarPropNotify, player.PlayerID, player.ClientSeq, g.PacketAvatarPropNotify(avatar)) + g.AddUserItem(player.PlayerID, rewardItemList, false, 0) + + avatarPromoteGetRewardRsp := &proto.AvatarPromoteGetRewardRsp{ + RewardId: uint32(rewardConfig.RewardID), + AvatarGuid: req.AvatarGuid, + PromoteLevel: req.PromoteLevel, + } + g.SendMsg(cmd.AvatarPromoteGetRewardRsp, player.PlayerID, player.ClientSeq, avatarPromoteGetRewardRsp) } -// PacketAvatarPropNotify 角色属性表更新通知 -func (g *GameManager) PacketAvatarPropNotify(avatar *model.Avatar) *proto.AvatarPropNotify { - avatarPropNotify := &proto.AvatarPropNotify{ - PropMap: make(map[uint32]int64, 5), - AvatarGuid: avatar.Guid, - } - // 角色等级 - avatarPropNotify.PropMap[uint32(constant.PLAYER_PROP_LEVEL)] = int64(avatar.Level) - // 角色经验 - avatarPropNotify.PropMap[uint32(constant.PLAYER_PROP_EXP)] = int64(avatar.Exp) - // 角色突破等级 - avatarPropNotify.PropMap[uint32(constant.PLAYER_PROP_BREAK_LEVEL)] = int64(avatar.Promote) - // 角色饱食度 - avatarPropNotify.PropMap[uint32(constant.PLAYER_PROP_SATIATION_VAL)] = int64(avatar.Satiation) - // 角色饱食度溢出 - avatarPropNotify.PropMap[uint32(constant.PLAYER_PROP_SATIATION_PENALTY_TIME)] = int64(avatar.SatiationPenalty) +// AvatarWearFlycloakReq 角色装备风之翼请求 +func (g *GameManager) AvatarWearFlycloakReq(player *model.Player, payloadMsg pb.Message) { + req := payloadMsg.(*proto.AvatarWearFlycloakReq) - return avatarPropNotify -} - -func (g *GameManager) UpdateUserAvatarFightProp(userId uint32, avatarId uint32) { - player := USER_MANAGER.GetOnlineUser(userId) - if player == nil { - logger.Error("player is nil, uid: %v", userId) + world := WORLD_MANAGER.GetWorldByID(player.WorldId) + scene := world.GetSceneById(player.SceneId) + if scene == nil { + logger.Error("scene is nil, sceneId: %v", player.SceneId) + g.SendError(cmd.AvatarWearFlycloakRsp, player, &proto.AvatarWearFlycloakRsp{}) return } - dbAvatar := player.GetDbAvatar() - avatar, ok := dbAvatar.AvatarMap[avatarId] + + // 确保角色存在 + avatar, ok := player.GameObjectGuidMap[req.AvatarGuid].(*model.Avatar) if !ok { - logger.Error("avatar is nil, avatarId: %v", avatar) + logger.Error("avatar error, avatarGuid: %v", req.AvatarGuid) + g.SendError(cmd.AvatarWearFlycloakRsp, player, &proto.AvatarWearFlycloakRsp{}, proto.Retcode_RET_CAN_NOT_FIND_AVATAR) return } - // 角色初始化面板 - dbAvatar.InitAvatarFightProp(avatar) - avatarFightPropNotify := &proto.AvatarFightPropNotify{ - AvatarGuid: avatar.Guid, - FightPropMap: avatar.FightPropMap, + // 确保要更换的风之翼已获得 + exist := false + for _, v := range player.FlyCloakList { + if v == req.FlycloakId { + exist = true + } } - g.SendMsg(cmd.AvatarFightPropNotify, userId, player.ClientSeq, avatarFightPropNotify) + if !exist { + logger.Error("flycloak not exist, flycloakId: %v", req.FlycloakId) + g.SendError(cmd.AvatarWearFlycloakRsp, player, &proto.AvatarWearFlycloakRsp{}, proto.Retcode_RET_NOT_HAS_FLYCLOAK) + return + } + + // 设置角色风之翼 + avatar.FlyCloak = req.FlycloakId + + avatarFlycloakChangeNotify := &proto.AvatarFlycloakChangeNotify{ + AvatarGuid: req.AvatarGuid, + FlycloakId: req.FlycloakId, + } + for _, scenePlayer := range scene.GetAllPlayer() { + g.SendMsg(cmd.AvatarFlycloakChangeNotify, scenePlayer.PlayerID, scenePlayer.ClientSeq, avatarFlycloakChangeNotify) + } + + avatarWearFlycloakRsp := &proto.AvatarWearFlycloakRsp{ + AvatarGuid: req.AvatarGuid, + FlycloakId: req.FlycloakId, + } + g.SendMsg(cmd.AvatarWearFlycloakRsp, player.PlayerID, player.ClientSeq, avatarWearFlycloakRsp) +} + +// AvatarChangeCostumeReq 角色更换时装请求 +func (g *GameManager) AvatarChangeCostumeReq(player *model.Player, payloadMsg pb.Message) { + req := payloadMsg.(*proto.AvatarChangeCostumeReq) + + world := WORLD_MANAGER.GetWorldByID(player.WorldId) + scene := world.GetSceneById(player.SceneId) + if scene == nil { + logger.Error("scene is nil, sceneId: %v", player.SceneId) + g.SendError(cmd.AvatarChangeCostumeRsp, player, &proto.AvatarChangeCostumeRsp{}) + return + } + + // 确保角色存在 + avatar, ok := player.GameObjectGuidMap[req.AvatarGuid].(*model.Avatar) + if !ok { + logger.Error("avatar error, avatarGuid: %v", req.AvatarGuid) + g.SendError(cmd.AvatarChangeCostumeRsp, player, &proto.AvatarChangeCostumeRsp{}, proto.Retcode_RET_COSTUME_AVATAR_ERROR) + return + } + + // 确保要更换的时装已获得 + exist := false + for _, v := range player.CostumeList { + if v == req.CostumeId { + exist = true + } + } + if req.CostumeId == 0 { + exist = true + } + if !exist { + logger.Error("costume not exist, costumeId: %v", req.CostumeId) + g.SendError(cmd.AvatarChangeCostumeRsp, player, &proto.AvatarChangeCostumeRsp{}, proto.Retcode_RET_NOT_HAS_COSTUME) + return + } + + // 设置角色时装 + avatar.Costume = req.CostumeId + + // 角色更换时装通知 + avatarChangeCostumeNotify := new(proto.AvatarChangeCostumeNotify) + // 要更换时装的角色实体不存在代表更换的是仓库内的角色 + if scene.GetWorld().GetPlayerWorldAvatarEntityId(player, avatar.AvatarId) == 0 { + avatarChangeCostumeNotify.EntityInfo = &proto.SceneEntityInfo{ + Entity: &proto.SceneEntityInfo_Avatar{ + Avatar: g.PacketSceneAvatarInfo(scene, player, avatar.AvatarId), + }, + } + } else { + avatarChangeCostumeNotify.EntityInfo = g.PacketSceneEntityInfoAvatar(scene, player, avatar.AvatarId) + } + for _, scenePlayer := range scene.GetAllPlayer() { + g.SendMsg(cmd.AvatarChangeCostumeNotify, scenePlayer.PlayerID, scenePlayer.ClientSeq, avatarChangeCostumeNotify) + } + + avatarChangeCostumeRsp := &proto.AvatarChangeCostumeRsp{ + AvatarGuid: req.AvatarGuid, + CostumeId: req.CostumeId, + } + g.SendMsg(cmd.AvatarChangeCostumeRsp, player.PlayerID, player.ClientSeq, avatarChangeCostumeRsp) } func (g *GameManager) PacketAvatarInfo(avatar *model.Avatar) *proto.AvatarInfo { @@ -451,3 +423,184 @@ func (g *GameManager) PacketAvatarInfo(avatar *model.Avatar) *proto.AvatarInfo { } return pbAvatar } + +// PacketAvatarPropNotify 角色属性表更新通知 +func (g *GameManager) PacketAvatarPropNotify(avatar *model.Avatar) *proto.AvatarPropNotify { + avatarPropNotify := &proto.AvatarPropNotify{ + PropMap: make(map[uint32]int64, 5), + AvatarGuid: avatar.Guid, + } + // 角色等级 + avatarPropNotify.PropMap[uint32(constant.PLAYER_PROP_LEVEL)] = int64(avatar.Level) + // 角色经验 + avatarPropNotify.PropMap[uint32(constant.PLAYER_PROP_EXP)] = int64(avatar.Exp) + // 角色突破等级 + avatarPropNotify.PropMap[uint32(constant.PLAYER_PROP_BREAK_LEVEL)] = int64(avatar.Promote) + // 角色饱食度 + avatarPropNotify.PropMap[uint32(constant.PLAYER_PROP_SATIATION_VAL)] = int64(avatar.Satiation) + // 角色饱食度溢出 + avatarPropNotify.PropMap[uint32(constant.PLAYER_PROP_SATIATION_PENALTY_TIME)] = int64(avatar.SatiationPenalty) + + return avatarPropNotify +} + +func (g *GameManager) GetAllAvatarDataConfig() map[int32]*gdconf.AvatarData { + allAvatarDataConfig := make(map[int32]*gdconf.AvatarData) + for avatarId, avatarData := range gdconf.GetAvatarDataMap() { + if avatarId <= 10000001 || avatarId >= 11000000 { + // 跳过无效角色 + continue + } + if avatarId == 10000005 || avatarId == 10000007 { + // 跳过主角 + continue + } + allAvatarDataConfig[avatarId] = avatarData + } + return allAvatarDataConfig +} + +func (g *GameManager) AddUserAvatar(userId uint32, avatarId uint32) { + player := USER_MANAGER.GetOnlineUser(userId) + if player == nil { + logger.Error("player is nil, uid: %v", userId) + return + } + // 判断玩家是否已有该角色 + dbAvatar := player.GetDbAvatar() + _, ok := dbAvatar.AvatarMap[avatarId] + if ok { + // TODO 如果已有转换命座材料 + return + } + dbAvatar.AddAvatar(player, avatarId) + + // 添加初始武器 + avatarDataConfig := gdconf.GetAvatarDataById(int32(avatarId)) + if avatarDataConfig == nil { + logger.Error("config is nil, itemId: %v", avatarId) + return + } + weaponId := g.AddUserWeapon(player.PlayerID, uint32(avatarDataConfig.InitialWeapon)) + + // 角色装上初始武器 + g.WearUserAvatarWeapon(player.PlayerID, avatarId, weaponId) + + g.UpdateUserAvatarFightProp(player.PlayerID, avatarId) + + avatarAddNotify := &proto.AvatarAddNotify{ + Avatar: g.PacketAvatarInfo(dbAvatar.AvatarMap[avatarId]), + IsInTeam: false, + } + g.SendMsg(cmd.AvatarAddNotify, userId, player.ClientSeq, avatarAddNotify) +} + +// AddUserFlycloak 给予玩家风之翼 +func (g *GameManager) AddUserFlycloak(userId uint32, flyCloakId uint32) { + player := USER_MANAGER.GetOnlineUser(userId) + if player == nil { + logger.Error("player is nil, uid: %v", userId) + return + } + // 验证玩家是否已拥有该风之翼 + for _, flycloak := range player.FlyCloakList { + if flycloak == flyCloakId { + logger.Error("player has flycloak, flycloakId: %v", flyCloakId) + return + } + } + player.FlyCloakList = append(player.FlyCloakList, flyCloakId) + + avatarGainFlycloakNotify := &proto.AvatarGainFlycloakNotify{ + FlycloakId: flyCloakId, + } + g.SendMsg(cmd.AvatarGainFlycloakNotify, userId, player.ClientSeq, avatarGainFlycloakNotify) +} + +// AddUserCostume 给予玩家时装 +func (g *GameManager) AddUserCostume(userId uint32, costumeId uint32) { + player := USER_MANAGER.GetOnlineUser(userId) + if player == nil { + logger.Error("player is nil, uid: %v", userId) + return + } + // 验证玩家是否已拥有该时装 + for _, costume := range player.CostumeList { + if costume == costumeId { + logger.Error("player has costume, costumeId: %v", costumeId) + return + } + } + player.CostumeList = append(player.CostumeList, costumeId) + + avatarGainCostumeNotify := &proto.AvatarGainCostumeNotify{ + CostumeId: costumeId, + } + g.SendMsg(cmd.AvatarGainCostumeNotify, userId, player.ClientSeq, avatarGainCostumeNotify) +} + +// UpgradePlayerAvatar 玩家角色升级 +func (g *GameManager) UpgradePlayerAvatar(player *model.Player, avatar *model.Avatar, expCount uint32) { + // 获取角色配置表 + avatarDataConfig := gdconf.GetAvatarDataById(int32(avatar.AvatarId)) + if avatarDataConfig == nil { + logger.Error("avatar config error, avatarId: %v", avatar.AvatarId) + return + } + // 获取角色突破配置表 + avatarPromoteConfig := gdconf.GetAvatarPromoteDataByIdAndLevel(avatarDataConfig.PromoteId, int32(avatar.Promote)) + if avatarPromoteConfig == nil { + logger.Error("avatar promote config error, promoteLevel: %v", avatar.Promote) + return + } + // 角色增加经验 + avatar.Exp += expCount + // 角色升级 + for { + // 获取角色等级配置表 + avatarLevelConfig := gdconf.GetAvatarLevelDataByLevel(int32(avatar.Level)) + if avatarLevelConfig == nil { + // 获取不到代表已经到达最大等级 + break + } + // 角色当前等级未突破则跳出循环 + if avatar.Level >= uint8(avatarPromoteConfig.LevelLimit) { + // 角色未突破溢出的经验处理 + avatar.Exp = 0 + break + } + // 角色经验小于升级所需的经验则跳出循环 + if avatar.Exp < uint32(avatarLevelConfig.Exp) { + break + } + // 角色等级提升 + avatar.Exp -= uint32(avatarLevelConfig.Exp) + avatar.Level++ + } + // 角色更新面板 + g.UpdateUserAvatarFightProp(player.PlayerID, avatar.AvatarId) + // 角色属性表更新通知 + g.SendMsg(cmd.AvatarPropNotify, player.PlayerID, player.ClientSeq, g.PacketAvatarPropNotify(avatar)) +} + +func (g *GameManager) UpdateUserAvatarFightProp(userId uint32, avatarId uint32) { + player := USER_MANAGER.GetOnlineUser(userId) + if player == nil { + logger.Error("player is nil, uid: %v", userId) + return + } + dbAvatar := player.GetDbAvatar() + avatar, ok := dbAvatar.AvatarMap[avatarId] + if !ok { + logger.Error("avatar is nil, avatarId: %v", avatar) + return + } + // 角色初始化面板 + dbAvatar.InitAvatarFightProp(avatar) + + avatarFightPropNotify := &proto.AvatarFightPropNotify{ + AvatarGuid: avatar.Guid, + FightPropMap: avatar.FightPropMap, + } + g.SendMsg(cmd.AvatarFightPropNotify, userId, player.ClientSeq, avatarFightPropNotify) +} diff --git a/gs/game/player_base.go b/gs/game/player_base.go index bf306567..75310ae2 100644 --- a/gs/game/player_base.go +++ b/gs/game/player_base.go @@ -8,15 +8,13 @@ import ( "hk4e/protocol/proto" ) -// AddUserPlayerExp 基于玩家冒险阅历 -func (g *GameManager) AddUserPlayerExp(userId uint32, expCount uint32) { +// HandlePlayerExpAdd 玩家冒险阅历增加处理 +func (g *GameManager) HandlePlayerExpAdd(userId uint32) { player := USER_MANAGER.GetOnlineUser(userId) if player == nil { logger.Error("player is nil, uid: %v", userId) return } - // 玩家增加冒险阅历 - player.PropertiesMap[constant.PLAYER_PROP_PLAYER_EXP] += expCount // 玩家升级 for { playerLevel := player.PropertiesMap[constant.PLAYER_PROP_PLAYER_LEVEL] diff --git a/gs/game/player_costume.go b/gs/game/player_costume.go deleted file mode 100644 index 117d3c59..00000000 --- a/gs/game/player_costume.go +++ /dev/null @@ -1,94 +0,0 @@ -package game - -import ( - "hk4e/gs/model" - "hk4e/pkg/logger" - "hk4e/protocol/cmd" - "hk4e/protocol/proto" - - pb "google.golang.org/protobuf/proto" -) - -// AddUserCostume 给予玩家时装 -func (g *GameManager) AddUserCostume(userId uint32, costumeId uint32) { - player := USER_MANAGER.GetOnlineUser(userId) - if player == nil { - logger.Error("player is nil, uid: %v", userId) - return - } - // 验证玩家是否已拥有该时装 - for _, costume := range player.CostumeList { - if costume == costumeId { - logger.Error("player has costume, costumeId: %v", costumeId) - return - } - } - player.CostumeList = append(player.CostumeList, costumeId) - - avatarGainCostumeNotify := &proto.AvatarGainCostumeNotify{ - CostumeId: costumeId, - } - g.SendMsg(cmd.AvatarGainCostumeNotify, userId, player.ClientSeq, avatarGainCostumeNotify) -} - -// AvatarChangeCostumeReq 角色更换时装请求 -func (g *GameManager) AvatarChangeCostumeReq(player *model.Player, payloadMsg pb.Message) { - req := payloadMsg.(*proto.AvatarChangeCostumeReq) - - world := WORLD_MANAGER.GetWorldByID(player.WorldId) - scene := world.GetSceneById(player.SceneId) - if scene == nil { - logger.Error("scene is nil, sceneId: %v", player.SceneId) - g.SendError(cmd.AvatarChangeCostumeRsp, player, &proto.AvatarChangeCostumeRsp{}) - return - } - - // 确保角色存在 - avatar, ok := player.GameObjectGuidMap[req.AvatarGuid].(*model.Avatar) - if !ok { - logger.Error("avatar error, avatarGuid: %v", req.AvatarGuid) - g.SendError(cmd.AvatarChangeCostumeRsp, player, &proto.AvatarChangeCostumeRsp{}, proto.Retcode_RET_COSTUME_AVATAR_ERROR) - return - } - - // 确保要更换的时装已获得 - exist := false - for _, v := range player.CostumeList { - if v == req.CostumeId { - exist = true - } - } - if req.CostumeId == 0 { - exist = true - } - if !exist { - logger.Error("costume not exist, costumeId: %v", req.CostumeId) - g.SendError(cmd.AvatarChangeCostumeRsp, player, &proto.AvatarChangeCostumeRsp{}, proto.Retcode_RET_NOT_HAS_COSTUME) - return - } - - // 设置角色时装 - avatar.Costume = req.CostumeId - - // 角色更换时装通知 - avatarChangeCostumeNotify := new(proto.AvatarChangeCostumeNotify) - // 要更换时装的角色实体不存在代表更换的是仓库内的角色 - if scene.GetWorld().GetPlayerWorldAvatarEntityId(player, avatar.AvatarId) == 0 { - avatarChangeCostumeNotify.EntityInfo = &proto.SceneEntityInfo{ - Entity: &proto.SceneEntityInfo_Avatar{ - Avatar: g.PacketSceneAvatarInfo(scene, player, avatar.AvatarId), - }, - } - } else { - avatarChangeCostumeNotify.EntityInfo = g.PacketSceneEntityInfoAvatar(scene, player, avatar.AvatarId) - } - for _, scenePlayer := range scene.GetAllPlayer() { - g.SendMsg(cmd.AvatarChangeCostumeNotify, scenePlayer.PlayerID, scenePlayer.ClientSeq, avatarChangeCostumeNotify) - } - - avatarChangeCostumeRsp := &proto.AvatarChangeCostumeRsp{ - AvatarGuid: req.AvatarGuid, - CostumeId: req.CostumeId, - } - g.SendMsg(cmd.AvatarChangeCostumeRsp, player.PlayerID, player.ClientSeq, avatarChangeCostumeRsp) -} diff --git a/gs/game/player_fight_sync.go b/gs/game/player_fight_sync.go index df16e524..42679442 100644 --- a/gs/game/player_fight_sync.go +++ b/gs/game/player_fight_sync.go @@ -230,10 +230,10 @@ func (g *GameManager) CombatInvocationsNotify(player *model.Player, payloadMsg p } entry.CombatData = newCombatData player.CombatInvokeHandler.AddEntry(entry.ForwardType, entry) - g.SendToWorldAEC(world, cmd.EvtAnimatorParameterNotify, player.ClientSeq, &proto.EvtAnimatorParameterNotify{ - AnimatorParamInfo: evtAnimatorParameterInfo, - ForwardType: entry.ForwardType, - }, player.PlayerID) + // g.SendToWorldAEC(world, cmd.EvtAnimatorParameterNotify, player.ClientSeq, &proto.EvtAnimatorParameterNotify{ + // AnimatorParamInfo: evtAnimatorParameterInfo, + // ForwardType: entry.ForwardType, + // }, player.PlayerID) case proto.CombatTypeArgument_COMBAT_ANIMATOR_STATE_CHANGED: evtAnimatorStateChangedInfo := new(proto.EvtAnimatorStateChangedInfo) err := pb.Unmarshal(entry.CombatData, evtAnimatorStateChangedInfo) @@ -252,10 +252,10 @@ func (g *GameManager) CombatInvocationsNotify(player *model.Player, payloadMsg p } entry.CombatData = newCombatData player.CombatInvokeHandler.AddEntry(entry.ForwardType, entry) - g.SendToWorldAEC(world, cmd.EvtAnimatorStateChangedNotify, player.ClientSeq, &proto.EvtAnimatorStateChangedNotify{ - ForwardType: entry.ForwardType, - EvtAnimatorStateChangedInfo: evtAnimatorStateChangedInfo, - }, player.PlayerID) + // g.SendToWorldAEC(world, cmd.EvtAnimatorStateChangedNotify, player.ClientSeq, &proto.EvtAnimatorStateChangedNotify{ + // ForwardType: entry.ForwardType, + // EvtAnimatorStateChangedInfo: evtAnimatorStateChangedInfo, + // }, player.PlayerID) default: player.CombatInvokeHandler.AddEntry(entry.ForwardType, entry) } diff --git a/gs/game/player_flycloak.go b/gs/game/player_flycloak.go deleted file mode 100644 index 01679fe0..00000000 --- a/gs/game/player_flycloak.go +++ /dev/null @@ -1,83 +0,0 @@ -package game - -import ( - "hk4e/gs/model" - "hk4e/pkg/logger" - "hk4e/protocol/cmd" - "hk4e/protocol/proto" - - pb "google.golang.org/protobuf/proto" -) - -// AddUserFlycloak 给予玩家风之翼 -func (g *GameManager) AddUserFlycloak(userId uint32, flyCloakId uint32) { - player := USER_MANAGER.GetOnlineUser(userId) - if player == nil { - logger.Error("player is nil, uid: %v", userId) - return - } - // 验证玩家是否已拥有该风之翼 - for _, flycloak := range player.FlyCloakList { - if flycloak == flyCloakId { - logger.Error("player has flycloak, flycloakId: %v", flyCloakId) - return - } - } - player.FlyCloakList = append(player.FlyCloakList, flyCloakId) - - avatarGainFlycloakNotify := &proto.AvatarGainFlycloakNotify{ - FlycloakId: flyCloakId, - } - g.SendMsg(cmd.AvatarGainFlycloakNotify, userId, player.ClientSeq, avatarGainFlycloakNotify) -} - -// AvatarWearFlycloakReq 角色装备风之翼请求 -func (g *GameManager) AvatarWearFlycloakReq(player *model.Player, payloadMsg pb.Message) { - req := payloadMsg.(*proto.AvatarWearFlycloakReq) - - world := WORLD_MANAGER.GetWorldByID(player.WorldId) - scene := world.GetSceneById(player.SceneId) - if scene == nil { - logger.Error("scene is nil, sceneId: %v", player.SceneId) - g.SendError(cmd.AvatarWearFlycloakRsp, player, &proto.AvatarWearFlycloakRsp{}) - return - } - - // 确保角色存在 - avatar, ok := player.GameObjectGuidMap[req.AvatarGuid].(*model.Avatar) - if !ok { - logger.Error("avatar error, avatarGuid: %v", req.AvatarGuid) - g.SendError(cmd.AvatarWearFlycloakRsp, player, &proto.AvatarWearFlycloakRsp{}, proto.Retcode_RET_CAN_NOT_FIND_AVATAR) - return - } - - // 确保要更换的风之翼已获得 - exist := false - for _, v := range player.FlyCloakList { - if v == req.FlycloakId { - exist = true - } - } - if !exist { - logger.Error("flycloak not exist, flycloakId: %v", req.FlycloakId) - g.SendError(cmd.AvatarWearFlycloakRsp, player, &proto.AvatarWearFlycloakRsp{}, proto.Retcode_RET_NOT_HAS_FLYCLOAK) - return - } - - // 设置角色风之翼 - avatar.FlyCloak = req.FlycloakId - - avatarFlycloakChangeNotify := &proto.AvatarFlycloakChangeNotify{ - AvatarGuid: req.AvatarGuid, - FlycloakId: req.FlycloakId, - } - for _, scenePlayer := range scene.GetAllPlayer() { - g.SendMsg(cmd.AvatarFlycloakChangeNotify, scenePlayer.PlayerID, scenePlayer.ClientSeq, avatarFlycloakChangeNotify) - } - - avatarWearFlycloakRsp := &proto.AvatarWearFlycloakRsp{ - AvatarGuid: req.AvatarGuid, - FlycloakId: req.FlycloakId, - } - g.SendMsg(cmd.AvatarWearFlycloakRsp, player.PlayerID, player.ClientSeq, avatarWearFlycloakRsp) -} diff --git a/gs/game/player_gacha.go b/gs/game/player_gacha.go index 1a1a8a2b..991418c0 100644 --- a/gs/game/player_gacha.go +++ b/gs/game/player_gacha.go @@ -220,12 +220,10 @@ func (g *GameManager) DoGachaReq(player *model.Player, payloadMsg pb.Message) { } // 先扣掉粉球或蓝球再进行抽卡 - g.CostUserItem(player.PlayerID, []*ChangeItem{ - { - ItemId: costItemId, - ChangeCount: gachaTimes, - }, - }) + ok := g.CostUserItem(player.PlayerID, []*ChangeItem{{ItemId: costItemId, ChangeCount: gachaTimes}}) + if !ok { + return + } doGachaRsp := &proto.DoGachaRsp{ GachaType: gachaType, @@ -272,8 +270,7 @@ func (g *GameManager) DoGachaReq(player *model.Player, payloadMsg pb.Message) { g.AddUserAvatar(player.PlayerID, avatarId) } else { constellationItemId := itemId + 100 - dbItem := player.GetDbItem() - if dbItem.GetItemCount(player, constellationItemId) < 6 { + if g.GetPlayerItemCount(player.PlayerID, constellationItemId) < 6 { g.AddUserItem(player.PlayerID, []*ChangeItem{{ItemId: constellationItemId, ChangeCount: 1}}, false, 0) } } diff --git a/gs/game/player_item.go b/gs/game/player_item.go index fec7906d..7510714d 100644 --- a/gs/game/player_item.go +++ b/gs/game/player_item.go @@ -29,30 +29,43 @@ func (g *GameManager) GetAllItemDataConfig() map[int32]*gdconf.ItemData { return allItemDataConfig } -// AddUserItem 玩家添加物品 -func (g *GameManager) AddUserItem(userId uint32, itemList []*ChangeItem, isHint bool, hintReason uint16) { +func (g *GameManager) GetPlayerItemCount(userId uint32, itemId uint32) uint32 { player := USER_MANAGER.GetOnlineUser(userId) if player == nil { logger.Error("player is nil, uid: %v", userId) - return + return 0 } + prop, ok := constant.VIRTUAL_ITEM_PROP[itemId] + if ok { + value := player.PropertiesMap[prop] + return value + } else { + dbItem := player.GetDbItem() + value := dbItem.GetItemCount(itemId) + return value + } +} + +// AddUserItem 玩家添加物品 +func (g *GameManager) AddUserItem(userId uint32, itemList []*ChangeItem, isHint bool, hintReason uint16) bool { + player := USER_MANAGER.GetOnlineUser(userId) + if player == nil { + logger.Error("player is nil, uid: %v", userId) + return false + } + dbItem := player.GetDbItem() playerPropNotify := &proto.PlayerPropNotify{ PropMap: make(map[uint32]*proto.PropValue), } - dbItem := player.GetDbItem() - for _, userItem := range itemList { - // 物品为虚拟物品则另外处理 - switch userItem.ItemId { - case constant.ITEM_ID_RESIN, constant.ITEM_ID_LEGENDARY_KEY, constant.ITEM_ID_HCOIN, constant.ITEM_ID_SCOIN, - constant.ITEM_ID_MCOIN, constant.ITEM_ID_HOME_COIN: - // 树脂 传说任务钥匙 原石 摩拉 创世结晶 洞天宝钱 - prop, ok := constant.VIRTUAL_ITEM_PROP[userItem.ItemId] - if !ok { - continue - } - // 角色属性物品数量增加 - player.PropertiesMap[prop] += userItem.ChangeCount - + storeItemChangeNotify := &proto.StoreItemChangeNotify{ + StoreType: proto.StoreType_STORE_PACK, + ItemList: make([]*proto.Item, 0), + } + for _, changeItem := range itemList { + prop, exist := constant.VIRTUAL_ITEM_PROP[changeItem.ItemId] + if exist { + // 物品为虚拟物品 角色属性物品数量增加 + player.PropertiesMap[prop] += changeItem.ChangeCount playerPropNotify.PropMap[uint32(prop)] = &proto.PropValue{ Type: uint32(prop), Val: int64(player.PropertiesMap[prop]), @@ -60,36 +73,35 @@ func (g *GameManager) AddUserItem(userId uint32, itemList []*ChangeItem, isHint Ival: int64(player.PropertiesMap[prop]), }, } - case constant.ITEM_ID_PLAYER_EXP: - // 冒险阅历 - g.AddUserPlayerExp(userId, userItem.ChangeCount) - default: - // 普通物品直接进背包 - dbItem.AddItem(player, userItem.ItemId, userItem.ChangeCount) + // 特殊属性变化处理函数 + switch changeItem.ItemId { + case constant.ITEM_ID_PLAYER_EXP: + // 冒险阅历 + g.HandlePlayerExpAdd(userId) + } + } else { + // 物品为普通物品 直接进背包 + // 校验背包物品容量 目前物品包括材料和家具 + if dbItem.GetItemMapLen() > constant.STORE_PACK_LIMIT_MATERIAL+constant.STORE_PACK_LIMIT_FURNITURE { + return false + } + dbItem.AddItem(player, changeItem.ItemId, changeItem.ChangeCount) } - } - if len(playerPropNotify.PropMap) > 0 { - g.SendMsg(cmd.PlayerPropNotify, userId, player.ClientSeq, playerPropNotify) - } - - storeItemChangeNotify := &proto.StoreItemChangeNotify{ - StoreType: proto.StoreType_STORE_PACK, - ItemList: make([]*proto.Item, 0), - } - for _, userItem := range itemList { pbItem := &proto.Item{ - ItemId: userItem.ItemId, - Guid: dbItem.GetItemGuid(userItem.ItemId), + ItemId: changeItem.ItemId, + Guid: dbItem.GetItemGuid(changeItem.ItemId), Detail: &proto.Item_Material{ Material: &proto.Material{ - Count: dbItem.GetItemCount(player, userItem.ItemId), + Count: dbItem.GetItemCount(changeItem.ItemId), }, }, } storeItemChangeNotify.ItemList = append(storeItemChangeNotify.ItemList, pbItem) } + if len(playerPropNotify.PropMap) > 0 { + g.SendMsg(cmd.PlayerPropNotify, userId, player.ClientSeq, playerPropNotify) + } g.SendMsg(cmd.StoreItemChangeNotify, userId, player.ClientSeq, storeItemChangeNotify) - if isHint { if hintReason == 0 { hintReason = uint16(proto.ActionReasonType_ACTION_REASON_SUBFIELD_DROP) @@ -98,44 +110,46 @@ func (g *GameManager) AddUserItem(userId uint32, itemList []*ChangeItem, isHint Reason: uint32(hintReason), ItemList: make([]*proto.ItemHint, 0), } - for _, userItem := range itemList { + for _, changeItem := range itemList { itemAddHintNotify.ItemList = append(itemAddHintNotify.ItemList, &proto.ItemHint{ - ItemId: userItem.ItemId, - Count: userItem.ChangeCount, + ItemId: changeItem.ItemId, + Count: changeItem.ChangeCount, IsNew: false, }) } g.SendMsg(cmd.ItemAddHintNotify, userId, player.ClientSeq, itemAddHintNotify) } + return true } -func (g *GameManager) CostUserItem(userId uint32, itemList []*ChangeItem) { +func (g *GameManager) CostUserItem(userId uint32, itemList []*ChangeItem) bool { player := USER_MANAGER.GetOnlineUser(userId) if player == nil { logger.Error("player is nil, uid: %v", userId) - return + return false } + dbItem := player.GetDbItem() playerPropNotify := &proto.PlayerPropNotify{ PropMap: make(map[uint32]*proto.PropValue), } - dbItem := player.GetDbItem() - for _, userItem := range itemList { - // 物品为虚拟物品则另外处理 - switch userItem.ItemId { - case constant.ITEM_ID_RESIN, constant.ITEM_ID_LEGENDARY_KEY, constant.ITEM_ID_HCOIN, constant.ITEM_ID_SCOIN, - constant.ITEM_ID_MCOIN, constant.ITEM_ID_HOME_COIN: - // 树脂 传说任务钥匙 原石 摩拉 创世结晶 洞天宝钱 - prop, ok := constant.VIRTUAL_ITEM_PROP[userItem.ItemId] - if !ok { - continue - } - // 角色属性物品数量减少 - if player.PropertiesMap[prop] < userItem.ChangeCount { - player.PropertiesMap[prop] = 0 - } else { - player.PropertiesMap[prop] -= userItem.ChangeCount - } - + storeItemChangeNotify := &proto.StoreItemChangeNotify{ + StoreType: proto.StoreType_STORE_PACK, + ItemList: make([]*proto.Item, 0), + } + storeItemDelNotify := &proto.StoreItemDelNotify{ + StoreType: proto.StoreType_STORE_PACK, + GuidList: make([]uint64, 0), + } + for _, changeItem := range itemList { + // 检查剩余道具数量 + count := g.GetPlayerItemCount(player.PlayerID, changeItem.ItemId) + if count < changeItem.ChangeCount { + return false + } + prop, exist := constant.VIRTUAL_ITEM_PROP[changeItem.ItemId] + if exist { + // 物品为虚拟物品 角色属性物品数量减少 + player.PropertiesMap[prop] -= changeItem.ChangeCount playerPropNotify.PropMap[uint32(prop)] = &proto.PropValue{ Type: uint32(prop), Val: int64(player.PropertiesMap[prop]), @@ -143,53 +157,42 @@ func (g *GameManager) CostUserItem(userId uint32, itemList []*ChangeItem) { Ival: int64(player.PropertiesMap[prop]), }, } - case constant.ITEM_ID_PLAYER_EXP: - // 冒险阅历应该也没人会去扣吧? - default: - // 普通物品直接扣除 - dbItem.CostItem(player, userItem.ItemId, userItem.ChangeCount) + // 特殊属性变化处理函数 + switch changeItem.ItemId { + case constant.ITEM_ID_PLAYER_EXP: + // 冒险阅历应该也没人会去扣吧? + g.HandlePlayerExpAdd(userId) + } + } else { + // 物品为普通物品 直接扣除 + dbItem.CostItem(player, changeItem.ItemId, changeItem.ChangeCount) + } + count = g.GetPlayerItemCount(player.PlayerID, changeItem.ItemId) + if count > 0 { + pbItem := &proto.Item{ + ItemId: changeItem.ItemId, + Guid: dbItem.GetItemGuid(changeItem.ItemId), + Detail: &proto.Item_Material{ + Material: &proto.Material{ + Count: count, + }, + }, + } + storeItemChangeNotify.ItemList = append(storeItemChangeNotify.ItemList, pbItem) + } else if count == 0 { + storeItemDelNotify.GuidList = append(storeItemDelNotify.GuidList, dbItem.GetItemGuid(changeItem.ItemId)) } - } - if len(playerPropNotify.PropMap) > 0 { - g.SendMsg(cmd.PlayerPropNotify, userId, player.ClientSeq, playerPropNotify) } - storeItemChangeNotify := &proto.StoreItemChangeNotify{ - StoreType: proto.StoreType_STORE_PACK, - ItemList: make([]*proto.Item, 0), - } - for _, userItem := range itemList { - count := dbItem.GetItemCount(player, userItem.ItemId) - if count == 0 { - continue - } - pbItem := &proto.Item{ - ItemId: userItem.ItemId, - Guid: dbItem.GetItemGuid(userItem.ItemId), - Detail: &proto.Item_Material{ - Material: &proto.Material{ - Count: count, - }, - }, - } - storeItemChangeNotify.ItemList = append(storeItemChangeNotify.ItemList, pbItem) + if len(playerPropNotify.PropMap) > 0 { + g.SendMsg(cmd.PlayerPropNotify, userId, player.ClientSeq, playerPropNotify) } if len(storeItemChangeNotify.ItemList) > 0 { g.SendMsg(cmd.StoreItemChangeNotify, userId, player.ClientSeq, storeItemChangeNotify) } - - storeItemDelNotify := &proto.StoreItemDelNotify{ - StoreType: proto.StoreType_STORE_PACK, - GuidList: make([]uint64, 0), - } - for _, userItem := range itemList { - count := dbItem.GetItemCount(player, userItem.ItemId) - if count > 0 { - continue - } - storeItemDelNotify.GuidList = append(storeItemDelNotify.GuidList, dbItem.GetItemGuid(userItem.ItemId)) - } if len(storeItemDelNotify.GuidList) > 0 { g.SendMsg(cmd.StoreItemDelNotify, userId, player.ClientSeq, storeItemDelNotify) } + + return true } diff --git a/gs/game/player_shop.go b/gs/game/player_shop.go index 1bcfc395..6aed3076 100644 --- a/gs/game/player_shop.go +++ b/gs/game/player_shop.go @@ -74,20 +74,19 @@ func (g *GameManager) BuyGoodsReq(player *model.Player, payloadMsg pb.Message) { return } - dbItem := player.GetDbItem() - if dbItem.GetItemCount(player, 201) < costHcoinCount { + if g.GetPlayerItemCount(player.PlayerID, 201) < costHcoinCount { + return + } + ok := g.CostUserItem(player.PlayerID, []*ChangeItem{{ItemId: 201, ChangeCount: costHcoinCount}}) + if !ok { return } - g.CostUserItem(player.PlayerID, []*ChangeItem{{ - ItemId: 201, - ChangeCount: costHcoinCount, - }}) g.AddUserItem(player.PlayerID, []*ChangeItem{{ ItemId: buyItemId, ChangeCount: buyItemCount, }}, true, uint16(proto.ActionReasonType_ACTION_REASON_SHOP)) - req.Goods.BoughtNum = dbItem.GetItemCount(player, buyItemId) + req.Goods.BoughtNum = g.GetPlayerItemCount(player.PlayerID, buyItemId) buyGoodsRsp := &proto.BuyGoodsRsp{ ShopType: req.ShopType, @@ -104,14 +103,13 @@ func (g *GameManager) McoinExchangeHcoinReq(player *model.Player, payloadMsg pb. } count := req.Hcoin - dbItem := player.GetDbItem() - if dbItem.GetItemCount(player, 203) < count { + if g.GetPlayerItemCount(player.PlayerID, 203) < count { + return + } + ok := g.CostUserItem(player.PlayerID, []*ChangeItem{{ItemId: 203, ChangeCount: count}}) + if !ok { return } - g.CostUserItem(player.PlayerID, []*ChangeItem{{ - ItemId: 203, - ChangeCount: count, - }}) g.AddUserItem(player.PlayerID, []*ChangeItem{{ ItemId: 201, diff --git a/gs/game/player_weapon.go b/gs/game/player_weapon.go index 614ab315..63b72631 100644 --- a/gs/game/player_weapon.go +++ b/gs/game/player_weapon.go @@ -124,13 +124,6 @@ func (g *GameManager) WeaponAwakenReq(player *model.Player, payloadMsg pb.Messag logger.Error("weapon config cost coin error, itemId: %v", weapon.ItemId) return } - // 摩拉数量是否足够 - dbItem := player.GetDbItem() - if dbItem.GetItemCount(player, constant.ITEM_ID_SCOIN) < weaponConfig.AwakenCoinCostList[weapon.Refinement] { - logger.Error("item count not enough, itemId: %v", constant.ITEM_ID_SCOIN) - g.SendError(cmd.WeaponAwakenRsp, player, &proto.WeaponAwakenRsp{}, proto.Retcode_RET_SCOIN_NOT_ENOUGH) - return - } // 一星二星的武器不能精炼 if weaponConfig.EquipLevel < constant.WEAPON_AWAKEN_MIN_EQUIPLEVEL { logger.Error("weapon equip level le 3, itemId: %v", weapon.ItemId) @@ -208,24 +201,24 @@ func (g *GameManager) WeaponAwakenReq(player *model.Player, payloadMsg pb.Messag return } // 消耗作为精炼材料的道具 - g.CostUserItem(player.PlayerID, []*ChangeItem{ - { - ItemId: item.ItemId, - ChangeCount: 1, - }, - }) + ok = g.CostUserItem(player.PlayerID, []*ChangeItem{{ItemId: item.ItemId, ChangeCount: 1}}) + if !ok { + logger.Error("item count not enough, uid: %v", player.PlayerID) + g.SendError(cmd.WeaponAwakenRsp, player, &proto.WeaponAwakenRsp{}, proto.Retcode_RET_ITEM_COUNT_NOT_ENOUGH) + return + } default: logger.Error("weapon awaken item type error, itemType: %v", itemDataConfig.Type) g.SendError(cmd.WeaponAwakenRsp, player, &proto.WeaponAwakenRsp{}) return } // 消耗摩拉 - g.CostUserItem(player.PlayerID, []*ChangeItem{ - { - ItemId: constant.ITEM_ID_SCOIN, - ChangeCount: weaponConfig.AwakenCoinCostList[weapon.Refinement], - }, - }) + ok = g.CostUserItem(player.PlayerID, []*ChangeItem{{ItemId: constant.ITEM_ID_SCOIN, ChangeCount: weaponConfig.AwakenCoinCostList[weapon.Refinement]}}) + if !ok { + logger.Error("item count not enough, uid: %v", player.PlayerID) + g.SendError(cmd.WeaponAwakenRsp, player, &proto.WeaponAwakenRsp{}, proto.Retcode_RET_SCOIN_NOT_ENOUGH) + return + } weaponAwakenRsp := &proto.WeaponAwakenRsp{ AvatarGuid: 0, @@ -313,9 +306,8 @@ func (g *GameManager) WeaponPromoteReq(player *model.Player, payloadMsg pb.Messa ChangeCount: uint32(weaponPromoteConfig.CostCoin), }) // 突破材料以及摩拉是否足够 - dbItem := player.GetDbItem() for _, item := range costItemList { - if dbItem.GetItemCount(player, item.ItemId) < item.ChangeCount { + if g.GetPlayerItemCount(player.PlayerID, item.ItemId) < item.ChangeCount { logger.Error("item count not enough, itemId: %v", item.ItemId) // 摩拉的错误提示与材料不同 if item.ItemId == constant.ITEM_ID_SCOIN { @@ -332,7 +324,14 @@ func (g *GameManager) WeaponPromoteReq(player *model.Player, payloadMsg pb.Messa return } // 消耗突破材料和摩拉 - g.CostUserItem(player.PlayerID, costItemList) + ok = g.CostUserItem(player.PlayerID, costItemList) + if !ok { + if !ok { + logger.Error("item count not enough, uid: %v", player.PlayerID) + g.SendError(cmd.WeaponPromoteRsp, player, &proto.WeaponPromoteRsp{}, proto.Retcode_RET_ITEM_COUNT_NOT_ENOUGH) + return + } + } // 突破前的信息 oldPromote := weapon.Promote @@ -582,9 +581,8 @@ func (g *GameManager) WeaponUpgradeReq(player *model.Player, payloadMsg pb.Messa ChangeCount: coinCost, }) // 校验物品是否足够 - dbItem := player.GetDbItem() for _, item := range costItemList { - if dbItem.GetItemCount(player, item.ItemId) < item.ChangeCount { + if g.GetPlayerItemCount(player.PlayerID, item.ItemId) < item.ChangeCount { logger.Error("item count not enough, itemId: %v", item.ItemId) // 摩拉的错误提示与材料不同 if item.ItemId == constant.ITEM_ID_SCOIN { @@ -617,7 +615,12 @@ func (g *GameManager) WeaponUpgradeReq(player *model.Player, payloadMsg pb.Messa costWeaponIdList = append(costWeaponIdList, foodWeapon.WeaponId) } // 消耗升级材料和摩拉 - g.CostUserItem(player.PlayerID, costItemList) + ok = g.CostUserItem(player.PlayerID, costItemList) + if !ok { + logger.Error("item count not enough, uid: %v", player.PlayerID) + g.SendError(cmd.WeaponUpgradeRsp, player, &proto.WeaponUpgradeRsp{}, proto.Retcode_RET_ITEM_COUNT_NOT_ENOUGH) + return + } // 消耗作为升级材料的武器 g.CostUserWeapon(player.PlayerID, costWeaponIdList) // 武器升级前的信息 diff --git a/gs/game/user_manager.go b/gs/game/user_manager.go index b306b531..127e6e4d 100644 --- a/gs/game/user_manager.go +++ b/gs/game/user_manager.go @@ -82,7 +82,8 @@ type PlayerRegInfo struct { } // CheckUserExistOnReg 玩家注册检查是否已存在 -func (u *UserManager) CheckUserExistOnReg(userId uint32, req *proto.SetPlayerBornDataReq, clientSeq uint32, gateAppId string) (exist bool, asyncWait bool) { +func (u *UserManager) CheckUserExistOnReg(userId uint32, + req *proto.SetPlayerBornDataReq, clientSeq uint32, gateAppId string) (exist bool, asyncWait bool) { _, exist = u.playerMap[userId] if exist { return true, false diff --git a/gs/model/db_item.go b/gs/model/db_item.go index 4038156e..1414f659 100644 --- a/gs/model/db_item.go +++ b/gs/model/db_item.go @@ -1,7 +1,5 @@ package model -import "hk4e/common/constant" - type DbItem struct { ItemMap map[uint32]*Item // 道具仓库 } @@ -37,28 +35,21 @@ func (i *DbItem) GetItemGuid(itemId uint32) uint64 { return itemInfo.Guid } -func (i *DbItem) GetItemCount(player *Player, itemId uint32) uint32 { - prop, ok := constant.VIRTUAL_ITEM_PROP[itemId] - if ok { - value := player.PropertiesMap[prop] - return value - } else { - itemInfo := i.ItemMap[itemId] - if itemInfo == nil { - return 0 - } - return itemInfo.Count +func (i *DbItem) GetItemCount(itemId uint32) uint32 { + itemInfo := i.ItemMap[itemId] + if itemInfo == nil { + return 0 } + return itemInfo.Count +} + +func (i *DbItem) GetItemMapLen() int { + return len(i.ItemMap) } func (i *DbItem) AddItem(player *Player, itemId uint32, count uint32) { itemInfo := i.ItemMap[itemId] if itemInfo == nil { - // 该物品为新物品时校验背包物品容量 - // 目前物品包括材料和家具 - if len(i.ItemMap) > constant.STORE_PACK_LIMIT_MATERIAL+constant.STORE_PACK_LIMIT_FURNITURE { - return - } itemInfo = &Item{ ItemId: itemId, Count: 0, @@ -76,14 +67,12 @@ func (i *DbItem) CostItem(player *Player, itemId uint32, count uint32) { return } if itemInfo.Count < count { - itemInfo.Count = 0 - } else { - itemInfo.Count -= count + return } + itemInfo.Count -= count + i.ItemMap[itemId] = itemInfo if itemInfo.Count == 0 { delete(i.ItemMap, itemId) delete(player.GameObjectGuidMap, itemInfo.Guid) - } else { - i.ItemMap[itemId] = itemInfo } }