From 86a65e6f9bdd48506cce6c3e1832bff2dd1f6c51 Mon Sep 17 00:00:00 2001 From: UnKownOwO <80520429@qq.com> Date: Sat, 26 Nov 2022 16:30:36 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E9=97=AE=E9=A2=98=E3=80=81?= =?UTF-8?q?=E6=B7=BB=E5=8A=A0give=E5=91=BD=E4=BB=A4=20=E4=BF=AE=E5=A4=8D?= =?UTF-8?q?=E4=BD=BF=E7=94=A8=E9=99=A4=E4=B8=BB=E8=A7=92=E5=A4=96=E8=A7=92?= =?UTF-8?q?=E8=89=B2=E6=97=A0=E6=B3=95=E8=BF=9B=E5=85=A5=E7=9A=84=E9=97=AE?= =?UTF-8?q?=E9=A2=98=20=E6=96=B0=E5=A2=9Egive=E5=91=BD=E4=BB=A4=20?= =?UTF-8?q?=E6=AD=A6=E5=99=A8=E6=95=B0=E9=87=8F=20=E7=B2=BE=E7=82=BC=20?= =?UTF-8?q?=E8=A7=92=E8=89=B2=E7=AD=89=E7=BA=A7=20=E5=91=BD=E5=BA=A7?= =?UTF-8?q?=E7=AD=89=E5=90=8E=E6=9C=9F=E5=A2=9E=E5=8A=A0=E5=8F=82=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- gs/game/command_controller.go | 161 ++++++++++++++++++++++++++++++---- gs/game/command_gm.go | 73 +++++++++++++++ gs/game/command_manager.go | 1 + gs/game/tick_manager.go | 6 +- gs/game/user_avatar.go | 24 +++-- gs/game/user_login.go | 47 +++------- gs/game/user_team.go | 16 ++-- gs/game/user_weapon.go | 4 + gs/model/weapon.go | 7 +- 9 files changed, 274 insertions(+), 65 deletions(-) create mode 100644 gs/game/command_gm.go diff --git a/gs/game/command_controller.go b/gs/game/command_controller.go index be56c0fc..9d30eedf 100644 --- a/gs/game/command_controller.go +++ b/gs/game/command_controller.go @@ -11,8 +11,9 @@ func (c *CommandManager) HelpCommand(cmd *CommandMessage) { executor := cmd.Executor c.SendMessage(executor, - "===== 帮助 / Help =====\n"+ - "传送:/tp {-u [UID]} {-s [场景ID]} -x [坐标X] -y [坐标Y] -z [坐标Z]\n", + "========== 帮助 / Help ==========\n\n"+ + "传送:/tp [-u ] [-s <场景ID>] -x <坐标X> -y <坐标Y> -z <坐标Z>\n\n"+ + "给予:/give [-u ] [-c <数量>] -i <物品ID|武器ID|角色ID/item/weapon/avatar/all>\n", ) } @@ -29,7 +30,7 @@ func (c *CommandManager) OpCommand(cmd *CommandMessage) { } // TeleportCommand 传送玩家命令 -// tp {-u [userId]} {-s [sceneId]} -x [posX] -y [posY] -z [posZ] +// tp [-u ] [-s ] -x -y -z func (c *CommandManager) TeleportCommand(cmd *CommandMessage) { game := c.gameManager @@ -42,14 +43,14 @@ func (c *CommandManager) TeleportCommand(cmd *CommandMessage) { // 判断是否填写必备参数 if cmd.Args["x"] == "" || cmd.Args["y"] == "" || cmd.Args["z"] == "" { - c.SendMessage(player, "参数不足,正确用法:/%v {-u [UID]} {-s [场景ID]} -x [坐标X] -y [坐标Y] -z [坐标Z]。", cmd.Name) + c.SendMessage(player, "参数不足,正确用法:/%v [-u ] [-s <场景ID>] -x <坐标X> -y <坐标Y> -z <坐标Z>", cmd.Name) return } // 初始值 - target := player - sceneId := target.SceneId - pos := &model.Vector{} + target := player // 目标 + sceneId := target.SceneId // 场景Id + pos := &model.Vector{} // 坐标 // 选择每个参数 for k, v := range cmd.Args { @@ -57,21 +58,24 @@ func (c *CommandManager) TeleportCommand(cmd *CommandMessage) { switch k { case "u": - var t uint64 - if t, err = strconv.ParseUint(v, 10, 32); err != nil { + var uid uint64 + if uid, err = strconv.ParseUint(v, 10, 32); err != nil { // 判断目标用户是否在线 - if user := game.userManager.GetOnlineUser(uint32(t)); user != nil { + if user := game.userManager.GetOnlineUser(uint32(uid)); user != nil { target = user - sceneId = target.SceneId + // 防止覆盖用户指定过的sceneId + if target.SceneId != sceneId { + sceneId = target.SceneId + } } else { c.SendMessage(player, "目标玩家不在线,UID: %v。", v) return } } case "s": - var s uint64 - if s, err = strconv.ParseUint(v, 10, 32); err == nil { - sceneId = uint32(s) + var sid uint64 + if sid, err = strconv.ParseUint(v, 10, 32); err == nil { + sceneId = uint32(sid) } case "x": // 玩家此时的位置X @@ -122,8 +126,133 @@ func (c *CommandManager) TeleportCommand(cmd *CommandMessage) { } // 传送玩家 - game.TeleportPlayer(target, sceneId, pos) + c.GMTeleportPlayer(target.PlayerID, sceneId, pos.X, pos.Y, pos.Z) // 发送消息给执行者 - c.SendMessage(player, "已将玩家 UID:%v 传送至 场景:%v X:%.2f Y:%.2f Z:%.2f。", target.PlayerID, sceneId, pos.X, pos.Y, pos.Z) + c.SendMessage(player, "已将玩家 UID:%v 传送至 场景:%v, X:%.2f, Y:%.2f, Z:%.2f。", target.PlayerID, sceneId, pos.X, pos.Y, pos.Z) +} + +// GiveCommand 给予物品命令 +// give [-u ] [-c ] -i +func (c *CommandManager) GiveCommand(cmd *CommandMessage) { + game := c.gameManager + + // 执行者如果不是玩家则必须输入目标UID + player, ok := cmd.Executor.(*model.Player) + if !ok && cmd.Args["u"] == "" { + c.SendMessage(cmd.Executor, "你不是玩家请指定目标UID。") + return + } + + // 判断是否填写必备参数 + if cmd.Args["i"] == "" { + c.SendMessage(player, "参数不足,正确用法:/%v [-u ] [-c <数量>] -i <物品ID|武器ID|角色ID/item/weapon/avatar/all>。", cmd.Name) + return + } + + // 初始值 + target := player // 目标 + count := uint32(1) // 数量 + itemId := uint32(0) // 物品Id + // 给予物品的模式 + // once 单个 / all 所有物品 + // item 物品 / weapon 武器 + mode := "once" + + // 选择每个参数 + for k, v := range cmd.Args { + var err error + + switch k { + case "u": + var uid uint64 + if uid, err = strconv.ParseUint(v, 10, 32); err != nil { + // 判断目标用户是否在线 + if user := game.userManager.GetOnlineUser(uint32(uid)); user != nil { + target = user + } else { + c.SendMessage(player, "目标玩家不在线,UID: %v。", v) + return + } + } + case "c": + var cnt uint64 + if cnt, err = strconv.ParseUint(v, 10, 32); err == nil { + count = uint32(cnt) + } + case "i": + switch v { + case "all", "item", "avatar", "weapon": + // 将模式修改为参数的值 + mode = v + default: + var id uint64 + if id, err = strconv.ParseUint(v, 10, 32); err != nil { + c.SendMessage(player, "参数 -%v 有误,允许内容: 。", k) + return + } + itemId = uint32(id) + } + default: + c.SendMessage(player, "参数 -%v 冗余。", k) + return + } + + // 解析错误的话应该是参数类型问题 + if err != nil { + c.SendMessage("参数 -%v 有误,类型错误。", k) + return + } + } + + switch mode { + case "once": + // 判断是否为物品 + _, ok := game.GetAllItemDataConfig()[int32(itemId)] + if ok { + // 给予玩家物品 + c.GMAddUserItem(target.PlayerID, itemId, count) + c.SendMessage(player, "已给予玩家 UID:%v, 物品ID: %v*数量: %v。", target.PlayerID, itemId, count) + return + } + // 判断是否为武器 + _, ok = game.GetAllWeaponDataConfig()[int32(itemId)] + if ok { + // 给予玩家武器 + c.GMAddUserWeapon(target.PlayerID, itemId, count) + c.SendMessage(player, "已给予玩家 UID:%v, 武器ID:%v*数量:%v。", target.PlayerID, itemId, count) + return + + } + // 判断是否为角色 + _, ok = game.GetAllAvatarDataConfig()[int32(itemId)] + if ok { + // 给予玩家武器 + c.GMAddUserAvatar(target.PlayerID, itemId) + c.SendMessage(player, "已给予玩家 UID:%v, 角色ID:%v*数量:%v。", target.PlayerID, itemId, count) + return + } + // 都执行到这里那肯定是都不匹配 + c.SendMessage(player, "物品ID:%v 不存在。", itemId) + case "item": + // 给予玩家所有物品 + c.GMAddUserAllItem(target.PlayerID, count) + c.SendMessage(player, "已给予玩家 UID:%v, 所有物品*%v。", target.PlayerID, count) + case "weapon": + // 给予玩家所有武器 + c.GMAddUserAllWeapon(target.PlayerID, count) + c.SendMessage(player, "已给予玩家 UID:%v, 所有武器*%v。", target.PlayerID, count) + case "avatar": + // 给予玩家所有角色 + c.GMAddUserAllAvatar(target.PlayerID) + c.SendMessage(player, "已给予玩家 UID:%v, 所有角色。", target.PlayerID) + case "all": + // 给予玩家所有物品 + c.GMAddUserAllItem(target.PlayerID, count) + // 给予玩家所有武器 + c.GMAddUserAllWeapon(target.PlayerID, count) + // 给予玩家所有角色 + c.GMAddUserAllAvatar(target.PlayerID) + c.SendMessage(player, "已给予玩家 UID:%v, 所有内容。", target.PlayerID) + } } diff --git a/gs/game/command_gm.go b/gs/game/command_gm.go new file mode 100644 index 00000000..08d8affa --- /dev/null +++ b/gs/game/command_gm.go @@ -0,0 +1,73 @@ +package game + +import ( + "hk4e/gs/model" + "hk4e/pkg/logger" +) + +// GMTeleportPlayer 传送玩家 +func (c *CommandManager) GMTeleportPlayer(userId, sceneId uint32, posX, posY, posZ float64) { + player := c.gameManager.userManager.GetOnlineUser(userId) + if player == nil { + logger.LOG.Error("player is nil, uid: %v", userId) + return + } + c.gameManager.TeleportPlayer(player, sceneId, &model.Vector{ + X: posX, + Y: posY, + Z: posZ, + }) +} + +// GMAddUserItem 给予玩家物品 +func (c *CommandManager) GMAddUserItem(userId, itemId, itemCount uint32) { + c.gameManager.AddUserItem(userId, []*UserItem{ + { + ItemId: itemId, + ChangeCount: itemCount, + }, + }, true, 0) +} + +// GMAddUserWeapon 给予玩家武器 +func (c *CommandManager) GMAddUserWeapon(userId, itemId, itemCount uint32) { + // 武器数量 + for i := uint32(0); i < itemCount; i++ { + // 给予武器 + c.gameManager.AddUserWeapon(userId, itemId) + } +} + +// GMAddUserAvatar 给予玩家角色 +func (c *CommandManager) GMAddUserAvatar(userId, avatarId uint32) { + player := c.gameManager.userManager.GetOnlineUser(userId) + if player == nil { + logger.LOG.Error("player is nil, uid: %v", userId) + return + } + // 添加角色 + c.gameManager.AddUserAvatar(userId, avatarId) + // todo 设置角色 等以后做到角色升级之类的再说 + //avatar := player.AvatarMap[avatarId] +} + +// GMAddUserAllItem 给予玩家所有物品 +func (c *CommandManager) GMAddUserAllItem(userId, itemCount uint32) { + for itemId := range c.gameManager.GetAllItemDataConfig() { + c.GMAddUserItem(userId, uint32(itemId), itemCount) + } +} + +// GMAddUserAllWeapon 给予玩家所有武器 +func (c *CommandManager) GMAddUserAllWeapon(userId, itemCount uint32) { + for itemId := range c.gameManager.GetAllWeaponDataConfig() { + c.GMAddUserWeapon(userId, uint32(itemId), itemCount) + } +} + +// GMAddUserAllAvatar 给予玩家所有角色 +func (c *CommandManager) GMAddUserAllAvatar(userId uint32) { + for avatarId := range c.gameManager.GetAllAvatarDataConfig() { + c.GMAddUserAvatar(userId, uint32(avatarId)) + } +} diff --git a/gs/game/command_manager.go b/gs/game/command_manager.go index 9f65be11..d49e0da3 100644 --- a/gs/game/command_manager.go +++ b/gs/game/command_manager.go @@ -71,6 +71,7 @@ func (c *CommandManager) InitRouter() { c.RegisterRouter(CommandPermNormal, c.HelpCommand, "help") c.RegisterRouter(CommandPermNormal, c.OpCommand, "op") c.RegisterRouter(CommandPermNormal, c.TeleportCommand, "teleport", "tp") + c.RegisterRouter(CommandPermNormal, c.GiveCommand, "give", "item") } // GM命令 { diff --git a/gs/game/tick_manager.go b/gs/game/tick_manager.go index 962ee71b..71f91068 100644 --- a/gs/game/tick_manager.go +++ b/gs/game/tick_manager.go @@ -88,7 +88,11 @@ func (t *TickManager) onTickMinute(now int64) { count := random.GetRandomInt32(0, 4) i := int32(0) for itemId := range allItemDataConfig { - itemDataConfig := allItemDataConfig[itemId] + itemDataConfig, ok := allItemDataConfig[itemId] + if !ok { + logger.LOG.Error("config is nil, itemId: %v", itemId) + return + } // TODO 3.0.0REL版本中 发送某些无效家具 可能会导致客户端背包家具界面卡死 if itemDataConfig.ItemEnumType == constant.ItemTypeConst.ITEM_FURNITURE { continue diff --git a/gs/game/user_avatar.go b/gs/game/user_avatar.go index 08cdf903..cc5a7606 100644 --- a/gs/game/user_avatar.go +++ b/gs/game/user_avatar.go @@ -35,9 +35,18 @@ func (g *GameManager) AddUserAvatar(userId uint32, avatarId uint32) { return } player.AddAvatar(avatarId) + avatar := player.AvatarMap[avatarId] + if avatar == nil { + logger.LOG.Error("avatar is nil, avatarId", avatarId) + return + } // 添加初始武器 - avatarDataConfig := gdc.CONF.AvatarDataMap[int32(avatarId)] + avatarDataConfig, ok := gdc.CONF.AvatarDataMap[int32(avatarId)] + if !ok { + logger.LOG.Error("config is nil, itemId: %v", avatarId) + return + } weaponId := g.AddUserWeapon(player.PlayerID, uint32(avatarDataConfig.InitialWeapon)) // 角色装上初始武器 @@ -47,7 +56,6 @@ func (g *GameManager) AddUserAvatar(userId uint32, avatarId uint32) { g.UpdateUserAvatarFightProp(player.PlayerID, avatarId) // PacketAvatarAddNotify - avatar := player.AvatarMap[avatarId] avatarAddNotify := new(proto.AvatarAddNotify) avatarAddNotify.Avatar = g.PacketAvatarInfo(avatar) avatarAddNotify.IsInTeam = false @@ -210,10 +218,12 @@ func (g *GameManager) AvatarWearFlycloakReq(player *model.Player, payloadMsg pb. } func (g *GameManager) PacketAvatarEquipChangeNotify(avatar *model.Avatar, weapon *model.Weapon, entityId uint32) *proto.AvatarEquipChangeNotify { - itemDataConfig := gdc.CONF.ItemDataMap[int32(weapon.ItemId)] + itemDataConfig, ok := gdc.CONF.ItemDataMap[int32(weapon.ItemId)] avatarEquipChangeNotify := new(proto.AvatarEquipChangeNotify) avatarEquipChangeNotify.AvatarGuid = avatar.Guid - avatarEquipChangeNotify.EquipType = uint32(itemDataConfig.EquipEnumType) + if ok { + avatarEquipChangeNotify.EquipType = uint32(itemDataConfig.EquipEnumType) + } avatarEquipChangeNotify.ItemId = weapon.ItemId avatarEquipChangeNotify.EquipGuid = weapon.Guid avatarEquipChangeNotify.Weapon = &proto.SceneWeaponInfo{ @@ -228,10 +238,12 @@ func (g *GameManager) PacketAvatarEquipChangeNotify(avatar *model.Avatar, weapon } func (g *GameManager) PacketAvatarEquipTakeOffNotify(avatar *model.Avatar, weapon *model.Weapon) *proto.AvatarEquipChangeNotify { - itemDataConfig := gdc.CONF.ItemDataMap[int32(weapon.ItemId)] avatarEquipChangeNotify := new(proto.AvatarEquipChangeNotify) avatarEquipChangeNotify.AvatarGuid = avatar.Guid - avatarEquipChangeNotify.EquipType = uint32(itemDataConfig.EquipEnumType) + itemDataConfig, ok := gdc.CONF.ItemDataMap[int32(weapon.ItemId)] + if ok { + avatarEquipChangeNotify.EquipType = uint32(itemDataConfig.EquipEnumType) + } return avatarEquipChangeNotify } diff --git a/gs/game/user_login.go b/gs/game/user_login.go index f4686d0f..3ebcd0a1 100644 --- a/gs/game/user_login.go +++ b/gs/game/user_login.go @@ -30,12 +30,6 @@ func (g *GameManager) OnLoginOk(userId uint32, player *model.Player, clientSeq u player.OnlineTime = uint32(time.Now().UnixMilli()) player.Online = true - // TODO 3.0.0REL版本 目前存在当前队伍活跃角色非主角时 登录进不去场景的情况 所以暂时先把四号队伍作为仅存在主角的保留队伍 - team := player.TeamConfig.GetTeamByIndex(3) - team.AvatarIdList = []uint32{player.MainCharAvatarId, 0, 0, 0} - player.TeamConfig.CurrTeamIndex = 3 - player.TeamConfig.CurrAvatarIndex = 0 - // 初始化 player.InitAll() player.TeamConfig.UpdateTeam() @@ -94,7 +88,12 @@ func (g *GameManager) OnLoginOk(userId uint32, player *model.Player, clientSeq u Guid: weapon.Guid, Detail: nil, } - if itemDataMapConfig[int32(weapon.ItemId)].ItemEnumType != constant.ItemTypeConst.ITEM_WEAPON { + itemData, ok := itemDataMapConfig[int32(weapon.ItemId)] + if !ok { + logger.LOG.Error("config is nil, itemId: %v", weapon.ItemId) + return + } + if itemData.ItemEnumType != constant.ItemTypeConst.ITEM_WEAPON { continue } affixMap := make(map[uint32]uint32) @@ -169,7 +168,7 @@ func (g *GameManager) OnLoginOk(userId uint32, player *model.Player, clientSeq u // PacketAvatarDataNotify avatarDataNotify := new(proto.AvatarDataNotify) - chooseAvatarId := player.TeamConfig.GetActiveAvatarId() + chooseAvatarId := player.MainCharAvatarId avatarDataNotify.CurAvatarTeamId = uint32(player.TeamConfig.GetActiveTeamId()) avatarDataNotify.ChooseAvatarGuid = player.AvatarMap[chooseAvatarId].Guid avatarDataNotify.OwnedFlycloakList = player.FlyCloakList @@ -236,6 +235,10 @@ func (g *GameManager) OnRegOk(exist bool, req *proto.SetPlayerBornDataReq, userI } player := g.CreatePlayer(userId, nickName, mainCharAvatarId) + if player == nil { + logger.LOG.Error("player is nil, uid: %v", userId) + return + } g.userManager.AddUser(player) g.SendMsg(cmd.SetPlayerBornDataRsp, userId, clientSeq, new(proto.SetPlayerBornDataRsp)) @@ -337,37 +340,13 @@ func (g *GameManager) CreatePlayer(userId uint32, nickName string, mainCharAvata player.DropInfo = model.NewDropInfo() player.ChatMsgMap = make(map[uint32][]*model.ChatMsg) - // 选哥哥的福报 - if mainCharAvatarId == 10000005 { - // 添加所有角色 - allAvatarDataConfig := g.GetAllAvatarDataConfig() - for avatarId, avatarDataConfig := range allAvatarDataConfig { - player.AddAvatar(uint32(avatarId)) - // 添加初始武器 - weaponId := uint64(g.snowflake.GenId()) - player.AddWeapon(uint32(avatarDataConfig.InitialWeapon), weaponId) - // 角色装上初始武器 - player.WearWeapon(uint32(avatarId), weaponId) - } - // 添加所有武器 - allWeaponDataConfig := g.GetAllWeaponDataConfig() - for itemId := range allWeaponDataConfig { - weaponId := uint64(g.snowflake.GenId()) - player.AddWeapon(uint32(itemId), weaponId) - } - // 添加所有道具 - allItemDataConfig := g.GetAllItemDataConfig() - for itemId := range allItemDataConfig { - player.AddItem(uint32(itemId), 1) - } - } - // 添加选定的主角 player.AddAvatar(mainCharAvatarId) // 添加初始武器 avatarDataConfig, ok := gdc.CONF.AvatarDataMap[int32(mainCharAvatarId)] if !ok { - logger.LOG.Error("avatarDataConfig error, mainCharAvatarId: %v", mainCharAvatarId) + logger.LOG.Error("config is nil, mainCharAvatarId: %v", mainCharAvatarId) + return nil } weaponId := uint64(g.snowflake.GenId()) player.AddWeapon(uint32(avatarDataConfig.InitialWeapon), weaponId) diff --git a/gs/game/user_team.go b/gs/game/user_team.go index 1264f29a..39a9a6de 100644 --- a/gs/game/user_team.go +++ b/gs/game/user_team.go @@ -290,14 +290,16 @@ func (g *GameManager) PacketSceneTeamUpdateNotify(world *World) *proto.SceneTeam acb := sceneTeamAvatar.AbilityControlBlock embryoId := 0 // add avatar abilities - for _, abilityId := range avatarDataConfig.Abilities { - embryoId++ - emb := &proto.AbilityEmbryo{ - AbilityId: uint32(embryoId), - AbilityNameHash: uint32(abilityId), - AbilityOverrideNameHash: uint32(constant.GameConstantConst.DEFAULT_ABILITY_NAME), + if avatarDataConfig != nil { + for _, abilityId := range avatarDataConfig.Abilities { + embryoId++ + emb := &proto.AbilityEmbryo{ + AbilityId: uint32(embryoId), + AbilityNameHash: uint32(abilityId), + AbilityOverrideNameHash: uint32(constant.GameConstantConst.DEFAULT_ABILITY_NAME), + } + acb.AbilityEmbryoList = append(acb.AbilityEmbryoList, emb) } - acb.AbilityEmbryoList = append(acb.AbilityEmbryoList, emb) } // add default abilities for _, abilityId := range constant.GameConstantConst.DEFAULT_ABILITY_HASHES { diff --git a/gs/game/user_weapon.go b/gs/game/user_weapon.go index ea94c1b3..fe43a102 100644 --- a/gs/game/user_weapon.go +++ b/gs/game/user_weapon.go @@ -46,6 +46,10 @@ func (g *GameManager) AddUserWeapon(userId uint32, itemId uint32) uint64 { weaponId := uint64(g.snowflake.GenId()) player.AddWeapon(itemId, weaponId) weapon := player.GetWeapon(weaponId) + if weapon == nil { + logger.LOG.Error("weapon is nil, itemId: %v, weaponId: %v", itemId, weaponId) + return 0 + } // PacketStoreItemChangeNotify storeItemChangeNotify := new(proto.StoreItemChangeNotify) diff --git a/gs/model/weapon.go b/gs/model/weapon.go index 395b95df..ed224f56 100644 --- a/gs/model/weapon.go +++ b/gs/model/weapon.go @@ -2,6 +2,7 @@ package model import ( gdc "hk4e/gs/config" + "hk4e/pkg/logger" ) type Weapon struct { @@ -63,7 +64,11 @@ func (p *Player) AddWeapon(itemId uint32, weaponId uint64) { MainPropId: 0, Guid: 0, } - itemDataConfig := gdc.CONF.ItemDataMap[int32(itemId)] + itemDataConfig, ok := gdc.CONF.ItemDataMap[int32(itemId)] + if !ok { + logger.LOG.Error("config is nil, itemId: %v", itemId) + return + } if itemDataConfig.SkillAffix != nil { for _, skillAffix := range itemDataConfig.SkillAffix { if skillAffix > 0 {