diff --git a/gdconf/game_data_config.go b/gdconf/game_data_config.go index d8b22e5a..37fa6a40 100644 --- a/gdconf/game_data_config.go +++ b/gdconf/game_data_config.go @@ -158,16 +158,18 @@ func (g *GameDataConfig) readCsvFileData(fileName string) []byte { return standardCsvData } -func RegScriptLib(fnName string, fn lua.LGFunction) { - for _, sceneLuaConfig := range CONF.SceneLuaConfigMap { - for _, block := range sceneLuaConfig.BlockMap { - for _, group := range block.GroupMap { - luaState := group.LuaState - scriptLib := luaState.NewTable() - luaState.SetField(scriptLib, fnName, luaState.NewFunction(fn)) - } - } - } +type ScriptLibFunc struct { + fnName string + fn lua.LGFunction +} + +var SCRIPT_LIB_FUNC_LIST = make([]*ScriptLibFunc, 0) + +func RegScriptLibFunc(fnName string, fn lua.LGFunction) { + SCRIPT_LIB_FUNC_LIST = append(SCRIPT_LIB_FUNC_LIST, &ScriptLibFunc{ + fnName: fnName, + fn: fn, + }) } func initLuaState(luaState *lua.LState) { @@ -181,6 +183,9 @@ func initLuaState(luaState *lua.LState) { luaState.SetGlobal("EntityType", entityType) luaState.SetField(entityType, "NONE", lua.LNumber(constant.ENTITY_TYPE_NONE)) luaState.SetField(entityType, "AVATAR", lua.LNumber(constant.ENTITY_TYPE_AVATAR)) + luaState.SetField(entityType, "MONSTER", lua.LNumber(constant.ENTITY_TYPE_MONSTER)) + luaState.SetField(entityType, "NPC", lua.LNumber(constant.ENTITY_TYPE_NPC)) + luaState.SetField(entityType, "GADGET", lua.LNumber(constant.ENTITY_TYPE_GADGET)) regionShape := luaState.NewTable() luaState.SetGlobal("RegionShape", regionShape) @@ -192,8 +197,11 @@ func initLuaState(luaState *lua.LState) { questState := luaState.NewTable() luaState.SetGlobal("QuestState", questState) - luaState.SetField(questState, "NONE", lua.LNumber(0)) - luaState.SetField(questState, "UNFINISHED", lua.LNumber(1)) + luaState.SetField(questState, "NONE", lua.LNumber(constant.QUEST_STATE_NONE)) + luaState.SetField(questState, "UNSTARTED", lua.LNumber(constant.QUEST_STATE_UNSTARTED)) + luaState.SetField(questState, "UNFINISHED", lua.LNumber(constant.QUEST_STATE_UNFINISHED)) + luaState.SetField(questState, "FINISHED", lua.LNumber(constant.QUEST_STATE_FINISHED)) + luaState.SetField(questState, "FAILED", lua.LNumber(constant.QUEST_STATE_FAILED)) gadgetState := luaState.NewTable() luaState.SetGlobal("GadgetState", gadgetState) @@ -228,7 +236,7 @@ func newLuaState(luaStr string) *lua.LState { return luaState } -func parseLuaTableToObject[T any](luaState *lua.LState, tableName string, object T) bool { +func getSceneLuaConfigTable[T any](luaState *lua.LState, tableName string, object T) bool { luaValue := luaState.GetGlobal(tableName) table, ok := luaValue.(*lua.LTable) if !ok { @@ -269,6 +277,24 @@ func parseLuaTableToObject[T any](luaState *lua.LState, tableName string, object return true } +func ParseLuaTableToObject[T any](table *lua.LTable, object T) bool { + tableObject := convLuaValueToGo(table) + jsonData, err := json.Marshal(tableObject) + if err != nil { + logger.Error("build json error: %v", err) + return false + } + if string(jsonData) == "{}" { + return true + } + err = json.Unmarshal(jsonData, object) + if err != nil { + logger.Error("parse json error: %v", err) + return false + } + return true +} + func convLuaValueToGo(lv lua.LValue) any { switch v := lv.(type) { case *lua.LNilType: diff --git a/gdconf/scene_lua_config.go b/gdconf/scene_lua_config.go index 438a1ca5..3ef96f9e 100644 --- a/gdconf/scene_lua_config.go +++ b/gdconf/scene_lua_config.go @@ -68,6 +68,18 @@ type Group struct { LuaState *lua.LState `json:"-"` } +func (g *Group) GetLuaState() *lua.LState { + if g.LuaState == nil { + g.LuaState = newLuaState(g.LuaStr) + scriptLib := g.LuaState.NewTable() + g.LuaState.SetGlobal("ScriptLib", scriptLib) + for _, scriptLibFunc := range SCRIPT_LIB_FUNC_LIST { + g.LuaState.SetField(scriptLib, scriptLibFunc.fnName, g.LuaState.NewFunction(scriptLibFunc.fn)) + } + } + return g.LuaState +} + type Replaceable struct { Value bool `json:"value"` Version int32 `json:"version"` @@ -137,12 +149,12 @@ func (g *GameDataConfig) loadGroup(group *Group, block *Block, sceneId int32, bl } group.LuaStr = string(groupLuaData) luaState := newLuaState(group.LuaStr) - group.LuaState = luaState // monsters group.MonsterList = make([]*Monster, 0) - ok := parseLuaTableToObject[*[]*Monster](luaState, "monsters", &group.MonsterList) + ok := getSceneLuaConfigTable[*[]*Monster](luaState, "monsters", &group.MonsterList) if !ok { logger.Error("get monsters object error, sceneId: %v, blockId: %v, groupId: %v", sceneId, blockId, groupId) + luaState.Close() return } for _, monster := range group.MonsterList { @@ -150,9 +162,10 @@ func (g *GameDataConfig) loadGroup(group *Group, block *Block, sceneId int32, bl } // npcs group.NpcList = make([]*Npc, 0) - ok = parseLuaTableToObject[*[]*Npc](luaState, "npcs", &group.NpcList) + ok = getSceneLuaConfigTable[*[]*Npc](luaState, "npcs", &group.NpcList) if !ok { logger.Error("get npcs object error, sceneId: %v, blockId: %v, groupId: %v", sceneId, blockId, groupId) + luaState.Close() return } for _, npc := range group.NpcList { @@ -160,9 +173,10 @@ func (g *GameDataConfig) loadGroup(group *Group, block *Block, sceneId int32, bl } // gadgets group.GadgetList = make([]*Gadget, 0) - ok = parseLuaTableToObject[*[]*Gadget](luaState, "gadgets", &group.GadgetList) + ok = getSceneLuaConfigTable[*[]*Gadget](luaState, "gadgets", &group.GadgetList) if !ok { logger.Error("get gadgets object error, sceneId: %v, blockId: %v, groupId: %v", sceneId, blockId, groupId) + luaState.Close() return } for _, gadget := range group.GadgetList { @@ -170,18 +184,21 @@ func (g *GameDataConfig) loadGroup(group *Group, block *Block, sceneId int32, bl } // regions group.RegionList = make([]*Region, 0) - ok = parseLuaTableToObject[*[]*Region](luaState, "regions", &group.RegionList) + ok = getSceneLuaConfigTable[*[]*Region](luaState, "regions", &group.RegionList) if !ok { logger.Error("get regions object error, sceneId: %v, blockId: %v, groupId: %v", sceneId, blockId, groupId) + luaState.Close() return } // triggers group.TriggerList = make([]*Trigger, 0) - ok = parseLuaTableToObject[*[]*Trigger](luaState, "triggers", &group.TriggerList) + ok = getSceneLuaConfigTable[*[]*Trigger](luaState, "triggers", &group.TriggerList) if !ok { logger.Error("get triggers object error, sceneId: %v, blockId: %v, groupId: %v", sceneId, blockId, groupId) + luaState.Close() return } + luaState.Close() block.groupMapLoadLock.Lock() block.GroupMap[group.Id] = group block.groupMapLoadLock.Unlock() @@ -204,7 +221,7 @@ func (g *GameDataConfig) loadSceneLuaConfig() { sceneLuaConfig.Id = sceneId // scene_config sceneLuaConfig.SceneConfig = new(SceneConfig) - ok := parseLuaTableToObject[*SceneConfig](luaState, "scene_config", sceneLuaConfig.SceneConfig) + ok := getSceneLuaConfigTable[*SceneConfig](luaState, "scene_config", sceneLuaConfig.SceneConfig) if !ok { logger.Error("get scene_config object error, sceneId: %v", sceneId) luaState.Close() @@ -213,7 +230,7 @@ func (g *GameDataConfig) loadSceneLuaConfig() { sceneLuaConfig.BlockMap = make(map[int32]*Block) // blocks blockIdList := make([]int32, 0) - ok = parseLuaTableToObject[*[]int32](luaState, "blocks", &blockIdList) + ok = getSceneLuaConfigTable[*[]int32](luaState, "blocks", &blockIdList) if !ok { logger.Error("get blocks object error, sceneId: %v", sceneId) luaState.Close() @@ -221,7 +238,7 @@ func (g *GameDataConfig) loadSceneLuaConfig() { } // block_rects blockRectList := make([]*BlockRange, 0) - ok = parseLuaTableToObject[*[]*BlockRange](luaState, "block_rects", &blockRectList) + ok = getSceneLuaConfigTable[*[]*BlockRange](luaState, "block_rects", &blockRectList) luaState.Close() if !ok { logger.Error("get block_rects object error, sceneId: %v", sceneId) @@ -244,7 +261,7 @@ func (g *GameDataConfig) loadSceneLuaConfig() { // groups block.GroupMap = make(map[int32]*Group) groupList := make([]*Group, 0) - ok = parseLuaTableToObject[*[]*Group](luaState, "groups", &groupList) + ok = getSceneLuaConfigTable[*[]*Group](luaState, "groups", &groupList) luaState.Close() if !ok { logger.Error("get groups object error, sceneId: %v, blockId: %v", sceneId, blockId) diff --git a/gs/game/lua_func.go b/gs/game/lua_func.go index 4b930e43..4c01a7fe 100644 --- a/gs/game/lua_func.go +++ b/gs/game/lua_func.go @@ -1,8 +1,12 @@ package game import ( + "hk4e/common/constant" "hk4e/gdconf" "hk4e/pkg/logger" + "hk4e/pkg/object" + "hk4e/protocol/cmd" + "hk4e/protocol/proto" lua "github.com/yuin/gopher-lua" ) @@ -50,21 +54,26 @@ func CallLuaFunc(luaState *lua.LState, luaFuncName string, luaCtx *LuaCtx, luaEv Protect: true, }, ctx, evt) if err != nil { - logger.Error("call lua error: %v", err) + logger.Error("call lua error, func: %v, error: %v", luaFuncName, err) return false } luaRet := luaState.Get(-1) luaState.Pop(1) - ret, ok := luaRet.(lua.LBool) - if !ok { + switch luaRet.(type) { + case lua.LBool: + return bool(luaRet.(lua.LBool)) + case lua.LNumber: + return object.ConvRetCodeToBool(int64(luaRet.(lua.LNumber))) + default: return false } - return bool(ret) } func RegLuaLibFunc() { - gdconf.RegScriptLib("GetEntityType", GetEntityType) - gdconf.RegScriptLib("GetQuestState", GetQuestState) + gdconf.RegScriptLibFunc("GetEntityType", GetEntityType) + gdconf.RegScriptLibFunc("GetQuestState", GetQuestState) + gdconf.RegScriptLibFunc("PrintContextLog", PrintContextLog) + gdconf.RegScriptLibFunc("BeginCameraSceneLook", BeginCameraSceneLook) } func GetEntityType(luaState *lua.LState) int { @@ -76,15 +85,19 @@ func GetEntityType(luaState *lua.LState) int { func GetQuestState(luaState *lua.LState) int { ctx, ok := luaState.Get(1).(*lua.LTable) if !ok { - luaState.Push(lua.LNumber(0)) + luaState.Push(lua.LNumber(constant.QUEST_STATE_NONE)) return 1 } uid, ok := luaState.GetField(ctx, "uid").(lua.LNumber) if !ok { - luaState.Push(lua.LNumber(0)) + luaState.Push(lua.LNumber(constant.QUEST_STATE_NONE)) return 1 } player := USER_MANAGER.GetOnlineUser(uint32(uid)) + if player == nil { + luaState.Push(lua.LNumber(constant.QUEST_STATE_NONE)) + return 1 + } entityId := luaState.ToInt(2) _ = entityId questId := luaState.ToInt(3) @@ -93,3 +106,45 @@ func GetQuestState(luaState *lua.LState) int { luaState.Push(lua.LNumber(quest.State)) return 1 } + +func PrintContextLog(luaState *lua.LState) int { + ctx, ok := luaState.Get(1).(*lua.LTable) + if !ok { + return 0 + } + uid, ok := luaState.GetField(ctx, "uid").(lua.LNumber) + if !ok { + return 0 + } + logInfo := luaState.ToString(2) + logger.Info("[LUA LOG] %v [UID %v]", logInfo, uid) + return 0 +} + +func BeginCameraSceneLook(luaState *lua.LState) int { + ctx, ok := luaState.Get(1).(*lua.LTable) + if !ok { + luaState.Push(lua.LNumber(-1)) + return 1 + } + uid, ok := luaState.GetField(ctx, "uid").(lua.LNumber) + if !ok { + luaState.Push(lua.LNumber(-1)) + return 1 + } + player := USER_MANAGER.GetOnlineUser(uint32(uid)) + if player == nil { + luaState.Push(lua.LNumber(-1)) + return 1 + } + cameraLockInfo, ok := luaState.Get(2).(*lua.LTable) + if !ok { + luaState.Push(lua.LNumber(-1)) + return 1 + } + ntf := new(proto.BeginCameraSceneLookNotify) + gdconf.ParseLuaTableToObject(cameraLockInfo, ntf) + GAME_MANAGER.SendMsg(cmd.BeginCameraSceneLookNotify, player.PlayerID, player.ClientSeq, ntf) + luaState.Push(lua.LNumber(0)) + return 1 +} diff --git a/gs/game/player_fight_sync.go b/gs/game/player_fight_sync.go index 5ce0925b..192d547b 100644 --- a/gs/game/player_fight_sync.go +++ b/gs/game/player_fight_sync.go @@ -384,6 +384,7 @@ func (g *GameManager) AoiPlayerMove(player *model.Player, oldPos *model.Vector, g.AddSceneEntityNotify(player, proto.VisionType_VISION_MEET, addEntityIdList, false, false) // 场景区域触发器 dbQuest := player.GetDbQuest() + updateQuest := false for _, group := range newVisionGroupMap { for _, region := range group.RegionList { shape := alg.NewShape() @@ -416,49 +417,79 @@ func (g *GameManager) AoiPlayerMove(player *model.Player, oldPos *model.Vector, Z: float32(newPos.Z), }) if !oldPosInRegion && newPosInRegion { - // EVENT_ENTER_REGION logger.Debug("player enter region: %v, uid: %v", region, player.PlayerID) for _, trigger := range group.TriggerList { if trigger.Event != constant.LUA_EVENT_ENTER_REGION { continue } - cond := CallLuaFunc(group.LuaState, trigger.Condition, &LuaCtx{ - uid: player.PlayerID, - }, &LuaEvt{ - param1: region.ConfigId, - targetEntityId: entityId, - }) + cond := CallLuaFunc(group.GetLuaState(), trigger.Condition, + &LuaCtx{uid: player.PlayerID}, + &LuaEvt{param1: region.ConfigId, targetEntityId: entityId}) if !cond { continue } - // TODO 这一块写得太炸裂了需要优化 - for _, triggerDataConfig := range gdconf.GetTriggerDataMap() { - if triggerDataConfig.TriggerName == trigger.Name { - for _, quest := range dbQuest.GetQuestMap() { - questDataConfig := gdconf.GetQuestDataById(int32(quest.QuestId)) - if questDataConfig == nil { - continue - } - for _, questCond := range questDataConfig.FinishCondList { - if questCond.Type != constant.QUEST_FINISH_COND_TYPE_TRIGGER_FIRE { - continue - } - if questCond.Param[0] != triggerDataConfig.TriggerId { - continue - } - dbQuest.ForceFinishQuest(quest.QuestId) - } - } - } + ok := CallLuaFunc(group.GetLuaState(), trigger.Action, + &LuaCtx{uid: player.PlayerID}, + &LuaEvt{}) + if !ok { + continue } + updateQuest = g.TriggerFire(dbQuest, trigger) } } else if oldPosInRegion && !newPosInRegion { - // EVENT_LEAVE_REGION logger.Debug("player leave region: %v, uid: %v", region, player.PlayerID) + for _, trigger := range group.TriggerList { + if trigger.Event != constant.LUA_EVENT_LEAVE_REGION { + continue + } + cond := CallLuaFunc(group.GetLuaState(), trigger.Condition, + &LuaCtx{uid: player.PlayerID}, + &LuaEvt{param1: region.ConfigId, targetEntityId: entityId}) + if !cond { + continue + } + ok := CallLuaFunc(group.GetLuaState(), trigger.Action, + &LuaCtx{uid: player.PlayerID}, + &LuaEvt{}) + if !ok { + continue + } + } } } } - g.AcceptQuest(player, true) + if updateQuest { + g.AcceptQuest(player, true) + } +} + +func (g *GameManager) TriggerFire(dbQuest *model.DbQuest, trigger *gdconf.Trigger) bool { + // TODO 这一块写得太炸裂了需要优化 + updateQuest := false + for _, triggerDataConfig := range gdconf.GetTriggerDataMap() { + if triggerDataConfig.TriggerName == trigger.Name { + for _, quest := range dbQuest.GetQuestMap() { + questDataConfig := gdconf.GetQuestDataById(int32(quest.QuestId)) + if questDataConfig == nil { + continue + } + for _, questCond := range questDataConfig.FinishCondList { + if questCond.Type != constant.QUEST_FINISH_COND_TYPE_TRIGGER_FIRE { + continue + } + if len(questCond.Param) != 1 { + continue + } + if questCond.Param[0] != triggerDataConfig.TriggerId { + continue + } + dbQuest.ForceFinishQuest(quest.QuestId) + updateQuest = true + } + } + } + } + return updateQuest } func (g *GameManager) AbilityInvocationsNotify(player *model.Player, payloadMsg pb.Message) { diff --git a/gs/game/player_quest.go b/gs/game/player_quest.go index 956f0205..507027cb 100644 --- a/gs/game/player_quest.go +++ b/gs/game/player_quest.go @@ -62,7 +62,7 @@ func (g *GameManager) AddQuestProgress(player *model.Player, req *proto.AddQuest } // AcceptQuest 接取当前条件下能接取到的全部任务 -func (g *GameManager) AcceptQuest(player *model.Player, isNtfClient bool) { +func (g *GameManager) AcceptQuest(player *model.Player, notifyClient bool) { dbQuest := player.GetDbQuest() addQuestIdList := make([]uint32, 0) for _, questData := range gdconf.GetQuestDataMap() { @@ -100,7 +100,7 @@ func (g *GameManager) AcceptQuest(player *model.Player, isNtfClient bool) { addQuestIdList = append(addQuestIdList, uint32(questData.QuestId)) } } - if isNtfClient { + if notifyClient { ntf := &proto.QuestListUpdateNotify{ QuestList: make([]*proto.Quest, 0), } diff --git a/gs/game/player_scene.go b/gs/game/player_scene.go index 13368bf7..77c60642 100644 --- a/gs/game/player_scene.go +++ b/gs/game/player_scene.go @@ -19,7 +19,7 @@ import ( const ( ENTITY_MAX_BATCH_SEND_NUM = 1000 // 单次同步的最大实体数量 - ENTITY_LOD = 300 // 实体加载视野距离 + ENTITY_LOD = 100 // 实体加载视野距离 ) func (g *GameManager) EnterSceneReadyReq(player *model.Player, payloadMsg pb.Message) { diff --git a/gs/game/world_manager.go b/gs/game/world_manager.go index 02ce2dec..dcc9cd37 100644 --- a/gs/game/world_manager.go +++ b/gs/game/world_manager.go @@ -15,7 +15,7 @@ import ( const ( ENTITY_NUM_UNLIMIT = false // 是否不限制场景内实体数量 - ENTITY_MAX_SEND_NUM = 300 // 场景内最大实体数量 + ENTITY_MAX_SEND_NUM = 500 // 场景内最大实体数量 MAX_MULTIPLAYER_WORLD_NUM = 10 // 本服务器最大多人世界数量 ) diff --git a/pkg/object/object.go b/pkg/object/object.go index e736c341..73f08dff 100644 --- a/pkg/object/object.go +++ b/pkg/object/object.go @@ -128,6 +128,14 @@ func ConvInt64ToBool(v int64) bool { } } +func ConvRetCodeToBool(v int64) bool { + if v == 0 { + return true + } else { + return false + } +} + func ConvListToMap[T any](l []T) map[uint64]T { ret := make(map[uint64]T) for index, value := range l { diff --git a/protocol/cmd/cmd_id_proto_obj_map.go b/protocol/cmd/cmd_id_proto_obj_map.go index d3e9554d..a91899ad 100644 --- a/protocol/cmd/cmd_id_proto_obj_map.go +++ b/protocol/cmd/cmd_id_proto_obj_map.go @@ -108,6 +108,7 @@ func (c *CmdProtoMap) registerAllMessage() { c.registerMessage(DungeonWayPointNotify, &proto.DungeonWayPointNotify{}) // 地牢副本相关 c.registerMessage(DungeonDataNotify, &proto.DungeonDataNotify{}) // 地牢副本相关 c.registerMessage(SceneAudioNotify, &proto.SceneAudioNotify{}) // 场景风物之琴音乐同步通知 + c.registerMessage(BeginCameraSceneLookNotify, &proto.BeginCameraSceneLookNotify{}) // 场景镜头注目通知 // 战斗与同步 c.registerMessage(AvatarFightPropNotify, &proto.AvatarFightPropNotify{}) // 角色战斗属性通知