From a288892f2696f4cdfddf3cbee28614f8a296ca0b Mon Sep 17 00:00:00 2001 From: UnKownOwO <80520429@qq.com> Date: Tue, 20 Dec 2022 21:32:33 +0800 Subject: [PATCH] =?UTF-8?q?=E6=BA=BA=E6=B0=B4=E4=BC=A0=E9=80=81=E8=87=B3?= =?UTF-8?q?=E5=AE=89=E5=85=A8=E4=BD=8D=E7=BD=AE=E5=88=9D=E6=AD=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- gs/game/route_manager.go | 3 +- gs/game/user_fight_sync.go | 42 +++++++------ gs/game/user_map.go | 1 - gs/game/user_scene.go | 12 ++++ gs/game/user_stamina.go | 90 +++++++++++++++------------- gs/model/player.go | 2 +- gs/model/stamina.go | 4 +- gs/model/vector.go | 7 +++ protocol/cmd/cmd_id_proto_obj_map.go | 4 +- 9 files changed, 102 insertions(+), 63 deletions(-) diff --git a/gs/game/route_manager.go b/gs/game/route_manager.go index 68e8c00b..17879a4c 100644 --- a/gs/game/route_manager.go +++ b/gs/game/route_manager.go @@ -38,7 +38,7 @@ func (r *RouteManager) doRoute(cmdId uint16, userId uint32, clientSeq uint32, pa if player == nil { logger.Error("player is nil, uid: %v", userId) // 临时为了调试便捷搞的重连 生产环境请务必去除 不然新用户会一直重连不能进入 - GAME_MANAGER.ReconnectPlayer(userId) + // GAME_MANAGER.ReconnectPlayer(userId) return } player.ClientSeq = clientSeq @@ -115,6 +115,7 @@ func (r *RouteManager) InitRoute() { r.registerRouter(cmd.EvtDestroyGadgetNotify, GAME_MANAGER.EvtDestroyGadgetNotify) r.registerRouter(cmd.CreateVehicleReq, GAME_MANAGER.CreateVehicleReq) r.registerRouter(cmd.VehicleInteractReq, GAME_MANAGER.VehicleInteractReq) + r.registerRouter(cmd.SceneEntityDrownReq, GAME_MANAGER.SceneEntityDrownReq) } func (r *RouteManager) RouteHandle(netMsg *mq.NetMsg) { diff --git a/gs/game/user_fight_sync.go b/gs/game/user_fight_sync.go index 4b8ef5e8..2b22b58c 100644 --- a/gs/game/user_fight_sync.go +++ b/gs/game/user_fight_sync.go @@ -113,27 +113,35 @@ func (g *GameManager) CombatInvocationsNotify(player *model.Player, payloadMsg p if sceneEntity.avatarEntity != nil { // 玩家实体在移动 // 更新玩家的位置信息 - player.Pos.X = float64(motionInfo.Pos.X) - player.Pos.Y = float64(motionInfo.Pos.Y) - player.Pos.Z = float64(motionInfo.Pos.Z) - player.Rot.X = float64(motionInfo.Rot.X) - player.Rot.Y = float64(motionInfo.Rot.Y) - player.Rot.Z = float64(motionInfo.Rot.Z) + switch player.StaminaInfo.State { + case proto.MotionState_MOTION_STATE_DANGER_RUN, proto.MotionState_MOTION_STATE_RUN, + proto.MotionState_MOTION_STATE_DANGER_STANDBY_MOVE, proto.MotionState_MOTION_STATE_DANGER_STANDBY, proto.MotionState_MOTION_STATE_LADDER_TO_STANDBY, proto.MotionState_MOTION_STATE_STANDBY_MOVE, proto.MotionState_MOTION_STATE_STANDBY, + proto.MotionState_MOTION_STATE_DANGER_WALK, proto.MotionState_MOTION_STATE_WALK, + proto.MotionState_MOTION_STATE_DASH: + // 仅在陆地时更新玩家位置 + player.Pos.X = float64(motionInfo.Pos.X) + player.Pos.Y = float64(motionInfo.Pos.Y) + player.Pos.Z = float64(motionInfo.Pos.Z) + player.Rot.X = float64(motionInfo.Rot.X) + player.Rot.Y = float64(motionInfo.Rot.Y) + player.Rot.Z = float64(motionInfo.Rot.Z) + default: + player.StaminaInfo.ActiveAvatarPos.X = float64(motionInfo.Pos.X) + player.StaminaInfo.ActiveAvatarPos.Y = float64(motionInfo.Pos.Y) + player.StaminaInfo.ActiveAvatarPos.Z = float64(motionInfo.Pos.Z) + } // 处理耐力消耗 g.ImmediateStamina(player, motionInfo.State) } else { - // 非玩家实体在移动 更新场景实体的位置信息 - sceneEntity.pos = &model.Vector{ - X: float64(motionInfo.Pos.X), - Y: float64(motionInfo.Pos.Y), - Z: float64(motionInfo.Pos.Z), - } - sceneEntity.rot = &model.Vector{ - X: float64(motionInfo.Rot.X), - Y: float64(motionInfo.Rot.Y), - Z: float64(motionInfo.Rot.Z), - } + // 非玩家实体在移动 + // 更新场景实体的位置信息 + sceneEntity.pos.X = float64(motionInfo.Pos.X) + sceneEntity.pos.Y = float64(motionInfo.Pos.Y) + sceneEntity.pos.Z = float64(motionInfo.Pos.Z) + sceneEntity.rot.X = float64(motionInfo.Rot.X) + sceneEntity.rot.Y = float64(motionInfo.Rot.Y) + sceneEntity.rot.Z = float64(motionInfo.Rot.Z) // 载具耐力消耗 if sceneEntity.gadgetEntity != nil && sceneEntity.gadgetEntity.gadgetVehicleEntity != nil { // 处理耐力消耗 diff --git a/gs/game/user_map.go b/gs/game/user_map.go index 189726d3..66c520fd 100644 --- a/gs/game/user_map.go +++ b/gs/game/user_map.go @@ -35,7 +35,6 @@ func (g *GameManager) SceneTransToPointReq(player *model.Player, payloadMsg pb.M g.TeleportPlayer(player, uint32(constant.EnterReasonConst.TransPoint), sceneId, pos) sceneTransToPointRsp := &proto.SceneTransToPointRsp{ - Retcode: 0, PointId: req.PointId, SceneId: req.SceneId, } diff --git a/gs/game/user_scene.go b/gs/game/user_scene.go index a8d79243..7f6db32f 100644 --- a/gs/game/user_scene.go +++ b/gs/game/user_scene.go @@ -533,6 +533,18 @@ func (g *GameManager) PacketFightPropMapToPbFightPropList(fightPropMap map[uint3 return fightPropList } +// SceneEntityDrownReq 实体溺水请求 +func (g *GameManager) SceneEntityDrownReq(player *model.Player, payloadMsg pb.Message) { + req := payloadMsg.(*proto.SceneEntityDrownReq) + + logger.Error("entity drown, entityId: %v", req.EntityId) + + // PacketSceneEntityDrownRsp + sceneEntityDrownRsp := new(proto.SceneEntityDrownRsp) + sceneEntityDrownRsp.EntityId = req.EntityId + g.SendMsg(cmd.SceneEntityDrownRsp, player.PlayerID, player.ClientSeq, sceneEntityDrownRsp) +} + func (g *GameManager) PacketSceneEntityInfoAvatar(scene *Scene, player *model.Player, avatarId uint32) *proto.SceneEntityInfo { entity := scene.GetEntity(scene.world.GetPlayerWorldAvatarEntityId(player, avatarId)) if entity == nil { diff --git a/gs/game/user_stamina.go b/gs/game/user_stamina.go index 7c9421b9..b3ad5ff8 100644 --- a/gs/game/user_stamina.go +++ b/gs/game/user_stamina.go @@ -1,6 +1,7 @@ package game import ( + gdc "hk4e/gs/config" "strings" "time" @@ -418,10 +419,15 @@ func (g *GameManager) UpdatePlayerStamina(player *model.Player, staminaCost int3 // DrownBackHandler 玩家溺水返回安全点 func (g *GameManager) DrownBackHandler(player *model.Player) { - // 溺水返回时间为0代表不进行返回 - if player.StaminaInfo.DrownBackTime == 0 { + // 玩家暂停跳过 + if player.Pause { return } + // 溺水返回时间为0代表不进行返回 + if player.StaminaInfo.DrownBackDelay == 0 { + return + } + world := WORLD_MANAGER.GetWorldByID(player.WorldId) scene := world.GetSceneById(player.SceneId) activeAvatar := world.GetPlayerWorldAvatar(player, world.GetPlayerActiveAvatarId(player)) @@ -431,54 +437,58 @@ func (g *GameManager) DrownBackHandler(player *model.Player) { return } - // 记录溺水安全点 + // TODO // 溺水安全点可能需要读取附近锚点坐标 // 多次溺水后提示溺水的死亡信息 // 官服 游戏离线也会回到安全位置 // 很显然目前这个很不完善 - switch player.StaminaInfo.State { - case proto.MotionState_MOTION_STATE_DANGER_RUN, proto.MotionState_MOTION_STATE_RUN, - proto.MotionState_MOTION_STATE_DANGER_STANDBY_MOVE, proto.MotionState_MOTION_STATE_DANGER_STANDBY, proto.MotionState_MOTION_STATE_LADDER_TO_STANDBY, proto.MotionState_MOTION_STATE_STANDBY_MOVE, proto.MotionState_MOTION_STATE_STANDBY, - proto.MotionState_MOTION_STATE_DANGER_WALK, proto.MotionState_MOTION_STATE_WALK, - proto.MotionState_MOTION_STATE_DASH: - player.StaminaInfo.DrownBackPos.X = player.Pos.X - player.StaminaInfo.DrownBackPos.Y = player.Pos.Y - player.StaminaInfo.DrownBackPos.Z = player.Pos.Z - } - // 临时 - if player.StaminaInfo.DrownBackPos.X == 0 && player.StaminaInfo.DrownBackPos.Y == 0 && player.StaminaInfo.DrownBackPos.Z == 0 { - player.StaminaInfo.DrownBackPos.X = player.Pos.X - player.StaminaInfo.DrownBackPos.Y = player.Pos.Y - player.StaminaInfo.DrownBackPos.Z = player.Pos.Z - } - - if player.StaminaInfo.DrownBackTime == 1 { - // 确保玩家已经完成加载场景 - if player.SceneLoadState == model.SceneEnterDone { - // 设置角色存活 - scene.SetEntityLifeState(avatarEntity, constant.LifeStateConst.LIFE_REVIVE, proto.PlayerDieType_PLAYER_DIE_TYPE_NONE) - // 重置溺水返回时间 - player.StaminaInfo.DrownBackTime = 0 + // 先传送玩家再设置角色存活否则同时设置会传送前显示角色实体 + if player.StaminaInfo.DrownBackDelay > 20 && player.SceneLoadState == model.SceneEnterDone { + // 设置角色存活 + scene.SetEntityLifeState(avatarEntity, constant.LifeStateConst.LIFE_REVIVE, proto.PlayerDieType_PLAYER_DIE_TYPE_NONE) + // 重置溺水返回时间 + player.StaminaInfo.DrownBackDelay = 0 + } else if player.StaminaInfo.DrownBackDelay == 20 { + // TODO 队伍扣血 + maxStamina := player.PropertiesMap[constant.PlayerPropertyConst.PROP_MAX_STAMINA] + // 设置玩家耐力为一半 + g.SetPlayerStamina(player, maxStamina/2) + // 如果玩家的位置比锚点距离近则优先使用玩家位置 + pos := &model.Vector{ + X: player.Pos.X, + Y: player.Pos.Y, + Z: player.Pos.Z, + } + // 获取最近角色实体的锚点 + // TODO 阻塞优化 16ms我感觉有点慢 + for _, entry := range gdc.CONF.ScenePointEntries { + if entry.PointData == nil || entry.PointData.TranPos == nil { + continue + } + pointPos := &model.Vector{ + X: entry.PointData.TranPos.X, + Y: entry.PointData.TranPos.Y, + Z: entry.PointData.TranPos.Z, + } + // 该坐标距离小于之前的则赋值 + if player.StaminaInfo.ActiveAvatarPos.Distance(pointPos) < player.StaminaInfo.ActiveAvatarPos.Distance(pos) { + pos = pointPos + } } - } else if time.Now().UnixMilli() >= player.StaminaInfo.DrownBackTime { - // 临时 防止一直淹死 尚未完善 - g.SetPlayerStamina(player, 10000) // 传送玩家至安全位置 - g.TeleportPlayer(player, uint32(constant.EnterReasonConst.Revival), player.SceneId, player.StaminaInfo.DrownBackPos) - - // 设置溺水返回时间为1 - // 1代表加载完场景后再复活玩家 - player.StaminaInfo.DrownBackTime = 1 - // 重置动作状态否则可能会导致多次溺水 - player.StaminaInfo.State = 0 + g.TeleportPlayer(player, uint32(constant.EnterReasonConst.Revival), player.SceneId, pos) + } + // 防止重置后又被修改 + if player.StaminaInfo.DrownBackDelay != 0 { + player.StaminaInfo.DrownBackDelay++ } } // HandleDrown 处理玩家溺水 func (g *GameManager) HandleDrown(player *model.Player, stamina uint32) { - // 溺水需要耐力等于0 返回时间不等于0代表已处理过溺水正在等待返回 - if stamina != 0 || player.StaminaInfo.DrownBackTime != 0 { + // 溺水需要耐力等于0 返回延时不等于0代表已处理过溺水正在等待返回 + if stamina != 0 || player.StaminaInfo.DrownBackDelay != 0 { return } @@ -496,8 +506,8 @@ func (g *GameManager) HandleDrown(player *model.Player, stamina uint32) { logger.Debug("player drown, curStamina: %v, state: %v", stamina, player.StaminaInfo.State) // 设置角色为死亡 scene.SetEntityLifeState(avatarEntity, constant.LifeStateConst.LIFE_DEAD, proto.PlayerDieType_PLAYER_DIE_TYPE_DRAWN) - // 溺水返回安全点的时间 - player.StaminaInfo.DrownBackTime = time.Now().Add(time.Second * 4).UnixMilli() + // 溺水返回安全点 计时开始 + player.StaminaInfo.DrownBackDelay = 1 } } diff --git a/gs/model/player.go b/gs/model/player.go index 6d1c9708..86a885ea 100644 --- a/gs/model/player.go +++ b/gs/model/player.go @@ -81,7 +81,7 @@ func (p *Player) InitAll() { p.GameObjectGuidMap = make(map[uint64]GameObject) p.CoopApplyMap = make(map[uint32]int64) p.StaminaInfo = new(StaminaInfo) - p.StaminaInfo.DrownBackPos = new(Vector) + p.StaminaInfo.ActiveAvatarPos = new(Vector) p.VehicleInfo = new(VehicleInfo) p.VehicleInfo.LastCreateEntityIdMap = make(map[uint32]uint32) p.InitAllAvatar() diff --git a/gs/model/stamina.go b/gs/model/stamina.go index 3d7a580e..9dc56a3e 100644 --- a/gs/model/stamina.go +++ b/gs/model/stamina.go @@ -14,8 +14,8 @@ type StaminaInfo struct { LastSkillId uint32 // 最后释放的技能Id LastSkillTime int64 // 最后释放技能的时间 LastSkillStartTime int64 // 最后执行开始技能耐力消耗的时间 - DrownBackTime int64 // 溺水返回安全点的时间 - DrownBackPos *Vector // 溺水返回的安全点坐标 + DrownBackDelay int64 // 溺水返回安全点延时 + ActiveAvatarPos *Vector // 当前角色位置 } // SetStaminaCost 设置动作需要消耗的耐力 diff --git a/gs/model/vector.go b/gs/model/vector.go index 22bb5ba4..eb5054ad 100644 --- a/gs/model/vector.go +++ b/gs/model/vector.go @@ -1,7 +1,14 @@ package model +import "math" + type Vector struct { X float64 `bson:"x"` Y float64 `bson:"y"` Z float64 `bson:"z"` } + +// Distance 两坐标之间的距离 +func (v *Vector) Distance(vector *Vector) float64 { + return math.Sqrt(math.Pow(v.X-vector.X, 2) + math.Pow(v.Y-vector.Y, 2) + math.Pow(v.Z-vector.Z, 2)) +} diff --git a/protocol/cmd/cmd_id_proto_obj_map.go b/protocol/cmd/cmd_id_proto_obj_map.go index f2178984..dbab2e94 100644 --- a/protocol/cmd/cmd_id_proto_obj_map.go +++ b/protocol/cmd/cmd_id_proto_obj_map.go @@ -97,6 +97,9 @@ func (c *CmdProtoMap) registerAllMessage() { c.registerMessage(LeaveWorldNotify, &proto.LeaveWorldNotify{}) // 删除客户端世界通知 c.registerMessage(SceneAvatarStaminaStepReq, &proto.SceneAvatarStaminaStepReq{}) // 缓慢游泳或缓慢攀爬时消耗耐力请求 c.registerMessage(SceneAvatarStaminaStepRsp, &proto.SceneAvatarStaminaStepRsp{}) // 缓慢游泳或缓慢攀爬时消耗耐力响应 + c.registerMessage(LifeStateChangeNotify, &proto.LifeStateChangeNotify{}) // 实体存活状态改变通知 + c.registerMessage(SceneEntityDrownReq, &proto.SceneEntityDrownReq{}) // 场景实体溺水请求 + c.registerMessage(SceneEntityDrownRsp, &proto.SceneEntityDrownRsp{}) // 场景实体溺水响应 // 战斗与同步 c.registerMessage(AvatarFightPropNotify, &proto.AvatarFightPropNotify{}) // 角色战斗属性通知 @@ -113,7 +116,6 @@ func (c *CmdProtoMap) registerAllMessage() { c.registerMessage(EvtEntityRenderersChangedNotify, &proto.EvtEntityRenderersChangedNotify{}) // 实体可视状态改变通知 c.registerMessage(EvtCreateGadgetNotify, &proto.EvtCreateGadgetNotify{}) // 创建实体通知 c.registerMessage(EvtDestroyGadgetNotify, &proto.EvtDestroyGadgetNotify{}) // 销毁实体通知 - c.registerMessage(LifeStateChangeNotify, &proto.LifeStateChangeNotify{}) // 实体存活状态改变通知 // 队伍 c.registerMessage(ChangeAvatarReq, &proto.ChangeAvatarReq{}) // 更换角色请求 切人