From a7b3f418398c3897fcbc6d921169471a38200236 Mon Sep 17 00:00:00 2001 From: flswld Date: Wed, 1 Mar 2023 10:50:59 +0800 Subject: [PATCH] =?UTF-8?q?=E5=8A=A0=E8=BD=BDlua=E8=84=9A=E6=9C=AC?= =?UTF-8?q?=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- gdconf/game_data_config.go | 59 ++++++++++-- gdconf/game_data_config_test.go | 2 +- .../{scene_detail.go => scene_lua_config.go} | 92 ++++++++++++------ gs/game/game_manager.go | 1 + gs/game/lua_func.go | 95 +++++++++++++++++++ gs/game/player_scene.go | 48 +++++----- gs/game/world_manager.go | 8 +- gs/model/vector.go | 7 -- 8 files changed, 239 insertions(+), 73 deletions(-) rename gdconf/{scene_detail.go => scene_lua_config.go} (75%) create mode 100644 gs/game/lua_func.go diff --git a/gdconf/game_data_config.go b/gdconf/game_data_config.go index 1248626f..5d1d64dc 100644 --- a/gdconf/game_data_config.go +++ b/gdconf/game_data_config.go @@ -33,7 +33,7 @@ type GameDataConfig struct { SceneDataMap map[int32]*SceneData // 场景 ScenePointMap map[int32]*ScenePoint // 场景传送点 SceneTagDataMap map[int32]*SceneTagData // 场景标签 - SceneDetailMap map[int32]*SceneDetail // 场景详情LUA配置数据 + SceneLuaConfigMap map[int32]*SceneLuaConfig // 场景LUA配置 WorldAreaDataMap map[int32]*WorldAreaData // 世界区域 GatherDataMap map[int32]*GatherData // 采集物 GatherDataPointTypeMap map[int32]*GatherData // 采集物场景节点索引 @@ -121,7 +121,7 @@ func (g *GameDataConfig) load() { g.loadScenePoint() // 场景传送点 g.loadSceneTagData() // 场景地图图标 if config.GetConfig().Hk4e.LoadSceneLuaConfig { - g.loadSceneDetail() // 场景详情LUA配置数据 + g.loadSceneLuaConfig() // 场景LUA配置 } g.loadWorldAreaData() // 世界区域 g.loadGatherData() // 采集物 @@ -157,14 +157,53 @@ func (g *GameDataConfig) readCsvFileData(fileName string) []byte { return standardCsvData } -func fixLuaState(luaStr string) *lua.LState { - fixLua := "" - fixLua += "GadgetState = {}\n" - fixLua += "EventType = {}\n" - fixLua += "RegionShape = {}\n" - fixLua += "VisionLevelType = {}\n" - luaStr = fixLua + luaStr - luaState := lua.NewState() +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)) + } + } + } +} + +func initLuaState(luaState *lua.LState) { + eventType := luaState.NewTable() + luaState.SetGlobal("EventType", eventType) + luaState.SetField(eventType, "NONE", lua.LNumber(0)) + luaState.SetField(eventType, "EVENT_ENTER_REGION", lua.LNumber(1)) + + entityType := luaState.NewTable() + luaState.SetGlobal("EntityType", entityType) + luaState.SetField(entityType, "NONE", lua.LNumber(0)) + luaState.SetField(entityType, "AVATAR", lua.LNumber(1)) + + regionShape := luaState.NewTable() + luaState.SetGlobal("RegionShape", regionShape) + luaState.SetField(regionShape, "NONE", lua.LNumber(0)) + luaState.SetField(regionShape, "SPHERE", lua.LNumber(1)) + + questState := luaState.NewTable() + luaState.SetGlobal("QuestState", questState) + luaState.SetField(questState, "NONE", lua.LNumber(0)) + luaState.SetField(questState, "UNFINISHED", lua.LNumber(1)) + + gadgetState := luaState.NewTable() + luaState.SetGlobal("GadgetState", gadgetState) + luaState.SetField(gadgetState, "NONE", lua.LNumber(0)) + + visionLevelType := luaState.NewTable() + luaState.SetGlobal("VisionLevelType", visionLevelType) + luaState.SetField(visionLevelType, "NONE", lua.LNumber(0)) +} + +func newLuaState(luaStr string) *lua.LState { + luaState := lua.NewState(lua.Options{ + IncludeGoStackTrace: true, + }) + initLuaState(luaState) err := luaState.DoString(luaStr) if err != nil { if strings.Contains(err.Error(), "module") && strings.Contains(err.Error(), "not found") { diff --git a/gdconf/game_data_config_test.go b/gdconf/game_data_config_test.go index 2cb6966a..04e4d253 100644 --- a/gdconf/game_data_config_test.go +++ b/gdconf/game_data_config_test.go @@ -156,7 +156,7 @@ func TestSceneBlock(t *testing.T) { logger.CloseLogger() }() InitGameDataConfig() - scene, exist := CONF.SceneDetailMap[3] + scene, exist := CONF.SceneLuaConfigMap[3] if !exist { panic("scene 3 not exist") } diff --git a/gdconf/scene_detail.go b/gdconf/scene_lua_config.go similarity index 75% rename from gdconf/scene_detail.go rename to gdconf/scene_lua_config.go index 08926a07..5a8bda24 100644 --- a/gdconf/scene_detail.go +++ b/gdconf/scene_lua_config.go @@ -6,6 +6,8 @@ import ( "sync" "hk4e/pkg/logger" + + lua "github.com/yuin/gopher-lua" ) // 场景详情配置数据 @@ -14,16 +16,16 @@ const ( SceneGroupLoaderLimit = 4 // 加载文件的并发数 此操作很耗内存 调大之前请确保你的机器内存足够 ) -type SceneDetail struct { +type SceneLuaConfig struct { Id int32 SceneConfig *SceneConfig // 地图配置 BlockMap map[int32]*Block // 所有的区块 } type Vector struct { - X float64 `json:"x"` - Y float64 `json:"y"` - Z float64 `json:"z"` + X float32 `json:"x"` + Y float32 `json:"y"` + Z float32 `json:"z"` } type SceneConfig struct { @@ -31,7 +33,7 @@ type SceneConfig struct { Size *Vector `json:"size"` BornPos *Vector `json:"born_pos"` BornRot *Vector `json:"born_rot"` - DieY float64 `json:"die_y"` + DieY float32 `json:"die_y"` VisionAnchor *Vector `json:"vision_anchor"` } @@ -55,7 +57,11 @@ type Group struct { IsReplaceable *Replaceable `json:"is_replaceable"` MonsterList []*Monster `json:"monsters"` // 怪物 NpcList []*Npc `json:"npcs"` // NPC - GadgetList []*Gadget `json:"gadgets"` // 装置 + GadgetList []*Gadget `json:"gadgets"` // 物件 + RegionList []*Region `json:"regions"` + TriggerList []*Trigger `json:"triggers"` + LuaStr string + LuaState *lua.LState } type Replaceable struct { @@ -91,6 +97,25 @@ type Gadget struct { PointType int32 `json:"point_type"` // 关联GatherData表 } +type Region struct { + ConfigId int32 `json:"config_id"` + Shape int32 `json:"shape"` + Radius float32 `json:"radius"` + Size *Vector `json:"size"` + Pos *Vector `json:"pos"` + AreaId int32 `json:"area_id"` +} + +type Trigger struct { + ConfigId int32 `json:"config_id"` + Name string `json:"name"` + Event int32 `json:"event"` + Source string `json:"source"` + Condition string `json:"condition"` + Action string `json:"action"` + TriggerCount int32 `json:"trigger_count"` +} + func (g *GameDataConfig) loadGroup(group *Group, block *Block, sceneId int32, blockId int32) { sceneLuaPrefix := g.luaPrefix + "scene/" sceneIdStr := strconv.Itoa(int(sceneId)) @@ -101,13 +126,14 @@ func (g *GameDataConfig) loadGroup(group *Group, block *Block, sceneId int32, bl logger.Error("open file error: %v, sceneId: %v, blockId: %v, groupId: %v", err, sceneId, blockId, groupId) return } - luaState := fixLuaState(string(groupLuaData)) + group.LuaStr = string(groupLuaData) + luaState := newLuaState(group.LuaStr) + group.LuaState = luaState // monsters group.MonsterList = make([]*Monster, 0) ok := parseLuaTableToObject[*[]*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 } // npcs @@ -115,24 +141,36 @@ func (g *GameDataConfig) loadGroup(group *Group, block *Block, sceneId int32, bl ok = parseLuaTableToObject[*[]*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 } // gadgets group.GadgetList = make([]*Gadget, 0) ok = parseLuaTableToObject[*[]*Gadget](luaState, "gadgets", &group.GadgetList) - luaState.Close() if !ok { logger.Error("get gadgets object error, sceneId: %v, blockId: %v, groupId: %v", sceneId, blockId, groupId) return } + // regions + group.RegionList = make([]*Region, 0) + ok = parseLuaTableToObject[*[]*Region](luaState, "regions", &group.RegionList) + if !ok { + logger.Error("get regions object error, sceneId: %v, blockId: %v, groupId: %v", sceneId, blockId, groupId) + return + } + // triggers + group.TriggerList = make([]*Trigger, 0) + ok = parseLuaTableToObject[*[]*Trigger](luaState, "triggers", &group.TriggerList) + if !ok { + logger.Error("get triggers object error, sceneId: %v, blockId: %v, groupId: %v", sceneId, blockId, groupId) + return + } block.groupMapLoadLock.Lock() block.GroupMap[group.Id] = group block.groupMapLoadLock.Unlock() } -func (g *GameDataConfig) loadSceneDetail() { - g.SceneDetailMap = make(map[int32]*SceneDetail) +func (g *GameDataConfig) loadSceneLuaConfig() { + g.SceneLuaConfigMap = make(map[int32]*SceneLuaConfig) sceneLuaPrefix := g.luaPrefix + "scene/" for _, sceneData := range g.SceneDataMap { sceneId := sceneData.SceneId @@ -142,18 +180,18 @@ func (g *GameDataConfig) loadSceneDetail() { logger.Info("open file error: %v, sceneId: %v", err, sceneId) continue } - luaState := fixLuaState(string(mainLuaData)) - sceneDetail := new(SceneDetail) - sceneDetail.Id = sceneId + luaState := newLuaState(string(mainLuaData)) + sceneLuaConfig := new(SceneLuaConfig) + sceneLuaConfig.Id = sceneId // scene_config - sceneDetail.SceneConfig = new(SceneConfig) - ok := parseLuaTableToObject[*SceneConfig](luaState, "scene_config", sceneDetail.SceneConfig) + sceneLuaConfig.SceneConfig = new(SceneConfig) + ok := parseLuaTableToObject[*SceneConfig](luaState, "scene_config", sceneLuaConfig.SceneConfig) if !ok { logger.Error("get scene_config object error, sceneId: %v", sceneId) luaState.Close() continue } - sceneDetail.BlockMap = make(map[int32]*Block) + sceneLuaConfig.BlockMap = make(map[int32]*Block) // blocks blockIdList := make([]int32, 0) ok = parseLuaTableToObject[*[]int32](luaState, "blocks", &blockIdList) @@ -183,7 +221,7 @@ func (g *GameDataConfig) loadSceneDetail() { logger.Error("open file error: %v, sceneId: %v, blockId: %v", err, sceneId, blockId) continue } - luaState = fixLuaState(string(blockLuaData)) + luaState = newLuaState(string(blockLuaData)) // groups block.GroupMap = make(map[int32]*Group) groupList := make([]*Group, 0) @@ -207,9 +245,9 @@ func (g *GameDataConfig) loadSceneDetail() { }() } wg.Wait() - sceneDetail.BlockMap[block.Id] = block + sceneLuaConfig.BlockMap[block.Id] = block } - g.SceneDetailMap[sceneId] = sceneDetail + g.SceneLuaConfigMap[sceneId] = sceneLuaConfig } sceneCount := 0 blockCount := 0 @@ -217,7 +255,7 @@ func (g *GameDataConfig) loadSceneDetail() { monsterCount := 0 npcCount := 0 gadgetCount := 0 - for _, scene := range g.SceneDetailMap { + for _, scene := range g.SceneLuaConfigMap { for _, block := range scene.BlockMap { for _, group := range block.GroupMap { monsterCount += len(group.MonsterList) @@ -233,19 +271,19 @@ func (g *GameDataConfig) loadSceneDetail() { sceneCount, blockCount, groupCount, monsterCount, npcCount, gadgetCount) } -func GetSceneDetailById(sceneId int32) *SceneDetail { - return CONF.SceneDetailMap[sceneId] +func GetSceneLuaConfigById(sceneId int32) *SceneLuaConfig { + return CONF.SceneLuaConfigMap[sceneId] } -func GetSceneDetailMap() map[int32]*SceneDetail { - return CONF.SceneDetailMap +func GetSceneLuaConfigMap() map[int32]*SceneLuaConfig { + return CONF.SceneLuaConfigMap } func GetSceneBlockConfig(sceneId int32, blockId int32) ([]*Monster, []*Npc, []*Gadget, bool) { monsterList := make([]*Monster, 0) npcList := make([]*Npc, 0) gadgetList := make([]*Gadget, 0) - sceneConfig, exist := CONF.SceneDetailMap[sceneId] + sceneConfig, exist := CONF.SceneLuaConfigMap[sceneId] if !exist { return nil, nil, nil, false } diff --git a/gs/game/game_manager.go b/gs/game/game_manager.go index 02295b97..5039a1d1 100644 --- a/gs/game/game_manager.go +++ b/gs/game/game_manager.go @@ -79,6 +79,7 @@ func NewGameManager(dao *dao.Dao, messageQueue *mq.MessageQueue, gsId uint32, gs TICK_MANAGER = NewTickManager() COMMAND_MANAGER = NewCommandManager() GCG_MANAGER = NewGCGManager() + RegLuaLibFunc() // 创建本服的Ai世界 uid := AiBaseUid + gsId name := AiName diff --git a/gs/game/lua_func.go b/gs/game/lua_func.go new file mode 100644 index 00000000..4b930e43 --- /dev/null +++ b/gs/game/lua_func.go @@ -0,0 +1,95 @@ +package game + +import ( + "hk4e/gdconf" + "hk4e/pkg/logger" + + lua "github.com/yuin/gopher-lua" +) + +type LuaCtx struct { + uid uint32 + ownerUid uint32 + sourceEntityId uint32 + targetEntityId uint32 +} + +type LuaEvt struct { + param1 int32 + param2 int32 + param3 int32 + param4 int32 + paramStr1 string + evtType int32 + uid uint32 + sourceName string + sourceEntityId uint32 + targetEntityId uint32 +} + +func CallLuaFunc(luaState *lua.LState, luaFuncName string, luaCtx *LuaCtx, luaEvt *LuaEvt) bool { + ctx := luaState.NewTable() + luaState.SetField(ctx, "uid", lua.LNumber(luaCtx.uid)) + luaState.SetField(ctx, "owner_uid", lua.LNumber(luaCtx.ownerUid)) + luaState.SetField(ctx, "source_entity_id", lua.LNumber(luaCtx.sourceEntityId)) + luaState.SetField(ctx, "target_entity_id", lua.LNumber(luaCtx.targetEntityId)) + evt := luaState.NewTable() + luaState.SetField(evt, "param1", lua.LNumber(luaEvt.param1)) + luaState.SetField(evt, "param2", lua.LNumber(luaEvt.param2)) + luaState.SetField(evt, "param3", lua.LNumber(luaEvt.param3)) + luaState.SetField(evt, "param4", lua.LNumber(luaEvt.param4)) + luaState.SetField(evt, "param_str1", lua.LString(luaEvt.paramStr1)) + luaState.SetField(evt, "type", lua.LNumber(luaEvt.evtType)) + luaState.SetField(evt, "uid", lua.LNumber(luaEvt.uid)) + luaState.SetField(evt, "source_name", lua.LString(luaEvt.sourceName)) + luaState.SetField(evt, "source_eid", lua.LNumber(luaEvt.sourceEntityId)) + luaState.SetField(evt, "target_eid", lua.LNumber(luaEvt.targetEntityId)) + err := luaState.CallByParam(lua.P{ + Fn: luaState.GetGlobal(luaFuncName), + NRet: 1, + Protect: true, + }, ctx, evt) + if err != nil { + logger.Error("call lua error: %v", err) + return false + } + luaRet := luaState.Get(-1) + luaState.Pop(1) + ret, ok := luaRet.(lua.LBool) + if !ok { + return false + } + return bool(ret) +} + +func RegLuaLibFunc() { + gdconf.RegScriptLib("GetEntityType", GetEntityType) + gdconf.RegScriptLib("GetQuestState", GetQuestState) +} + +func GetEntityType(luaState *lua.LState) int { + entityId := luaState.ToInt(1) + luaState.Push(lua.LNumber(entityId >> 24)) + return 1 +} + +func GetQuestState(luaState *lua.LState) int { + ctx, ok := luaState.Get(1).(*lua.LTable) + if !ok { + luaState.Push(lua.LNumber(0)) + return 1 + } + uid, ok := luaState.GetField(ctx, "uid").(lua.LNumber) + if !ok { + luaState.Push(lua.LNumber(0)) + return 1 + } + player := USER_MANAGER.GetOnlineUser(uint32(uid)) + entityId := luaState.ToInt(2) + _ = entityId + questId := luaState.ToInt(3) + dbQuest := player.GetDbQuest() + quest := dbQuest.GetQuestById(uint32(questId)) + luaState.Push(lua.LNumber(quest.State)) + return 1 +} diff --git a/gs/game/player_scene.go b/gs/game/player_scene.go index 55ac0ab4..b6b213b7 100644 --- a/gs/game/player_scene.go +++ b/gs/game/player_scene.go @@ -370,24 +370,24 @@ func (g *GameManager) CreateConfigEntity(scene *Scene, objectId int64, entityCon case *gdconf.Monster: monster := entityConfig.(*gdconf.Monster) return scene.CreateEntityMonster(&model.Vector{ - X: monster.Pos.X, - Y: monster.Pos.Y, - Z: monster.Pos.Z, + X: float64(monster.Pos.X), + Y: float64(monster.Pos.Y), + Z: float64(monster.Pos.Z), }, &model.Vector{ - X: monster.Rot.X, - Y: monster.Rot.Y, - Z: monster.Rot.Z, + X: float64(monster.Rot.X), + Y: float64(monster.Rot.Y), + Z: float64(monster.Rot.Z), }, uint32(monster.MonsterId), uint8(monster.Level), g.GetTempFightPropMap(), uint32(monster.ConfigId), objectId) case *gdconf.Npc: npc := entityConfig.(*gdconf.Npc) return scene.CreateEntityNpc(&model.Vector{ - X: npc.Pos.X, - Y: npc.Pos.Y, - Z: npc.Pos.Z, + X: float64(npc.Pos.X), + Y: float64(npc.Pos.Y), + Z: float64(npc.Pos.Z), }, &model.Vector{ - X: npc.Rot.X, - Y: npc.Rot.Y, - Z: npc.Rot.Z, + X: float64(npc.Rot.X), + Y: float64(npc.Rot.Y), + Z: float64(npc.Rot.Z), }, uint32(npc.NpcId), 0, 0, 0, uint32(npc.ConfigId), objectId) case *gdconf.Gadget: gadget := entityConfig.(*gdconf.Gadget) @@ -398,23 +398,23 @@ func (g *GameManager) CreateConfigEntity(scene *Scene, objectId int64, entityCon return 0 } return scene.CreateEntityGadgetGather(&model.Vector{ - X: gadget.Pos.X, - Y: gadget.Pos.Y, - Z: gadget.Pos.Z, + X: float64(gadget.Pos.X), + Y: float64(gadget.Pos.Y), + Z: float64(gadget.Pos.Z), }, &model.Vector{ - X: gadget.Rot.X, - Y: gadget.Rot.Y, - Z: gadget.Rot.Z, + X: float64(gadget.Rot.X), + Y: float64(gadget.Rot.Y), + Z: float64(gadget.Rot.Z), }, uint32(gatherDataConfig.GadgetId), uint32(gatherDataConfig.GatherId), uint32(gadget.ConfigId), objectId) } else { return scene.CreateEntityGadgetNormal(&model.Vector{ - X: gadget.Pos.X, - Y: gadget.Pos.Y, - Z: gadget.Pos.Z, + X: float64(gadget.Pos.X), + Y: float64(gadget.Pos.Y), + Z: float64(gadget.Pos.Z), }, &model.Vector{ - X: gadget.Rot.X, - Y: gadget.Rot.Y, - Z: gadget.Rot.Z, + X: float64(gadget.Rot.X), + Y: float64(gadget.Rot.Y), + Z: float64(gadget.Rot.Z), }, uint32(gadget.GadgetId), uint32(gadget.ConfigId), objectId) } default: diff --git a/gs/game/world_manager.go b/gs/game/world_manager.go index b84153ba..c90a2d70 100644 --- a/gs/game/world_manager.go +++ b/gs/game/world_manager.go @@ -32,7 +32,7 @@ func NewWorldManager(snowflake *alg.SnowflakeWorker) (r *WorldManager) { r.worldMap = make(map[uint32]*World) r.snowflake = snowflake r.sceneBlockAoiMap = make(map[uint32]*alg.AoiManager) - for _, sceneConfig := range gdconf.GetSceneDetailMap() { + for _, sceneLuaConfig := range gdconf.GetSceneLuaConfigMap() { minX := int16(0) maxX := int16(0) minZ := int16(0) @@ -41,7 +41,7 @@ func NewWorldManager(snowflake *alg.SnowflakeWorker) (r *WorldManager) { blockYLen := int16(0) blockZLen := int16(0) ok := true - for _, blockConfig := range sceneConfig.BlockMap { + for _, blockConfig := range sceneLuaConfig.BlockMap { if int16(blockConfig.BlockRange.Min.X) < minX { minX = int16(blockConfig.BlockRange.Min.X) } @@ -112,7 +112,7 @@ func NewWorldManager(snowflake *alg.SnowflakeWorker) (r *WorldManager) { aoiManager := alg.NewAoiManager() aoiManager.SetAoiRange(minX, maxX, -1.0, 1.0, minZ, maxZ) aoiManager.Init3DRectAoiManager(numX, 1, numZ) - for _, blockConfig := range sceneConfig.BlockMap { + for _, blockConfig := range sceneLuaConfig.BlockMap { for _, groupConfig := range blockConfig.GroupMap { for _, monsterConfig := range groupConfig.MonsterList { aoiManager.AddObjectToGridByPos(r.snowflake.GenId(), monsterConfig, @@ -134,7 +134,7 @@ func NewWorldManager(snowflake *alg.SnowflakeWorker) (r *WorldManager) { } } } - r.sceneBlockAoiMap[uint32(sceneConfig.Id)] = aoiManager + r.sceneBlockAoiMap[uint32(sceneLuaConfig.Id)] = aoiManager } r.multiplayerWorldNum = 0 return r diff --git a/gs/model/vector.go b/gs/model/vector.go index f6bc2ed1..9201b112 100644 --- a/gs/model/vector.go +++ b/gs/model/vector.go @@ -1,14 +1,7 @@ package model -import "math" - type Vector struct { X float64 Y float64 Z float64 } - -// Distance 两坐标之间的距离 -func (v *Vector) Distance(vector *Vector) float64 { - return math.Sqrt(math.Pow(v.X-vector.X, 2) + math.Pow(v.Y-vector.Y, 2) + math.Pow(v.Z-vector.Z, 2)) -}