From b396bc2e5713692131821864405c6632256639ec Mon Sep 17 00:00:00 2001 From: flswld Date: Mon, 27 Mar 2023 17:11:09 +0800 Subject: [PATCH] =?UTF-8?q?=E5=9C=BA=E6=99=AF=E7=BB=84=E7=AE=A1=E7=90=86?= =?UTF-8?q?=E5=92=8C=E5=9C=BA=E6=99=AF=E5=AE=9E=E4=BD=93=E7=8E=A9=E5=AE=B6?= =?UTF-8?q?=E8=A7=86=E9=87=8E=E7=AE=A1=E7=90=86=E5=88=86=E7=A6=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- gs/game/player_fight_sync.go | 108 +++----- gs/game/player_scene.go | 464 ++++++++++++++++++++--------------- gs/game/player_stamina.go | 29 +-- gs/game/player_team.go | 3 + gs/game/world_manager.go | 41 +--- gs/game/world_scene.go | 68 +---- 6 files changed, 331 insertions(+), 382 deletions(-) diff --git a/gs/game/player_fight_sync.go b/gs/game/player_fight_sync.go index 7df75fab..3a2190d4 100644 --- a/gs/game/player_fight_sync.go +++ b/gs/game/player_fight_sync.go @@ -1,8 +1,6 @@ package game import ( - "math" - "hk4e/common/constant" "hk4e/gdconf" "hk4e/gs/model" @@ -132,13 +130,9 @@ func (g *GameManager) CombatInvocationsNotify(player *model.Player, payloadMsg p } fightProp[constant.FIGHT_PROP_CUR_HP] = currHp } - entityFightPropUpdateNotify := &proto.EntityFightPropUpdateNotify{ - FightPropMap: fightProp, - EntityId: target.GetId(), - } - g.SendToWorldA(world, cmd.EntityFightPropUpdateNotify, player.ClientSeq, entityFightPropUpdateNotify) - if currHp == 0 && target.GetEntityType() != constant.ENTITY_TYPE_AVATAR { - scene.SetEntityLifeState(target, constant.LIFE_STATE_DEAD, proto.PlayerDieType_PLAYER_DIE_GM) + g.EntityFightPropUpdateNotifyBroadcast(world, target) + if currHp == 0 && target.GetEntityType() == constant.ENTITY_TYPE_MONSTER { + g.KillEntity(scene, target.GetId(), proto.PlayerDieType_PLAYER_DIE_GM) } combatData, err := pb.Marshal(evtBeingHitInfo) if err != nil { @@ -258,72 +252,48 @@ func (g *GameManager) AoiPlayerMove(player *model.Player, oldPos *model.Vector, // 跨越了block格子 logger.Debug("player cross grid, oldGid: %v, newGid: %v, uid: %v", oldGid, newGid, player.PlayerID) } - // 旧位置视野范围内的group - oldVisionGroupMap := make(map[uint32]*gdconf.Group) - oldGroupList := aoiManager.GetObjectListByPos(float32(oldPos.X), 0.0, float32(oldPos.Z)) - for groupId, groupAny := range oldGroupList { - groupConfig := groupAny.(*gdconf.Group) - distance2D := math.Sqrt((oldPos.X-float64(groupConfig.Pos.X))*(oldPos.X-float64(groupConfig.Pos.X)) + - (oldPos.Z-float64(groupConfig.Pos.Z))*(oldPos.Z-float64(groupConfig.Pos.Z))) - if distance2D > ENTITY_LOD { - continue - } - if groupConfig.DynamicLoad { - continue - } - oldVisionGroupMap[uint32(groupId)] = groupConfig - } - // 新位置视野范围内的group - newVisionGroupMap := make(map[uint32]*gdconf.Group) - newGroupList := aoiManager.GetObjectListByPos(float32(newPos.X), 0.0, float32(newPos.Z)) - for groupId, groupAny := range newGroupList { - groupConfig := groupAny.(*gdconf.Group) - distance2D := math.Sqrt((newPos.X-float64(groupConfig.Pos.X))*(newPos.X-float64(groupConfig.Pos.X)) + - (newPos.Z-float64(groupConfig.Pos.Z))*(newPos.Z-float64(groupConfig.Pos.Z))) - if distance2D > ENTITY_LOD { - continue - } - if groupConfig.DynamicLoad { - continue - } - newVisionGroupMap[uint32(groupId)] = groupConfig - } - // 消失的场景实体 - delEntityIdList := make([]uint32, 0) - for groupId, groupConfig := range oldVisionGroupMap { - _, exist := newVisionGroupMap[groupId] + // 加载和卸载的group + oldNeighborGroupMap := g.GetNeighborGroup(player.SceneId, oldPos) + newNeighborGroupMap := g.GetNeighborGroup(player.SceneId, newPos) + for groupId, groupConfig := range oldNeighborGroupMap { + _, exist := newNeighborGroupMap[groupId] if exist { continue } - // 旧有新没有的group即为消失的 - group := scene.GetGroupById(groupId) - if group == nil { - continue - } - for _, entity := range group.GetAllEntity() { - delEntityIdList = append(delEntityIdList, entity.GetId()) - } + // 旧有新没有的group即为卸载的 if !world.GetMultiplayer() { // 处理多人世界不同玩家不同位置的group卸载情况 g.RemoveGroup(player, scene, groupConfig) } } - // 出现的场景实体 - addEntityIdList := make([]uint32, 0) - for groupId, groupConfig := range newVisionGroupMap { - _, exist := oldVisionGroupMap[groupId] + for groupId, groupConfig := range newNeighborGroupMap { + _, exist := oldNeighborGroupMap[groupId] if exist { continue } - // 新有旧没有的group即为出现的 + // 新有旧没有的group即为加载的 g.AddSceneGroup(player, scene, groupConfig) - group := scene.GetGroupById(groupId) - if group == nil { + } + // 消失和出现的场景实体 + oldVisionEntityMap := g.GetVisionEntity(scene, oldPos) + newVisionEntityMap := g.GetVisionEntity(scene, newPos) + delEntityIdList := make([]uint32, 0) + for entityId := range oldVisionEntityMap { + _, exist := newVisionEntityMap[entityId] + if exist { continue } - for _, entity := range group.GetAllEntity() { - addEntityIdList = append(addEntityIdList, entity.GetId()) + // 旧有新没有的实体即为消失的 + delEntityIdList = append(delEntityIdList, entityId) + } + addEntityIdList := make([]uint32, 0) + for entityId := range newVisionEntityMap { + _, exist := oldVisionEntityMap[entityId] + if exist { + continue } + // 新有旧没有的实体即为出现的 + addEntityIdList = append(addEntityIdList, entityId) } // 同步客户端消失和出现的场景实体 if len(delEntityIdList) > 0 { @@ -452,11 +422,14 @@ func (g *GameManager) AbilityInvocationsNotify(player *model.Player, payloadMsg if player.SceneLoadState != model.SceneEnterDone { return } + world := WORLD_MANAGER.GetWorldByID(player.WorldId) + if world == nil { + return + } for _, entry := range req.Invokes { // logger.Debug("AbilityInvocationsNotify: %v", entry, player.PlayerID) switch entry.ArgumentType { case proto.AbilityInvokeArgument_ABILITY_META_MODIFIER_CHANGE: - world := WORLD_MANAGER.GetWorldByID(player.WorldId) worldAvatar := world.GetWorldAvatarByEntityId(entry.EntityId) if worldAvatar != nil { for _, ability := range worldAvatar.abilityList { @@ -575,7 +548,6 @@ func (g *GameManager) EvtDoSkillSuccNotify(player *model.Player, payloadMsg pb.M return } logger.Debug("EvtDoSkillSuccNotify: %v", req) - // 处理技能开始的耐力消耗 g.SkillStartStamina(player, req.CasterId, req.SkillId) } @@ -585,7 +557,7 @@ func (g *GameManager) EvtAvatarEnterFocusNotify(player *model.Player, payloadMsg if player.SceneLoadState != model.SceneEnterDone { return } - logger.Debug("EvtAvatarEnterFocusNotify: %v", req) + // logger.Debug("EvtAvatarEnterFocusNotify: %v", req) world := WORLD_MANAGER.GetWorldByID(player.WorldId) g.SendToWorldA(world, cmd.EvtAvatarEnterFocusNotify, player.ClientSeq, req) } @@ -595,7 +567,7 @@ func (g *GameManager) EvtAvatarUpdateFocusNotify(player *model.Player, payloadMs if player.SceneLoadState != model.SceneEnterDone { return } - logger.Debug("EvtAvatarUpdateFocusNotify: %v", req) + // logger.Debug("EvtAvatarUpdateFocusNotify: %v", req) world := WORLD_MANAGER.GetWorldByID(player.WorldId) g.SendToWorldA(world, cmd.EvtAvatarUpdateFocusNotify, player.ClientSeq, req) } @@ -605,7 +577,7 @@ func (g *GameManager) EvtAvatarExitFocusNotify(player *model.Player, payloadMsg if player.SceneLoadState != model.SceneEnterDone { return } - logger.Debug("EvtAvatarExitFocusNotify: %v", req) + // logger.Debug("EvtAvatarExitFocusNotify: %v", req) world := WORLD_MANAGER.GetWorldByID(player.WorldId) g.SendToWorldA(world, cmd.EvtAvatarExitFocusNotify, player.ClientSeq, req) } @@ -615,7 +587,7 @@ func (g *GameManager) EvtEntityRenderersChangedNotify(player *model.Player, payl if player.SceneLoadState != model.SceneEnterDone { return } - logger.Debug("EvtEntityRenderersChangedNotify: %v", req) + // logger.Debug("EvtEntityRenderersChangedNotify: %v", req) world := WORLD_MANAGER.GetWorldByID(player.WorldId) g.SendToWorldA(world, cmd.EvtEntityRenderersChangedNotify, player.ClientSeq, req) } @@ -625,7 +597,7 @@ func (g *GameManager) EvtCreateGadgetNotify(player *model.Player, payloadMsg pb. if player.SceneLoadState != model.SceneEnterDone { return } - logger.Debug("EvtCreateGadgetNotify: %v", req) + // logger.Debug("EvtCreateGadgetNotify: %v", req) world := WORLD_MANAGER.GetWorldByID(player.WorldId) if world == nil { logger.Error("world is nil, WorldId: %v", player.WorldId) @@ -652,7 +624,7 @@ func (g *GameManager) EvtDestroyGadgetNotify(player *model.Player, payloadMsg pb if player.SceneLoadState != model.SceneEnterDone { return } - logger.Debug("EvtDestroyGadgetNotify: %v", req) + // logger.Debug("EvtDestroyGadgetNotify: %v", req) world := WORLD_MANAGER.GetWorldByID(player.WorldId) scene := world.GetSceneById(player.SceneId) if scene == nil { diff --git a/gs/game/player_scene.go b/gs/game/player_scene.go index 9217e90d..82ab2fd8 100644 --- a/gs/game/player_scene.go +++ b/gs/game/player_scene.go @@ -20,7 +20,8 @@ import ( const ( ENTITY_MAX_BATCH_SEND_NUM = 1000 // 单次同步的最大实体数量 - ENTITY_LOD = 100 // 实体加载视野距离 + ENTITY_VISION_DISTANCE = 100 // 实体视野距离 + GROUP_LOAD_DISTANCE = 250 // 场景组加载距离 ) func (g *GameManager) EnterSceneReadyReq(player *model.Player, payloadMsg pb.Message) { @@ -34,35 +35,10 @@ func (g *GameManager) EnterSceneReadyReq(player *model.Player, payloadMsg pb.Mes return } if ctx.OldSceneId != 0 { - aoiManager, exist := WORLD_MANAGER.GetSceneBlockAoiMap()[ctx.OldSceneId] - if !exist { - logger.Error("player scene not exist in aoi, sceneId: %v, uid: %v", ctx.OldSceneId, player.PlayerID) - return - } - objectList := aoiManager.GetObjectListByPos(float32(ctx.OldPos.X), 0.0, float32(ctx.OldPos.Z)) - delEntityIdList := make([]uint32, 0) oldScene := world.GetSceneById(ctx.OldSceneId) - for _, groupAny := range objectList { - groupConfig := groupAny.(*gdconf.Group) - distance2D := math.Sqrt((ctx.OldPos.X-float64(groupConfig.Pos.X))*(ctx.OldPos.X-float64(groupConfig.Pos.X)) + - (ctx.OldPos.Z-float64(groupConfig.Pos.Z))*(ctx.OldPos.Z-float64(groupConfig.Pos.Z))) - if distance2D > ENTITY_LOD { - continue - } - if groupConfig.DynamicLoad { - continue - } - group := oldScene.GetGroupById(uint32(groupConfig.Id)) - if group == nil { - continue - } - for _, entity := range group.GetAllEntity() { - delEntityIdList = append(delEntityIdList, entity.GetId()) - } - if !world.GetMultiplayer() { - // 处理多人世界不同玩家不同位置的group卸载情况 - g.RemoveGroup(player, oldScene, groupConfig) - } + delEntityIdList := make([]uint32, 0) + for entityId := range g.GetVisionEntity(oldScene, ctx.OldPos) { + delEntityIdList = append(delEntityIdList, entityId) } g.RemoveSceneEntityNotifyToPlayer(player, proto.VisionType_VISION_MISS, delEntityIdList) } @@ -314,22 +290,7 @@ func (g *GameManager) EnterSceneDoneReq(player *model.Player, payloadMsg pb.Mess g.AddSceneEntityNotify(player, visionType, []uint32{activeAvatarEntityId}, true, false) // 加载附近的group - aoiManager, exist := WORLD_MANAGER.GetSceneBlockAoiMap()[scene.GetId()] - if !exist { - logger.Error("player scene not exist in aoi, sceneId: %v, uid: %v", scene.GetId(), player.PlayerID) - return - } - objectList := aoiManager.GetObjectListByPos(float32(player.Pos.X), 0.0, float32(player.Pos.Z)) - for _, groupAny := range objectList { - groupConfig := groupAny.(*gdconf.Group) - distance2D := math.Sqrt((player.Pos.X-float64(groupConfig.Pos.X))*(player.Pos.X-float64(groupConfig.Pos.X)) + - (player.Pos.Z-float64(groupConfig.Pos.Z))*(player.Pos.Z-float64(groupConfig.Pos.Z))) - if distance2D > ENTITY_LOD { - continue - } - if groupConfig.DynamicLoad { - continue - } + for _, groupConfig := range g.GetNeighborGroup(scene.GetId(), player.Pos) { g.AddSceneGroup(player, scene, groupConfig) } if player.SceneJump { @@ -337,9 +298,10 @@ func (g *GameManager) EnterSceneDoneReq(player *model.Player, payloadMsg pb.Mess } else { visionType = proto.VisionType_VISION_TRANSPORT } + // 同步客户端视野内的场景实体 entityIdList := make([]uint32, 0) - entityMap := scene.GetAllEntity() - for _, entity := range entityMap { + visionEntityMap := g.GetVisionEntity(scene, player.Pos) + for _, entity := range visionEntityMap { if entity.GetId() == activeAvatarEntityId { continue } @@ -391,8 +353,7 @@ func (g *GameManager) SceneEntityDrownReq(player *model.Player, payloadMsg pb.Me return } scene := world.GetSceneById(player.SceneId) - entity := scene.GetEntity(req.EntityId) - scene.SetEntityLifeState(entity, constant.LIFE_STATE_DEAD, proto.PlayerDieType_PLAYER_DIE_DRAWN) + g.KillEntity(scene, req.EntityId, proto.PlayerDieType_PLAYER_DIE_DRAWN) sceneEntityDrownRsp := &proto.SceneEntityDrownRsp{ EntityId: req.EntityId, @@ -400,143 +361,6 @@ func (g *GameManager) SceneEntityDrownReq(player *model.Player, payloadMsg pb.Me g.SendMsg(cmd.SceneEntityDrownRsp, player.PlayerID, player.ClientSeq, sceneEntityDrownRsp) } -var SceneTransactionSeq uint32 = 0 - -func (g *GameManager) PacketPlayerEnterSceneNotifyLogin(player *model.Player, enterType proto.EnterType) *proto.PlayerEnterSceneNotify { - world := WORLD_MANAGER.GetWorldByID(player.WorldId) - scene := world.GetSceneById(player.SceneId) - if scene == nil { - logger.Error("scene is nil, sceneId: %v", player.SceneId) - return new(proto.PlayerEnterSceneNotify) - } - enterSceneToken := world.AddEnterSceneContext(&EnterSceneContext{ - OldSceneId: 0, - Uid: player.PlayerID, - }) - playerEnterSceneNotify := &proto.PlayerEnterSceneNotify{ - SceneId: player.SceneId, - Pos: &proto.Vector{X: float32(player.Pos.X), Y: float32(player.Pos.Y), Z: float32(player.Pos.Z)}, - SceneBeginTime: uint64(scene.GetSceneCreateTime()), - Type: enterType, - TargetUid: player.PlayerID, - EnterSceneToken: enterSceneToken, - WorldLevel: player.PropertiesMap[constant.PLAYER_PROP_PLAYER_WORLD_LEVEL], - EnterReason: uint32(proto.EnterReason_ENTER_REASON_LOGIN), - IsFirstLoginEnterScene: true, - WorldType: 1, - SceneTagIdList: make([]uint32, 0), - } - SceneTransactionSeq++ - playerEnterSceneNotify.SceneTransaction = strconv.Itoa(int(player.SceneId)) + "-" + - strconv.Itoa(int(player.PlayerID)) + "-" + - strconv.Itoa(int(time.Now().Unix())) + "-" + - strconv.Itoa(int(SceneTransactionSeq)) - for _, sceneTagDataConfig := range gdconf.GetSceneTagDataMap() { - if uint32(sceneTagDataConfig.SceneId) == player.SceneId { - playerEnterSceneNotify.SceneTagIdList = append(playerEnterSceneNotify.SceneTagIdList, uint32(sceneTagDataConfig.SceneTagId)) - } - } - return playerEnterSceneNotify -} - -func (g *GameManager) PacketPlayerEnterSceneNotifyTp( - player *model.Player, - enterType proto.EnterType, - enterReason uint32, - prevSceneId uint32, - prevPos *model.Vector, - dungeonId uint32, -) *proto.PlayerEnterSceneNotify { - return g.PacketPlayerEnterSceneNotifyMp(player, player, enterType, enterReason, prevSceneId, prevPos, dungeonId) -} - -func (g *GameManager) PacketPlayerEnterSceneNotifyMp( - player *model.Player, - targetPlayer *model.Player, - enterType proto.EnterType, - enterReason uint32, - prevSceneId uint32, - prevPos *model.Vector, - dungeonId uint32, -) *proto.PlayerEnterSceneNotify { - world := WORLD_MANAGER.GetWorldByID(player.WorldId) - scene := world.GetSceneById(player.SceneId) - if scene == nil { - logger.Error("scene is nil, sceneId: %v", player.SceneId) - return new(proto.PlayerEnterSceneNotify) - } - enterSceneToken := world.AddEnterSceneContext(&EnterSceneContext{ - OldSceneId: prevSceneId, - OldPos: &model.Vector{ - X: prevPos.X, - Y: prevPos.Y, - Z: prevPos.Z, - }, - OldRot: &model.Vector{ - X: 0, - Y: 0, - Z: 0, - }, - Uid: player.PlayerID, - }) - playerEnterSceneNotify := &proto.PlayerEnterSceneNotify{ - PrevSceneId: prevSceneId, - PrevPos: &proto.Vector{X: float32(prevPos.X), Y: float32(prevPos.Y), Z: float32(prevPos.Z)}, - SceneId: player.SceneId, - Pos: &proto.Vector{X: float32(player.Pos.X), Y: float32(player.Pos.Y), Z: float32(player.Pos.Z)}, - SceneBeginTime: uint64(scene.GetSceneCreateTime()), - Type: enterType, - TargetUid: targetPlayer.PlayerID, - EnterSceneToken: enterSceneToken, - WorldLevel: targetPlayer.PropertiesMap[constant.PLAYER_PROP_PLAYER_WORLD_LEVEL], - EnterReason: enterReason, - WorldType: 1, - DungeonId: dungeonId, - SceneTagIdList: make([]uint32, 0), - } - SceneTransactionSeq++ - playerEnterSceneNotify.SceneTransaction = strconv.Itoa(int(player.SceneId)) + "-" + - strconv.Itoa(int(targetPlayer.PlayerID)) + "-" + - strconv.Itoa(int(time.Now().Unix())) + "-" + - strconv.Itoa(int(SceneTransactionSeq)) - for _, sceneTagDataConfig := range gdconf.GetSceneTagDataMap() { - if uint32(sceneTagDataConfig.SceneId) == player.SceneId { - playerEnterSceneNotify.SceneTagIdList = append(playerEnterSceneNotify.SceneTagIdList, uint32(sceneTagDataConfig.SceneTagId)) - } - } - return playerEnterSceneNotify -} - -func (g *GameManager) AddSceneGroup(player *model.Player, scene *Scene, groupConfig *gdconf.Group) { - initSuiteId := int(groupConfig.GroupInitConfig.Suite) - if initSuiteId < 1 || initSuiteId > len(groupConfig.SuiteList) { - logger.Error("invalid init suite id: %v, uid: %v", initSuiteId, player.PlayerID) - return - } - scene.AddGroupSuite(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) -} - -func (g *GameManager) RemoveGroup(player *model.Player, scene *Scene, groupConfig *gdconf.Group) { - group := scene.GetGroupById(uint32(groupConfig.Id)) - if group == nil { - logger.Error("group not exist, groupId: %v, uid: %v", groupConfig.Id, player.PlayerID) - return - } - for suiteId := range group.GetAllSuite() { - scene.RemoveGroupSuite(uint32(groupConfig.Id), suiteId) - } - ntf := &proto.GroupUnloadNotify{ - GroupList: make([]uint32, 0), - } - ntf.GroupList = append(ntf.GroupList, uint32(groupConfig.Id)) - g.SendMsg(cmd.GroupUnloadNotify, player.PlayerID, player.ClientSeq, ntf) -} - func (g *GameManager) AddSceneEntityNotifyToPlayer(player *model.Player, visionType proto.VisionType, entityList []*proto.SceneEntityInfo) { sceneEntityAppearNotify := &proto.SceneEntityAppearNotify{ AppearType: visionType, @@ -642,16 +466,266 @@ func (g *GameManager) AddSceneEntityNotify(player *model.Player, visionType prot } } -func (g *GameManager) EntityFightPropUpdateNotifyBroadcast(scene *Scene, entity *Entity, fightPropId uint32) { - for _, player := range scene.GetAllPlayer() { - fightProp := entity.GetFightProp() - ntf := &proto.EntityFightPropUpdateNotify{ - FightPropMap: make(map[uint32]float32), - EntityId: entity.GetId(), - } - ntf.FightPropMap[fightPropId] = fightProp[fightPropId] - g.SendMsg(cmd.EntityFightPropUpdateNotify, player.PlayerID, player.ClientSeq, ntf) +func (g *GameManager) EntityFightPropUpdateNotifyBroadcast(world *World, entity *Entity) { + ntf := &proto.EntityFightPropUpdateNotify{ + FightPropMap: entity.GetFightProp(), + EntityId: entity.GetId(), } + g.SendToWorldA(world, cmd.EntityFightPropUpdateNotify, 0, ntf) +} + +func (g *GameManager) KillPlayerAvatar(player *model.Player, dieType proto.PlayerDieType) { + world := WORLD_MANAGER.GetWorldByID(player.WorldId) + if world == nil { + return + } + activeAvatarId := world.GetPlayerActiveAvatarId(player) + worldAvatar := world.GetPlayerWorldAvatar(player, activeAvatarId) + scene := world.GetSceneById(player.SceneId) + avatarEntity := scene.GetEntity(worldAvatar.GetAvatarEntityId()) + + dbAvatar := player.GetDbAvatar() + avatar, exist := dbAvatar.AvatarMap[activeAvatarId] + if !exist { + logger.Error("get active avatar is nil, avatarId: %v", activeAvatarId) + return + } + + avatarEntity.lifeState = constant.LIFE_STATE_DEAD + + ntf := &proto.AvatarLifeStateChangeNotify{ + LifeState: uint32(avatarEntity.lifeState), + AttackTag: "", + DieType: dieType, + ServerBuffList: nil, + MoveReliableSeq: avatarEntity.lastMoveReliableSeq, + SourceEntityId: 0, + AvatarGuid: avatar.Guid, + } + g.SendToWorldA(world, cmd.AvatarLifeStateChangeNotify, 0, ntf) +} + +func (g *GameManager) RevivePlayerAvatar(player *model.Player) { + world := WORLD_MANAGER.GetWorldByID(player.WorldId) + if world == nil { + return + } + activeAvatarId := world.GetPlayerActiveAvatarId(player) + worldAvatar := world.GetPlayerWorldAvatar(player, activeAvatarId) + scene := world.GetSceneById(player.SceneId) + avatarEntity := scene.GetEntity(worldAvatar.GetAvatarEntityId()) + + dbAvatar := player.GetDbAvatar() + avatar, exist := dbAvatar.AvatarMap[activeAvatarId] + if !exist { + logger.Error("get active avatar is nil, avatarId: %v", activeAvatarId) + return + } + + avatar.LifeState = constant.LIFE_STATE_ALIVE + // 设置血量 + avatar.FightPropMap[constant.FIGHT_PROP_CUR_HP] = 110 + g.EntityFightPropUpdateNotifyBroadcast(world, avatarEntity) + + avatarEntity.lifeState = constant.LIFE_STATE_REVIVE + + ntf := &proto.AvatarLifeStateChangeNotify{ + AvatarGuid: avatar.Guid, + LifeState: uint32(avatarEntity.lifeState), + DieType: proto.PlayerDieType_PLAYER_DIE_NONE, + MoveReliableSeq: avatarEntity.lastMoveReliableSeq, + } + g.SendToWorldA(world, cmd.AvatarLifeStateChangeNotify, 0, ntf) +} + +func (g *GameManager) KillEntity(scene *Scene, entityId uint32, dieType proto.PlayerDieType) { + entity := scene.GetEntity(entityId) + entity.lifeState = constant.LIFE_STATE_DEAD + // 设置血量 + entity.fightProp[constant.FIGHT_PROP_CUR_HP] = 0 + g.EntityFightPropUpdateNotifyBroadcast(scene.world, entity) + ntf := &proto.LifeStateChangeNotify{ + EntityId: entity.id, + LifeState: uint32(entity.lifeState), + DieType: dieType, + MoveReliableSeq: entity.lastMoveReliableSeq, + } + g.SendToWorldA(scene.world, cmd.LifeStateChangeNotify, 0, ntf) + + // 删除实体 + scene.DestroyEntity(entity.id) + g.RemoveSceneEntityNotifyBroadcast(scene, proto.VisionType_VISION_DIE, []uint32{entity.id}) +} + +func (g *GameManager) GetVisionEntity(scene *Scene, pos *model.Vector) map[uint32]*Entity { + visionEntity := make(map[uint32]*Entity) + for _, entity := range scene.GetAllEntity() { + if math.Abs(pos.X-entity.pos.X) > ENTITY_VISION_DISTANCE || + math.Abs(pos.Z-entity.pos.Z) > ENTITY_VISION_DISTANCE { + continue + } + visionEntity[entity.GetId()] = entity + } + return visionEntity +} + +func (g *GameManager) GetNeighborGroup(sceneId uint32, pos *model.Vector) map[uint32]*gdconf.Group { + aoiManager, exist := WORLD_MANAGER.GetSceneBlockAoiMap()[sceneId] + if !exist { + logger.Error("scene not exist in aoi, sceneId: %v", sceneId) + return nil + } + objectList := aoiManager.GetObjectListByPos(float32(pos.X), 0.0, float32(pos.Z)) + neighborGroup := make(map[uint32]*gdconf.Group) + for _, groupAny := range objectList { + groupConfig := groupAny.(*gdconf.Group) + if math.Abs(pos.X-float64(groupConfig.Pos.X)) > GROUP_LOAD_DISTANCE || + math.Abs(pos.Z-float64(groupConfig.Pos.Z)) > GROUP_LOAD_DISTANCE { + continue + } + if groupConfig.DynamicLoad { + continue + } + neighborGroup[uint32(groupConfig.Id)] = groupConfig + } + return neighborGroup +} + +func (g *GameManager) AddSceneGroup(player *model.Player, scene *Scene, groupConfig *gdconf.Group) { + initSuiteId := int(groupConfig.GroupInitConfig.Suite) + if initSuiteId < 1 || initSuiteId > len(groupConfig.SuiteList) { + logger.Error("invalid init suite id: %v, uid: %v", initSuiteId, player.PlayerID) + return + } + scene.AddGroupSuite(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) +} + +func (g *GameManager) RemoveGroup(player *model.Player, scene *Scene, groupConfig *gdconf.Group) { + group := scene.GetGroupById(uint32(groupConfig.Id)) + if group == nil { + logger.Error("group not exist, groupId: %v, uid: %v", groupConfig.Id, player.PlayerID) + return + } + for suiteId := range group.GetAllSuite() { + scene.RemoveGroupSuite(uint32(groupConfig.Id), suiteId) + } + ntf := &proto.GroupUnloadNotify{ + GroupList: make([]uint32, 0), + } + ntf.GroupList = append(ntf.GroupList, uint32(groupConfig.Id)) + g.SendMsg(cmd.GroupUnloadNotify, player.PlayerID, player.ClientSeq, ntf) +} + +var SceneTransactionSeq uint32 = 0 + +func (g *GameManager) PacketPlayerEnterSceneNotifyLogin(player *model.Player, enterType proto.EnterType) *proto.PlayerEnterSceneNotify { + world := WORLD_MANAGER.GetWorldByID(player.WorldId) + scene := world.GetSceneById(player.SceneId) + if scene == nil { + logger.Error("scene is nil, sceneId: %v", player.SceneId) + return new(proto.PlayerEnterSceneNotify) + } + enterSceneToken := world.AddEnterSceneContext(&EnterSceneContext{ + OldSceneId: 0, + Uid: player.PlayerID, + }) + playerEnterSceneNotify := &proto.PlayerEnterSceneNotify{ + SceneId: player.SceneId, + Pos: &proto.Vector{X: float32(player.Pos.X), Y: float32(player.Pos.Y), Z: float32(player.Pos.Z)}, + SceneBeginTime: uint64(scene.GetSceneCreateTime()), + Type: enterType, + TargetUid: player.PlayerID, + EnterSceneToken: enterSceneToken, + WorldLevel: player.PropertiesMap[constant.PLAYER_PROP_PLAYER_WORLD_LEVEL], + EnterReason: uint32(proto.EnterReason_ENTER_REASON_LOGIN), + IsFirstLoginEnterScene: true, + WorldType: 1, + SceneTagIdList: make([]uint32, 0), + } + SceneTransactionSeq++ + playerEnterSceneNotify.SceneTransaction = strconv.Itoa(int(player.SceneId)) + "-" + + strconv.Itoa(int(player.PlayerID)) + "-" + + strconv.Itoa(int(time.Now().Unix())) + "-" + + strconv.Itoa(int(SceneTransactionSeq)) + for _, sceneTagDataConfig := range gdconf.GetSceneTagDataMap() { + if uint32(sceneTagDataConfig.SceneId) == player.SceneId { + playerEnterSceneNotify.SceneTagIdList = append(playerEnterSceneNotify.SceneTagIdList, uint32(sceneTagDataConfig.SceneTagId)) + } + } + return playerEnterSceneNotify +} + +func (g *GameManager) PacketPlayerEnterSceneNotifyTp( + player *model.Player, + enterType proto.EnterType, + enterReason uint32, + prevSceneId uint32, + prevPos *model.Vector, + dungeonId uint32, +) *proto.PlayerEnterSceneNotify { + return g.PacketPlayerEnterSceneNotifyMp(player, player, enterType, enterReason, prevSceneId, prevPos, dungeonId) +} + +func (g *GameManager) PacketPlayerEnterSceneNotifyMp( + player *model.Player, + targetPlayer *model.Player, + enterType proto.EnterType, + enterReason uint32, + prevSceneId uint32, + prevPos *model.Vector, + dungeonId uint32, +) *proto.PlayerEnterSceneNotify { + world := WORLD_MANAGER.GetWorldByID(player.WorldId) + scene := world.GetSceneById(player.SceneId) + if scene == nil { + logger.Error("scene is nil, sceneId: %v", player.SceneId) + return new(proto.PlayerEnterSceneNotify) + } + enterSceneToken := world.AddEnterSceneContext(&EnterSceneContext{ + OldSceneId: prevSceneId, + OldPos: &model.Vector{ + X: prevPos.X, + Y: prevPos.Y, + Z: prevPos.Z, + }, + OldRot: &model.Vector{ + X: 0, + Y: 0, + Z: 0, + }, + Uid: player.PlayerID, + }) + playerEnterSceneNotify := &proto.PlayerEnterSceneNotify{ + PrevSceneId: prevSceneId, + PrevPos: &proto.Vector{X: float32(prevPos.X), Y: float32(prevPos.Y), Z: float32(prevPos.Z)}, + SceneId: player.SceneId, + Pos: &proto.Vector{X: float32(player.Pos.X), Y: float32(player.Pos.Y), Z: float32(player.Pos.Z)}, + SceneBeginTime: uint64(scene.GetSceneCreateTime()), + Type: enterType, + TargetUid: targetPlayer.PlayerID, + EnterSceneToken: enterSceneToken, + WorldLevel: targetPlayer.PropertiesMap[constant.PLAYER_PROP_PLAYER_WORLD_LEVEL], + EnterReason: enterReason, + WorldType: 1, + DungeonId: dungeonId, + SceneTagIdList: make([]uint32, 0), + } + SceneTransactionSeq++ + playerEnterSceneNotify.SceneTransaction = strconv.Itoa(int(player.SceneId)) + "-" + + strconv.Itoa(int(targetPlayer.PlayerID)) + "-" + + strconv.Itoa(int(time.Now().Unix())) + "-" + + strconv.Itoa(int(SceneTransactionSeq)) + for _, sceneTagDataConfig := range gdconf.GetSceneTagDataMap() { + if uint32(sceneTagDataConfig.SceneId) == player.SceneId { + playerEnterSceneNotify.SceneTagIdList = append(playerEnterSceneNotify.SceneTagIdList, uint32(sceneTagDataConfig.SceneTagId)) + } + } + return playerEnterSceneNotify } func (g *GameManager) PacketFightPropMapToPbFightPropList(fightPropMap map[uint32]float32) []*proto.FightPropPair { diff --git a/gs/game/player_stamina.go b/gs/game/player_stamina.go index a483bee9..2d2c61c6 100644 --- a/gs/game/player_stamina.go +++ b/gs/game/player_stamina.go @@ -448,18 +448,6 @@ func (g *GameManager) DrownBackHandler(player *model.Player) { return } - world := WORLD_MANAGER.GetWorldByID(player.WorldId) - if world == nil { - return - } - scene := world.GetSceneById(player.SceneId) - activeAvatar := world.GetPlayerWorldAvatar(player, world.GetPlayerActiveAvatarId(player)) - avatarEntity := scene.GetEntity(activeAvatar.GetAvatarEntityId()) - if avatarEntity == nil { - logger.Error("avatar entity is nil, entityId: %v", activeAvatar.GetAvatarEntityId()) - return - } - // TODO 耐力未完成的内容: // 一直溺水回到距离最近的位置 ? // 溺水队伍扣血 @@ -470,7 +458,7 @@ func (g *GameManager) DrownBackHandler(player *model.Player) { // 先传送玩家再设置角色存活否则同时设置会传送前显示角色实体 if player.StaminaInfo.DrownBackDelay > 20 && player.SceneLoadState == model.SceneEnterDone { // 设置角色存活 - scene.SetEntityLifeState(avatarEntity, constant.LIFE_STATE_REVIVE, proto.PlayerDieType_PLAYER_DIE_NONE) + g.RevivePlayerAvatar(player) // 重置溺水返回时间 player.StaminaInfo.DrownBackDelay = 0 } else if player.StaminaInfo.DrownBackDelay == 20 { @@ -500,24 +488,11 @@ func (g *GameManager) HandleDrown(player *model.Player, stamina uint32) { return } - world := WORLD_MANAGER.GetWorldByID(player.WorldId) - scene := world.GetSceneById(player.SceneId) - if scene == nil { - logger.Error("scene is nil, sceneId: %v", player.SceneId) - return - } - activeAvatar := world.GetPlayerWorldAvatar(player, world.GetPlayerActiveAvatarId(player)) - avatarEntity := scene.GetEntity(activeAvatar.GetAvatarEntityId()) - if avatarEntity == nil { - logger.Error("avatar entity is nil, entityId: %v", activeAvatar.GetAvatarEntityId()) - return - } - // 确保玩家正在游泳 if player.StaminaInfo.State == proto.MotionState_MOTION_SWIM_MOVE || player.StaminaInfo.State == proto.MotionState_MOTION_SWIM_DASH { logger.Debug("player drown, curStamina: %v, state: %v", stamina, player.StaminaInfo.State) // 设置角色为死亡 - scene.SetEntityLifeState(avatarEntity, constant.LIFE_STATE_DEAD, proto.PlayerDieType_PLAYER_DIE_DRAWN) + g.KillPlayerAvatar(player, proto.PlayerDieType_PLAYER_DIE_DRAWN) // 溺水返回安全点 计时开始 player.StaminaInfo.DrownBackDelay = 1 } diff --git a/gs/game/player_team.go b/gs/game/player_team.go index 0ff432e1..03a2060b 100644 --- a/gs/game/player_team.go +++ b/gs/game/player_team.go @@ -78,6 +78,9 @@ func (g *GameManager) ChangeAvatarReq(player *model.Player, payloadMsg pb.Messag func (g *GameManager) SetUpAvatarTeamReq(player *model.Player, payloadMsg pb.Message) { req := payloadMsg.(*proto.SetUpAvatarTeamReq) world := WORLD_MANAGER.GetWorldByID(player.WorldId) + if world == nil { + return + } if world.GetMultiplayer() { g.SendError(cmd.SetUpAvatarTeamRsp, player, &proto.SetUpAvatarTeamRsp{}) return diff --git a/gs/game/world_manager.go b/gs/game/world_manager.go index 8f30575f..23c0efb8 100644 --- a/gs/game/world_manager.go +++ b/gs/game/world_manager.go @@ -16,7 +16,7 @@ import ( const ( ENTITY_NUM_UNLIMIT = true // 是否不限制场景内实体数量 - ENTITY_MAX_SEND_NUM = 500 // 场景内最大实体数量 + ENTITY_MAX_SEND_NUM = 1000 // 场景内最大实体数量 MAX_MULTIPLAYER_WORLD_NUM = 10 // 本服务器最大多人世界数量 ) @@ -117,9 +117,7 @@ func (w *WorldManager) LoadSceneBlockAoiMap() { minZ := int16(0) maxZ := int16(0) blockXLen := int16(0) - blockYLen := int16(0) blockZLen := int16(0) - ok := true for _, blockConfig := range sceneLuaConfig.BlockMap { if int16(blockConfig.BlockRange.Min.X) < minX { minX = int16(blockConfig.BlockRange.Min.X) @@ -134,54 +132,37 @@ func (w *WorldManager) LoadSceneBlockAoiMap() { maxZ = int16(blockConfig.BlockRange.Max.Z) } xLen := int16(blockConfig.BlockRange.Max.X - blockConfig.BlockRange.Min.X) - yLen := int16(blockConfig.BlockRange.Max.Y - blockConfig.BlockRange.Min.Y) zLen := int16(blockConfig.BlockRange.Max.Z - blockConfig.BlockRange.Min.Z) if blockXLen == 0 { blockXLen = xLen } else { if blockXLen != xLen { - ok = false - break - } - } - if blockYLen == 0 { - blockYLen = yLen - } else { - if blockYLen != yLen { - ok = false - break + logger.Error("config scene block size not same, scene id: %v", sceneLuaConfig.Id) + return } } if blockZLen == 0 { blockZLen = zLen } else { if blockZLen != zLen { - ok = false - break + logger.Error("config scene block size not same, scene id: %v", sceneLuaConfig.Id) + return } } } - if !ok { - logger.Error("config scene block size not same, scene id: %v", sceneLuaConfig.Id) - continue - } numX := int16(0) - if blockXLen != 0 { + if (maxX-minX) != 0 && blockXLen != 0 { numX = (maxX - minX) / blockXLen } else { - numX = 1 - } - if numX == 0 { - numX = 1 + logger.Error("config scene block size is zero, scene id: %v", sceneLuaConfig.Id) + return } numZ := int16(0) - if blockZLen != 0 { + if (maxZ-minZ) != 0 && blockZLen != 0 { numZ = (maxZ - minZ) / blockZLen } else { - numZ = 1 - } - if numZ == 0 { - numZ = 1 + logger.Error("config scene block size is zero, scene id: %v", sceneLuaConfig.Id) + return } // 将每个block作为aoi格子 并在格子中放入block拥有的所有group aoiManager := alg.NewAoiManager() diff --git a/gs/game/world_scene.go b/gs/game/world_scene.go index 24a9ece9..2110b8b4 100644 --- a/gs/game/world_scene.go +++ b/gs/game/world_scene.go @@ -8,7 +8,6 @@ import ( "hk4e/gdconf" "hk4e/gs/model" "hk4e/pkg/logger" - "hk4e/protocol/cmd" "hk4e/protocol/proto" ) @@ -87,65 +86,6 @@ func (s *Scene) RemovePlayer(player *model.Player) { } } -func (s *Scene) SetEntityLifeState(entity *Entity, lifeState uint16, dieType proto.PlayerDieType) { - if entity.GetEntityType() == constant.ENTITY_TYPE_AVATAR { - // 获取玩家对象 - player := USER_MANAGER.GetOnlineUser(entity.avatarEntity.uid) - if player == nil { - logger.Error("player is nil, uid: %v", entity.avatarEntity.uid) - return - } - // 获取角色 - dbAvatar := player.GetDbAvatar() - avatar, ok := dbAvatar.AvatarMap[entity.avatarEntity.avatarId] - if !ok { - logger.Error("avatar is nil, avatarId: %v", avatar) - return - } - // 设置角色存活状态 - if lifeState == constant.LIFE_STATE_REVIVE { - avatar.LifeState = constant.LIFE_STATE_ALIVE - // 设置血量 - entity.fightProp[constant.FIGHT_PROP_CUR_HP] = 110 - GAME_MANAGER.EntityFightPropUpdateNotifyBroadcast(s, entity, constant.FIGHT_PROP_CUR_HP) - } - - avatarLifeStateChangeNotify := &proto.AvatarLifeStateChangeNotify{ - LifeState: uint32(lifeState), - AttackTag: "", - DieType: dieType, - ServerBuffList: nil, - MoveReliableSeq: entity.lastMoveReliableSeq, - SourceEntityId: 0, - AvatarGuid: avatar.Guid, - } - GAME_MANAGER.SendToWorldA(s.world, cmd.AvatarLifeStateChangeNotify, 0, avatarLifeStateChangeNotify) - } else { - // 设置存活状态 - entity.lifeState = lifeState - - if lifeState == constant.LIFE_STATE_DEAD { - // 设置血量 - entity.fightProp[constant.FIGHT_PROP_CUR_HP] = 0 - GAME_MANAGER.EntityFightPropUpdateNotifyBroadcast(s, entity, constant.FIGHT_PROP_CUR_HP) - } - - lifeStateChangeNotify := &proto.LifeStateChangeNotify{ - EntityId: entity.id, - AttackTag: "", - MoveReliableSeq: entity.lastMoveReliableSeq, - DieType: dieType, - LifeState: uint32(lifeState), - SourceEntityId: 0, - } - GAME_MANAGER.SendToWorldA(s.world, cmd.LifeStateChangeNotify, 0, lifeStateChangeNotify) - - // 删除实体 - s.DestroyEntity(entity.id) - GAME_MANAGER.RemoveSceneEntityNotifyBroadcast(s, proto.VisionType_VISION_DIE, []uint32{entity.id}) - } -} - func (s *Scene) CreateEntityAvatar(player *model.Player, avatarId uint32) uint32 { entityId := s.world.GetNextWorldEntityId(constant.ENTITY_TYPE_AVATAR) dbAvatar := player.GetDbAvatar() @@ -185,8 +125,12 @@ func (s *Scene) CreateEntityWeapon() uint32 { moveState: uint16(proto.MotionState_MOTION_NONE), lastMoveSceneTimeMs: 0, lastMoveReliableSeq: 0, - fightProp: nil, - entityType: constant.ENTITY_TYPE_WEAPON, + fightProp: map[uint32]float32{ + constant.FIGHT_PROP_CUR_HP: math.MaxFloat32, + constant.FIGHT_PROP_MAX_HP: math.MaxFloat32, + constant.FIGHT_PROP_BASE_HP: float32(1), + }, + entityType: constant.ENTITY_TYPE_WEAPON, } s.CreateEntity(entity) return entity.id