diff --git a/gs/game/tick_manager.go b/gs/game/tick_manager.go index 131b56bc..7e747b2a 100644 --- a/gs/game/tick_manager.go +++ b/gs/game/tick_manager.go @@ -143,39 +143,39 @@ func (t *TickManager) onTick5Second(now int64) { } } for _, player := range world.playerMap { - if world.multiplayer { - scene := world.GetSceneById(player.SceneId) - - // 多人世界其他玩家的坐标位置广播 - worldPlayerLocationNotify := &proto.WorldPlayerLocationNotify{ - PlayerWorldLocList: make([]*proto.PlayerWorldLocationInfo, 0), - } - for _, worldPlayer := range world.playerMap { - playerWorldLocationInfo := &proto.PlayerWorldLocationInfo{ - SceneId: worldPlayer.SceneId, - PlayerLoc: &proto.PlayerLocationInfo{ - Uid: worldPlayer.PlayerID, - Pos: &proto.Vector{ - X: float32(worldPlayer.Pos.X), - Y: float32(worldPlayer.Pos.Y), - Z: float32(worldPlayer.Pos.Z), - }, - Rot: &proto.Vector{ - X: float32(worldPlayer.Rot.X), - Y: float32(worldPlayer.Rot.Y), - Z: float32(worldPlayer.Rot.Z), - }, + // 多人世界其他玩家的坐标位置广播 + worldPlayerLocationNotify := &proto.WorldPlayerLocationNotify{ + PlayerWorldLocList: make([]*proto.PlayerWorldLocationInfo, 0), + } + for _, worldPlayer := range world.playerMap { + playerWorldLocationInfo := &proto.PlayerWorldLocationInfo{ + SceneId: worldPlayer.SceneId, + PlayerLoc: &proto.PlayerLocationInfo{ + Uid: worldPlayer.PlayerID, + Pos: &proto.Vector{ + X: float32(worldPlayer.Pos.X), + Y: float32(worldPlayer.Pos.Y), + Z: float32(worldPlayer.Pos.Z), }, - } - worldPlayerLocationNotify.PlayerWorldLocList = append(worldPlayerLocationNotify.PlayerWorldLocList, playerWorldLocationInfo) + Rot: &proto.Vector{ + X: float32(worldPlayer.Rot.X), + Y: float32(worldPlayer.Rot.Y), + Z: float32(worldPlayer.Rot.Z), + }, + }, } - GAME_MANAGER.SendMsg(cmd.WorldPlayerLocationNotify, player.PlayerID, 0, worldPlayerLocationNotify) + worldPlayerLocationNotify.PlayerWorldLocList = append(worldPlayerLocationNotify.PlayerWorldLocList, playerWorldLocationInfo) + } + GAME_MANAGER.SendMsg(cmd.WorldPlayerLocationNotify, player.PlayerID, 0, worldPlayerLocationNotify) + for _, scene := range world.sceneMap { scenePlayerLocationNotify := &proto.ScenePlayerLocationNotify{ - SceneId: player.SceneId, - PlayerLocList: make([]*proto.PlayerLocationInfo, 0), + SceneId: scene.id, + PlayerLocList: make([]*proto.PlayerLocationInfo, 0), + VehicleLocList: make([]*proto.VehicleLocationInfo, 0), } for _, scenePlayer := range scene.playerMap { + // 玩家位置 playerLocationInfo := &proto.PlayerLocationInfo{ Uid: scenePlayer.PlayerID, Pos: &proto.Vector{ @@ -190,6 +190,35 @@ func (t *TickManager) onTick5Second(now int64) { }, } scenePlayerLocationNotify.PlayerLocList = append(scenePlayerLocationNotify.PlayerLocList, playerLocationInfo) + // 载具位置 + for _, entityId := range scenePlayer.VehicleInfo.LastCreateEntityIdMap { + entity := scene.GetEntity(entityId) + // 确保实体类型是否为载具 + if entity != nil && entity.gadgetEntity != nil && entity.gadgetEntity.gadgetVehicleEntity != nil { + vehicleLocationInfo := &proto.VehicleLocationInfo{ + Rot: &proto.Vector{ + X: float32(entity.rot.X), + Y: float32(entity.rot.Y), + Z: float32(entity.rot.Z), + }, + EntityId: entity.id, + CurHp: entity.fightProp[uint32(constant.FightPropertyConst.FIGHT_PROP_CUR_HP)], + OwnerUid: entity.gadgetEntity.gadgetVehicleEntity.owner.PlayerID, + Pos: &proto.Vector{ + X: float32(entity.pos.X), + Y: float32(entity.pos.Y), + Z: float32(entity.pos.Z), + }, + UidList: make([]uint32, 0, len(entity.gadgetEntity.gadgetVehicleEntity.memberMap)), + GadgetId: entity.gadgetEntity.gadgetVehicleEntity.vehicleId, + MaxHp: entity.fightProp[uint32(constant.FightPropertyConst.FIGHT_PROP_MAX_HP)], + } + for _, p := range entity.gadgetEntity.gadgetVehicleEntity.memberMap { + vehicleLocationInfo.UidList = append(vehicleLocationInfo.UidList, p.PlayerID) + } + scenePlayerLocationNotify.VehicleLocList = append(scenePlayerLocationNotify.VehicleLocList, vehicleLocationInfo) + } + } } GAME_MANAGER.SendMsg(cmd.ScenePlayerLocationNotify, player.PlayerID, 0, scenePlayerLocationNotify) } @@ -209,20 +238,31 @@ func (t *TickManager) onTickSecond(now int64) { worldPlayerRTTNotify.PlayerRttList = append(worldPlayerRTTNotify.PlayerRttList, playerRTTInfo) } GAME_MANAGER.SendMsg(cmd.WorldPlayerRTTNotify, player.PlayerID, 0, worldPlayerRTTNotify) + // 玩家安全位置更新 + 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.SafePos.X = player.Pos.X + player.SafePos.Y = player.Pos.Y + player.SafePos.Z = player.Pos.Z + } + } + if !world.IsBigWorld() && world.owner.SceneLoadState == model.SceneEnterDone { // 刷怪 - if !world.IsBigWorld() && world.owner.SceneLoadState == model.SceneEnterDone { - scene := world.GetSceneById(3) - monsterEntityCount := 0 - for _, entity := range scene.entityMap { - if entity.entityType == uint32(proto.ProtEntityType_PROT_ENTITY_TYPE_MONSTER) { - monsterEntityCount++ - } - } - if monsterEntityCount < 30 { - monsterEntityId := t.createMonster(world.owner, scene) - GAME_MANAGER.AddSceneEntityNotify(world.owner, proto.VisionType_VISION_TYPE_BORN, []uint32{monsterEntityId}, true, false) + scene := world.GetSceneById(3) + monsterEntityCount := 0 + for _, entity := range scene.entityMap { + if entity.entityType == uint32(proto.ProtEntityType_PROT_ENTITY_TYPE_MONSTER) { + monsterEntityCount++ } } + if monsterEntityCount < 30 { + monsterEntityId := t.createMonster(scene) + GAME_MANAGER.AddSceneEntityNotify(world.owner, proto.VisionType_VISION_TYPE_BORN, []uint32{monsterEntityId}, true, false) + } } } } @@ -241,7 +281,7 @@ func (t *TickManager) onTick200MilliSecond(now int64) { func (t *TickManager) onTick100MilliSecond(now int64) { } -func (t *TickManager) createMonster(player *model.Player, scene *Scene) uint32 { +func (t *TickManager) createMonster(scene *Scene) uint32 { pos := &model.Vector{ X: 2747, Y: 194, diff --git a/gs/game/user_fight_sync.go b/gs/game/user_fight_sync.go index 03d45f92..eab2492b 100644 --- a/gs/game/user_fight_sync.go +++ b/gs/game/user_fight_sync.go @@ -119,23 +119,12 @@ func (g *GameManager) CombatInvocationsNotify(player *model.Player, payloadMsg p if sceneEntity.avatarEntity != nil { // 玩家实体在移动 // 更新玩家的位置信息 - 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) - } + 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) // 处理耐力消耗 g.ImmediateStamina(player, motionInfo.State) diff --git a/gs/game/user_login.go b/gs/game/user_login.go index a6c8ccd4..25327bc4 100644 --- a/gs/game/user_login.go +++ b/gs/game/user_login.go @@ -47,6 +47,12 @@ func (g *GameManager) OnLoginOk(userId uint32, player *model.Player, clientSeq u // 初始化 player.InitAll() // player.TeamConfig.UpdateTeam() + + // 确保玩家位置安全 + player.Pos.X = player.SafePos.X + player.Pos.Y = player.SafePos.Y + player.Pos.Z = player.SafePos.Z + // 创建世界 world := WORLD_MANAGER.CreateWorld(player) world.AddPlayer(player, player.SceneId) @@ -374,6 +380,7 @@ func (g *GameManager) CreatePlayer(userId uint32, nickName string, mainCharAvata player.CostumeList = append(player.CostumeList, 201601) player.CostumeList = append(player.CostumeList, 203101) + player.SafePos = &model.Vector{X: 2747, Y: 194, Z: -1719} player.Pos = &model.Vector{X: 2747, Y: 194, Z: -1719} player.Rot = &model.Vector{X: 0, Y: 307, Z: 0} diff --git a/gs/game/user_stamina.go b/gs/game/user_stamina.go index 259e9d67..c3590033 100644 --- a/gs/game/user_stamina.go +++ b/gs/game/user_stamina.go @@ -4,8 +4,6 @@ import ( "strings" "time" - gdc "hk4e/gs/config" - "hk4e/gdconf" "hk4e/gs/constant" "hk4e/gs/model" @@ -438,11 +436,12 @@ func (g *GameManager) DrownBackHandler(player *model.Player) { return } - // TODO - // 溺水安全点可能需要读取附近锚点坐标 - // 多次溺水后提示溺水的死亡信息 - // 官服 游戏离线也会回到安全位置 - // 很显然目前这个很不完善 + // TODO 耐力未完成的内容: + // 一直溺水回到距离最近的位置 ? + // 溺水队伍扣血 + // 队伍都没血了显示死亡界面 + // 技能耐力消耗配置表 + // 食物影响消耗的耐力 // 先传送玩家再设置角色存活否则同时设置会传送前显示角色实体 if player.StaminaInfo.DrownBackDelay > 20 && player.SceneLoadState == model.SceneEnterDone { @@ -457,26 +456,26 @@ func (g *GameManager) DrownBackHandler(player *model.Player) { g.SetPlayerStamina(player, maxStamina/2) // 如果玩家的位置比锚点距离近则优先使用玩家位置 pos := &model.Vector{ - X: player.Pos.X, - Y: player.Pos.Y, - Z: player.Pos.Z, + X: player.SafePos.X, + Y: player.SafePos.Y, + Z: player.SafePos.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 - } - } + //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.SafePos.Distance(pointPos) < player.SafePos.Distance(pos) { + // pos = pointPos + // } + //} // 传送玩家至安全位置 g.TeleportPlayer(player, uint32(constant.EnterReasonConst.Revival), player.SceneId, pos) } diff --git a/gs/model/player.go b/gs/model/player.go index 86a885ea..578f503d 100644 --- a/gs/model/player.go +++ b/gs/model/player.go @@ -42,6 +42,7 @@ type Player struct { FlyCloakList []uint32 `bson:"flyCloakList"` // 风之翼列表 CostumeList []uint32 `bson:"costumeList"` // 角色衣装列表 SceneId uint32 `bson:"sceneId"` // 场景 + SafePos *Vector `bson:"safePos"` // 玩家在陆地时的坐标 Pos *Vector `bson:"pos"` // 玩家坐标 Rot *Vector `bson:"rot"` // 玩家朝向 ItemMap map[uint32]*Item `bson:"itemMap"` // 玩家统一大背包仓库 @@ -81,7 +82,6 @@ func (p *Player) InitAll() { p.GameObjectGuidMap = make(map[uint64]GameObject) p.CoopApplyMap = make(map[uint32]int64) p.StaminaInfo = new(StaminaInfo) - 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 9dc56a3e..9b6f483f 100644 --- a/gs/model/stamina.go +++ b/gs/model/stamina.go @@ -14,8 +14,7 @@ type StaminaInfo struct { LastSkillId uint32 // 最后释放的技能Id LastSkillTime int64 // 最后释放技能的时间 LastSkillStartTime int64 // 最后执行开始技能耐力消耗的时间 - DrownBackDelay int64 // 溺水返回安全点延时 - ActiveAvatarPos *Vector // 当前角色位置 + DrownBackDelay uint8 // 溺水返回安全点延时 } // SetStaminaCost 设置动作需要消耗的耐力 diff --git a/gs/model/vehicle.go b/gs/model/vehicle.go index 8de69296..33256fd2 100644 --- a/gs/model/vehicle.go +++ b/gs/model/vehicle.go @@ -1,7 +1,8 @@ package model type VehicleInfo struct { - InVehicleEntityId uint32 // 玩家所在载具的实体Id - LastCreateTime int64 // 最后一次创建载具的时间 + InVehicleEntityId uint32 // 玩家所在载具的实体Id + LastCreateTime int64 // 最后一次创建载具的时间 + // TODO 玩家可以在其他世界创建载具 需要额外处理 LastCreateEntityIdMap map[uint32]uint32 // 最后一次创建载具的实体Id map[vehicleId]EntityId }