diff --git a/common/constant/gadget_type.go b/common/constant/gadget_type.go new file mode 100644 index 00000000..60af0844 --- /dev/null +++ b/common/constant/gadget_type.go @@ -0,0 +1,72 @@ +package constant + +const ( + GADGET_TYPE_NONE = 0 + GADGET_TYPE_AVATAR = 1 + GADGET_TYPE_MONSTER = 2 + GADGET_TYPE_BULLET = 3 + GADGET_TYPE_ATTACK_PHYISICAL_UNIT = 4 + GADGET_TYPE_AOE = 5 + GADGET_TYPE_CAMERA = 6 + GADGET_TYPE_ENVIRO_AREA = 7 + GADGET_TYPE_EQUIP = 8 + GADGET_TYPE_MONSTER_EQUIP = 9 + GADGET_TYPE_GRASS = 10 + GADGET_TYPE_LEVEL = 11 + GADGET_TYPE_NPC = 12 + GADGET_TYPE_TRANS_POINT_FIRST = 13 + GADGET_TYPE_TRANS_POINT_FIRST_GADGET = 14 + GADGET_TYPE_TRANS_POINT_SECOND = 15 + GADGET_TYPE_TRANS_POINT_SECOND_GADGET = 16 + GADGET_TYPE_DROP_ITEM = 17 + GADGET_TYPE_FIELD = 18 + GADGET_TYPE_GADGET = 19 + GADGET_TYPE_WATER = 20 + GADGET_TYPE_GATHER_POINT = 21 + GADGET_TYPE_GATHER_OBJECT = 22 + GADGET_TYPE_AIRFLOW_FIELD = 23 + GADGET_TYPE_SPEEDUP_FIELD = 24 + GADGET_TYPE_GEAR = 25 + GADGET_TYPE_CHEST = 26 + GADGET_TYPE_ENERGY_BALL = 27 + GADGET_TYPE_ELEM_CRYSTAL = 28 + GADGET_TYPE_TIMELINE = 29 + GADGET_TYPE_WORKTOP = 30 + GADGET_TYPE_TEAM = 31 + GADGET_TYPE_PLATFORM = 32 + GADGET_TYPE_AMBER_WIND = 33 + GADGET_TYPE_ENV_ANIMAL = 34 + GADGET_TYPE_SEAL_GADGET = 35 + GADGET_TYPE_TREE = 36 + GADGET_TYPE_BUSH = 37 + GADGET_TYPE_QUEST_GADGET = 38 + GADGET_TYPE_LIGHTNING = 39 + GADGET_TYPE_REWARD_POINT = 40 + GADGET_TYPE_REWARD_STATUE = 41 + GADGET_TYPE_MP_LEVEL = 42 + GADGET_TYPE_WIND_SEED = 43 + GADGET_TYPE_MP_PLAY_REWARD_POINT = 44 + GADGET_TYPE_VIEW_POINT = 45 + GADGET_TYPE_REMOTE_AVATAR = 46 + GADGET_TYPE_GENERAL_REWARD_POINT = 47 + GADGET_TYPE_PLAY_TEAM = 48 + GADGET_TYPE_OFFERING_GADGET = 49 + GADGET_TYPE_EYE_POINT = 50 + GADGET_TYPE_MIRACLE_RING = 51 + GADGET_TYPE_FOUNDATION = 52 + GADGET_TYPE_WIDGET_GADGET = 53 + GADGET_TYPE_VEHICLE = 54 + GADGET_TYPE_SUB_EQUIP = 55 + GADGET_TYPE_FISH_ROD = 56 + GADGET_TYPE_CUSTOM_TILE = 57 + GADGET_TYPE_FISH_POOL = 58 + GADGET_TYPE_CUSTOM_GADGET = 59 + GADGET_TYPE_BLACK_MUD = 60 + GADGET_TYPE_ROGUELIKE_OPERATOR_GADGET = 61 + GADGET_TYPE_NIGHT_CROW_GADGET = 62 + GADGET_TYPE_PROJECTOR = 63 + GADGET_TYPE_SCREEN = 64 + GADGET_TYPE_ECHO_SHELL = 65 + GADGET_TYPE_UI_INTERACT_GADGET = 66 + GADGET_TYPE_PLACE_HOLDER = 99 +) diff --git a/gdconf/gadget_data.go b/gdconf/gadget_data.go new file mode 100644 index 00000000..6a64f6d3 --- /dev/null +++ b/gdconf/gadget_data.go @@ -0,0 +1,46 @@ +package gdconf + +import ( + "hk4e/pkg/logger" +) + +// GadgetData 物件配置表 +type GadgetData struct { + GadgetId int32 `csv:"ID"` + Type int32 `csv:"类型,omitempty"` + DefaultCamp int32 `csv:"默认阵营,omitempty"` + CanInteract int32 `csv:"能否交互,omitempty"` + Desc string `csv:"描述,omitempty"` +} + +func (g *GameDataConfig) loadGadgetData() { + g.GadgetDataMap = make(map[int32]*GadgetData) + fileNameList := []string{ + "GadgetData_AbilitySpecial.txt", + "GadgetData_Affix.txt", + "GadgetData_Avatar.txt", + "GadgetData_Equip.txt", + "GadgetData_FishingRod.txt", + "GadgetData_Homeworld.txt", + "GadgetData_Level.txt", + "GadgetData_Monster.txt", + "GadgetData_Quest.txt", + "GadgetData_Vehicle.txt", + } + for _, fileName := range fileNameList { + gadgetDataList := make([]*GadgetData, 0) + readTable[GadgetData](g.txtPrefix+fileName, &gadgetDataList) + for _, gadgetData := range gadgetDataList { + g.GadgetDataMap[gadgetData.GadgetId] = gadgetData + } + } + logger.Info("GadgetData count: %v", len(g.GadgetDataMap)) +} + +func GetGadgetDataById(gadgetId int32) *GadgetData { + return CONF.GadgetDataMap[gadgetId] +} + +func GetGadgetDataMap() map[int32]*GadgetData { + return CONF.GadgetDataMap +} diff --git a/gdconf/game_data_config.go b/gdconf/game_data_config.go index 1f95bc0e..a64f8163 100644 --- a/gdconf/game_data_config.go +++ b/gdconf/game_data_config.go @@ -63,6 +63,7 @@ type GameDataConfig struct { MonsterDropDataMap map[string]map[int32]*MonsterDropData // 怪物掉落 ChestDropDataMap map[string]map[int32]*ChestDropData // 宝箱掉落 DungeonDataMap map[int32]*DungeonData // 地牢 + GadgetDataMap map[int32]*GadgetData // 物件 GCGCharDataMap map[int32]*GCGCharData // 七圣召唤角色卡牌 GCGSkillDataMap map[int32]*GCGSkillData // 七圣召唤卡牌技能 GachaDropGroupDataMap map[int32]*GachaDropGroupData // 卡池掉落组 临时的 @@ -162,6 +163,7 @@ func (g *GameDataConfig) load() { g.loadMonsterDropData() // 怪物掉落 g.loadChestDropData() // 宝箱掉落 g.loadDungeonData() // 地牢 + g.loadGadgetData() // 物件 g.loadGCGCharData() // 七圣召唤角色卡牌 g.loadGCGSkillData() // 七圣召唤卡牌技能 g.loadGachaDropGroupData() // 卡池掉落组 临时的 diff --git a/gs/game/game_manager.go b/gs/game/game_manager.go index 18c7b452..4eb2521c 100644 --- a/gs/game/game_manager.go +++ b/gs/game/game_manager.go @@ -72,7 +72,7 @@ func NewGameManager(dao *dao.Dao, messageQueue *mq.MessageQueue, gsId uint32, gs TICK_MANAGER = NewTickManager() COMMAND_MANAGER = NewCommandManager() GCG_MANAGER = NewGCGManager() - RegLuaLibFunc() + RegLuaScriptLibFunc() // 创建本服的Ai世界 uid := AiBaseUid + gsId name := AiName diff --git a/gs/game/lua_func.go b/gs/game/lua_func.go index fc80b054..9ffc6a16 100644 --- a/gs/game/lua_func.go +++ b/gs/game/lua_func.go @@ -33,6 +33,7 @@ type LuaEvt struct { targetEntityId uint32 } +// CallLuaFunc 调用LUA方法 func CallLuaFunc(luaState *lua.LState, luaFuncName string, luaCtx *LuaCtx, luaEvt *LuaEvt) bool { ctx := luaState.NewTable() luaState.SetField(ctx, "uid", lua.LNumber(luaCtx.uid)) @@ -72,7 +73,36 @@ func CallLuaFunc(luaState *lua.LState, luaFuncName string, luaCtx *LuaCtx, luaEv } } -func RegLuaLibFunc() { +// GetContextPlayer 获取上下文中的玩家对象 +func GetContextPlayer(ctx *lua.LTable, luaState *lua.LState) *model.Player { + uid, ok := luaState.GetField(ctx, "uid").(lua.LNumber) + if !ok { + return nil + } + player := USER_MANAGER.GetOnlineUser(uint32(uid)) + return player +} + +// GetContextGroup 获取上下文中的场景组对象 +func GetContextGroup(player *model.Player, ctx *lua.LTable, luaState *lua.LState) *Group { + world := WORLD_MANAGER.GetWorldByID(player.WorldId) + if world == nil { + return nil + } + groupId, ok := luaState.GetField(ctx, "groupId").(lua.LNumber) + if !ok { + return nil + } + scene := world.GetSceneById(player.SceneId) + group := scene.GetGroupById(uint32(groupId)) + if group == nil { + return nil + } + return group +} + +// RegLuaScriptLibFunc 注册LUA侧ScriptLib调用的Golang方法 +func RegLuaScriptLibFunc() { gdconf.RegScriptLibFunc("GetEntityType", GetEntityType) gdconf.RegScriptLibFunc("GetQuestState", GetQuestState) gdconf.RegScriptLibFunc("PrintLog", PrintLog) @@ -130,7 +160,7 @@ func PrintContextLog(luaState *lua.LState) int { return 0 } logInfo := luaState.ToString(2) - logger.Info("[LUA CTX LOG] %v [UID %v]", logInfo, uid) + logger.Info("[LUA CTX LOG] %v [UID: %v]", logInfo, uid) return 0 } @@ -250,33 +280,7 @@ func MarkPlayerAction(luaState *lua.LState) int { param1 := luaState.ToInt(2) param2 := luaState.ToInt(3) param3 := luaState.ToInt(4) - logger.Debug("[MarkPlayerAction] [%v %v %v] uid: %v", param1, param2, param3, player.PlayerID) + logger.Debug("[MarkPlayerAction] [%v %v %v] [UID: %v]", param1, param2, param3, player.PlayerID) luaState.Push(lua.LNumber(0)) return 1 } - -func GetContextPlayer(ctx *lua.LTable, luaState *lua.LState) *model.Player { - uid, ok := luaState.GetField(ctx, "uid").(lua.LNumber) - if !ok { - return nil - } - player := USER_MANAGER.GetOnlineUser(uint32(uid)) - return player -} - -func GetContextGroup(player *model.Player, ctx *lua.LTable, luaState *lua.LState) *Group { - world := WORLD_MANAGER.GetWorldByID(player.WorldId) - if world == nil { - return nil - } - groupId, ok := luaState.GetField(ctx, "groupId").(lua.LNumber) - if !ok { - return nil - } - scene := world.GetSceneById(player.SceneId) - group := scene.GetGroupById(uint32(groupId)) - if group == nil { - return nil - } - return group -} diff --git a/gs/game/player_world.go b/gs/game/player_world.go index e4cc005a..326351d8 100644 --- a/gs/game/player_world.go +++ b/gs/game/player_world.go @@ -286,12 +286,68 @@ func (g *GameManager) PlayerQuitDungeonReq(player *model.Player, payloadMsg pb.M func (g *GameManager) GadgetInteractReq(player *model.Player, payloadMsg pb.Message) { req := payloadMsg.(*proto.GadgetInteractReq) - logger.Debug("GadgetInteractReq: %+v, uid: %v", req, player.PlayerID) + world := WORLD_MANAGER.GetWorldByID(player.WorldId) + if world == nil { + logger.Error("get world is nil, worldId: %v, uid: %v", player.WorldId, player.PlayerID) + return + } + scene := world.GetSceneById(player.SceneId) + entity := scene.GetEntity(req.GadgetEntityId) + if entity == nil { + logger.Error("get entity is nil, entityId: %v, uid: %v", req.GadgetEntityId, player.PlayerID) + return + } + if entity.GetEntityType() != constant.ENTITY_TYPE_GADGET { + logger.Error("entity type is not gadget, entityType: %v, uid: %v", entity.GetEntityType(), player.PlayerID) + return + } + gadgetEntity := entity.GetGadgetEntity() + gadgetDataConfig := gdconf.GetGadgetDataById(int32(gadgetEntity.GetGadgetId())) + if gadgetDataConfig == nil { + logger.Error("get gadget data config is nil, gadgetId: %v, uid: %v", gadgetEntity.GetGadgetId(), player.PlayerID) + return + } + if gadgetDataConfig.CanInteract == 0 { + logger.Error("gadget can not be interact, gadgetId: %v, uid: %v", gadgetEntity.GetGadgetId(), player.PlayerID) + return + } + interactType := proto.InteractType_INTERACT_NONE + switch gadgetDataConfig.Type { + case constant.GADGET_TYPE_GADGET: + logger.Debug("==========GADGET_TYPE_GADGET==========") + // 掉落物捡起 + interactType = proto.InteractType_INTERACT_PICK_ITEM + g.KillEntity(player, scene, entity.GetId(), proto.PlayerDieType_PLAYER_DIE_NONE) + case constant.GADGET_TYPE_ENERGY_BALL: + logger.Debug("==========GADGET_TYPE_ENERGY_BALL==========") + // 元素能量球吸收 + interactType = proto.InteractType_INTERACT_PICK_ITEM + case constant.GADGET_TYPE_GATHER_OBJECT: + logger.Debug("==========GADGET_TYPE_GATHER_OBJECT==========") + // 采集物摘取 + interactType = proto.InteractType_INTERACT_GATHER + g.KillEntity(player, scene, entity.GetId(), proto.PlayerDieType_PLAYER_DIE_NONE) + case constant.GADGET_TYPE_CHEST: + logger.Debug("==========GADGET_TYPE_CHEST==========") + // 宝箱开启 + interactType = proto.InteractType_INTERACT_OPEN_CHEST + if req.OpType == proto.InterOpType_INTER_OP_FINISH { + // 宝箱交互结束 开启宝箱 + g.SendMsg(cmd.WorldChestOpenNotify, player.PlayerID, player.ClientSeq, &proto.WorldChestOpenNotify{ + GroupId: entity.GetGroupId(), + SceneId: scene.GetId(), + ConfigId: entity.GetConfigId(), + }) + g.ChangeGadgetState(player, scene.GetId(), constant.GADGET_STATE_CHEST_OPENED) + g.KillEntity(player, scene, entity.GetId(), proto.PlayerDieType_PLAYER_DIE_NONE) + } + } + rsp := &proto.GadgetInteractRsp{ GadgetEntityId: req.GadgetEntityId, - InteractType: 0, - OpType: req.OpType, GadgetId: req.GadgetId, + OpType: req.OpType, + InteractType: interactType, } g.SendMsg(cmd.GadgetInteractRsp, player.PlayerID, player.ClientSeq, rsp) } diff --git a/gs/game/world_scene.go b/gs/game/world_scene.go index 5a9204de..765081e4 100644 --- a/gs/game/world_scene.go +++ b/gs/game/world_scene.go @@ -429,7 +429,7 @@ func (s *Scene) createConfigEntity(groupId uint32, entityConfig any) uint32 { }, uint32(npc.NpcId), 0, 0, 0, uint32(npc.ConfigId), groupId) case *gdconf.Gadget: gadget := entityConfig.(*gdconf.Gadget) - // 70500000并不是实际的装置id 根据节点类型对应采集物配置表 + // 70500000并不是实际的物件id 根据节点类型对应采集物配置表 if gadget.PointType != 0 && gadget.GadgetId == 70500000 { gatherDataConfig := gdconf.GetGatherDataByPointType(gadget.PointType) if gatherDataConfig == nil { diff --git a/protocol/cmd/cmd_id_proto_obj_map.go b/protocol/cmd/cmd_id_proto_obj_map.go index 0a709493..520b4fc7 100644 --- a/protocol/cmd/cmd_id_proto_obj_map.go +++ b/protocol/cmd/cmd_id_proto_obj_map.go @@ -133,6 +133,7 @@ func (c *CmdProtoMap) registerAllMessage() { c.regMsg(GadgetInteractReq, func() any { return new(proto.GadgetInteractReq) }) // 物件交互请求 c.regMsg(GadgetInteractRsp, func() any { return new(proto.GadgetInteractRsp) }) // 物件交互响应 c.regMsg(GadgetStateNotify, func() any { return new(proto.GadgetStateNotify) }) // 物件状态更新通知 + c.regMsg(WorldChestOpenNotify, func() any { return new(proto.WorldChestOpenNotify) }) // 宝箱开启通知 // 战斗与同步 c.regMsg(AvatarFightPropNotify, func() any { return new(proto.AvatarFightPropNotify) }) // 角色战斗属性通知