Files
hk4e/gs/game/player_fight_sync.go
2023-04-14 22:07:41 +08:00

802 lines
30 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package game
import (
"strings"
"time"
"hk4e/common/constant"
"hk4e/gdconf"
"hk4e/gs/model"
"hk4e/pkg/logger"
"hk4e/pkg/reflection"
"hk4e/protocol/cmd"
"hk4e/protocol/proto"
pb "google.golang.org/protobuf/proto"
)
var cmdProtoMap *cmd.CmdProtoMap = nil
func DoForward[IET model.InvokeEntryType](player *model.Player, invokeHandler *model.InvokeHandler[IET],
cmdId uint16, newNtf pb.Message, forwardField string,
srcNtf pb.Message, copyFieldList []string) {
if cmdProtoMap == nil {
cmdProtoMap = cmd.NewCmdProtoMap()
}
world := WORLD_MANAGER.GetWorldByID(player.WorldId)
if world == nil {
return
}
scene := world.GetSceneById(player.SceneId)
if srcNtf != nil && copyFieldList != nil {
for _, fieldName := range copyFieldList {
reflection.CopyStructField(newNtf, srcNtf, fieldName)
}
}
if invokeHandler.AllLen() == 0 && invokeHandler.AllExceptCurLen() == 0 && invokeHandler.HostLen() == 0 {
return
}
if invokeHandler.AllLen() > 0 {
reflection.SetStructFieldValue(newNtf, forwardField, invokeHandler.EntryListForwardAll)
GAME.SendToSceneA(scene, cmdId, player.ClientSeq, newNtf)
}
if invokeHandler.AllExceptCurLen() > 0 {
reflection.SetStructFieldValue(newNtf, forwardField, invokeHandler.EntryListForwardAllExceptCur)
GAME.SendToSceneAEC(scene, cmdId, player.ClientSeq, newNtf, player.PlayerID)
}
if invokeHandler.HostLen() > 0 {
reflection.SetStructFieldValue(newNtf, forwardField, invokeHandler.EntryListForwardHost)
GAME.SendToWorldH(world, cmdId, player.ClientSeq, newNtf)
}
}
func (g *Game) UnionCmdNotify(player *model.Player, payloadMsg pb.Message) {
req := payloadMsg.(*proto.UnionCmdNotify)
_ = req
if player.SceneLoadState != model.SceneEnterDone {
return
}
DoForward[proto.CombatInvokeEntry](player, player.CombatInvokeHandler,
cmd.CombatInvocationsNotify, new(proto.CombatInvocationsNotify), "InvokeList",
nil, nil)
DoForward[proto.AbilityInvokeEntry](player, player.AbilityInvokeHandler,
cmd.AbilityInvocationsNotify, new(proto.AbilityInvocationsNotify), "Invokes",
nil, nil)
player.CombatInvokeHandler.Clear()
player.AbilityInvokeHandler.Clear()
}
func (g *Game) MassiveEntityElementOpBatchNotify(player *model.Player, payloadMsg pb.Message) {
req := payloadMsg.(*proto.MassiveEntityElementOpBatchNotify)
if player.SceneLoadState != model.SceneEnterDone {
return
}
world := WORLD_MANAGER.GetWorldByID(player.WorldId)
if world == nil {
return
}
scene := world.GetSceneById(player.SceneId)
req.OpIdx = scene.GetMeeoIndex()
scene.SetMeeoIndex(scene.GetMeeoIndex() + 1)
g.SendToSceneA(scene, cmd.MassiveEntityElementOpBatchNotify, player.ClientSeq, req)
}
func (g *Game) CombatInvocationsNotify(player *model.Player, payloadMsg pb.Message) {
req := payloadMsg.(*proto.CombatInvocationsNotify)
if player.SceneLoadState != model.SceneEnterDone {
return
}
world := WORLD_MANAGER.GetWorldByID(player.WorldId)
if world == nil {
return
}
scene := world.GetSceneById(player.SceneId)
for _, entry := range req.InvokeList {
switch entry.ArgumentType {
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", err)
break
}
// logger.Debug("EvtBeingHitInfo: %v, ForwardType: %v", evtBeingHitInfo, entry.ForwardType)
attackResult := evtBeingHitInfo.AttackResult
if attackResult == nil {
logger.Error("attackResult is nil")
break
}
target := scene.GetEntity(attackResult.DefenseId)
if target == nil {
logger.Error("could not found target, defense id: %v", attackResult.DefenseId)
break
}
fightProp := target.GetFightProp()
currHp := fightProp[constant.FIGHT_PROP_CUR_HP]
currHp -= attackResult.Damage
if currHp < 0 {
currHp = 0
}
fightProp[constant.FIGHT_PROP_CUR_HP] = currHp
g.EntityFightPropUpdateNotifyBroadcast(scene, target)
switch target.GetEntityType() {
case constant.ENTITY_TYPE_AVATAR:
case constant.ENTITY_TYPE_MONSTER:
if currHp == 0 {
g.KillEntity(player, scene, target.GetId(), proto.PlayerDieType_PLAYER_DIE_GM)
}
case constant.ENTITY_TYPE_GADGET:
gadgetEntity := target.GetGadgetEntity()
gadgetDataConfig := gdconf.GetGadgetDataById(int32(gadgetEntity.GetGadgetId()))
if gadgetDataConfig == nil {
logger.Error("get gadget data config is nil, gadgetId: %v", gadgetEntity.GetGadgetId())
break
}
logger.Debug("[EvtBeingHit] GadgetData: %+v, EntityId: %v, uid: %v", gadgetDataConfig, target.GetId(), player.PlayerID)
g.handleGadgetEntityBeHitLow(player, target, attackResult.ElementType)
}
case proto.CombatTypeArgument_ENTITY_MOVE:
entityMoveInfo := new(proto.EntityMoveInfo)
err := pb.Unmarshal(entry.CombatData, entityMoveInfo)
if err != nil {
logger.Error("parse EntityMoveInfo error: %v", err)
break
}
// logger.Debug("EntityMoveInfo: %v, ForwardType: %v", entityMoveInfo, entry.ForwardType)
motionInfo := entityMoveInfo.MotionInfo
if motionInfo.Pos == nil || motionInfo.Rot == nil {
break
}
sceneEntity := scene.GetEntity(entityMoveInfo.EntityId)
if sceneEntity == nil {
break
}
if sceneEntity.GetEntityType() == constant.ENTITY_TYPE_AVATAR {
// 玩家实体在移动
g.SceneBlockAoiPlayerMove(player, world, scene, player.Pos,
&model.Vector{X: float64(motionInfo.Pos.X), Y: float64(motionInfo.Pos.Y), Z: float64(motionInfo.Pos.Z)},
sceneEntity.GetId(),
)
if WORLD_MANAGER.IsBigWorld(world) {
g.BigWorldAoiPlayerMove(player, world, scene, player.Pos,
&model.Vector{X: float64(motionInfo.Pos.X), Y: float64(motionInfo.Pos.Y), Z: float64(motionInfo.Pos.Z)},
)
}
// 更新玩家的位置信息
player.Pos.X, player.Pos.Y, player.Pos.Z = float64(motionInfo.Pos.X), float64(motionInfo.Pos.Y), float64(motionInfo.Pos.Z)
player.Rot.X, player.Rot.Y, player.Rot.Z = float64(motionInfo.Rot.X), float64(motionInfo.Rot.Y), float64(motionInfo.Rot.Z)
// 玩家安全位置更新
switch motionInfo.State {
case proto.MotionState_MOTION_DANGER_RUN,
proto.MotionState_MOTION_RUN,
proto.MotionState_MOTION_DANGER_STANDBY_MOVE,
proto.MotionState_MOTION_DANGER_STANDBY,
proto.MotionState_MOTION_LADDER_TO_STANDBY,
proto.MotionState_MOTION_STANDBY_MOVE,
proto.MotionState_MOTION_STANDBY,
proto.MotionState_MOTION_DANGER_WALK,
proto.MotionState_MOTION_WALK,
proto.MotionState_MOTION_DASH:
// 仅在陆地时更新玩家安全位置
player.SafePos.X, player.SafePos.Y, player.SafePos.Z = player.Pos.X, player.Pos.Y, player.Pos.Z
}
// 处理耐力消耗
g.ImmediateStamina(player, motionInfo.State)
} else {
// 其他实体在移动
// 更新场景实体的位置信息
pos := sceneEntity.GetPos()
pos.X, pos.Y, pos.Z = float64(motionInfo.Pos.X), float64(motionInfo.Pos.Y), float64(motionInfo.Pos.Z)
rot := sceneEntity.GetRot()
rot.X, rot.Y, rot.Z = float64(motionInfo.Rot.X), float64(motionInfo.Rot.Y), float64(motionInfo.Rot.Z)
if sceneEntity.GetEntityType() == constant.ENTITY_TYPE_GADGET {
// 载具耐力消耗
gadgetEntity := sceneEntity.GetGadgetEntity()
if gadgetEntity.GetGadgetVehicleEntity() != nil {
// 处理耐力消耗
g.ImmediateStamina(player, motionInfo.State)
// 处理载具销毁请求
g.VehicleDestroyMotion(player, sceneEntity, motionInfo.State)
}
}
}
sceneEntity.SetMoveState(uint16(motionInfo.State))
sceneEntity.SetLastMoveSceneTimeMs(entityMoveInfo.SceneTime)
sceneEntity.SetLastMoveReliableSeq(entityMoveInfo.ReliableSeq)
// 众里寻他千百度 蓦然回首 那人却在灯火阑珊处
if motionInfo.State == proto.MotionState_MOTION_NOTIFY || motionInfo.State == proto.MotionState_MOTION_FIGHT {
// 只要转发了这两个包的其中之一 客户端的动画就会被打断
continue
}
case proto.CombatTypeArgument_COMBAT_ANIMATOR_PARAMETER_CHANGED:
evtAnimatorParameterInfo := new(proto.EvtAnimatorParameterInfo)
err := pb.Unmarshal(entry.CombatData, evtAnimatorParameterInfo)
if err != nil {
logger.Error("parse EvtAnimatorParameterInfo error: %v", err)
break
}
// logger.Debug("EvtAnimatorParameterInfo: %v, ForwardType: %v", evtAnimatorParameterInfo, entry.ForwardType)
case proto.CombatTypeArgument_COMBAT_ANIMATOR_STATE_CHANGED:
evtAnimatorStateChangedInfo := new(proto.EvtAnimatorStateChangedInfo)
err := pb.Unmarshal(entry.CombatData, evtAnimatorStateChangedInfo)
if err != nil {
logger.Error("parse EvtAnimatorStateChangedInfo error: %v", err)
break
}
// logger.Debug("EvtAnimatorStateChangedInfo: %v, ForwardType: %v", evtAnimatorStateChangedInfo, entry.ForwardType)
}
player.CombatInvokeHandler.AddEntry(entry.ForwardType, entry)
}
}
func (g *Game) SceneBlockAoiPlayerMove(player *model.Player, world *World, scene *Scene, oldPos *model.Vector, newPos *model.Vector, entityId uint32) {
// 服务器处理玩家移动场景区块aoi事件频率限制
now := uint64(time.Now().UnixMilli())
if now-player.LastSceneBlockAoiMoveTime < 200 {
return
}
player.LastSceneBlockAoiMoveTime = now
sceneBlockAoiMap := WORLD_MANAGER.GetSceneBlockAoiMap()
aoiManager, exist := sceneBlockAoiMap[player.SceneId]
if !exist {
logger.Error("get scene block aoi is nil, sceneId: %v, uid: %v", player.SceneId, player.PlayerID)
return
}
oldGid := aoiManager.GetGidByPos(float32(oldPos.X), 0.0, float32(oldPos.Z))
newGid := aoiManager.GetGidByPos(float32(newPos.X), 0.0, float32(newPos.Z))
if oldGid != newGid {
// 跨越了block格子
logger.Debug("player cross scene block grid, oldGid: %v, newGid: %v, uid: %v", oldGid, newGid, player.PlayerID)
}
// 加载和卸载的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即为卸载的
if !world.GetMultiplayer() {
// 单人世界直接卸载group
g.RemoveSceneGroup(player, scene, groupConfig)
} else {
// 多人世界group附近没有任何玩家则卸载
remove := true
for _, otherPlayer := range scene.GetAllPlayer() {
for otherPlayerGroupId := range g.GetNeighborGroup(otherPlayer.SceneId, otherPlayer.Pos) {
if otherPlayerGroupId == groupId {
remove = false
break
}
}
if !remove {
break
}
}
if remove {
g.RemoveSceneGroup(player, scene, groupConfig)
}
}
}
for groupId, groupConfig := range newNeighborGroupMap {
_, exist := oldNeighborGroupMap[groupId]
if exist {
continue
}
// 新有旧没有的group即为加载的
g.AddSceneGroup(player, scene, groupConfig)
}
// 消失和出现的场景实体
oldVisionEntityMap := g.GetVisionEntity(scene, oldPos)
newVisionEntityMap := g.GetVisionEntity(scene, newPos)
delEntityIdList := make([]uint32, 0)
for entityId, entity := range oldVisionEntityMap {
_, exist := newVisionEntityMap[entityId]
if exist {
continue
}
if WORLD_MANAGER.IsBigWorld(world) {
if entity.GetEntityType() == constant.ENTITY_TYPE_AVATAR {
continue
}
}
// 旧有新没有的实体即为消失的
delEntityIdList = append(delEntityIdList, entityId)
}
addEntityIdList := make([]uint32, 0)
for entityId, entity := range newVisionEntityMap {
_, exist := oldVisionEntityMap[entityId]
if exist {
continue
}
if WORLD_MANAGER.IsBigWorld(world) {
if entity.GetEntityType() == constant.ENTITY_TYPE_AVATAR {
continue
}
}
// 新有旧没有的实体即为出现的
addEntityIdList = append(addEntityIdList, entityId)
}
// 同步客户端消失和出现的场景实体
if len(delEntityIdList) > 0 {
g.RemoveSceneEntityNotifyToPlayer(player, proto.VisionType_VISION_MISS, delEntityIdList)
}
if len(addEntityIdList) > 0 {
g.AddSceneEntityNotify(player, proto.VisionType_VISION_MEET, addEntityIdList, false, false)
}
// 场景区域触发器检测
g.SceneRegionTriggerCheck(player, oldPos, newPos, entityId)
}
func (g *Game) BigWorldAoiPlayerMove(player *model.Player, world *World, scene *Scene, oldPos *model.Vector, newPos *model.Vector) {
bigWorldAoi := world.GetBigWorldAoi()
oldGid := bigWorldAoi.GetGidByPos(float32(oldPos.X), float32(oldPos.Y), float32(oldPos.Z))
newGid := bigWorldAoi.GetGidByPos(float32(newPos.X), float32(newPos.Y), float32(newPos.Z))
if oldGid != newGid {
// 玩家跨越了格子
logger.Debug("player cross big world aoi grid, oldGid: %v, newGid: %v, uid: %v", oldGid, newGid, player.PlayerID)
// 找出本次移动所带来的消失和出现的格子
oldGridList := bigWorldAoi.GetSurrGridListByGid(oldGid)
newGridList := bigWorldAoi.GetSurrGridListByGid(newGid)
delGridIdList := make([]uint32, 0)
for _, oldGrid := range oldGridList {
exist := false
for _, newGrid := range newGridList {
if oldGrid.GetGid() == newGrid.GetGid() {
exist = true
break
}
}
if exist {
continue
}
delGridIdList = append(delGridIdList, oldGrid.GetGid())
}
addGridIdList := make([]uint32, 0)
for _, newGrid := range newGridList {
exist := false
for _, oldGrid := range oldGridList {
if newGrid.GetGid() == oldGrid.GetGid() {
exist = true
break
}
}
if exist {
continue
}
addGridIdList = append(addGridIdList, newGrid.GetGid())
}
activeAvatarId := world.GetPlayerActiveAvatarId(player)
activeWorldAvatar := world.GetPlayerWorldAvatar(player, activeAvatarId)
// 老格子移除玩家
bigWorldAoi.RemoveObjectFromGrid(int64(player.PlayerID), oldGid)
// 处理消失的格子
for _, delGridId := range delGridIdList {
// 通知自己 老格子里的其它玩家消失
oldOtherWorldAvatarMap := bigWorldAoi.GetObjectListByGid(delGridId)
delEntityIdList := make([]uint32, 0)
for _, otherWorldAvatarAny := range oldOtherWorldAvatarMap {
otherWorldAvatar := otherWorldAvatarAny.(*WorldAvatar)
delEntityIdList = append(delEntityIdList, otherWorldAvatar.GetAvatarEntityId())
}
if len(delEntityIdList) > 0 {
g.RemoveSceneEntityNotifyToPlayer(player, proto.VisionType_VISION_MISS, delEntityIdList)
}
// 通知老格子里的其它玩家 自己消失
for otherPlayerId := range oldOtherWorldAvatarMap {
otherPlayer := USER_MANAGER.GetOnlineUser(uint32(otherPlayerId))
if otherPlayer == nil {
logger.Error("get player is nil, target uid: %v, uid: %v", otherPlayerId, player.PlayerID)
continue
}
g.RemoveSceneEntityNotifyToPlayer(otherPlayer, proto.VisionType_VISION_MISS, []uint32{activeWorldAvatar.GetAvatarEntityId()})
}
}
// 处理出现的格子
for _, addGridId := range addGridIdList {
// 通知自己 新格子里的其他玩家出现
newOtherWorldAvatarMap := bigWorldAoi.GetObjectListByGid(addGridId)
addEntityIdList := make([]uint32, 0)
for _, otherWorldAvatarAny := range newOtherWorldAvatarMap {
otherWorldAvatar := otherWorldAvatarAny.(*WorldAvatar)
addEntityIdList = append(addEntityIdList, otherWorldAvatar.GetAvatarEntityId())
}
if len(addEntityIdList) > 0 {
g.AddSceneEntityNotify(player, proto.VisionType_VISION_MEET, addEntityIdList, false, false)
}
// 通知新格子里的其他玩家 自己出现
for otherPlayerId := range newOtherWorldAvatarMap {
otherPlayer := USER_MANAGER.GetOnlineUser(uint32(otherPlayerId))
if otherPlayer == nil {
logger.Error("get player is nil, target uid: %v, uid: %v", otherPlayerId, player.PlayerID)
continue
}
sceneEntityInfoAvatar := g.PacketSceneEntityInfoAvatar(scene, player, world.GetPlayerActiveAvatarId(player))
g.AddSceneEntityNotifyToPlayer(otherPlayer, proto.VisionType_VISION_MEET, []*proto.SceneEntityInfo{sceneEntityInfoAvatar})
}
}
// 新格子添加玩家
bigWorldAoi.AddObjectToGrid(int64(player.PlayerID), activeWorldAvatar, newGid)
}
}
func (g *Game) AbilityInvocationsNotify(player *model.Player, payloadMsg pb.Message) {
req := payloadMsg.(*proto.AbilityInvocationsNotify)
if player.SceneLoadState != model.SceneEnterDone {
return
}
for _, entry := range req.Invokes {
player.AbilityInvokeHandler.AddEntry(entry.ForwardType, entry)
switch entry.ArgumentType {
case proto.AbilityInvokeArgument_ABILITY_META_MODIFIER_CHANGE:
modifierChange := new(proto.AbilityMetaModifierChange)
err := pb.Unmarshal(entry.AbilityData, modifierChange)
if err != nil {
logger.Error("parse AbilityMetaModifierChange error: %v", err)
continue
}
// logger.Debug("EntityId: %v, ModifierChange: %v", entry.EntityId, modifierChange)
// 处理耐力消耗
g.HandleAbilityStamina(player, entry)
g.handleGadgetEntityAbilityLow(player, entry.EntityId, entry.ArgumentType, modifierChange)
case proto.AbilityInvokeArgument_ABILITY_MIXIN_COST_STAMINA:
costStamina := new(proto.AbilityMixinCostStamina)
err := pb.Unmarshal(entry.AbilityData, costStamina)
if err != nil {
logger.Error("parse AbilityMixinCostStamina error: %v", err)
continue
}
// logger.Debug("EntityId: %v, MixinCostStamina: %v", entry.EntityId, costStamina)
// 处理耐力消耗
g.HandleAbilityStamina(player, entry)
case proto.AbilityInvokeArgument_ABILITY_META_MODIFIER_DURABILITY_CHANGE:
modifierDurabilityChange := new(proto.AbilityMetaModifierDurabilityChange)
err := pb.Unmarshal(entry.AbilityData, modifierDurabilityChange)
if err != nil {
logger.Error("parse AbilityMetaModifierDurabilityChange error: %v", err)
continue
}
// logger.Debug("EntityId: %v, DurabilityChange: %v", entry.EntityId, modifierDurabilityChange)
}
}
}
func (g *Game) ClientAbilityInitFinishNotify(player *model.Player, payloadMsg pb.Message) {
req := payloadMsg.(*proto.ClientAbilityInitFinishNotify)
if player.SceneLoadState != model.SceneEnterDone {
return
}
invokeHandler := model.NewInvokeHandler[proto.AbilityInvokeEntry]()
for _, entry := range req.Invokes {
// logger.Debug("ClientAbilityInitFinishNotify: %v", entry)
invokeHandler.AddEntry(entry.ForwardType, entry)
}
DoForward[proto.AbilityInvokeEntry](player, invokeHandler,
cmd.ClientAbilityInitFinishNotify, new(proto.ClientAbilityInitFinishNotify), "Invokes",
req, []string{"EntityId"})
}
func (g *Game) ClientAbilityChangeNotify(player *model.Player, payloadMsg pb.Message) {
req := payloadMsg.(*proto.ClientAbilityChangeNotify)
if player.SceneLoadState != model.SceneEnterDone {
return
}
invokeHandler := model.NewInvokeHandler[proto.AbilityInvokeEntry]()
for _, entry := range req.Invokes {
// logger.Debug("ClientAbilityChangeNotify: %v", entry)
invokeHandler.AddEntry(entry.ForwardType, entry)
}
DoForward[proto.AbilityInvokeEntry](player, invokeHandler,
cmd.ClientAbilityChangeNotify, new(proto.ClientAbilityChangeNotify), "Invokes",
req, []string{"IsInitHash", "EntityId"})
world := WORLD_MANAGER.GetWorldByID(player.WorldId)
if world == nil {
return
}
for _, abilityInvokeEntry := range req.Invokes {
switch abilityInvokeEntry.ArgumentType {
case proto.AbilityInvokeArgument_ABILITY_META_ADD_NEW_ABILITY:
abilityMetaAddAbility := new(proto.AbilityMetaAddAbility)
err := pb.Unmarshal(abilityInvokeEntry.AbilityData, abilityMetaAddAbility)
if err != nil {
logger.Error("parse AbilityMetaAddAbility error: %v", err)
continue
}
worldAvatar := world.GetWorldAvatarByEntityId(abilityInvokeEntry.EntityId)
if worldAvatar == nil {
continue
}
if abilityMetaAddAbility.Ability == nil {
continue
}
worldAvatar.AddAbility(abilityMetaAddAbility.Ability)
case proto.AbilityInvokeArgument_ABILITY_META_MODIFIER_CHANGE:
abilityMetaModifierChange := new(proto.AbilityMetaModifierChange)
err := pb.Unmarshal(abilityInvokeEntry.AbilityData, abilityMetaModifierChange)
if err != nil {
logger.Error("parse AbilityMetaModifierChange error: %v", err)
continue
}
abilityAppliedModifier := &proto.AbilityAppliedModifier{
ModifierLocalId: abilityMetaModifierChange.ModifierLocalId,
ParentAbilityEntityId: 0,
ParentAbilityName: abilityMetaModifierChange.ParentAbilityName,
ParentAbilityOverride: abilityMetaModifierChange.ParentAbilityOverride,
InstancedAbilityId: abilityInvokeEntry.Head.InstancedAbilityId,
InstancedModifierId: abilityInvokeEntry.Head.InstancedModifierId,
ExistDuration: 0,
AttachedInstancedModifier: abilityMetaModifierChange.AttachedInstancedModifier,
ApplyEntityId: abilityMetaModifierChange.ApplyEntityId,
IsAttachedParentAbility: abilityMetaModifierChange.IsAttachedParentAbility,
ModifierDurability: nil,
SbuffUid: 0,
IsServerbuffModifier: abilityInvokeEntry.Head.IsServerbuffModifier,
}
worldAvatar := world.GetWorldAvatarByEntityId(abilityInvokeEntry.EntityId)
if worldAvatar == nil {
continue
}
worldAvatar.AddModifier(abilityAppliedModifier)
}
}
}
func (g *Game) EvtDoSkillSuccNotify(player *model.Player, payloadMsg pb.Message) {
req := payloadMsg.(*proto.EvtDoSkillSuccNotify)
if player.SceneLoadState != model.SceneEnterDone {
return
}
logger.Debug("EvtDoSkillSuccNotify: %v", req)
// 处理技能开始的耐力消耗
g.SkillStartStamina(player, req.CasterId, req.SkillId)
g.TriggerQuest(player, constant.QUEST_FINISH_COND_TYPE_SKILL, "", int32(req.SkillId))
}
func (g *Game) EvtAvatarEnterFocusNotify(player *model.Player, payloadMsg pb.Message) {
req := payloadMsg.(*proto.EvtAvatarEnterFocusNotify)
if player.SceneLoadState != model.SceneEnterDone {
return
}
// logger.Debug("EvtAvatarEnterFocusNotify: %v", req)
world := WORLD_MANAGER.GetWorldByID(player.WorldId)
if world == nil {
return
}
scene := world.GetSceneById(player.SceneId)
g.SendToSceneA(scene, cmd.EvtAvatarEnterFocusNotify, player.ClientSeq, req)
}
func (g *Game) EvtAvatarUpdateFocusNotify(player *model.Player, payloadMsg pb.Message) {
req := payloadMsg.(*proto.EvtAvatarUpdateFocusNotify)
if player.SceneLoadState != model.SceneEnterDone {
return
}
// logger.Debug("EvtAvatarUpdateFocusNotify: %v", req)
world := WORLD_MANAGER.GetWorldByID(player.WorldId)
if world == nil {
return
}
scene := world.GetSceneById(player.SceneId)
g.SendToSceneA(scene, cmd.EvtAvatarUpdateFocusNotify, player.ClientSeq, req)
}
func (g *Game) EvtAvatarExitFocusNotify(player *model.Player, payloadMsg pb.Message) {
req := payloadMsg.(*proto.EvtAvatarExitFocusNotify)
if player.SceneLoadState != model.SceneEnterDone {
return
}
// logger.Debug("EvtAvatarExitFocusNotify: %v", req)
world := WORLD_MANAGER.GetWorldByID(player.WorldId)
if world == nil {
return
}
scene := world.GetSceneById(player.SceneId)
g.SendToSceneA(scene, cmd.EvtAvatarExitFocusNotify, player.ClientSeq, req)
}
func (g *Game) EvtEntityRenderersChangedNotify(player *model.Player, payloadMsg pb.Message) {
req := payloadMsg.(*proto.EvtEntityRenderersChangedNotify)
if player.SceneLoadState != model.SceneEnterDone {
return
}
// logger.Debug("EvtEntityRenderersChangedNotify: %v", req)
world := WORLD_MANAGER.GetWorldByID(player.WorldId)
if world == nil {
return
}
scene := world.GetSceneById(player.SceneId)
g.SendToSceneA(scene, cmd.EvtEntityRenderersChangedNotify, player.ClientSeq, req)
}
func (g *Game) EvtCreateGadgetNotify(player *model.Player, payloadMsg pb.Message) {
req := payloadMsg.(*proto.EvtCreateGadgetNotify)
if player.SceneLoadState != model.SceneEnterDone {
return
}
// logger.Debug("EvtCreateGadgetNotify: %v", req)
world := WORLD_MANAGER.GetWorldByID(player.WorldId)
if world == nil {
return
}
scene := world.GetSceneById(player.SceneId)
if req.InitPos == nil {
return
}
scene.CreateEntityGadgetClient(&model.Vector{
X: float64(req.InitPos.X),
Y: float64(req.InitPos.Y),
Z: float64(req.InitPos.Z),
}, &model.Vector{
X: float64(req.InitEulerAngles.X),
Y: float64(req.InitEulerAngles.Y),
Z: float64(req.InitEulerAngles.Z),
}, req.EntityId, req.ConfigId, req.CampId, req.CampType, req.OwnerEntityId, req.TargetEntityId, req.PropOwnerEntityId)
g.AddSceneEntityNotify(player, proto.VisionType_VISION_BORN, []uint32{req.EntityId}, true, true)
}
func (g *Game) EvtDestroyGadgetNotify(player *model.Player, payloadMsg pb.Message) {
req := payloadMsg.(*proto.EvtDestroyGadgetNotify)
if player.SceneLoadState != model.SceneEnterDone {
return
}
// logger.Debug("EvtDestroyGadgetNotify: %v", req)
world := WORLD_MANAGER.GetWorldByID(player.WorldId)
if world == nil {
return
}
scene := world.GetSceneById(player.SceneId)
scene.DestroyEntity(req.EntityId)
g.RemoveSceneEntityNotifyBroadcast(scene, proto.VisionType_VISION_MISS, []uint32{req.EntityId}, false, 0)
}
func (g *Game) EvtAiSyncSkillCdNotify(player *model.Player, payloadMsg pb.Message) {
req := payloadMsg.(*proto.EvtAiSyncSkillCdNotify)
if player.SceneLoadState != model.SceneEnterDone {
return
}
// logger.Debug("EvtAiSyncSkillCdNotify: %v", req)
world := WORLD_MANAGER.GetWorldByID(player.WorldId)
if world == nil {
return
}
scene := world.GetSceneById(player.SceneId)
g.SendToSceneA(scene, cmd.EvtAiSyncSkillCdNotify, player.ClientSeq, req)
}
func (g *Game) EvtAiSyncCombatThreatInfoNotify(player *model.Player, payloadMsg pb.Message) {
req := payloadMsg.(*proto.EvtAiSyncCombatThreatInfoNotify)
if player.SceneLoadState != model.SceneEnterDone {
return
}
// logger.Debug("EvtAiSyncCombatThreatInfoNotify: %v", req)
world := WORLD_MANAGER.GetWorldByID(player.WorldId)
if world == nil {
return
}
scene := world.GetSceneById(player.SceneId)
g.SendToSceneA(scene, cmd.EvtAiSyncCombatThreatInfoNotify, player.ClientSeq, req)
}
func (g *Game) EntityConfigHashNotify(player *model.Player, payloadMsg pb.Message) {
req := payloadMsg.(*proto.EntityConfigHashNotify)
_ = req
}
func (g *Game) MonsterAIConfigHashNotify(player *model.Player, payloadMsg pb.Message) {
req := payloadMsg.(*proto.MonsterAIConfigHashNotify)
_ = req
}
func (g *Game) SetEntityClientDataNotify(player *model.Player, payloadMsg pb.Message) {
req := payloadMsg.(*proto.SetEntityClientDataNotify)
g.SendMsg(cmd.SetEntityClientDataNotify, player.PlayerID, player.ClientSeq, req)
}
func (g *Game) EntityAiSyncNotify(player *model.Player, payloadMsg pb.Message) {
req := payloadMsg.(*proto.EntityAiSyncNotify)
entityAiSyncNotify := &proto.EntityAiSyncNotify{
InfoList: make([]*proto.AiSyncInfo, 0),
}
for _, monsterId := range req.LocalAvatarAlertedMonsterList {
entityAiSyncNotify.InfoList = append(entityAiSyncNotify.InfoList, &proto.AiSyncInfo{
EntityId: monsterId,
HasPathToTarget: true,
IsSelfKilling: false,
})
}
g.SendMsg(cmd.EntityAiSyncNotify, player.PlayerID, player.ClientSeq, entityAiSyncNotify)
}
// TODO 一些很low的解决方案 我本来是不想写的 有多low要多low有多low
func (g *Game) handleGadgetEntityBeHitLow(player *model.Player, entity *Entity, hitElementType uint32) {
world := WORLD_MANAGER.GetWorldByID(player.WorldId)
if world == nil {
return
}
scene := world.GetSceneById(player.SceneId)
if entity.GetEntityType() != constant.ENTITY_TYPE_GADGET {
return
}
gadgetEntity := entity.GetGadgetEntity()
gadgetId := gadgetEntity.GetGadgetId()
gadgetDataConfig := gdconf.GetGadgetDataById(int32(gadgetId))
if gadgetDataConfig == nil {
logger.Error("get gadget data config is nil, gadgetId: %v", gadgetEntity.GetGadgetId())
return
}
if strings.Contains(gadgetDataConfig.Name, "火把") ||
strings.Contains(gadgetDataConfig.Name, "火盆") ||
strings.Contains(gadgetDataConfig.Name, "篝火") {
// 火把点燃
if hitElementType != constant.ELEMENT_TYPE_FIRE {
return
}
g.ChangeGadgetState(player, entity.GetId(), constant.GADGET_STATE_GEAR_START)
} else if strings.Contains(gadgetDataConfig.ServerLuaScript, "Controller") {
// 元素方碑点亮
gadgetElementType := uint32(0)
if strings.Contains(gadgetDataConfig.ServerLuaScript, "Fire") {
gadgetElementType = constant.ELEMENT_TYPE_FIRE
} else if strings.Contains(gadgetDataConfig.ServerLuaScript, "Water") {
gadgetElementType = constant.ELEMENT_TYPE_WATER
} else if strings.Contains(gadgetDataConfig.ServerLuaScript, "Grass") {
gadgetElementType = constant.ELEMENT_TYPE_GRASS
} else if strings.Contains(gadgetDataConfig.ServerLuaScript, "Elec") {
gadgetElementType = constant.ELEMENT_TYPE_ELEC
} else if strings.Contains(gadgetDataConfig.ServerLuaScript, "Ice") {
gadgetElementType = constant.ELEMENT_TYPE_ICE
} else if strings.Contains(gadgetDataConfig.ServerLuaScript, "Wind") {
gadgetElementType = constant.ELEMENT_TYPE_WIND
} else if strings.Contains(gadgetDataConfig.ServerLuaScript, "Rock") {
gadgetElementType = constant.ELEMENT_TYPE_ROCK
}
if hitElementType != gadgetElementType {
return
}
g.ChangeGadgetState(player, entity.GetId(), constant.GADGET_STATE_GEAR_START)
} else if strings.Contains(gadgetDataConfig.ServerLuaScript, "SubfieldDrop_WoodenObject_Broken") {
// 木箱破碎
g.KillEntity(player, scene, entity.GetId(), proto.PlayerDieType_PLAYER_DIE_GM)
}
}
func (g *Game) handleGadgetEntityAbilityLow(player *model.Player, entityId uint32, argument proto.AbilityInvokeArgument, entry pb.Message) {
world := WORLD_MANAGER.GetWorldByID(player.WorldId)
if world == nil {
return
}
scene := world.GetSceneById(player.SceneId)
entity := scene.GetEntity(entityId)
if entity == nil {
return
}
switch argument {
case proto.AbilityInvokeArgument_ABILITY_META_MODIFIER_CHANGE:
// 物件破碎
modifierChange := entry.(*proto.AbilityMetaModifierChange)
if modifierChange.Action != proto.ModifierAction_REMOVED {
return
}
if entity.GetEntityType() != constant.ENTITY_TYPE_GADGET {
return
}
gadgetEntity := entity.GetGadgetEntity()
gadgetId := gadgetEntity.GetGadgetId()
gadgetDataConfig := gdconf.GetGadgetDataById(int32(gadgetId))
if gadgetDataConfig == nil {
logger.Error("get gadget data config is nil, gadgetId: %v", gadgetEntity.GetGadgetId())
return
}
if strings.Contains(gadgetDataConfig.Name, "碎石堆") ||
strings.Contains(gadgetDataConfig.ServerLuaScript, "SubfieldDrop_WoodenObject_Broken") {
logger.Debug("物件破碎, entityId: %v, modifierChange: %v, uid: %v", entityId, modifierChange, player.PlayerID)
g.KillEntity(player, scene, entity.GetId(), proto.PlayerDieType_PLAYER_DIE_GM)
} else if strings.Contains(gadgetDataConfig.ServerLuaScript, "SubfieldDrop_Ore") {
g.KillEntity(player, scene, entity.GetId(), proto.PlayerDieType_PLAYER_DIE_GM)
g.CreateDropGadget(player, entity.GetPos(), 70900001, 233, 1)
}
}
}