重击体力消耗

This commit is contained in:
huangxiaolei
2022-12-12 19:13:32 +08:00
parent 62b08c2ac7
commit 3e9e375e19
10 changed files with 228 additions and 101 deletions

View File

@@ -9,10 +9,11 @@ import (
// 角色技能配置表 // 角色技能配置表
type AvatarSkillData struct { type AvatarSkillData struct {
AvatarSkillId int32 `csv:"AvatarSkillId"` // ID AvatarSkillId int32 `csv:"AvatarSkillId"` // ID
CostStamina int32 `csv:"CostStamina,omitempty"` // 消耗体力 AbilityName string `csv:"AbilityName,omitempty"` // Ability名称
CostElemType int32 `csv:"CostElemType,omitempty"` // 消耗能量类型 CostStamina int32 `csv:"CostStamina,omitempty"` // 消耗体力
CostElemVal int32 `csv:"CostElemVal,omitempty"` // 消耗能量 CostElemType int32 `csv:"CostElemType,omitempty"` // 消耗能量类型
CostElemVal int32 `csv:"CostElemVal,omitempty"` // 消耗能量值
} }
func (g *GameDataConfig) loadAvatarSkillData() { func (g *GameDataConfig) loadAvatarSkillData() {

View File

@@ -1,5 +1,5 @@
AvatarSkillId,,,,,CostStamina,CostElemType,CostElemVal,,,,,,,,,,,,,,,,,,,, AvatarSkillId,AbilityName,,,,CostStamina,CostElemType,CostElemVal,,,,,,,,,,,,,,,,,,,,
int32,,,,,int32,int32,int32,,,,,,,,,,,,,,,,,,,, int32,string,,,,int32,int32,int32,,,,,,,,,,,,,,,,,,,,
ID,Ability名称,是远程,技能CD,无视冷却缩减属性,消耗体力,消耗能量类型,消耗能量值,可累积次数,TriggerID,索敌范围,索敌公式权重1,索敌公式权重2,索敌公式权重3,索敌公式权重4,是默认镜头,支持按钮拖动,是否显示箭头,是否监控状态,默认锁定,图标名称,升级技能组ID,技能能量键值,消耗能量最小值,CanDoSkill为false强制可用,处理冷却所属技能槽,是否存档,shareCDID ID,Ability名称,是远程,技能CD,无视冷却缩减属性,消耗体力,消耗能量类型,消耗能量值,可累积次数,TriggerID,索敌范围,索敌公式权重1,索敌公式权重2,索敌公式权重3,索敌公式权重4,是默认镜头,支持按钮拖动,是否显示箭头,是否监控状态,默认锁定,图标名称,升级技能组ID,技能能量键值,消耗能量最小值,CanDoSkill为false强制可用,处理冷却所属技能槽,是否存档,shareCDID
10001,,,0,,1,,,1,0,CircleLockEnemyR5H6HC,1,1,0.3,0,1,,,,,,0,,,,,, 10001,,,0,,1,,,1,0,CircleLockEnemyR5H6HC,1,1,0.3,0,1,,,,,,0,,,,,,
10002,,,0,,1,,,1,0,CircleLockEnemyR5H6HC,1,1,0.3,0,1,,,,,,0,,,,,, 10002,,,0,,1,,,1,0,CircleLockEnemyR5H6HC,1,1,0.3,0,1,,,,,,0,,,,,,
@@ -270,7 +270,7 @@ ID,Ability
10655,,,15,,0,4,60,1,5,CircleLockEnemyR8H6HC,1,1,0.3,0,1,,,,,,6539,,,,,, 10655,,,15,,0,4,60,1,5,CircleLockEnemyR8H6HC,1,1,0.3,0,1,,,,,,6539,,,,,,
10656,Avatar_Shinobu_Constellation6_Limbo_Trigger,,60,1,0,,,1,0,CircleLockEnemyR5H6HC,1,1,0.3,0,1,,,,,,0,,,,,1, 10656,Avatar_Shinobu_Constellation6_Limbo_Trigger,,60,1,0,,,1,0,CircleLockEnemyR5H6HC,1,1,0.3,0,1,,,,,,0,,,,,1,
10657,Avatar_Shinobu_Constellation6_Limbo_Trigger,,60,1,0,,,1,0,CircleLockEnemyR5H6HC,1,1,0.3,0,1,,,,,,0,,,,,1, 10657,Avatar_Shinobu_Constellation6_Limbo_Trigger,,60,1,0,,,1,0,CircleLockEnemyR5H6HC,1,1,0.3,0,1,,,,,,0,,,,,1,
10661,Avatar_Ayato_ExtraAttack,,0,,0,,,1,0,CircleLockEnemyR5H6HC,1,1,0.3,0,1,,,,,,6631,,,,,, 10661,Avatar_Ayato_ExtraAttack,,0,,6000,,,1,0,CircleLockEnemyR5H6HC,1,1,0.3,0,1,,,,,,6631,,,,,,
10662,,,12,,0,,,1,2,CircleLockEnemyR8H6HC,1,1,0.3,0,1,,,,,,6632,,,,,, 10662,,,12,,0,,,1,2,CircleLockEnemyR8H6HC,1,1,0.3,0,1,,,,,,6632,,,,,,
10663,Avatar_Ayato_KendoPose_Click,,0,,0,,,1,0,CircleLockEnemyR10H6HC,1,1,0.3,0,1,,,,,,0,,,,,, 10663,Avatar_Ayato_KendoPose_Click,,0,,0,,,1,0,CircleLockEnemyR10H6HC,1,1,0.3,0,1,,,,,,0,,,,,,
10665,,,20,,0,2,80,1,5,CircleLockEnemyR5H6HC,1,1,0.3,0,1,,,,,,6639,,,,,, 10665,,,20,,0,2,80,1,5,CircleLockEnemyR5H6HC,1,1,0.3,0,1,,,,,,6639,,,,,,
1 AvatarSkillId AbilityName CostStamina CostElemType CostElemVal
2 int32 string int32 int32 int32
3 ID Ability名称 Ability名称 是远程 是远程 技能CD 技能CD 无视冷却缩减属性 消耗体力 消耗能量类型 消耗能量值 无视冷却缩减属性 可累积次数 可累积次数 TriggerID TriggerID 索敌范围 索敌范围 索敌公式权重1 索敌公式权重1 索敌公式权重2 索敌公式权重2 索敌公式权重3 索敌公式权重3 索敌公式权重4 索敌公式权重4 是默认镜头 是默认镜头 支持按钮拖动 支持按钮拖动 是否显示箭头 是否显示箭头 是否监控状态 是否监控状态 默认锁定 默认锁定 图标名称 图标名称 升级技能组ID 升级技能组ID 技能能量键值 技能能量键值 消耗能量最小值 消耗能量最小值 CanDoSkill为false强制可用 CanDoSkill为false强制可用 处理冷却所属技能槽 处理冷却所属技能槽 是否存档 shareCDID 是否存档 shareCDID
4 10001 0 0 1 1 1 0 0 CircleLockEnemyR5H6HC CircleLockEnemyR5H6HC 1 1 1 0.3 0.3 0 0 1 1 0 0
5 10002 0 0 1 1 1 0 0 CircleLockEnemyR5H6HC CircleLockEnemyR5H6HC 1 1 1 0.3 0.3 0 0 1 1 0 0
270 10655 15 15 0 4 60 1 1 5 5 CircleLockEnemyR8H6HC CircleLockEnemyR8H6HC 1 1 1 0.3 0.3 0 0 1 1 6539 6539
271 10656 Avatar_Shinobu_Constellation6_Limbo_Trigger Avatar_Shinobu_Constellation6_Limbo_Trigger 60 60 1 0 1 1 0 0 CircleLockEnemyR5H6HC CircleLockEnemyR5H6HC 1 1 1 0.3 0.3 0 0 1 1 0 0 1 1
272 10657 Avatar_Shinobu_Constellation6_Limbo_Trigger Avatar_Shinobu_Constellation6_Limbo_Trigger 60 60 1 0 1 1 0 0 CircleLockEnemyR5H6HC CircleLockEnemyR5H6HC 1 1 1 0.3 0.3 0 0 1 1 0 0 1 1
273 10661 Avatar_Ayato_ExtraAttack Avatar_Ayato_ExtraAttack 0 0 0 6000 1 1 0 0 CircleLockEnemyR5H6HC CircleLockEnemyR5H6HC 1 1 1 0.3 0.3 0 0 1 1 6631 6631
274 10662 12 12 0 1 1 2 2 CircleLockEnemyR8H6HC CircleLockEnemyR8H6HC 1 1 1 0.3 0.3 0 0 1 1 6632 6632
275 10663 Avatar_Ayato_KendoPose_Click Avatar_Ayato_KendoPose_Click 0 0 0 1 1 0 0 CircleLockEnemyR10H6HC CircleLockEnemyR10H6HC 1 1 1 0.3 0.3 0 0 1 1 0 0
276 10665 20 20 0 2 80 1 1 5 5 CircleLockEnemyR5H6HC CircleLockEnemyR5H6HC 1 1 1 0.3 0.3 0 0 1 1 6639 6639

View File

@@ -3,6 +3,7 @@ package game
import ( import (
"hk4e/gs/model" "hk4e/gs/model"
"hk4e/pkg/logger" "hk4e/pkg/logger"
"hk4e/pkg/object"
"time" "time"
) )
@@ -43,8 +44,8 @@ func (l *LocalEventManager) LocalEventHandle(localEvent *LocalEvent) {
case RunUserCopyAndSave: case RunUserCopyAndSave:
startTime := time.Now().UnixNano() startTime := time.Now().UnixNano()
// 拷贝一份数据避免并发访问 // 拷贝一份数据避免并发访问
insertPlayerList := make([]model.Player, 0, len(USER_MANAGER.playerMap)) insertPlayerList := make([]*model.Player, 0)
updatePlayerList := make([]model.Player, 0, len(USER_MANAGER.playerMap)) updatePlayerList := make([]*model.Player, 0)
for uid, player := range USER_MANAGER.playerMap { for uid, player := range USER_MANAGER.playerMap {
if uid < 100000000 { if uid < 100000000 {
continue continue
@@ -53,26 +54,36 @@ func (l *LocalEventManager) LocalEventHandle(localEvent *LocalEvent) {
case model.DbNone: case model.DbNone:
break break
case model.DbInsert: case model.DbInsert:
insertPlayerList = append(insertPlayerList, *player) playerCopy := new(model.Player)
err := object.FastDeepCopy(playerCopy, player)
if err != nil {
logger.LOG.Error("deep copy player error: %v", err)
continue
}
insertPlayerList = append(insertPlayerList, playerCopy)
USER_MANAGER.playerMap[uid].DbState = model.DbNormal USER_MANAGER.playerMap[uid].DbState = model.DbNormal
case model.DbDelete: case model.DbDelete:
updatePlayerList = append(updatePlayerList, *player) playerCopy := new(model.Player)
err := object.FastDeepCopy(playerCopy, player)
if err != nil {
logger.LOG.Error("deep copy player error: %v", err)
continue
}
updatePlayerList = append(updatePlayerList, playerCopy)
delete(USER_MANAGER.playerMap, uid) delete(USER_MANAGER.playerMap, uid)
case model.DbNormal: case model.DbNormal:
updatePlayerList = append(updatePlayerList, *player) playerCopy := new(model.Player)
err := object.FastDeepCopy(playerCopy, player)
if err != nil {
logger.LOG.Error("deep copy player error: %v", err)
continue
}
updatePlayerList = append(updatePlayerList, playerCopy)
} }
} }
insertPlayerPointerList := make([]*model.Player, 0, len(insertPlayerList))
updatePlayerPointerList := make([]*model.Player, 0, len(updatePlayerList))
for _, player := range insertPlayerList {
insertPlayerPointerList = append(insertPlayerPointerList, &player)
}
for _, player := range updatePlayerList {
updatePlayerPointerList = append(updatePlayerPointerList, &player)
}
USER_MANAGER.saveUserChan <- &SaveUserData{ USER_MANAGER.saveUserChan <- &SaveUserData{
insertPlayerList: insertPlayerPointerList, insertPlayerList: insertPlayerList,
updatePlayerList: updatePlayerPointerList, updatePlayerList: updatePlayerList,
} }
endTime := time.Now().UnixNano() endTime := time.Now().UnixNano()
costTime := endTime - startTime costTime := endTime - startTime

View File

@@ -10,8 +10,12 @@ import (
pb "google.golang.org/protobuf/proto" pb "google.golang.org/protobuf/proto"
) )
var cmdProtoMap *cmd.CmdProtoMap = nil
func DoForward[IET model.InvokeEntryType](player *model.Player, req pb.Message, copyFieldList []string, forwardField string, invokeHandler *model.InvokeHandler[IET]) { func DoForward[IET model.InvokeEntryType](player *model.Player, req pb.Message, copyFieldList []string, forwardField string, invokeHandler *model.InvokeHandler[IET]) {
cmdProtoMap := cmd.NewCmdProtoMap() if cmdProtoMap == nil {
cmdProtoMap = cmd.NewCmdProtoMap()
}
cmdId := cmdProtoMap.GetCmdIdByProtoObj(req) cmdId := cmdProtoMap.GetCmdIdByProtoObj(req)
world := WORLD_MANAGER.GetWorldByID(player.WorldId) world := WORLD_MANAGER.GetWorldByID(player.WorldId)
if invokeHandler.AllLen() == 0 && invokeHandler.AllExceptCurLen() == 0 && invokeHandler.HostLen() == 0 { if invokeHandler.AllLen() == 0 && invokeHandler.AllExceptCurLen() == 0 && invokeHandler.HostLen() == 0 {
@@ -53,6 +57,9 @@ func (g *GameManager) UnionCmdNotify(player *model.Player, payloadMsg pb.Message
//logger.LOG.Debug("user send union cmd, uid: %v", player.PlayerID) //logger.LOG.Debug("user send union cmd, uid: %v", player.PlayerID)
req := payloadMsg.(*proto.UnionCmdNotify) req := payloadMsg.(*proto.UnionCmdNotify)
_ = req _ = req
if player.SceneLoadState != model.SceneEnterDone {
return
}
DoForward[proto.CombatInvokeEntry](player, &proto.CombatInvocationsNotify{}, []string{}, "InvokeList", player.CombatInvokeHandler) DoForward[proto.CombatInvokeEntry](player, &proto.CombatInvocationsNotify{}, []string{}, "InvokeList", player.CombatInvokeHandler)
DoForward[proto.AbilityInvokeEntry](player, &proto.AbilityInvocationsNotify{}, []string{}, "Invokes", player.AbilityInvokeHandler) DoForward[proto.AbilityInvokeEntry](player, &proto.AbilityInvocationsNotify{}, []string{}, "Invokes", player.AbilityInvokeHandler)
player.CombatInvokeHandler.Clear() player.CombatInvokeHandler.Clear()
@@ -62,6 +69,9 @@ func (g *GameManager) UnionCmdNotify(player *model.Player, payloadMsg pb.Message
func (g *GameManager) MassiveEntityElementOpBatchNotify(player *model.Player, payloadMsg pb.Message) { func (g *GameManager) MassiveEntityElementOpBatchNotify(player *model.Player, payloadMsg pb.Message) {
//logger.LOG.Debug("user meeo sync, uid: %v", player.PlayerID) //logger.LOG.Debug("user meeo sync, uid: %v", player.PlayerID)
req := payloadMsg.(*proto.MassiveEntityElementOpBatchNotify) req := payloadMsg.(*proto.MassiveEntityElementOpBatchNotify)
if player.SceneLoadState != model.SceneEnterDone {
return
}
ntf := req ntf := req
world := WORLD_MANAGER.GetWorldByID(player.WorldId) world := WORLD_MANAGER.GetWorldByID(player.WorldId)
if world == nil { if world == nil {
@@ -80,12 +90,8 @@ func (g *GameManager) CombatInvocationsNotify(player *model.Player, payloadMsg p
return return
} }
world := WORLD_MANAGER.GetWorldByID(player.WorldId) world := WORLD_MANAGER.GetWorldByID(player.WorldId)
if world == nil {
return
}
scene := world.GetSceneById(player.SceneId) scene := world.GetSceneById(player.SceneId)
for _, entry := range req.InvokeList { for _, entry := range req.InvokeList {
//logger.LOG.Debug("AT: %v, FT: %v, UID: %v", entry.ArgumentType, entry.ForwardType, player.PlayerID)
switch entry.ArgumentType { switch entry.ArgumentType {
case proto.CombatTypeArgument_COMBAT_TYPE_ARGUMENT_EVT_BEING_HIT: case proto.CombatTypeArgument_COMBAT_TYPE_ARGUMENT_EVT_BEING_HIT:
player.CombatInvokeHandler.AddEntry(entry.ForwardType, entry) player.CombatInvokeHandler.AddEntry(entry.ForwardType, entry)
@@ -93,7 +99,7 @@ func (g *GameManager) CombatInvocationsNotify(player *model.Player, payloadMsg p
entityMoveInfo := new(proto.EntityMoveInfo) entityMoveInfo := new(proto.EntityMoveInfo)
err := pb.Unmarshal(entry.CombatData, entityMoveInfo) err := pb.Unmarshal(entry.CombatData, entityMoveInfo)
if err != nil { if err != nil {
logger.LOG.Error("parse combat invocations entity move info error: %v", err) logger.LOG.Error("parse EntityMoveInfo error: %v", err)
continue continue
} }
motionInfo := entityMoveInfo.MotionInfo motionInfo := entityMoveInfo.MotionInfo
@@ -129,7 +135,6 @@ func (g *GameManager) CombatInvocationsNotify(player *model.Player, payloadMsg p
sceneEntity.moveState = uint16(motionInfo.State) sceneEntity.moveState = uint16(motionInfo.State)
sceneEntity.lastMoveSceneTimeMs = entityMoveInfo.SceneTime sceneEntity.lastMoveSceneTimeMs = entityMoveInfo.SceneTime
sceneEntity.lastMoveReliableSeq = entityMoveInfo.ReliableSeq sceneEntity.lastMoveReliableSeq = entityMoveInfo.ReliableSeq
//logger.LOG.Debug("entity move, id: %v, pos: %v, uid: %v", sceneEntity.id, sceneEntity.pos, player.PlayerID)
// 处理耐力消耗 // 处理耐力消耗
g.HandleStamina(player, motionInfo.State) g.HandleStamina(player, motionInfo.State)
@@ -141,7 +146,7 @@ func (g *GameManager) CombatInvocationsNotify(player *model.Player, payloadMsg p
if err != nil { if err != nil {
logger.LOG.Error("parse EvtAnimatorStateChangedInfo error: %v", err) logger.LOG.Error("parse EvtAnimatorStateChangedInfo error: %v", err)
} }
logger.LOG.Debug("%v", evtAnimatorStateChangedInfo) logger.LOG.Debug("EvtAnimatorStateChangedInfo: %v", entry, player.PlayerID)
player.CombatInvokeHandler.AddEntry(entry.ForwardType, entry) player.CombatInvokeHandler.AddEntry(entry.ForwardType, entry)
default: default:
player.CombatInvokeHandler.AddEntry(entry.ForwardType, entry) player.CombatInvokeHandler.AddEntry(entry.ForwardType, entry)
@@ -152,13 +157,39 @@ func (g *GameManager) CombatInvocationsNotify(player *model.Player, payloadMsg p
func (g *GameManager) AbilityInvocationsNotify(player *model.Player, payloadMsg pb.Message) { func (g *GameManager) AbilityInvocationsNotify(player *model.Player, payloadMsg pb.Message) {
//logger.LOG.Debug("user ability invocations, uid: %v", player.PlayerID) //logger.LOG.Debug("user ability invocations, uid: %v", player.PlayerID)
req := payloadMsg.(*proto.AbilityInvocationsNotify) req := payloadMsg.(*proto.AbilityInvocationsNotify)
if player.SceneLoadState != model.SceneEnterDone {
return
}
for _, entry := range req.Invokes { for _, entry := range req.Invokes {
//logger.LOG.Debug("AT: %v, FT: %v, UID: %v", entry.ArgumentType, entry.ForwardType, player.PlayerID) //logger.LOG.Debug("AbilityInvocationsNotify: %v", entry, player.PlayerID)
// 处理能力调用 //switch entry.ArgumentType {
g.HandleAbilityInvoke(player, entry) //case proto.AbilityInvokeArgument_ABILITY_INVOKE_ARGUMENT_META_MODIFIER_CHANGE:
// world := WORLD_MANAGER.GetWorldByID(player.WorldId)
// worldAvatar := world.GetWorldAvatarByEntityId(entry.EntityId)
// if worldAvatar != nil {
// for _, ability := range worldAvatar.abilityList {
// if ability.InstancedAbilityId == entry.Head.InstancedAbilityId {
// logger.LOG.Error("A: %v", ability)
// }
// }
// for _, modifier := range worldAvatar.modifierList {
// if modifier.InstancedAbilityId == entry.Head.InstancedAbilityId {
// logger.LOG.Error("B: %v", modifier)
// }
// }
// for _, modifier := range worldAvatar.modifierList {
// if modifier.InstancedModifierId == entry.Head.InstancedModifierId {
// logger.LOG.Error("C: %v", modifier)
// }
// }
// }
//case proto.AbilityInvokeArgument_ABILITY_INVOKE_ARGUMENT_NONE:
//}
// 处理耐力消耗
g.HandleAbilityStamina(player, entry)
player.AbilityInvokeHandler.AddEntry(entry.ForwardType, entry) player.AbilityInvokeHandler.AddEntry(entry.ForwardType, entry)
} }
} }
@@ -166,13 +197,12 @@ func (g *GameManager) AbilityInvocationsNotify(player *model.Player, payloadMsg
func (g *GameManager) ClientAbilityInitFinishNotify(player *model.Player, payloadMsg pb.Message) { func (g *GameManager) ClientAbilityInitFinishNotify(player *model.Player, payloadMsg pb.Message) {
//logger.LOG.Debug("user client ability init finish, uid: %v", player.PlayerID) //logger.LOG.Debug("user client ability init finish, uid: %v", player.PlayerID)
req := payloadMsg.(*proto.ClientAbilityInitFinishNotify) req := payloadMsg.(*proto.ClientAbilityInitFinishNotify)
if player.SceneLoadState != model.SceneEnterDone {
return
}
invokeHandler := model.NewInvokeHandler[proto.AbilityInvokeEntry]() invokeHandler := model.NewInvokeHandler[proto.AbilityInvokeEntry]()
for _, entry := range req.Invokes { for _, entry := range req.Invokes {
//logger.LOG.Debug("AT: %v, FT: %v, UID: %v", entry.ArgumentType, entry.ForwardType, player.PlayerID) logger.LOG.Debug("ClientAbilityInitFinishNotify: %v", entry, player.PlayerID)
// 处理能力调用
g.HandleAbilityInvoke(player, entry)
invokeHandler.AddEntry(entry.ForwardType, entry) invokeHandler.AddEntry(entry.ForwardType, entry)
} }
DoForward[proto.AbilityInvokeEntry](player, &proto.ClientAbilityInitFinishNotify{}, []string{"EntityId"}, "Invokes", invokeHandler) DoForward[proto.AbilityInvokeEntry](player, &proto.ClientAbilityInitFinishNotify{}, []string{"EntityId"}, "Invokes", invokeHandler)
@@ -181,8 +211,13 @@ func (g *GameManager) ClientAbilityInitFinishNotify(player *model.Player, payloa
func (g *GameManager) ClientAbilityChangeNotify(player *model.Player, payloadMsg pb.Message) { func (g *GameManager) ClientAbilityChangeNotify(player *model.Player, payloadMsg pb.Message) {
//logger.LOG.Debug("user client ability change, uid: %v", player.PlayerID) //logger.LOG.Debug("user client ability change, uid: %v", player.PlayerID)
req := payloadMsg.(*proto.ClientAbilityChangeNotify) req := payloadMsg.(*proto.ClientAbilityChangeNotify)
if player.SceneLoadState != model.SceneEnterDone {
return
}
invokeHandler := model.NewInvokeHandler[proto.AbilityInvokeEntry]() invokeHandler := model.NewInvokeHandler[proto.AbilityInvokeEntry]()
for _, entry := range req.Invokes { for _, entry := range req.Invokes {
logger.LOG.Debug("ClientAbilityChangeNotify: %v", entry, player.PlayerID)
invokeHandler.AddEntry(entry.ForwardType, entry) invokeHandler.AddEntry(entry.ForwardType, entry)
} }
DoForward[proto.AbilityInvokeEntry](player, req, []string{"EntityId", "IsInitHash"}, "Invokes", invokeHandler) DoForward[proto.AbilityInvokeEntry](player, req, []string{"EntityId", "IsInitHash"}, "Invokes", invokeHandler)
@@ -240,15 +275,18 @@ func (g *GameManager) ClientAbilityChangeNotify(player *model.Player, payloadMsg
func (g *GameManager) EvtDoSkillSuccNotify(player *model.Player, payloadMsg pb.Message) { func (g *GameManager) EvtDoSkillSuccNotify(player *model.Player, payloadMsg pb.Message) {
logger.LOG.Debug("user event do skill success, uid: %v", player.PlayerID) logger.LOG.Debug("user event do skill success, uid: %v", player.PlayerID)
req := payloadMsg.(*proto.EvtDoSkillSuccNotify) req := payloadMsg.(*proto.EvtDoSkillSuccNotify)
if player.SceneLoadState != model.SceneEnterDone {
return
}
logger.LOG.Debug("EvtDoSkillSuccNotify: %v", req) logger.LOG.Debug("EvtDoSkillSuccNotify: %v", req)
// 处理技能开始时的耐力消耗
g.HandleSkillStartStamina(player, req.SkillId)
} }
func (g *GameManager) EvtAvatarEnterFocusNotify(player *model.Player, payloadMsg pb.Message) { func (g *GameManager) EvtAvatarEnterFocusNotify(player *model.Player, payloadMsg pb.Message) {
logger.LOG.Debug("user avatar enter focus, uid: %v", player.PlayerID) logger.LOG.Debug("user avatar enter focus, uid: %v", player.PlayerID)
req := payloadMsg.(*proto.EvtAvatarEnterFocusNotify) req := payloadMsg.(*proto.EvtAvatarEnterFocusNotify)
if player.SceneLoadState != model.SceneEnterDone {
return
}
logger.LOG.Debug("EvtAvatarEnterFocusNotify: %v", req) logger.LOG.Debug("EvtAvatarEnterFocusNotify: %v", req)
world := WORLD_MANAGER.GetWorldByID(player.WorldId) world := WORLD_MANAGER.GetWorldByID(player.WorldId)
g.SendToWorldA(world, cmd.EvtAvatarEnterFocusNotify, player.ClientSeq, req) g.SendToWorldA(world, cmd.EvtAvatarEnterFocusNotify, player.ClientSeq, req)
@@ -257,6 +295,9 @@ func (g *GameManager) EvtAvatarEnterFocusNotify(player *model.Player, payloadMsg
func (g *GameManager) EvtAvatarUpdateFocusNotify(player *model.Player, payloadMsg pb.Message) { func (g *GameManager) EvtAvatarUpdateFocusNotify(player *model.Player, payloadMsg pb.Message) {
logger.LOG.Debug("user avatar update focus, uid: %v", player.PlayerID) logger.LOG.Debug("user avatar update focus, uid: %v", player.PlayerID)
req := payloadMsg.(*proto.EvtAvatarUpdateFocusNotify) req := payloadMsg.(*proto.EvtAvatarUpdateFocusNotify)
if player.SceneLoadState != model.SceneEnterDone {
return
}
logger.LOG.Debug("EvtAvatarUpdateFocusNotify: %v", req) logger.LOG.Debug("EvtAvatarUpdateFocusNotify: %v", req)
world := WORLD_MANAGER.GetWorldByID(player.WorldId) world := WORLD_MANAGER.GetWorldByID(player.WorldId)
g.SendToWorldA(world, cmd.EvtAvatarUpdateFocusNotify, player.ClientSeq, req) g.SendToWorldA(world, cmd.EvtAvatarUpdateFocusNotify, player.ClientSeq, req)
@@ -265,6 +306,9 @@ func (g *GameManager) EvtAvatarUpdateFocusNotify(player *model.Player, payloadMs
func (g *GameManager) EvtAvatarExitFocusNotify(player *model.Player, payloadMsg pb.Message) { func (g *GameManager) EvtAvatarExitFocusNotify(player *model.Player, payloadMsg pb.Message) {
logger.LOG.Debug("user avatar exit focus, uid: %v", player.PlayerID) logger.LOG.Debug("user avatar exit focus, uid: %v", player.PlayerID)
req := payloadMsg.(*proto.EvtAvatarExitFocusNotify) req := payloadMsg.(*proto.EvtAvatarExitFocusNotify)
if player.SceneLoadState != model.SceneEnterDone {
return
}
logger.LOG.Debug("EvtAvatarExitFocusNotify: %v", req) logger.LOG.Debug("EvtAvatarExitFocusNotify: %v", req)
world := WORLD_MANAGER.GetWorldByID(player.WorldId) world := WORLD_MANAGER.GetWorldByID(player.WorldId)
g.SendToWorldA(world, cmd.EvtAvatarExitFocusNotify, player.ClientSeq, req) g.SendToWorldA(world, cmd.EvtAvatarExitFocusNotify, player.ClientSeq, req)
@@ -273,6 +317,9 @@ func (g *GameManager) EvtAvatarExitFocusNotify(player *model.Player, payloadMsg
func (g *GameManager) EvtEntityRenderersChangedNotify(player *model.Player, payloadMsg pb.Message) { func (g *GameManager) EvtEntityRenderersChangedNotify(player *model.Player, payloadMsg pb.Message) {
logger.LOG.Debug("user entity render change, uid: %v", player.PlayerID) logger.LOG.Debug("user entity render change, uid: %v", player.PlayerID)
req := payloadMsg.(*proto.EvtEntityRenderersChangedNotify) req := payloadMsg.(*proto.EvtEntityRenderersChangedNotify)
if player.SceneLoadState != model.SceneEnterDone {
return
}
logger.LOG.Debug("EvtEntityRenderersChangedNotify: %v", req) logger.LOG.Debug("EvtEntityRenderersChangedNotify: %v", req)
world := WORLD_MANAGER.GetWorldByID(player.WorldId) world := WORLD_MANAGER.GetWorldByID(player.WorldId)
g.SendToWorldA(world, cmd.EvtEntityRenderersChangedNotify, player.ClientSeq, req) g.SendToWorldA(world, cmd.EvtEntityRenderersChangedNotify, player.ClientSeq, req)
@@ -281,6 +328,9 @@ func (g *GameManager) EvtEntityRenderersChangedNotify(player *model.Player, payl
func (g *GameManager) EvtCreateGadgetNotify(player *model.Player, payloadMsg pb.Message) { func (g *GameManager) EvtCreateGadgetNotify(player *model.Player, payloadMsg pb.Message) {
logger.LOG.Debug("user create gadget, uid: %v", player.PlayerID) logger.LOG.Debug("user create gadget, uid: %v", player.PlayerID)
req := payloadMsg.(*proto.EvtCreateGadgetNotify) req := payloadMsg.(*proto.EvtCreateGadgetNotify)
if player.SceneLoadState != model.SceneEnterDone {
return
}
logger.LOG.Debug("EvtCreateGadgetNotify: %v", req) logger.LOG.Debug("EvtCreateGadgetNotify: %v", req)
world := WORLD_MANAGER.GetWorldByID(player.WorldId) world := WORLD_MANAGER.GetWorldByID(player.WorldId)
scene := world.GetSceneById(player.SceneId) scene := world.GetSceneById(player.SceneId)
@@ -299,6 +349,9 @@ func (g *GameManager) EvtCreateGadgetNotify(player *model.Player, payloadMsg pb.
func (g *GameManager) EvtDestroyGadgetNotify(player *model.Player, payloadMsg pb.Message) { func (g *GameManager) EvtDestroyGadgetNotify(player *model.Player, payloadMsg pb.Message) {
logger.LOG.Debug("user destroy gadget, uid: %v", player.PlayerID) logger.LOG.Debug("user destroy gadget, uid: %v", player.PlayerID)
req := payloadMsg.(*proto.EvtDestroyGadgetNotify) req := payloadMsg.(*proto.EvtDestroyGadgetNotify)
if player.SceneLoadState != model.SceneEnterDone {
return
}
logger.LOG.Debug("EvtDestroyGadgetNotify: %v", req) logger.LOG.Debug("EvtDestroyGadgetNotify: %v", req)
world := WORLD_MANAGER.GetWorldByID(player.WorldId) world := WORLD_MANAGER.GetWorldByID(player.WorldId)
scene := world.GetSceneById(player.SceneId) scene := world.GetSceneById(player.SceneId)

View File

@@ -5,30 +5,60 @@ import (
"hk4e/gdconf" "hk4e/gdconf"
"hk4e/gs/constant" "hk4e/gs/constant"
"hk4e/gs/model" "hk4e/gs/model"
"hk4e/pkg/endec"
"hk4e/pkg/logger" "hk4e/pkg/logger"
"hk4e/protocol/cmd" "hk4e/protocol/cmd"
"hk4e/protocol/proto" "hk4e/protocol/proto"
"time" "time"
) )
// HandleAbilityInvoke 处理能力调用 // HandleAbilityStamina 处理来自ability的耐力消耗
func (g *GameManager) HandleAbilityInvoke(player *model.Player, entry *proto.AbilityInvokeEntry) { func (g *GameManager) HandleAbilityStamina(player *model.Player, entry *proto.AbilityInvokeEntry) {
//logger.LOG.Debug("ability invoke handle, entry: %v", entry.ArgumentType)
switch entry.ArgumentType { switch entry.ArgumentType {
case proto.AbilityInvokeArgument_ABILITY_INVOKE_ARGUMENT_MIXIN_COST_STAMINA: case proto.AbilityInvokeArgument_ABILITY_INVOKE_ARGUMENT_MIXIN_COST_STAMINA:
// 消耗耐力 // 大剑重击耐力消耗
costStamina := new(proto.AbilityMixinCostStamina)
//costStamina := new(proto.AbilityMixinCostStamina) err := pb.Unmarshal(entry.AbilityData, costStamina)
//err := pb.Unmarshal(entry.AbilityData, costStamina) if err != nil {
//if err != nil { logger.LOG.Error("unmarshal ability data err: %v", err)
// logger.LOG.Error("unmarshal ability data err: %v", err) return
// return }
//}
// 处理技能持续时的耐力消耗
g.HandleSkillSustainStamina(player) g.HandleSkillSustainStamina(player)
case proto.AbilityInvokeArgument_ABILITY_INVOKE_ARGUMENT_META_MODIFIER_CHANGE:
// 普通角色重击耐力消耗
world := WORLD_MANAGER.GetWorldByID(player.WorldId)
// 获取世界中的角色实体
worldAvatar := world.GetWorldAvatarByEntityId(entry.EntityId)
if worldAvatar == nil {
return
}
// 查找是不是属于该角色实体的ability id
abilityNameHashCode := uint32(0)
for _, ability := range worldAvatar.abilityList {
if ability.InstancedAbilityId == entry.Head.InstancedAbilityId {
logger.LOG.Error("%v", ability)
abilityNameHashCode = ability.AbilityName.GetHash()
}
}
if abilityNameHashCode == 0 {
return
}
// 根据ability name查找到对应的技能表里的技能配置
var avatarAbility *gdconf.AvatarSkillData = nil
for _, avatarSkillData := range gdconf.CONF.AvatarSkillDataMap {
hashCode := endec.Hk4eAbilityHashCode(avatarSkillData.AbilityName)
if uint32(hashCode) == abilityNameHashCode {
avatarAbility = avatarSkillData
}
}
if avatarAbility == nil {
return
}
// 获取该技能对应的耐力消耗
_ = avatarAbility.CostStamina
logger.LOG.Error("%v", avatarAbility.CostStamina)
default:
break
} }
} }
@@ -132,21 +162,21 @@ func (g *GameManager) HandleSkillSustainStamina(player *model.Player) {
player.StaminaInfo.LastSkillTime = time.Now().UnixMilli() player.StaminaInfo.LastSkillTime = time.Now().UnixMilli()
} }
// HandleSkillStartStamina 处理技能开始时即时耐力消耗 //// HandleSkillStartStamina 处理技能开始时即时耐力消耗
func (g *GameManager) HandleSkillStartStamina(player *model.Player, skillId uint32) { //func (g *GameManager) HandleSkillStartStamina(player *model.Player, skillId uint32) {
logger.LOG.Error("stamina skill start, skillId: %v", skillId) // logger.LOG.Error("stamina skill start, skillId: %v", skillId)
avatarSkillConfig, ok := gdconf.CONF.AvatarSkillDataMap[int32(skillId)] // avatarSkillConfig, ok := gdconf.CONF.AvatarSkillDataMap[int32(skillId)]
if !ok { // if !ok {
logger.LOG.Error("avatarSkillConfig error, skillId: %v", skillId) // logger.LOG.Error("avatarSkillConfig error, skillId: %v", skillId)
return // return
} // }
// 根据配置消耗耐力 // // 根据配置消耗耐力
g.UpdateStamina(player, -avatarSkillConfig.CostStamina*100) // g.UpdateStamina(player, -avatarSkillConfig.CostStamina*100)
//
// 记录最后释放的技能 // // 记录最后释放的技能
player.StaminaInfo.LastSkillId = skillId // player.StaminaInfo.LastSkillId = skillId
player.StaminaInfo.LastSkillTime = time.Now().UnixMilli() // player.StaminaInfo.LastSkillTime = time.Now().UnixMilli()
} //}
// StaminaHandler 处理持续耐力消耗 // StaminaHandler 处理持续耐力消耗
func (g *GameManager) StaminaHandler(player *model.Player) { func (g *GameManager) StaminaHandler(player *model.Player) {

View File

@@ -169,10 +169,17 @@ func (w *World) AddPlayer(player *model.Player, sceneId uint32) {
activeAvatarId := player.TeamConfig.GetActiveAvatarId() activeAvatarId := player.TeamConfig.GetActiveAvatarId()
w.SetPlayerLocalTeam(player, []uint32{activeAvatarId}) w.SetPlayerLocalTeam(player, []uint32{activeAvatarId})
} }
for _, worldPlayer := range w.playerMap {
w.SetPlayerAvatarIndex(worldPlayer, 0)
}
w.UpdateMultiplayerTeam() w.UpdateMultiplayerTeam()
for _, worldPlayer := range w.playerMap {
list := w.GetPlayerWorldAvatarList(worldPlayer)
maxIndex := len(list) - 1
index := int(worldPlayer.TeamConfig.CurrAvatarIndex)
if index > maxIndex {
w.SetPlayerAvatarIndex(worldPlayer, 0)
} else {
w.SetPlayerAvatarIndex(worldPlayer, index)
}
}
scene := w.GetSceneById(sceneId) scene := w.GetSceneById(sceneId)
scene.AddPlayer(player) scene.AddPlayer(player)
w.InitPlayerTeamEntityId(player) w.InitPlayerTeamEntityId(player)

View File

@@ -22,7 +22,7 @@ type GameObject interface {
} }
type Player struct { type Player struct {
// 离线数据 // 离线数据 请尽量不要定义接口等复杂数据结构
ID primitive.ObjectID `bson:"_id,omitempty"` ID primitive.ObjectID `bson:"_id,omitempty"`
PlayerID uint32 `bson:"playerID"` // 玩家uid PlayerID uint32 `bson:"playerID"` // 玩家uid
NickName string `bson:"nickname"` // 玩家昵称 NickName string `bson:"nickname"` // 玩家昵称
@@ -52,22 +52,22 @@ type Player struct {
MainCharAvatarId uint32 `bson:"mainCharAvatarId"` // 主角id MainCharAvatarId uint32 `bson:"mainCharAvatarId"` // 主角id
ChatMsgMap map[uint32][]*ChatMsg `bson:"chatMsgMap"` // 聊天信息 ChatMsgMap map[uint32][]*ChatMsg `bson:"chatMsgMap"` // 聊天信息
IsGM uint8 `bson:"isGM"` // 管理员权限等级 IsGM uint8 `bson:"isGM"` // 管理员权限等级
// 在线数据 // 在线数据 请随意 记得加忽略字段的tag
EnterSceneToken uint32 `bson:"-"` // 玩家的世界进入令牌 EnterSceneToken uint32 `bson:"-" msgpack:"-"` // 玩家的世界进入令牌
DbState int `bson:"-"` // 数据库存档状态 DbState int `bson:"-" msgpack:"-"` // 数据库存档状态
WorldId uint32 `bson:"-"` // 所在的世界id WorldId uint32 `bson:"-" msgpack:"-"` // 所在的世界id
GameObjectGuidCounter uint64 `bson:"-"` // 游戏对象guid计数器 GameObjectGuidCounter uint64 `bson:"-" msgpack:"-"` // 游戏对象guid计数器
ClientTime uint32 `bson:"-"` // 玩家客户端的本地时钟 ClientTime uint32 `bson:"-" msgpack:"-"` // 玩家客户端的本地时钟
ClientRTT uint32 `bson:"-"` // 玩家客户端往返时延 ClientRTT uint32 `bson:"-" msgpack:"-"` // 玩家客户端往返时延
GameObjectGuidMap map[uint64]GameObject `bson:"-"` // 游戏对象guid映射表 GameObjectGuidMap map[uint64]GameObject `bson:"-" msgpack:"-"` // 游戏对象guid映射表
Online bool `bson:"-"` // 在线状态 Online bool `bson:"-" msgpack:"-"` // 在线状态
Pause bool `bson:"-"` // 暂停状态 Pause bool `bson:"-" msgpack:"-"` // 暂停状态
SceneLoadState int `bson:"-"` // 场景加载状态 SceneLoadState int `bson:"-" msgpack:"-"` // 场景加载状态
CoopApplyMap map[uint32]int64 `bson:"-"` // 敲门申请的玩家uid及时间 CoopApplyMap map[uint32]int64 `bson:"-" msgpack:"-"` // 敲门申请的玩家uid及时间
StaminaInfo *StaminaInfo `bson:"-"` // 耐力临时数据 StaminaInfo *StaminaInfo `bson:"-" msgpack:"-"` // 耐力临时数据
ClientSeq uint32 `bson:"-"` // 客户端发包请求的序号 ClientSeq uint32 `bson:"-" msgpack:"-"` // 客户端发包请求的序号
CombatInvokeHandler *InvokeHandler[proto.CombatInvokeEntry] `bson:"-"` CombatInvokeHandler *InvokeHandler[proto.CombatInvokeEntry] `bson:"-" msgpack:"-"` // combat转发器
AbilityInvokeHandler *InvokeHandler[proto.AbilityInvokeEntry] `bson:"-"` AbilityInvokeHandler *InvokeHandler[proto.AbilityInvokeEntry] `bson:"-" msgpack:"-"` // ability转发器
} }
func (p *Player) GetNextGameObjectGuid() uint64 { func (p *Player) GetNextGameObjectGuid() uint64 {

View File

@@ -6,8 +6,8 @@ import (
) )
type Team struct { type Team struct {
Name string `bson:"name"` Name string `bson:"name"`
AvatarIdList [4]uint32 `bson:"avatarIdList"` AvatarIdList []uint32 `bson:"avatarIdList"`
} }
func (t *Team) GetAvatarIdList() []uint32 { func (t *Team) GetAvatarIdList() []uint32 {
@@ -22,7 +22,7 @@ func (t *Team) GetAvatarIdList() []uint32 {
} }
func (t *Team) SetAvatarIdList(avatarIdList []uint32) { func (t *Team) SetAvatarIdList(avatarIdList []uint32) {
t.AvatarIdList = [4]uint32{0, 0, 0, 0} t.AvatarIdList = make([]uint32, 4)
for index := range t.AvatarIdList { for index := range t.AvatarIdList {
if index >= len(avatarIdList) { if index >= len(avatarIdList) {
break break
@@ -42,10 +42,10 @@ type TeamInfo struct {
func NewTeamInfo() (r *TeamInfo) { func NewTeamInfo() (r *TeamInfo) {
r = &TeamInfo{ r = &TeamInfo{
TeamList: []*Team{ TeamList: []*Team{
{Name: "冒险", AvatarIdList: [4]uint32{0, 0, 0, 0}}, {Name: "冒险", AvatarIdList: make([]uint32, 4)},
{Name: "委托", AvatarIdList: [4]uint32{0, 0, 0, 0}}, {Name: "委托", AvatarIdList: make([]uint32, 4)},
{Name: "秘境", AvatarIdList: [4]uint32{0, 0, 0, 0}}, {Name: "秘境", AvatarIdList: make([]uint32, 4)},
{Name: "联机", AvatarIdList: [4]uint32{0, 0, 0, 0}}, {Name: "联机", AvatarIdList: make([]uint32, 4)},
}, },
CurrTeamIndex: 0, CurrTeamIndex: 0,
CurrAvatarIndex: 0, CurrAvatarIndex: 0,

View File

@@ -27,3 +27,10 @@ func TestAesCFB(t *testing.T) {
dec, _ := AesCFBDecrypt(enc, key, key[0:16]) dec, _ := AesCFBDecrypt(enc, key, key[0:16])
fmt.Printf("dec: %v\n", dec) fmt.Printf("dec: %v\n", dec)
} }
func TestHk4eAbilityHashCode(t *testing.T) {
hashCode := Hk4eAbilityHashCode("Avatar_Ayato_ExtraAttack")
fmt.Printf("Avatar_Ayato_ExtraAttack hashCode: %v\n", hashCode)
hashCode = Hk4eAbilityHashCode("Avatar_Ayato_ExtraAttack_CreateBullet")
fmt.Printf("Avatar_Ayato_ExtraAttack_CreateBullet hashCode: %v\n", hashCode)
}

View File

@@ -4,14 +4,32 @@ import (
"bytes" "bytes"
"encoding/gob" "encoding/gob"
"fmt" "fmt"
"github.com/vmihailenco/msgpack/v5"
) )
func DeepCopy(src, dest any) error { func DeepCopy(dst, src any) error {
var buf bytes.Buffer var buf bytes.Buffer
if err := gob.NewEncoder(&buf).Encode(src); err != nil { err := gob.NewEncoder(&buf).Encode(src)
if err != nil {
return err return err
} }
return gob.NewDecoder(bytes.NewBuffer(buf.Bytes())).Decode(dest) err = gob.NewDecoder(bytes.NewBuffer(buf.Bytes())).Decode(dst)
if err != nil {
return err
}
return nil
}
func FastDeepCopy(dst, src any) error {
data, err := msgpack.Marshal(src)
if err != nil {
return err
}
err = msgpack.Unmarshal(data, dst)
if err != nil {
return err
}
return nil
} }
func ConvBoolToInt64(v bool) int64 { func ConvBoolToInt64(v bool) int64 {