From e554b99e7ef8f945a1e03eb20e2d3f3632a9fe4f Mon Sep 17 00:00:00 2001 From: flswld Date: Sat, 8 Apr 2023 22:53:41 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=9E=E7=8E=B0=E6=9B=B4=E5=A4=9A=E7=9A=84?= =?UTF-8?q?=E8=A7=A6=E5=8F=91=E5=99=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- anticheat/handle/handle.go | 85 ++++++-- gdconf/game_data_config.go | 5 + gdconf/player_level_data.go | 2 +- gdconf/refresh_policy_data.go | 73 +++++++ gdconf/scene_lua_config.go | 53 +++-- gs/game/game_command_gm.go | 33 +-- gs/game/game_tick_manager.go | 6 +- gs/game/game_world_scene.go | 160 ++------------ gs/game/lua_func.go | 298 +++++++++++++++++++++++++- gs/game/lua_trigger.go | 391 +++++++++++++++++++++------------- gs/game/player_base.go | 2 +- gs/game/player_fight_sync.go | 2 +- gs/game/player_scene.go | 254 ++++++++++++++++++++-- gs/model/db_world.go | 65 ++++++ 14 files changed, 1065 insertions(+), 364 deletions(-) create mode 100644 gdconf/refresh_policy_data.go diff --git a/anticheat/handle/handle.go b/anticheat/handle/handle.go index 92de9d70..41a0d6fa 100644 --- a/anticheat/handle/handle.go +++ b/anticheat/handle/handle.go @@ -17,10 +17,11 @@ import ( ) const ( - MoveVectorCacheNum = 10 - MaxMoveSpeed = 50.0 - JumpDistance = 100.0 - PointDistance = 10.0 + MoveVectorCacheNum = 10 + MaxMoveSpeed = 100.0 + JumpDistance = 500.0 + PointDistance = 10.0 + AttackCountLimitEntitySec = 10 ) type MoveVector struct { @@ -28,9 +29,15 @@ type MoveVector struct { time int64 } +type AttackEntity struct { + attackStartTime uint64 + attackCount uint32 +} + type AnticheatContext struct { - sceneId uint32 - moveVectorList []*MoveVector + sceneId uint32 + moveVectorList []*MoveVector + attackEntityMap map[uint32]*AttackEntity } func (a *AnticheatContext) Move(pos *proto.Vector) bool { @@ -98,10 +105,33 @@ func (a *AnticheatContext) GetMoveSpeed() float32 { return avgMoveSpeed } +func (a *AnticheatContext) Attack(defEntityId uint32) bool { + now := uint64(time.Now().UnixMilli()) + attackEntity, exist := a.attackEntityMap[defEntityId] + if !exist { + attackEntity = &AttackEntity{ + attackStartTime: now, + attackCount: 0, + } + a.attackEntityMap[defEntityId] = attackEntity + } + attackEntity.attackCount++ + if attackEntity.attackCount > AttackCountLimitEntitySec { + if now-attackEntity.attackStartTime < 1000 { + return false + } else { + attackEntity.attackStartTime = now + attackEntity.attackCount = 0 + } + } + return true +} + func NewAnticheatContext() *AnticheatContext { r := &AnticheatContext{ - sceneId: 0, - moveVectorList: make([]*MoveVector, 0), + sceneId: 0, + moveVectorList: make([]*MoveVector, 0), + attackEntityMap: make(map[uint32]*AttackEntity), } return r } @@ -167,6 +197,11 @@ func (h *Handle) run() { func (h *Handle) CombatInvocationsNotify(userId uint32, gateAppId string, payloadMsg pb.Message) { req := payloadMsg.(*proto.CombatInvocationsNotify) + ctx := h.GetPlayerAcCtx(userId) + if ctx == nil { + logger.Error("get player anticheat context is nil, uid: %v", userId) + return + } for _, entry := range req.InvokeList { switch entry.ArgumentType { case proto.CombatTypeArgument_ENTITY_MOVE: @@ -179,18 +214,20 @@ func (h *Handle) CombatInvocationsNotify(userId uint32, gateAppId string, payloa if GetEntityType(entityMoveInfo.EntityId) != constant.ENTITY_TYPE_AVATAR { continue } - if entityMoveInfo.MotionInfo.Pos == nil { + if entityMoveInfo.MotionInfo == nil { + continue + } + motionInfo := entityMoveInfo.MotionInfo + if motionInfo.Pos == nil { continue } // 玩家超速移动检测 - ctx := h.GetPlayerAcCtx(userId) - if ctx == nil { - logger.Error("get player anticheat context is nil, uid: %v", userId) + if ctx.sceneId != 3 { continue } - ok := ctx.Move(entityMoveInfo.MotionInfo.Pos) + ok := ctx.Move(motionInfo.Pos) if !ok { - logger.Warn("player move jump, pos: %v, uid: %v", entityMoveInfo.MotionInfo.Pos, userId) + logger.Warn("player move jump, pos: %v, uid: %v", motionInfo.Pos, userId) h.KickPlayer(userId, gateAppId) continue } @@ -201,6 +238,26 @@ func (h *Handle) CombatInvocationsNotify(userId uint32, gateAppId string, payloa h.KickPlayer(userId, gateAppId) continue } + case proto.CombatTypeArgument_COMBAT_EVT_BEING_HIT: + evtBeingHitInfo := new(proto.EvtBeingHitInfo) + err := pb.Unmarshal(entry.CombatData, evtBeingHitInfo) + if err != nil { + logger.Error("parse EvtBeingHitInfo error: %v, uid: %v", err, userId) + continue + } + attackResult := evtBeingHitInfo.AttackResult + if attackResult == nil { + continue + } + if GetEntityType(attackResult.DefenseId) != constant.ENTITY_TYPE_MONSTER { + continue + } + ok := ctx.Attack(attackResult.DefenseId) + if !ok { + logger.Warn("player attack monster feq too high, uid: %v", userId) + h.KickPlayer(userId, gateAppId) + continue + } } } } diff --git a/gdconf/game_data_config.go b/gdconf/game_data_config.go index 01e4a081..d1297e15 100644 --- a/gdconf/game_data_config.go +++ b/gdconf/game_data_config.go @@ -65,6 +65,7 @@ type GameDataConfig struct { ChestDropDataMap map[string]map[int32]*ChestDropData // 宝箱掉落 DungeonDataMap map[int32]*DungeonData // 地牢 GadgetDataMap map[int32]*GadgetData // 物件 + RefreshPolicyDataMap map[int32]*RefreshPolicyData // 刷新策略 GCGCharDataMap map[int32]*GCGCharData // 七圣召唤角色卡牌 GCGSkillDataMap map[int32]*GCGSkillData // 七圣召唤卡牌技能 GachaDropGroupDataMap map[int32]*GachaDropGroupData // 卡池掉落组 临时的 @@ -166,6 +167,7 @@ func (g *GameDataConfig) load() { g.loadChestDropData() // 宝箱掉落 g.loadDungeonData() // 地牢 g.loadGadgetData() // 物件 + g.loadRefreshPolicyData() // 刷新策略 g.loadGCGCharData() // 七圣召唤角色卡牌 g.loadGCGSkillData() // 七圣召唤卡牌技能 g.loadGachaDropGroupData() // 卡池掉落组 临时的 @@ -291,6 +293,9 @@ func initLuaState(luaState *lua.LState) { luaState.SetField(eventType, "EVENT_ANY_MONSTER_DIE", lua.LNumber(constant.LUA_EVENT_ANY_MONSTER_DIE)) luaState.SetField(eventType, "EVENT_ANY_MONSTER_LIVE", lua.LNumber(constant.LUA_EVENT_ANY_MONSTER_LIVE)) luaState.SetField(eventType, "EVENT_QUEST_START", lua.LNumber(constant.LUA_EVENT_QUEST_START)) + luaState.SetField(eventType, "EVENT_GADGET_CREATE", lua.LNumber(constant.LUA_EVENT_GADGET_CREATE)) + luaState.SetField(eventType, "EVENT_GADGET_STATE_CHANGE", lua.LNumber(constant.LUA_EVENT_GADGET_STATE_CHANGE)) + luaState.SetField(eventType, "EVENT_GROUP_LOAD", lua.LNumber(constant.LUA_EVENT_GROUP_LOAD)) entityType := luaState.NewTable() luaState.SetGlobal("EntityType", entityType) diff --git a/gdconf/player_level_data.go b/gdconf/player_level_data.go index 9047f05f..88433b00 100644 --- a/gdconf/player_level_data.go +++ b/gdconf/player_level_data.go @@ -20,7 +20,7 @@ func (g *GameDataConfig) loadPlayerLevelData() { logger.Info("PlayerLevelData count: %v", len(g.PlayerLevelDataMap)) } -func GetPlayerLevelDataById(level int32) *PlayerLevelData { +func GetPlayerLevelDataByLevel(level int32) *PlayerLevelData { return CONF.PlayerLevelDataMap[level] } diff --git a/gdconf/refresh_policy_data.go b/gdconf/refresh_policy_data.go new file mode 100644 index 00000000..3a8785e6 --- /dev/null +++ b/gdconf/refresh_policy_data.go @@ -0,0 +1,73 @@ +package gdconf + +import ( + "fmt" + "strconv" + "strings" + + "hk4e/pkg/logger" +) + +const ( + RefreshTypeNone = 0 + RefreshTypeAfterTime = 1 + RefreshTypeDayTime = 2 + RefreshTypeDayTimeRange = 3 + RefreshTypeDay = 4 +) + +// RefreshPolicyData 刷新策略配置表 +type RefreshPolicyData struct { + RefreshId int32 `csv:"刷新ID"` + RefreshType int32 `csv:"刷新方式,omitempty"` + RefreshTimeStr string `csv:"刷新时间,omitempty"` + + RefreshTime int32 + RefreshTimeRange [2]int32 +} + +func (g *GameDataConfig) loadRefreshPolicyData() { + g.RefreshPolicyDataMap = make(map[int32]*RefreshPolicyData) + refreshPolicyDataList := make([]*RefreshPolicyData, 0) + readTable[RefreshPolicyData](g.txtPrefix+"RefreshPolicyData.txt", &refreshPolicyDataList) + for _, refreshPolicyData := range refreshPolicyDataList { + if refreshPolicyData.RefreshType < RefreshTypeNone || refreshPolicyData.RefreshType > RefreshTypeDay { + info := fmt.Sprintf("invalid refresh type: %v", refreshPolicyData) + panic(info) + } + if refreshPolicyData.RefreshType == RefreshTypeDayTimeRange { + split := strings.Split(refreshPolicyData.RefreshTimeStr, ";") + if len(split) != 2 { + info := fmt.Sprintf("refresh time format error: %v", refreshPolicyData) + panic(info) + } + startTime, err := strconv.Atoi(split[0]) + if err != nil { + panic(err) + } + endTime, err := strconv.Atoi(split[1]) + if err != nil { + panic(err) + } + refreshPolicyData.RefreshTimeRange = [2]int32{int32(startTime), int32(endTime)} + } else if refreshPolicyData.RefreshType == RefreshTypeNone { + refreshPolicyData.RefreshTime = 0 + } else { + refreshTime, err := strconv.Atoi(refreshPolicyData.RefreshTimeStr) + if err != nil { + panic(err) + } + refreshPolicyData.RefreshTime = int32(refreshTime) + } + g.RefreshPolicyDataMap[refreshPolicyData.RefreshId] = refreshPolicyData + } + logger.Info("RefreshPolicyData count: %v", len(g.RefreshPolicyDataMap)) +} + +func GetRefreshPolicyDataById(refreshId int32) *RefreshPolicyData { + return CONF.RefreshPolicyDataMap[refreshId] +} + +func GetRefreshPolicyDataMap() map[int32]*RefreshPolicyData { + return CONF.RefreshPolicyDataMap +} diff --git a/gdconf/scene_lua_config.go b/gdconf/scene_lua_config.go index c2ab8119..25cc085c 100644 --- a/gdconf/scene_lua_config.go +++ b/gdconf/scene_lua_config.go @@ -54,21 +54,22 @@ type BlockRange struct { } type Group struct { - Id int32 `json:"id"` - RefreshId int32 `json:"refresh_id"` - Area int32 `json:"area"` - Pos *Vector `json:"pos"` - DynamicLoad bool `json:"dynamic_load"` - IsReplaceable *Replaceable `json:"is_replaceable"` - MonsterMap map[int32]*Monster `json:"-"` // 怪物 - NpcMap map[int32]*Npc `json:"-"` // NPC - GadgetMap map[int32]*Gadget `json:"-"` // 物件 - RegionMap map[int32]*Region `json:"-"` // 区域 - TriggerMap map[string]*Trigger `json:"-"` // 触发器 - GroupInitConfig *GroupInitConfig `json:"-"` // 初始化配置 - SuiteMap map[int32]*Suite `json:"-"` // 小组配置 - LuaStr string `json:"-"` // LUA原始字符串缓存 - LuaState *lua.LState `json:"-"` // LUA虚拟机实例 + Id int32 `json:"id"` + RefreshId int32 `json:"refresh_id"` + Area int32 `json:"area"` + Pos *Vector `json:"pos"` + DynamicLoad bool `json:"dynamic_load"` + IsReplaceable *Replaceable `json:"is_replaceable"` + MonsterMap map[int32]*Monster `json:"-"` // 怪物 + NpcMap map[int32]*Npc `json:"-"` // NPC + GadgetMap map[int32]*Gadget `json:"-"` // 物件 + RegionMap map[int32]*Region `json:"-"` // 区域 + TriggerMap map[string]*Trigger `json:"-"` // 触发器 + VariableMap map[string]*Variable `json:"-"` // 变量 + GroupInitConfig *GroupInitConfig `json:"-"` // 初始化配置 + SuiteMap map[int32]*Suite `json:"-"` // 小组配置 + LuaStr string `json:"-"` // LUA原始字符串缓存 + LuaState *lua.LState `json:"-"` // LUA虚拟机实例 } type GroupInitConfig struct { @@ -91,6 +92,7 @@ type Monster struct { Level int32 `json:"level"` AreaId int32 `json:"area_id"` DropTag string `json:"drop_tag"` // 关联MonsterDropData表 + IsOneOff bool `json:"isOneoff"` } type Npc struct { @@ -112,6 +114,8 @@ type Gadget struct { State int32 `json:"state"` VisionLevel int32 `json:"vision_level"` DropTag string `json:"drop_tag"` + IsOneOff bool `json:"isOneoff"` + ChestDropId int32 `json:"chest_drop_id"` } type Region struct { @@ -135,6 +139,13 @@ type Trigger struct { TriggerCount int32 `json:"trigger_count"` } +type Variable struct { + ConfigId int32 `json:"config_id"` + Name string `json:"name"` + Value int32 `json:"value"` + NoRefresh bool `json:"no_refresh"` +} + type SuiteLuaTable struct { MonsterConfigIdList any `json:"monsters"` // 怪物 GadgetConfigIdList any `json:"gadgets"` // 物件 @@ -231,6 +242,18 @@ func (g *GameDataConfig) loadGroup(group *Group, block *Block, sceneId int32, bl for _, trigger := range triggerList { group.TriggerMap[trigger.Name] = trigger } + // variables + variableList := make([]*Variable, 0) + ok = getSceneLuaConfigTable[*[]*Variable](luaState, "variables", &variableList) + if !ok { + logger.Error("get variables object error, sceneId: %v, blockId: %v, groupId: %v", sceneId, blockId, groupId) + luaState.Close() + return + } + group.VariableMap = make(map[string]*Variable) + for _, variable := range variableList { + group.VariableMap[variable.Name] = variable + } // suites suiteLuaTableList := make([]*SuiteLuaTable, 0) ok = getSceneLuaConfigTable[*[]*SuiteLuaTable](luaState, "suites", &suiteLuaTableList) diff --git a/gs/game/game_command_gm.go b/gs/game/game_command_gm.go index 86a5496f..9a8a512e 100644 --- a/gs/game/game_command_gm.go +++ b/gs/game/game_command_gm.go @@ -26,21 +26,24 @@ func (g *GMCmd) GMTeleportPlayer(userId, sceneId, dungeonId uint32, posX, posY, return } dungeonPointId := uint32(0) - end := false - for _, pointData := range gdconf.GetScenePointMapBySceneId(int32(sceneId)) { - if end { - break - } - for _, v := range pointData.DungeonIds { - if uint32(v) == dungeonId { - dungeonPointId = uint32(pointData.Id) - end = true + if dungeonId != 0 { + end := false + for _, pointData := range gdconf.GetScenePointMapBySceneId(int32(sceneId)) { + if end { break } + for _, v := range pointData.DungeonIds { + if uint32(v) == dungeonId { + dungeonPointId = uint32(pointData.Id) + end = true + break + } + } + } + if dungeonPointId == 0 { + logger.Error("dungeon pointid not found, dungeonId: %v, uid: %v", dungeonId, userId) + return } - } - if dungeonPointId == 0 { - return } GAME.TeleportPlayer( player, @@ -230,17 +233,17 @@ func (g *GMCmd) GMUnlockAllPoint(userId uint32, sceneId uint32) { } // GMCreateGadget 在玩家附近创建物件实体 -func (g *GMCmd) GMCreateGadget(userId uint32, posX, posY, posZ float64, gadgetId, itemId, count uint32) { +func (g *GMCmd) GMCreateGadget(userId uint32, posX, posY, posZ float64, gadgetId uint32) { player := USER_MANAGER.GetOnlineUser(userId) if player == nil { logger.Error("player is nil, uid: %v", userId) return } - GAME.CreateDropGadget(player, &model.Vector{ + GAME.CreateGadget(player, &model.Vector{ X: posX, Y: posY, Z: posZ, - }, gadgetId, itemId, count) + }, gadgetId, nil) } // 系统级GM指令 diff --git a/gs/game/game_tick_manager.go b/gs/game/game_tick_manager.go index 26610b6e..890edf9e 100644 --- a/gs/game/game_tick_manager.go +++ b/gs/game/game_tick_manager.go @@ -119,10 +119,10 @@ func (t *TickManager) userTimerHandle(userId uint32, action int, data []any) { case UserTimerActionTest: logger.Debug("UserTimerActionTest, data: %v, uid: %v", data[0], userId) case UserTimerActionLuaCreateMonster: - logger.Debug("UserTimerActionLuaCreateMonster, groupId: %v, monsterConfigId: %v, uid: %v", data[0], data[1], userId) + logger.Debug("UserTimerActionLuaCreateMonster, groupId: %v, configId: %v, uid: %v", data[0], data[1], userId) groupId := data[0].(uint32) - monsterConfigId := data[1].(uint32) - GAME.AddSceneGroupMonster(player, groupId, monsterConfigId) + configId := data[1].(uint32) + GAME.AddSceneGroupMonster(player, groupId, configId) } } diff --git a/gs/game/game_world_scene.go b/gs/game/game_world_scene.go index 329dc653..f3e3a88b 100644 --- a/gs/game/game_world_scene.go +++ b/gs/game/game_world_scene.go @@ -5,7 +5,6 @@ import ( "time" "hk4e/common/constant" - "hk4e/gdconf" "hk4e/gs/model" "hk4e/pkg/logger" "hk4e/protocol/proto" @@ -304,80 +303,19 @@ func (s *Scene) GetEntity(entityId uint32) *Entity { return s.entityMap[entityId] } -func (s *Scene) AddGroupSuiteMonster(groupId uint32, suiteId uint8, monsterConfigId uint32) uint32 { - group, exist := s.groupMap[groupId] - if !exist { - logger.Error("group not exist, groupId: %v", groupId) - return 0 - } - suite, exist := group.suiteMap[suiteId] - if !exist { - logger.Error("suite not exist, suiteId: %v", suiteId) - return 0 - } - groupConfig := gdconf.GetSceneGroup(int32(groupId)) - if groupConfig == nil { - logger.Error("get scene group config is nil, groupId: %v", groupId) - return 0 - } - monsterConfig, exist := groupConfig.MonsterMap[int32(monsterConfigId)] - if !exist { - logger.Error("monster config not exist, monsterConfigId: %v", monsterConfigId) - return 0 - } - entityId := s.createConfigEntity(uint32(groupConfig.Id), monsterConfig) - entity := s.GetEntity(entityId) - suite.entityMap[entityId] = entity - return entityId -} - -func (s *Scene) AddGroupSuite(groupId uint32, suiteId uint8) { - groupConfig := gdconf.GetSceneGroup(int32(groupId)) - if groupConfig == nil { - logger.Error("get scene group config is nil, groupId: %v", groupId) - return - } - suiteConfig, exist := groupConfig.SuiteMap[int32(suiteId)] - if !exist { - logger.Error("invalid suiteId: %v", suiteId) - return - } - suite := &Suite{ - entityMap: make(map[uint32]*Entity), - } - for _, monsterConfigId := range suiteConfig.MonsterConfigIdList { - monsterConfig, exist := groupConfig.MonsterMap[monsterConfigId] - if !exist { - logger.Error("monster config not exist, monsterConfigId: %v", monsterConfigId) - continue - } - entityId := s.createConfigEntity(uint32(groupConfig.Id), monsterConfig) - entity := s.GetEntity(entityId) - suite.entityMap[entityId] = entity - } - for _, gadgetConfigId := range suiteConfig.GadgetConfigIdList { - gadgetConfig, exist := groupConfig.GadgetMap[gadgetConfigId] - if !exist { - logger.Error("gadget config not exist, gadgetConfigId: %v", gadgetConfigId) - continue - } - entityId := s.createConfigEntity(uint32(groupConfig.Id), gadgetConfig) - entity := s.GetEntity(entityId) - suite.entityMap[entityId] = entity - } - for _, npcConfig := range groupConfig.NpcMap { - entityId := s.createConfigEntity(uint32(groupConfig.Id), npcConfig) - entity := s.GetEntity(entityId) - suite.entityMap[entityId] = entity - } +func (s *Scene) AddGroupSuite(groupId uint32, suiteId uint8, entityMap map[uint32]*Entity) { group, exist := s.groupMap[groupId] if !exist { group = &Group{ + id: groupId, suiteMap: make(map[uint8]*Suite), } s.groupMap[groupId] = group } - group.suiteMap[suiteId] = suite + group.suiteMap[suiteId] = &Suite{ + id: suiteId, + entityMap: entityMap, + } } func (s *Scene) RemoveGroupSuite(groupId uint32, suiteId uint8) { @@ -397,90 +335,20 @@ func (s *Scene) RemoveGroupSuite(groupId uint32, suiteId uint8) { delete(group.suiteMap, suiteId) } -// 创建配置表里的实体 -func (s *Scene) createConfigEntity(groupId uint32, entityConfig any) uint32 { - switch entityConfig.(type) { - case *gdconf.Monster: - monster := entityConfig.(*gdconf.Monster) - return s.CreateEntityMonster( - &model.Vector{X: float64(monster.Pos.X), Y: float64(monster.Pos.Y), Z: float64(monster.Pos.Z)}, - &model.Vector{X: float64(monster.Rot.X), Y: float64(monster.Rot.Y), Z: float64(monster.Rot.Z)}, - uint32(monster.MonsterId), uint8(monster.Level), getTempFightPropMap(), uint32(monster.ConfigId), groupId, - ) - case *gdconf.Npc: - npc := entityConfig.(*gdconf.Npc) - return s.CreateEntityNpc( - &model.Vector{X: float64(npc.Pos.X), Y: float64(npc.Pos.Y), Z: float64(npc.Pos.Z)}, - &model.Vector{X: float64(npc.Rot.X), Y: float64(npc.Rot.Y), Z: float64(npc.Rot.Z)}, - uint32(npc.NpcId), 0, 0, 0, uint32(npc.ConfigId), groupId, - ) - case *gdconf.Gadget: - gadget := entityConfig.(*gdconf.Gadget) - // 70500000并不是实际的物件id 根据节点类型对应采集物配置表 - if gadget.PointType != 0 && gadget.GadgetId == 70500000 { - gatherDataConfig := gdconf.GetGatherDataByPointType(gadget.PointType) - if gatherDataConfig == nil { - return 0 - } - return s.CreateEntityGadgetNormal( - &model.Vector{X: float64(gadget.Pos.X), Y: float64(gadget.Pos.Y), Z: float64(gadget.Pos.Z)}, - &model.Vector{X: float64(gadget.Rot.X), Y: float64(gadget.Rot.Y), Z: float64(gadget.Rot.Z)}, - uint32(gatherDataConfig.GadgetId), - uint32(constant.GADGET_STATE_DEFAULT), - &GadgetNormalEntity{ - isDrop: false, - itemId: uint32(gatherDataConfig.ItemId), - count: 1, - }, - uint32(gadget.ConfigId), - groupId, - ) - } else { - return s.CreateEntityGadgetNormal( - &model.Vector{X: float64(gadget.Pos.X), Y: float64(gadget.Pos.Y), Z: float64(gadget.Pos.Z)}, - &model.Vector{X: float64(gadget.Rot.X), Y: float64(gadget.Rot.Y), Z: float64(gadget.Rot.Z)}, - uint32(gadget.GadgetId), - uint32(gadget.State), - new(GadgetNormalEntity), - uint32(gadget.ConfigId), - groupId, - ) - } - default: - return 0 - } -} - -// TODO 临时写死 -func getTempFightPropMap() map[uint32]float32 { - fpm := map[uint32]float32{ - constant.FIGHT_PROP_BASE_ATTACK: float32(50.0), - constant.FIGHT_PROP_CUR_ATTACK: float32(50.0), - constant.FIGHT_PROP_BASE_DEFENSE: float32(500.0), - constant.FIGHT_PROP_CUR_DEFENSE: float32(500.0), - constant.FIGHT_PROP_BASE_HP: float32(50.0), - constant.FIGHT_PROP_CUR_HP: float32(50.0), - constant.FIGHT_PROP_MAX_HP: float32(50.0), - constant.FIGHT_PROP_PHYSICAL_SUB_HURT: float32(0.1), - constant.FIGHT_PROP_ICE_SUB_HURT: float32(0.1), - constant.FIGHT_PROP_FIRE_SUB_HURT: float32(0.1), - constant.FIGHT_PROP_ELEC_SUB_HURT: float32(0.1), - constant.FIGHT_PROP_WIND_SUB_HURT: float32(0.1), - constant.FIGHT_PROP_ROCK_SUB_HURT: float32(0.1), - constant.FIGHT_PROP_GRASS_SUB_HURT: float32(0.1), - constant.FIGHT_PROP_WATER_SUB_HURT: float32(0.1), - } - return fpm -} - type Group struct { + id uint32 suiteMap map[uint8]*Suite } type Suite struct { + id uint8 entityMap map[uint32]*Entity } +func (g *Group) GetId() uint32 { + return g.id +} + func (g *Group) GetSuiteById(suiteId uint8) *Suite { return g.suiteMap[suiteId] } @@ -521,6 +389,10 @@ func (g *Group) DestroyEntity(entityId uint32) { } } +func (s *Suite) GetId() uint8 { + return s.id +} + func (s *Suite) GetEntityById(entityId uint32) *Entity { return s.entityMap[entityId] } diff --git a/gs/game/lua_func.go b/gs/game/lua_func.go index 199b3ccd..b7127476 100644 --- a/gs/game/lua_func.go +++ b/gs/game/lua_func.go @@ -110,10 +110,20 @@ func RegLuaScriptLibFunc() { gdconf.RegScriptLibFunc("BeginCameraSceneLook", BeginCameraSceneLook) gdconf.RegScriptLibFunc("GetGroupMonsterCount", GetGroupMonsterCount) gdconf.RegScriptLibFunc("ChangeGroupGadget", ChangeGroupGadget) + gdconf.RegScriptLibFunc("GetGadgetStateByConfigId", GetGadgetStateByConfigId) gdconf.RegScriptLibFunc("SetGadgetStateByConfigId", SetGadgetStateByConfigId) gdconf.RegScriptLibFunc("MarkPlayerAction", MarkPlayerAction) gdconf.RegScriptLibFunc("AddQuestProgress", AddQuestProgress) gdconf.RegScriptLibFunc("CreateMonster", CreateMonster) + gdconf.RegScriptLibFunc("CreateGadget", CreateGadget) + gdconf.RegScriptLibFunc("KillEntityByConfigId", KillEntityByConfigId) + gdconf.RegScriptLibFunc("AddExtraGroupSuite", AddExtraGroupSuite) + gdconf.RegScriptLibFunc("GetGroupVariableValue", GetGroupVariableValue) + gdconf.RegScriptLibFunc("GetGroupVariableValueByGroup", GetGroupVariableValueByGroup) + gdconf.RegScriptLibFunc("SetGroupVariableValue", SetGroupVariableValue) + gdconf.RegScriptLibFunc("SetGroupVariableValueByGroup", SetGroupVariableValueByGroup) + gdconf.RegScriptLibFunc("ChangeGroupVariableValue", ChangeGroupVariableValue) + gdconf.RegScriptLibFunc("ChangeGroupVariableValueByGroup", ChangeGroupVariableValueByGroup) } func GetEntityType(luaState *lua.LState) int { @@ -185,6 +195,7 @@ func BeginCameraSceneLook(luaState *lua.LState) int { ntf := new(proto.BeginCameraSceneLookNotify) gdconf.ParseLuaTableToObject(cameraLockInfo, ntf) GAME.SendMsg(cmd.BeginCameraSceneLookNotify, player.PlayerID, player.ClientSeq, ntf) + logger.Debug("BeginCameraSceneLook, ntf: %v, uid: %v", ntf, player.PlayerID) luaState.Push(lua.LNumber(0)) return 1 } @@ -244,6 +255,44 @@ func ChangeGroupGadget(luaState *lua.LState) int { return 1 } +func GetGadgetStateByConfigId(luaState *lua.LState) int { + ctx, ok := luaState.Get(1).(*lua.LTable) + if !ok { + luaState.Push(lua.LNumber(-1)) + return 1 + } + player := GetContextPlayer(ctx, luaState) + if player == nil { + luaState.Push(lua.LNumber(-1)) + return 1 + } + groupId := luaState.ToInt(2) + configId := luaState.ToInt(3) + world := WORLD_MANAGER.GetWorldByID(player.WorldId) + if world == nil { + luaState.Push(lua.LNumber(-1)) + return 1 + } + scene := world.GetSceneById(player.SceneId) + group := scene.GetGroupById(uint32(groupId)) + if group == nil { + luaState.Push(lua.LNumber(-1)) + return 1 + } + entity := group.GetEntityByConfigId(uint32(configId)) + if entity == nil { + luaState.Push(lua.LNumber(-1)) + return 1 + } + if entity.GetEntityType() != constant.ENTITY_TYPE_GADGET { + luaState.Push(lua.LNumber(-1)) + return 1 + } + gadgetEntity := entity.GetGadgetEntity() + luaState.Push(lua.LNumber(gadgetEntity.GetGadgetState())) + return 1 +} + func SetGadgetStateByConfigId(luaState *lua.LState) int { ctx, ok := luaState.Get(1).(*lua.LTable) if !ok { @@ -304,7 +353,7 @@ func AddQuestProgress(luaState *lua.LState) int { return 1 } -type CreateMonsterInfo struct { +type LuaTableParam struct { ConfigId int32 `json:"config_id"` DelayTime int32 `json:"delay_time"` } @@ -325,15 +374,252 @@ func CreateMonster(luaState *lua.LState) int { luaState.Push(lua.LNumber(-1)) return 1 } - createMonsterInfoTable, ok := luaState.Get(2).(*lua.LTable) + luaTable, ok := luaState.Get(2).(*lua.LTable) if !ok { luaState.Push(lua.LNumber(-1)) return 1 } - createMonsterInfo := new(CreateMonsterInfo) - gdconf.ParseLuaTableToObject[*CreateMonsterInfo](createMonsterInfoTable, createMonsterInfo) - TICK_MANAGER.CreateUserTimer(player.PlayerID, UserTimerActionLuaCreateMonster, uint32(createMonsterInfo.DelayTime), - uint32(groupId), uint32(createMonsterInfo.ConfigId)) + luaTableParam := new(LuaTableParam) + gdconf.ParseLuaTableToObject[*LuaTableParam](luaTable, luaTableParam) + TICK_MANAGER.CreateUserTimer(player.PlayerID, UserTimerActionLuaCreateMonster, uint32(luaTableParam.DelayTime), + uint32(groupId), uint32(luaTableParam.ConfigId)) + luaState.Push(lua.LNumber(0)) + return 1 +} + +func CreateGadget(luaState *lua.LState) int { + ctx, ok := luaState.Get(1).(*lua.LTable) + if !ok { + luaState.Push(lua.LNumber(-1)) + return 1 + } + player := GetContextPlayer(ctx, luaState) + if player == nil { + luaState.Push(lua.LNumber(-1)) + return 1 + } + groupId, ok := luaState.GetField(ctx, "groupId").(lua.LNumber) + if !ok { + luaState.Push(lua.LNumber(-1)) + return 1 + } + luaTable, ok := luaState.Get(2).(*lua.LTable) + if !ok { + luaState.Push(lua.LNumber(-1)) + return 1 + } + luaTableParam := new(LuaTableParam) + gdconf.ParseLuaTableToObject[*LuaTableParam](luaTable, luaTableParam) + groupConfig := gdconf.GetSceneGroup(int32(groupId)) + if groupConfig == nil { + luaState.Push(lua.LNumber(-1)) + return 1 + } + gadget := groupConfig.GadgetMap[luaTableParam.ConfigId] + if gadget == nil { + luaState.Push(lua.LNumber(-1)) + return 1 + } + GAME.CreateGadget(player, &model.Vector{X: float64(gadget.Pos.X), Y: float64(gadget.Pos.Y), Z: float64(gadget.Pos.Z)}, + uint32(gadget.GadgetId), nil) + luaState.Push(lua.LNumber(0)) + return 1 +} + +func KillEntityByConfigId(luaState *lua.LState) int { + ctx, ok := luaState.Get(1).(*lua.LTable) + if !ok { + luaState.Push(lua.LNumber(-1)) + return 1 + } + player := GetContextPlayer(ctx, luaState) + if player == nil { + luaState.Push(lua.LNumber(-1)) + return 1 + } + groupId, ok := luaState.GetField(ctx, "groupId").(lua.LNumber) + if !ok { + luaState.Push(lua.LNumber(-1)) + return 1 + } + luaTable, ok := luaState.Get(2).(*lua.LTable) + if !ok { + luaState.Push(lua.LNumber(-1)) + return 1 + } + luaTableParam := new(LuaTableParam) + gdconf.ParseLuaTableToObject[*LuaTableParam](luaTable, luaTableParam) + world := WORLD_MANAGER.GetWorldByID(player.WorldId) + if world == nil { + luaState.Push(lua.LNumber(-1)) + return 1 + } + scene := world.GetSceneById(player.SceneId) + group := scene.GetGroupById(uint32(groupId)) + entity := group.GetEntityByConfigId(uint32(luaTableParam.ConfigId)) + GAME.KillEntity(player, scene, entity.GetId(), proto.PlayerDieType_PLAYER_DIE_NONE) + luaState.Push(lua.LNumber(0)) + return 1 +} + +func AddExtraGroupSuite(luaState *lua.LState) int { + ctx, ok := luaState.Get(1).(*lua.LTable) + if !ok { + luaState.Push(lua.LNumber(-1)) + return 1 + } + player := GetContextPlayer(ctx, luaState) + if player == nil { + luaState.Push(lua.LNumber(-1)) + return 1 + } + groupId := luaState.ToInt(2) + suiteId := luaState.ToInt(3) + GAME.AddSceneGroupSuite(player, uint32(groupId), uint8(suiteId)) + luaState.Push(lua.LNumber(0)) + return 1 +} + +func GetGroupVariableValue(luaState *lua.LState) int { + ctx, ok := luaState.Get(1).(*lua.LTable) + if !ok { + luaState.Push(lua.LNumber(-1)) + return 1 + } + player := GetContextPlayer(ctx, luaState) + if player == nil { + luaState.Push(lua.LNumber(-1)) + return 1 + } + groupId, ok := luaState.GetField(ctx, "groupId").(lua.LNumber) + if !ok { + luaState.Push(lua.LNumber(-1)) + return 1 + } + name := luaState.ToString(2) + dbWorld := player.GetDbWorld() + dbScene := dbWorld.GetSceneById(player.SceneId) + dbSceneGroup := dbScene.GetSceneGroupById(uint32(groupId)) + value := dbSceneGroup.GetVariableByName(name) + luaState.Push(lua.LNumber(value)) + return 1 +} + +func GetGroupVariableValueByGroup(luaState *lua.LState) int { + ctx, ok := luaState.Get(1).(*lua.LTable) + if !ok { + luaState.Push(lua.LNumber(-1)) + return 1 + } + player := GetContextPlayer(ctx, luaState) + if player == nil { + luaState.Push(lua.LNumber(-1)) + return 1 + } + name := luaState.ToString(2) + groupId := luaState.ToInt(3) + dbWorld := player.GetDbWorld() + dbScene := dbWorld.GetSceneById(player.SceneId) + dbSceneGroup := dbScene.GetSceneGroupById(uint32(groupId)) + value := dbSceneGroup.GetVariableByName(name) + luaState.Push(lua.LNumber(value)) + return 1 +} + +func SetGroupVariableValue(luaState *lua.LState) int { + ctx, ok := luaState.Get(1).(*lua.LTable) + if !ok { + luaState.Push(lua.LNumber(-1)) + return 1 + } + player := GetContextPlayer(ctx, luaState) + if player == nil { + luaState.Push(lua.LNumber(-1)) + return 1 + } + groupId, ok := luaState.GetField(ctx, "groupId").(lua.LNumber) + if !ok { + luaState.Push(lua.LNumber(-1)) + return 1 + } + name := luaState.ToString(2) + value := luaState.ToInt(3) + dbWorld := player.GetDbWorld() + dbScene := dbWorld.GetSceneById(player.SceneId) + dbSceneGroup := dbScene.GetSceneGroupById(uint32(groupId)) + dbSceneGroup.SetVariable(name, int32(value)) + luaState.Push(lua.LNumber(0)) + return 1 +} + +func SetGroupVariableValueByGroup(luaState *lua.LState) int { + ctx, ok := luaState.Get(1).(*lua.LTable) + if !ok { + luaState.Push(lua.LNumber(-1)) + return 1 + } + player := GetContextPlayer(ctx, luaState) + if player == nil { + luaState.Push(lua.LNumber(-1)) + return 1 + } + name := luaState.ToString(2) + value := luaState.ToInt(3) + groupId := luaState.ToInt(4) + dbWorld := player.GetDbWorld() + dbScene := dbWorld.GetSceneById(player.SceneId) + dbSceneGroup := dbScene.GetSceneGroupById(uint32(groupId)) + dbSceneGroup.SetVariable(name, int32(value)) + luaState.Push(lua.LNumber(0)) + return 1 +} + +func ChangeGroupVariableValue(luaState *lua.LState) int { + ctx, ok := luaState.Get(1).(*lua.LTable) + if !ok { + luaState.Push(lua.LNumber(-1)) + return 1 + } + player := GetContextPlayer(ctx, luaState) + if player == nil { + luaState.Push(lua.LNumber(-1)) + return 1 + } + groupId, ok := luaState.GetField(ctx, "groupId").(lua.LNumber) + if !ok { + luaState.Push(lua.LNumber(-1)) + return 1 + } + name := luaState.ToString(2) + change := luaState.ToInt(3) + dbWorld := player.GetDbWorld() + dbScene := dbWorld.GetSceneById(player.SceneId) + dbSceneGroup := dbScene.GetSceneGroupById(uint32(groupId)) + value := dbSceneGroup.GetVariableByName(name) + dbSceneGroup.SetVariable(name, value+int32(change)) + luaState.Push(lua.LNumber(0)) + return 1 +} + +func ChangeGroupVariableValueByGroup(luaState *lua.LState) int { + ctx, ok := luaState.Get(1).(*lua.LTable) + if !ok { + luaState.Push(lua.LNumber(-1)) + return 1 + } + player := GetContextPlayer(ctx, luaState) + if player == nil { + luaState.Push(lua.LNumber(-1)) + return 1 + } + name := luaState.ToString(2) + change := luaState.ToInt(3) + groupId := luaState.ToInt(4) + dbWorld := player.GetDbWorld() + dbScene := dbWorld.GetSceneById(player.SceneId) + dbSceneGroup := dbScene.GetSceneGroupById(uint32(groupId)) + value := dbSceneGroup.GetVariableByName(name) + dbSceneGroup.SetVariable(name, value+int32(change)) luaState.Push(lua.LNumber(0)) return 1 } diff --git a/gs/game/lua_trigger.go b/gs/game/lua_trigger.go index 5132de51..caa706d1 100644 --- a/gs/game/lua_trigger.go +++ b/gs/game/lua_trigger.go @@ -8,8 +8,12 @@ import ( "hk4e/pkg/logger" ) -// SceneRegionTriggerCheck 场景区域触发器检测 -func (g *Game) SceneRegionTriggerCheck(player *model.Player, scene *Scene, oldPos *model.Vector, newPos *model.Vector, entityId uint32) { +func forEachPlayerSceneGroup(player *model.Player, handleFunc func(suiteConfig *gdconf.Suite, groupConfig *gdconf.Group)) { + world := WORLD_MANAGER.GetWorldByID(player.WorldId) + if world == nil { + return + } + scene := world.GetSceneById(player.SceneId) for groupId, group := range scene.GetAllGroup() { groupConfig := gdconf.GetSceneGroup(int32(groupId)) if groupConfig == nil { @@ -18,133 +22,12 @@ func (g *Game) SceneRegionTriggerCheck(player *model.Player, scene *Scene, oldPo } for suiteId := range group.GetAllSuite() { suiteConfig := groupConfig.SuiteMap[int32(suiteId)] - for _, regionConfigId := range suiteConfig.RegionConfigIdList { - regionConfig := groupConfig.RegionMap[regionConfigId] - if regionConfig == nil { - continue - } - shape := alg.NewShape() - switch uint8(regionConfig.Shape) { - case constant.REGION_SHAPE_SPHERE: - shape.NewSphere(&alg.Vector3{X: regionConfig.Pos.X, Y: regionConfig.Pos.Y, Z: regionConfig.Pos.Z}, regionConfig.Radius) - case constant.REGION_SHAPE_CUBIC: - shape.NewCubic(&alg.Vector3{X: regionConfig.Pos.X, Y: regionConfig.Pos.Y, Z: regionConfig.Pos.Z}, - &alg.Vector3{X: regionConfig.Size.X, Y: regionConfig.Size.Y, Z: regionConfig.Size.Z}) - case constant.REGION_SHAPE_CYLINDER: - shape.NewCylinder(&alg.Vector3{X: regionConfig.Pos.X, Y: regionConfig.Pos.Y, Z: regionConfig.Pos.Z}, - regionConfig.Radius, regionConfig.Height) - case constant.REGION_SHAPE_POLYGON: - vector2PointArray := make([]*alg.Vector2, 0) - for _, vector := range regionConfig.PointArray { - // z就是y - vector2PointArray = append(vector2PointArray, &alg.Vector2{X: vector.X, Z: vector.Y}) - } - shape.NewPolygon(&alg.Vector3{X: regionConfig.Pos.X, Y: regionConfig.Pos.Y, Z: regionConfig.Pos.Z}, - vector2PointArray, regionConfig.Height) - } - oldPosInRegion := shape.Contain(&alg.Vector3{X: float32(oldPos.X), Y: float32(oldPos.Y), Z: float32(oldPos.Z)}) - newPosInRegion := shape.Contain(&alg.Vector3{X: float32(newPos.X), Y: float32(newPos.Y), Z: float32(newPos.Z)}) - if !oldPosInRegion && newPosInRegion { - logger.Debug("player enter region: %v, uid: %v", regionConfig, player.PlayerID) - for _, triggerName := range suiteConfig.TriggerNameList { - triggerConfig := groupConfig.TriggerMap[triggerName] - if triggerConfig.Event != constant.LUA_EVENT_ENTER_REGION { - continue - } - if triggerConfig.Condition != "" { - cond := CallLuaFunc(groupConfig.GetLuaState(), triggerConfig.Condition, - &LuaCtx{uid: player.PlayerID}, - &LuaEvt{param1: regionConfig.ConfigId, targetEntityId: entityId}) - if !cond { - continue - } - } - logger.Debug("scene group trigger fire, trigger: %+v, uid: %v", triggerConfig, player.PlayerID) - if triggerConfig.Action != "" { - logger.Debug("scene group trigger do action, trigger: %+v, uid: %v", triggerConfig, player.PlayerID) - ok := CallLuaFunc(groupConfig.GetLuaState(), triggerConfig.Action, - &LuaCtx{uid: player.PlayerID}, - &LuaEvt{}) - if !ok { - logger.Error("trigger action fail, trigger: %+v, uid: %v", triggerConfig, player.PlayerID) - } - } - for _, triggerDataConfig := range gdconf.GetTriggerDataMap() { - if triggerDataConfig.TriggerName == triggerConfig.Name { - g.TriggerQuest(player, constant.QUEST_FINISH_COND_TYPE_TRIGGER_FIRE, "", triggerDataConfig.TriggerId) - } - } - } - } else if oldPosInRegion && !newPosInRegion { - logger.Debug("player leave region: %v, uid: %v", regionConfig, player.PlayerID) - for _, triggerName := range suiteConfig.TriggerNameList { - triggerConfig := groupConfig.TriggerMap[triggerName] - if triggerConfig.Event != constant.LUA_EVENT_LEAVE_REGION { - continue - } - if triggerConfig.Condition != "" { - cond := CallLuaFunc(groupConfig.GetLuaState(), triggerConfig.Condition, - &LuaCtx{uid: player.PlayerID}, - &LuaEvt{param1: regionConfig.ConfigId, targetEntityId: entityId}) - if !cond { - continue - } - } - logger.Debug("scene group trigger fire, trigger: %+v, uid: %v", triggerConfig, player.PlayerID) - if triggerConfig.Action != "" { - logger.Debug("scene group trigger do action, trigger: %+v, uid: %v", triggerConfig, player.PlayerID) - ok := CallLuaFunc(groupConfig.GetLuaState(), triggerConfig.Action, - &LuaCtx{uid: player.PlayerID}, - &LuaEvt{}) - if !ok { - logger.Error("trigger action fail, trigger: %+v, uid: %v", triggerConfig, player.PlayerID) - } - } - } - } - } + handleFunc(suiteConfig, groupConfig) } } } -// MonsterDieTriggerCheck 怪物死亡触发器检测 -func (g *Game) MonsterDieTriggerCheck(player *model.Player, groupId uint32, group *Group) { - groupConfig := gdconf.GetSceneGroup(int32(groupId)) - if groupConfig == nil { - logger.Error("get group config is nil, groupId: %v, uid: %v", groupId, player.PlayerID) - return - } - for suiteId := range group.GetAllSuite() { - suiteConfig := groupConfig.SuiteMap[int32(suiteId)] - for _, triggerName := range suiteConfig.TriggerNameList { - triggerConfig := groupConfig.TriggerMap[triggerName] - if triggerConfig.Event != constant.LUA_EVENT_ANY_MONSTER_DIE { - continue - } - if triggerConfig.Condition != "" { - cond := CallLuaFunc(groupConfig.GetLuaState(), triggerConfig.Condition, - &LuaCtx{uid: player.PlayerID, groupId: groupId}, - &LuaEvt{}) - if !cond { - continue - } - } - logger.Debug("scene group trigger fire, trigger: %+v, uid: %v", triggerConfig, player.PlayerID) - if triggerConfig.Action != "" { - logger.Debug("scene group trigger do action, trigger: %+v, uid: %v", triggerConfig, player.PlayerID) - ok := CallLuaFunc(groupConfig.GetLuaState(), triggerConfig.Action, - &LuaCtx{uid: player.PlayerID, groupId: groupId}, - &LuaEvt{}) - if !ok { - logger.Error("trigger action fail, trigger: %+v, uid: %v", triggerConfig, player.PlayerID) - } - } - } - } -} - -// QuestStartTriggerCheck 任务开始触发器检测 -func (g *Game) QuestStartTriggerCheck(player *model.Player, questId uint32) { +func forEachPlayerSceneGroupTrigger(player *model.Player, handleFunc func(triggerConfig *gdconf.Trigger, groupConfig *gdconf.Group)) { world := WORLD_MANAGER.GetWorldByID(player.WorldId) if world == nil { return @@ -160,28 +43,244 @@ func (g *Game) QuestStartTriggerCheck(player *model.Player, questId uint32) { suiteConfig := groupConfig.SuiteMap[int32(suiteId)] for _, triggerName := range suiteConfig.TriggerNameList { triggerConfig := groupConfig.TriggerMap[triggerName] - if triggerConfig.Event != constant.LUA_EVENT_QUEST_START { - continue - } - if triggerConfig.Condition != "" { - cond := CallLuaFunc(groupConfig.GetLuaState(), triggerConfig.Condition, - &LuaCtx{uid: player.PlayerID}, - &LuaEvt{param1: int32(questId)}) - if !cond { - continue - } - } - logger.Debug("scene group trigger fire, trigger: %+v, uid: %v", triggerConfig, player.PlayerID) - if triggerConfig.Action != "" { - logger.Debug("scene group trigger do action, trigger: %+v, uid: %v", triggerConfig, player.PlayerID) - ok := CallLuaFunc(groupConfig.GetLuaState(), triggerConfig.Action, - &LuaCtx{uid: player.PlayerID, groupId: groupId}, - &LuaEvt{}) - if !ok { - logger.Error("trigger action fail, trigger: %+v, uid: %v", triggerConfig, player.PlayerID) - } - } + handleFunc(triggerConfig, groupConfig) } } } } + +func forEachGroupTrigger(player *model.Player, group *Group, handleFunc func(triggerConfig *gdconf.Trigger, groupConfig *gdconf.Group)) { + groupConfig := gdconf.GetSceneGroup(int32(group.GetId())) + if groupConfig == nil { + logger.Error("get group config is nil, groupId: %v, uid: %v", group.GetId(), player.PlayerID) + return + } + for suiteId := range group.GetAllSuite() { + suiteConfig := groupConfig.SuiteMap[int32(suiteId)] + for _, triggerName := range suiteConfig.TriggerNameList { + triggerConfig := groupConfig.TriggerMap[triggerName] + handleFunc(triggerConfig, groupConfig) + } + } +} + +// SceneRegionTriggerCheck 场景区域触发器检测 +func (g *Game) SceneRegionTriggerCheck(player *model.Player, oldPos *model.Vector, newPos *model.Vector, entityId uint32) { + forEachPlayerSceneGroup(player, func(suiteConfig *gdconf.Suite, groupConfig *gdconf.Group) { + for _, regionConfigId := range suiteConfig.RegionConfigIdList { + regionConfig := groupConfig.RegionMap[regionConfigId] + if regionConfig == nil { + continue + } + shape := alg.NewShape() + switch uint8(regionConfig.Shape) { + case constant.REGION_SHAPE_SPHERE: + shape.NewSphere(&alg.Vector3{X: regionConfig.Pos.X, Y: regionConfig.Pos.Y, Z: regionConfig.Pos.Z}, regionConfig.Radius) + case constant.REGION_SHAPE_CUBIC: + shape.NewCubic(&alg.Vector3{X: regionConfig.Pos.X, Y: regionConfig.Pos.Y, Z: regionConfig.Pos.Z}, + &alg.Vector3{X: regionConfig.Size.X, Y: regionConfig.Size.Y, Z: regionConfig.Size.Z}) + case constant.REGION_SHAPE_CYLINDER: + shape.NewCylinder(&alg.Vector3{X: regionConfig.Pos.X, Y: regionConfig.Pos.Y, Z: regionConfig.Pos.Z}, + regionConfig.Radius, regionConfig.Height) + case constant.REGION_SHAPE_POLYGON: + vector2PointArray := make([]*alg.Vector2, 0) + for _, vector := range regionConfig.PointArray { + // z就是y + vector2PointArray = append(vector2PointArray, &alg.Vector2{X: vector.X, Z: vector.Y}) + } + shape.NewPolygon(&alg.Vector3{X: regionConfig.Pos.X, Y: regionConfig.Pos.Y, Z: regionConfig.Pos.Z}, + vector2PointArray, regionConfig.Height) + } + oldPosInRegion := shape.Contain(&alg.Vector3{X: float32(oldPos.X), Y: float32(oldPos.Y), Z: float32(oldPos.Z)}) + newPosInRegion := shape.Contain(&alg.Vector3{X: float32(newPos.X), Y: float32(newPos.Y), Z: float32(newPos.Z)}) + if !oldPosInRegion && newPosInRegion { + logger.Debug("player enter region: %v, uid: %v", regionConfig, player.PlayerID) + for _, triggerName := range suiteConfig.TriggerNameList { + triggerConfig := groupConfig.TriggerMap[triggerName] + if triggerConfig.Event != constant.LUA_EVENT_ENTER_REGION { + continue + } + if triggerConfig.Condition != "" { + cond := CallLuaFunc(groupConfig.GetLuaState(), triggerConfig.Condition, + &LuaCtx{uid: player.PlayerID, groupId: uint32(groupConfig.Id)}, + &LuaEvt{param1: regionConfig.ConfigId, targetEntityId: entityId}) + if !cond { + continue + } + } + logger.Debug("scene group trigger fire, trigger: %+v, uid: %v", triggerConfig, player.PlayerID) + if triggerConfig.Action != "" { + logger.Debug("scene group trigger do action, trigger: %+v, uid: %v", triggerConfig, player.PlayerID) + ok := CallLuaFunc(groupConfig.GetLuaState(), triggerConfig.Action, + &LuaCtx{uid: player.PlayerID, groupId: uint32(groupConfig.Id)}, + &LuaEvt{}) + if !ok { + logger.Error("trigger action fail, trigger: %+v, uid: %v", triggerConfig, player.PlayerID) + } + } + for _, triggerDataConfig := range gdconf.GetTriggerDataMap() { + if triggerDataConfig.TriggerName == triggerConfig.Name { + g.TriggerQuest(player, constant.QUEST_FINISH_COND_TYPE_TRIGGER_FIRE, "", triggerDataConfig.TriggerId) + } + } + } + } else if oldPosInRegion && !newPosInRegion { + logger.Debug("player leave region: %v, uid: %v", regionConfig, player.PlayerID) + for _, triggerName := range suiteConfig.TriggerNameList { + triggerConfig := groupConfig.TriggerMap[triggerName] + if triggerConfig.Event != constant.LUA_EVENT_LEAVE_REGION { + continue + } + if triggerConfig.Condition != "" { + cond := CallLuaFunc(groupConfig.GetLuaState(), triggerConfig.Condition, + &LuaCtx{uid: player.PlayerID, groupId: uint32(groupConfig.Id)}, + &LuaEvt{param1: regionConfig.ConfigId, targetEntityId: entityId}) + if !cond { + continue + } + } + logger.Debug("scene group trigger fire, trigger: %+v, uid: %v", triggerConfig, player.PlayerID) + if triggerConfig.Action != "" { + logger.Debug("scene group trigger do action, trigger: %+v, uid: %v", triggerConfig, player.PlayerID) + ok := CallLuaFunc(groupConfig.GetLuaState(), triggerConfig.Action, + &LuaCtx{uid: player.PlayerID, groupId: uint32(groupConfig.Id)}, + &LuaEvt{}) + if !ok { + logger.Error("trigger action fail, trigger: %+v, uid: %v", triggerConfig, player.PlayerID) + } + } + } + } + } + }) +} + +// MonsterDieTriggerCheck 怪物死亡触发器检测 +func (g *Game) MonsterDieTriggerCheck(player *model.Player, group *Group) { + forEachGroupTrigger(player, group, func(triggerConfig *gdconf.Trigger, groupConfig *gdconf.Group) { + if triggerConfig.Event != constant.LUA_EVENT_ANY_MONSTER_DIE { + return + } + if triggerConfig.Condition != "" { + cond := CallLuaFunc(groupConfig.GetLuaState(), triggerConfig.Condition, + &LuaCtx{uid: player.PlayerID, groupId: uint32(groupConfig.Id)}, + &LuaEvt{}) + if !cond { + return + } + } + if triggerConfig.Action != "" { + logger.Debug("scene group trigger do action, trigger: %+v, uid: %v", triggerConfig, player.PlayerID) + ok := CallLuaFunc(groupConfig.GetLuaState(), triggerConfig.Action, + &LuaCtx{uid: player.PlayerID, groupId: uint32(groupConfig.Id)}, + &LuaEvt{}) + if !ok { + logger.Error("trigger action fail, trigger: %+v, uid: %v", triggerConfig, player.PlayerID) + } + } + }) +} + +// QuestStartTriggerCheck 任务开始触发器检测 +func (g *Game) QuestStartTriggerCheck(player *model.Player, questId uint32) { + forEachPlayerSceneGroupTrigger(player, func(triggerConfig *gdconf.Trigger, groupConfig *gdconf.Group) { + if triggerConfig.Event != constant.LUA_EVENT_QUEST_START { + return + } + if triggerConfig.Condition != "" { + cond := CallLuaFunc(groupConfig.GetLuaState(), triggerConfig.Condition, + &LuaCtx{uid: player.PlayerID, groupId: uint32(groupConfig.Id)}, + &LuaEvt{param1: int32(questId)}) + if !cond { + return + } + } + if triggerConfig.Action != "" { + logger.Debug("scene group trigger do action, trigger: %+v, uid: %v", triggerConfig, player.PlayerID) + ok := CallLuaFunc(groupConfig.GetLuaState(), triggerConfig.Action, + &LuaCtx{uid: player.PlayerID, groupId: uint32(groupConfig.Id)}, + &LuaEvt{}) + if !ok { + logger.Error("trigger action fail, trigger: %+v, uid: %v", triggerConfig, player.PlayerID) + } + } + }) +} + +// GadgetCreateTriggerCheck 物件创建触发器检测 +func (g *Game) GadgetCreateTriggerCheck(player *model.Player, group *Group, configId uint32) { + forEachGroupTrigger(player, group, func(triggerConfig *gdconf.Trigger, groupConfig *gdconf.Group) { + if triggerConfig.Event != constant.LUA_EVENT_GADGET_CREATE { + return + } + if triggerConfig.Condition != "" { + cond := CallLuaFunc(groupConfig.GetLuaState(), triggerConfig.Condition, + &LuaCtx{uid: player.PlayerID, groupId: uint32(groupConfig.Id)}, + &LuaEvt{param1: int32(configId)}) + if !cond { + return + } + } + if triggerConfig.Action != "" { + logger.Debug("scene group trigger do action, trigger: %+v, uid: %v", triggerConfig, player.PlayerID) + ok := CallLuaFunc(groupConfig.GetLuaState(), triggerConfig.Action, + &LuaCtx{uid: player.PlayerID, groupId: uint32(groupConfig.Id)}, + &LuaEvt{}) + if !ok { + logger.Error("trigger action fail, trigger: %+v, uid: %v", triggerConfig, player.PlayerID) + } + } + }) +} + +// GadgetStateChangeTriggerCheck 物件状态变更触发器检测 +func (g *Game) GadgetStateChangeTriggerCheck(player *model.Player, group *Group, configId uint32, state uint8) { + forEachGroupTrigger(player, group, func(triggerConfig *gdconf.Trigger, groupConfig *gdconf.Group) { + if triggerConfig.Event != constant.LUA_EVENT_GADGET_STATE_CHANGE { + return + } + if triggerConfig.Condition != "" { + cond := CallLuaFunc(groupConfig.GetLuaState(), triggerConfig.Condition, + &LuaCtx{uid: player.PlayerID, groupId: uint32(groupConfig.Id)}, + &LuaEvt{param1: int32(state), param2: int32(configId)}) + if !cond { + return + } + } + if triggerConfig.Action != "" { + logger.Debug("scene group trigger do action, trigger: %+v, uid: %v", triggerConfig, player.PlayerID) + ok := CallLuaFunc(groupConfig.GetLuaState(), triggerConfig.Action, + &LuaCtx{uid: player.PlayerID, groupId: uint32(groupConfig.Id)}, + &LuaEvt{}) + if !ok { + logger.Error("trigger action fail, trigger: %+v, uid: %v", triggerConfig, player.PlayerID) + } + } + }) +} + +// GroupLoadTriggerCheck 场景组加载触发器检测 +func (g *Game) GroupLoadTriggerCheck(player *model.Player, group *Group) { + forEachGroupTrigger(player, group, func(triggerConfig *gdconf.Trigger, groupConfig *gdconf.Group) { + if triggerConfig.Event != constant.LUA_EVENT_GROUP_LOAD { + return + } + if triggerConfig.Condition != "" { + cond := CallLuaFunc(groupConfig.GetLuaState(), triggerConfig.Condition, + &LuaCtx{uid: player.PlayerID, groupId: uint32(groupConfig.Id)}, + &LuaEvt{}) + if !cond { + return + } + } + if triggerConfig.Action != "" { + logger.Debug("scene group trigger do action, trigger: %+v, uid: %v", triggerConfig, player.PlayerID) + ok := CallLuaFunc(groupConfig.GetLuaState(), triggerConfig.Action, + &LuaCtx{uid: player.PlayerID, groupId: uint32(groupConfig.Id)}, + &LuaEvt{}) + if !ok { + logger.Error("trigger action fail, trigger: %+v, uid: %v", triggerConfig, player.PlayerID) + } + } + }) +} diff --git a/gs/game/player_base.go b/gs/game/player_base.go index 3d244d53..40a6779b 100644 --- a/gs/game/player_base.go +++ b/gs/game/player_base.go @@ -19,7 +19,7 @@ func (g *Game) HandlePlayerExpAdd(userId uint32) { for { playerLevel := player.PropertiesMap[constant.PLAYER_PROP_PLAYER_LEVEL] // 读取玩家等级配置表 - playerLevelConfig := gdconf.GetPlayerLevelDataById(int32(playerLevel)) + playerLevelConfig := gdconf.GetPlayerLevelDataByLevel(int32(playerLevel)) if playerLevelConfig == nil { // 获取不到代表已经到达最大等级 break diff --git a/gs/game/player_fight_sync.go b/gs/game/player_fight_sync.go index d22db754..ce0eb45e 100644 --- a/gs/game/player_fight_sync.go +++ b/gs/game/player_fight_sync.go @@ -167,7 +167,7 @@ func (g *Game) CombatInvocationsNotify(player *model.Player, payloadMsg pb.Messa Z: float64(motionInfo.Pos.Z), }) // 场景区域触发器检测 - g.SceneRegionTriggerCheck(player, scene, player.Pos, &model.Vector{ + g.SceneRegionTriggerCheck(player, player.Pos, &model.Vector{ X: float64(motionInfo.Pos.X), Y: float64(motionInfo.Pos.Y), Z: float64(motionInfo.Pos.Z), diff --git a/gs/game/player_scene.go b/gs/game/player_scene.go index e1e32524..b0b7cb7d 100644 --- a/gs/game/player_scene.go +++ b/gs/game/player_scene.go @@ -523,27 +523,33 @@ func (g *Game) KillEntity(player *model.Player, scene *Scene, entityId uint32, d } entity.lifeState = constant.LIFE_STATE_DEAD ntf := &proto.LifeStateChangeNotify{ - EntityId: entity.id, - LifeState: uint32(entity.lifeState), + EntityId: entity.GetId(), + LifeState: uint32(entity.GetLifeState()), DieType: dieType, - MoveReliableSeq: entity.lastMoveReliableSeq, + MoveReliableSeq: entity.GetLastMoveReliableSeq(), } g.SendToWorldA(scene.world, cmd.LifeStateChangeNotify, 0, ntf) - g.RemoveSceneEntityNotifyBroadcast(scene, proto.VisionType_VISION_DIE, []uint32{entity.id}) + g.RemoveSceneEntityNotifyBroadcast(scene, proto.VisionType_VISION_DIE, []uint32{entity.GetId()}) // 删除实体 scene.DestroyEntity(entity.GetId()) - group := scene.GetGroupById(entity.groupId) + group := scene.GetGroupById(entity.GetGroupId()) if group == nil { return } + + dbWorld := player.GetDbWorld() + dbScene := dbWorld.GetSceneById(scene.GetId()) + dbSceneGroup := dbScene.GetSceneGroupById(entity.GetGroupId()) + dbSceneGroup.AddKill(entity.GetConfigId()) + group.DestroyEntity(entity.GetId()) // 怪物死亡触发器检测 if entity.GetEntityType() == constant.ENTITY_TYPE_MONSTER { - g.MonsterDieTriggerCheck(player, entity.GetGroupId(), group) + g.MonsterDieTriggerCheck(player, group) } } -// ChangeGadgetState 改变物件实体状态 +// ChangeGadgetState 改变物件状态 func (g *Game) ChangeGadgetState(player *model.Player, entityId uint32, state uint32) { world := WORLD_MANAGER.GetWorldByID(player.WorldId) if world == nil { @@ -568,6 +574,21 @@ func (g *Game) ChangeGadgetState(player *model.Player, entityId uint32, state ui IsEnableInteract: true, } g.SendMsg(cmd.GadgetStateNotify, player.PlayerID, player.ClientSeq, ntf) + + groupId := entity.GetGroupId() + group := scene.GetGroupById(groupId) + if group == nil { + logger.Error("group not exist, groupId: %v, uid: %v", groupId, player.PlayerID) + return + } + + dbWorld := player.GetDbWorld() + dbScene := dbWorld.GetSceneById(scene.GetId()) + dbSceneGroup := dbScene.GetSceneGroupById(groupId) + dbSceneGroup.ChangeGadgetState(entity.GetConfigId(), uint8(gadgetEntity.GetGadgetState())) + + // 物件状态变更触发器检测 + g.GadgetStateChangeTriggerCheck(player, group, entity.GetConfigId(), uint8(gadgetEntity.GetGadgetState())) } // GetVisionEntity 获取某位置视野内的全部实体 @@ -614,12 +635,31 @@ func (g *Game) AddSceneGroup(player *model.Player, scene *Scene, groupConfig *gd logger.Error("invalid init suite id: %v, uid: %v", initSuiteId, player.PlayerID) return } - scene.AddGroupSuite(uint32(groupConfig.Id), uint8(initSuiteId)) + g.AddSceneGroupSuiteCore(player, scene, uint32(groupConfig.Id), uint8(initSuiteId)) ntf := &proto.GroupSuiteNotify{ GroupMap: make(map[uint32]uint32), } ntf.GroupMap[uint32(groupConfig.Id)] = uint32(initSuiteId) g.SendMsg(cmd.GroupSuiteNotify, player.PlayerID, player.ClientSeq, ntf) + + dbWorld := player.GetDbWorld() + dbScene := dbWorld.GetSceneById(scene.GetId()) + dbSceneGroup := dbScene.GetSceneGroupById(uint32(groupConfig.Id)) + for _, variable := range groupConfig.VariableMap { + exist := dbSceneGroup.CheckVariableExist(variable.Name) + if exist && variable.NoRefresh { + continue + } + dbSceneGroup.SetVariable(variable.Name, variable.Value) + } + + group := scene.GetGroupById(uint32(groupConfig.Id)) + if group == nil { + logger.Error("group not exist, groupId: %v, uid: %v", groupConfig.Id, player.PlayerID) + return + } + // 场景组加载触发器检测 + g.GroupLoadTriggerCheck(player, group) } // RemoveSceneGroup 卸载场景组 @@ -639,6 +679,152 @@ func (g *Game) RemoveSceneGroup(player *model.Player, scene *Scene, groupConfig g.SendMsg(cmd.GroupUnloadNotify, player.PlayerID, player.ClientSeq, ntf) } +func (g *Game) AddSceneGroupSuiteCore(player *model.Player, scene *Scene, groupId uint32, suiteId uint8) { + groupConfig := gdconf.GetSceneGroup(int32(groupId)) + if groupConfig == nil { + logger.Error("get scene group config is nil, groupId: %v", groupId) + return + } + suiteConfig, exist := groupConfig.SuiteMap[int32(suiteId)] + if !exist { + logger.Error("invalid suiteId: %v", suiteId) + return + } + entityMap := make(map[uint32]*Entity) + for _, monsterConfigId := range suiteConfig.MonsterConfigIdList { + monsterConfig, exist := groupConfig.MonsterMap[monsterConfigId] + if !exist { + logger.Error("monster config not exist, monsterConfigId: %v", monsterConfigId) + continue + } + entityId := g.CreateConfigEntity(player, scene, uint32(groupConfig.Id), monsterConfig) + if entityId == 0 { + continue + } + entity := scene.GetEntity(entityId) + entityMap[entityId] = entity + } + for _, gadgetConfigId := range suiteConfig.GadgetConfigIdList { + gadgetConfig, exist := groupConfig.GadgetMap[gadgetConfigId] + if !exist { + logger.Error("gadget config not exist, gadgetConfigId: %v", gadgetConfigId) + continue + } + entityId := g.CreateConfigEntity(player, scene, uint32(groupConfig.Id), gadgetConfig) + if entityId == 0 { + continue + } + entity := scene.GetEntity(entityId) + entityMap[entityId] = entity + } + for _, npcConfig := range groupConfig.NpcMap { + entityId := g.CreateConfigEntity(player, scene, uint32(groupConfig.Id), npcConfig) + if entityId == 0 { + continue + } + entity := scene.GetEntity(entityId) + entityMap[entityId] = entity + } + scene.AddGroupSuite(groupId, suiteId, entityMap) + group := scene.GetGroupById(groupId) + for _, gadgetConfigId := range suiteConfig.GadgetConfigIdList { + // 物件创建触发器检测 + GAME.GadgetCreateTriggerCheck(player, group, uint32(gadgetConfigId)) + } +} + +// CreateConfigEntity 创建配置表里的实体 +func (g *Game) CreateConfigEntity(player *model.Player, scene *Scene, groupId uint32, entityConfig any) uint32 { + dbWorld := player.GetDbWorld() + dbScene := dbWorld.GetSceneById(scene.GetId()) + dbSceneGroup := dbScene.GetSceneGroupById(groupId) + switch entityConfig.(type) { + case *gdconf.Monster: + monster := entityConfig.(*gdconf.Monster) + isKill := dbSceneGroup.CheckIsKill(uint32(monster.ConfigId)) + if isKill { + return 0 + } + return scene.CreateEntityMonster( + &model.Vector{X: float64(monster.Pos.X), Y: float64(monster.Pos.Y), Z: float64(monster.Pos.Z)}, + &model.Vector{X: float64(monster.Rot.X), Y: float64(monster.Rot.Y), Z: float64(monster.Rot.Z)}, + uint32(monster.MonsterId), uint8(monster.Level), getTempFightPropMap(), uint32(monster.ConfigId), groupId, + ) + case *gdconf.Npc: + npc := entityConfig.(*gdconf.Npc) + return scene.CreateEntityNpc( + &model.Vector{X: float64(npc.Pos.X), Y: float64(npc.Pos.Y), Z: float64(npc.Pos.Z)}, + &model.Vector{X: float64(npc.Rot.X), Y: float64(npc.Rot.Y), Z: float64(npc.Rot.Z)}, + uint32(npc.NpcId), 0, 0, 0, uint32(npc.ConfigId), groupId, + ) + case *gdconf.Gadget: + gadget := entityConfig.(*gdconf.Gadget) + isKill := dbSceneGroup.CheckIsKill(uint32(gadget.ConfigId)) + if isKill { + return 0 + } + // 70500000并不是实际的物件id 根据节点类型对应采集物配置表 + if gadget.PointType != 0 && gadget.GadgetId == 70500000 { + gatherDataConfig := gdconf.GetGatherDataByPointType(gadget.PointType) + if gatherDataConfig == nil { + return 0 + } + return scene.CreateEntityGadgetNormal( + &model.Vector{X: float64(gadget.Pos.X), Y: float64(gadget.Pos.Y), Z: float64(gadget.Pos.Z)}, + &model.Vector{X: float64(gadget.Rot.X), Y: float64(gadget.Rot.Y), Z: float64(gadget.Rot.Z)}, + uint32(gatherDataConfig.GadgetId), + uint32(constant.GADGET_STATE_DEFAULT), + &GadgetNormalEntity{ + isDrop: false, + itemId: uint32(gatherDataConfig.ItemId), + count: 1, + }, + uint32(gadget.ConfigId), + groupId, + ) + } else { + state := uint8(gadget.State) + exist := dbSceneGroup.CheckGadgetExist(uint32(gadget.ConfigId)) + if exist { + state = dbSceneGroup.GetGadgetState(uint32(gadget.ConfigId)) + } + return scene.CreateEntityGadgetNormal( + &model.Vector{X: float64(gadget.Pos.X), Y: float64(gadget.Pos.Y), Z: float64(gadget.Pos.Z)}, + &model.Vector{X: float64(gadget.Rot.X), Y: float64(gadget.Rot.Y), Z: float64(gadget.Rot.Z)}, + uint32(gadget.GadgetId), + uint32(state), + new(GadgetNormalEntity), + uint32(gadget.ConfigId), + groupId, + ) + } + default: + return 0 + } +} + +// TODO 临时写死 +func getTempFightPropMap() map[uint32]float32 { + fpm := map[uint32]float32{ + constant.FIGHT_PROP_BASE_ATTACK: float32(50.0), + constant.FIGHT_PROP_CUR_ATTACK: float32(50.0), + constant.FIGHT_PROP_BASE_DEFENSE: float32(500.0), + constant.FIGHT_PROP_CUR_DEFENSE: float32(500.0), + constant.FIGHT_PROP_BASE_HP: float32(50.0), + constant.FIGHT_PROP_CUR_HP: float32(50.0), + constant.FIGHT_PROP_MAX_HP: float32(50.0), + constant.FIGHT_PROP_PHYSICAL_SUB_HURT: float32(0.1), + constant.FIGHT_PROP_ICE_SUB_HURT: float32(0.1), + constant.FIGHT_PROP_FIRE_SUB_HURT: float32(0.1), + constant.FIGHT_PROP_ELEC_SUB_HURT: float32(0.1), + constant.FIGHT_PROP_WIND_SUB_HURT: float32(0.1), + constant.FIGHT_PROP_ROCK_SUB_HURT: float32(0.1), + constant.FIGHT_PROP_GRASS_SUB_HURT: float32(0.1), + constant.FIGHT_PROP_WATER_SUB_HURT: float32(0.1), + } + return fpm +} + // TODO Group和Suite的初始化和加载卸载逻辑还没完全理清 所以现在这里写得略答辩 func (g *Game) AddSceneGroupSuite(player *model.Player, groupId uint32, suiteId uint8) { @@ -657,7 +843,7 @@ func (g *Game) AddSceneGroupSuite(player *model.Player, groupId uint32, suiteId return } scene := world.GetSceneById(player.SceneId) - scene.AddGroupSuite(uint32(groupConfig.Id), suiteId) + g.AddSceneGroupSuiteCore(player, scene, groupId, suiteId) ntf := &proto.GroupSuiteNotify{ GroupMap: make(map[uint32]uint32), } @@ -672,7 +858,7 @@ func (g *Game) AddSceneGroupSuite(player *model.Player, groupId uint32, suiteId g.AddSceneEntityNotify(player, proto.VisionType_VISION_BORN, entityIdList, true, false) } -func (g *Game) AddSceneGroupMonster(player *model.Player, groupId uint32, monsterConfigId uint32) { +func (g *Game) AddSceneGroupMonster(player *model.Player, groupId uint32, configId uint32) { groupConfig := gdconf.GetSceneGroup(int32(groupId)) if groupConfig == nil { logger.Error("get group config is nil, groupId: %v, uid: %v", groupId, player.PlayerID) @@ -690,12 +876,39 @@ func (g *Game) AddSceneGroupMonster(player *model.Player, groupId uint32, monste return } scene := world.GetSceneById(player.SceneId) - entityId := scene.AddGroupSuiteMonster(groupId, uint8(initSuiteId), monsterConfigId) + group, exist := scene.groupMap[groupId] + if !exist { + logger.Error("group not exist, groupId: %v", groupId) + return + } + suite, exist := group.suiteMap[uint8(initSuiteId)] + if !exist { + logger.Error("suite not exist, suiteId: %v", initSuiteId) + return + } + monsterConfig, exist := groupConfig.MonsterMap[int32(configId)] + if !exist { + logger.Error("monster config not exist, configId: %v", configId) + return + } + entityId := g.CreateConfigEntity(player, scene, uint32(groupConfig.Id), monsterConfig) + if entityId == 0 { + return + } + entity := scene.GetEntity(entityId) + suite.entityMap[entityId] = entity g.AddSceneEntityNotify(player, proto.VisionType_VISION_BORN, []uint32{entityId}, true, false) } -// CreateDropGadget 创建掉落物的物件实体 -func (g *Game) CreateDropGadget(player *model.Player, pos *model.Vector, gadgetId, itemId, count uint32) { +// CreateGadget 创建物件实体 +func (g *Game) CreateGadget(player *model.Player, pos *model.Vector, gadgetId uint32, normalEntity *GadgetNormalEntity) { + if normalEntity == nil { + normalEntity = &GadgetNormalEntity{ + isDrop: false, + itemId: 0, + count: 0, + } + } world := WORLD_MANAGER.GetWorldByID(player.WorldId) if world == nil { logger.Error("get world is nil, worldId: %v", player.WorldId) @@ -708,16 +921,21 @@ func (g *Game) CreateDropGadget(player *model.Player, pos *model.Vector, gadgetI pos, rot, gadgetId, constant.GADGET_STATE_DEFAULT, - &GadgetNormalEntity{ - isDrop: true, - itemId: itemId, - count: count, - }, + normalEntity, 0, 0, ) g.AddSceneEntityNotify(player, proto.VisionType_VISION_BORN, []uint32{entityId}, true, false) } +// CreateDropGadget 创建掉落物的物件实体 +func (g *Game) CreateDropGadget(player *model.Player, pos *model.Vector, gadgetId, itemId, count uint32) { + g.CreateGadget(player, pos, gadgetId, &GadgetNormalEntity{ + isDrop: true, + itemId: itemId, + count: count, + }) +} + // 打包相关封装函数 var SceneTransactionSeq uint32 = 0 diff --git a/gs/model/db_world.go b/gs/model/db_world.go index 0b11dd5a..0fa64a0d 100644 --- a/gs/model/db_world.go +++ b/gs/model/db_world.go @@ -1,12 +1,20 @@ package model import ( + "hk4e/common/constant" "hk4e/gdconf" ) +type DbSceneGroup struct { + VariableMap map[string]int32 + KillConfigMap map[uint32]bool + GadgetStateMap map[uint32]uint8 +} + type DbScene struct { SceneId uint32 UnlockPointMap map[uint32]bool + SceneGroupMap map[uint32]*DbSceneGroup } type DbWorld struct { @@ -31,6 +39,7 @@ func NewScene(sceneId uint32) *DbScene { r := &DbScene{ SceneId: sceneId, UnlockPointMap: make(map[uint32]bool), + SceneGroupMap: make(map[uint32]*DbSceneGroup), } return r } @@ -70,3 +79,59 @@ func (s *DbScene) CheckPointUnlock(pointId uint32) bool { _, exist := s.UnlockPointMap[pointId] return exist } + +func (s *DbScene) GetSceneGroupById(groupId uint32) *DbSceneGroup { + dbSceneGroup, exist := s.SceneGroupMap[groupId] + if !exist { + dbSceneGroup = &DbSceneGroup{ + VariableMap: make(map[string]int32), + KillConfigMap: make(map[uint32]bool), + GadgetStateMap: make(map[uint32]uint8), + } + s.SceneGroupMap[groupId] = dbSceneGroup + } + return dbSceneGroup +} + +func (g *DbSceneGroup) GetVariableByName(name string) int32 { + return g.VariableMap[name] +} + +func (g *DbSceneGroup) SetVariable(name string, value int32) { + g.VariableMap[name] = value +} + +func (g *DbSceneGroup) CheckVariableExist(name string) bool { + _, exist := g.VariableMap[name] + return exist +} + +func (g *DbSceneGroup) AddKill(configId uint32) { + g.KillConfigMap[configId] = true +} + +func (g *DbSceneGroup) CheckIsKill(configId uint32) bool { + _, exist := g.KillConfigMap[configId] + return exist +} + +func (g *DbSceneGroup) RemoveAllKill() { + g.KillConfigMap = make(map[uint32]bool) +} + +func (g *DbSceneGroup) GetGadgetState(configId uint32) uint8 { + state, exist := g.GadgetStateMap[configId] + if !exist { + return constant.GADGET_STATE_DEFAULT + } + return state +} + +func (g *DbSceneGroup) ChangeGadgetState(configId uint32, state uint8) { + g.GadgetStateMap[configId] = state +} + +func (g *DbSceneGroup) CheckGadgetExist(configId uint32) bool { + _, exist := g.GadgetStateMap[configId] + return exist +}