diff --git a/gdconf/avatar_skill_data.go b/gdconf/avatar_skill_data.go index 161e20b4..53ff2f0f 100644 --- a/gdconf/avatar_skill_data.go +++ b/gdconf/avatar_skill_data.go @@ -9,10 +9,11 @@ import ( // 角色技能配置表 type AvatarSkillData struct { - AvatarSkillId int32 `csv:"AvatarSkillId"` // ID - CostStamina int32 `csv:"CostStamina,omitempty"` // 消耗体力 - CostElemType int32 `csv:"CostElemType,omitempty"` // 消耗能量类型 - CostElemVal int32 `csv:"CostElemVal,omitempty"` // 消耗能量值 + AvatarSkillId int32 `csv:"AvatarSkillId"` // ID + AbilityName string `csv:"AbilityName,omitempty"` // Ability名称 + CostStamina int32 `csv:"CostStamina,omitempty"` // 消耗体力 + CostElemType int32 `csv:"CostElemType,omitempty"` // 消耗能量类型 + CostElemVal int32 `csv:"CostElemVal,omitempty"` // 消耗能量值 } func (g *GameDataConfig) loadAvatarSkillData() { diff --git a/gdconf/game_data_config/csv/AvatarSkillData.csv b/gdconf/game_data_config/csv/AvatarSkillData.csv index 13d7f4e2..5abe5b56 100644 --- a/gdconf/game_data_config/csv/AvatarSkillData.csv +++ b/gdconf/game_data_config/csv/AvatarSkillData.csv @@ -1,5 +1,5 @@ -AvatarSkillId,,,,,CostStamina,CostElemType,CostElemVal,,,,,,,,,,,,,,,,,,,, -int32,,,,,int32,int32,int32,,,,,,,,,,,,,,,,,,,, +AvatarSkillId,AbilityName,,,,CostStamina,CostElemType,CostElemVal,,,,,,,,,,,,,,,,,,,, +int32,string,,,,int32,int32,int32,,,,,,,,,,,,,,,,,,,, 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,,,,,, 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,,,,,, 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, -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,,,,,, 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,,,,,, diff --git a/gs/game/local_event_manager.go b/gs/game/local_event_manager.go index ff5753dc..c5762bd4 100644 --- a/gs/game/local_event_manager.go +++ b/gs/game/local_event_manager.go @@ -3,6 +3,7 @@ package game import ( "hk4e/gs/model" "hk4e/pkg/logger" + "hk4e/pkg/object" "time" ) @@ -43,8 +44,8 @@ func (l *LocalEventManager) LocalEventHandle(localEvent *LocalEvent) { case RunUserCopyAndSave: startTime := time.Now().UnixNano() // 拷贝一份数据避免并发访问 - insertPlayerList := make([]model.Player, 0, len(USER_MANAGER.playerMap)) - updatePlayerList := make([]model.Player, 0, len(USER_MANAGER.playerMap)) + insertPlayerList := make([]*model.Player, 0) + updatePlayerList := make([]*model.Player, 0) for uid, player := range USER_MANAGER.playerMap { if uid < 100000000 { continue @@ -53,26 +54,36 @@ func (l *LocalEventManager) LocalEventHandle(localEvent *LocalEvent) { case model.DbNone: break 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 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) 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{ - insertPlayerList: insertPlayerPointerList, - updatePlayerList: updatePlayerPointerList, + insertPlayerList: insertPlayerList, + updatePlayerList: updatePlayerList, } endTime := time.Now().UnixNano() costTime := endTime - startTime diff --git a/gs/game/user_fight_sync.go b/gs/game/user_fight_sync.go index 2db7c3a6..d8882c5d 100644 --- a/gs/game/user_fight_sync.go +++ b/gs/game/user_fight_sync.go @@ -10,8 +10,12 @@ import ( 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]) { - cmdProtoMap := cmd.NewCmdProtoMap() + if cmdProtoMap == nil { + cmdProtoMap = cmd.NewCmdProtoMap() + } cmdId := cmdProtoMap.GetCmdIdByProtoObj(req) world := WORLD_MANAGER.GetWorldByID(player.WorldId) 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) req := payloadMsg.(*proto.UnionCmdNotify) _ = req + if player.SceneLoadState != model.SceneEnterDone { + return + } DoForward[proto.CombatInvokeEntry](player, &proto.CombatInvocationsNotify{}, []string{}, "InvokeList", player.CombatInvokeHandler) DoForward[proto.AbilityInvokeEntry](player, &proto.AbilityInvocationsNotify{}, []string{}, "Invokes", player.AbilityInvokeHandler) 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) { //logger.LOG.Debug("user meeo sync, uid: %v", player.PlayerID) req := payloadMsg.(*proto.MassiveEntityElementOpBatchNotify) + if player.SceneLoadState != model.SceneEnterDone { + return + } ntf := req world := WORLD_MANAGER.GetWorldByID(player.WorldId) if world == nil { @@ -80,12 +90,8 @@ func (g *GameManager) CombatInvocationsNotify(player *model.Player, payloadMsg p return } world := WORLD_MANAGER.GetWorldByID(player.WorldId) - if world == nil { - return - } scene := world.GetSceneById(player.SceneId) for _, entry := range req.InvokeList { - //logger.LOG.Debug("AT: %v, FT: %v, UID: %v", entry.ArgumentType, entry.ForwardType, player.PlayerID) switch entry.ArgumentType { case proto.CombatTypeArgument_COMBAT_TYPE_ARGUMENT_EVT_BEING_HIT: player.CombatInvokeHandler.AddEntry(entry.ForwardType, entry) @@ -93,7 +99,7 @@ func (g *GameManager) CombatInvocationsNotify(player *model.Player, payloadMsg p entityMoveInfo := new(proto.EntityMoveInfo) err := pb.Unmarshal(entry.CombatData, entityMoveInfo) if err != nil { - logger.LOG.Error("parse combat invocations entity move info error: %v", err) + logger.LOG.Error("parse EntityMoveInfo error: %v", err) continue } motionInfo := entityMoveInfo.MotionInfo @@ -129,7 +135,6 @@ func (g *GameManager) CombatInvocationsNotify(player *model.Player, payloadMsg p sceneEntity.moveState = uint16(motionInfo.State) sceneEntity.lastMoveSceneTimeMs = entityMoveInfo.SceneTime 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) @@ -141,7 +146,7 @@ func (g *GameManager) CombatInvocationsNotify(player *model.Player, payloadMsg p if err != nil { 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) default: 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) { //logger.LOG.Debug("user ability invocations, uid: %v", player.PlayerID) req := payloadMsg.(*proto.AbilityInvocationsNotify) + if player.SceneLoadState != model.SceneEnterDone { + return + } 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) - // 处理能力调用 - g.HandleAbilityInvoke(player, entry) + //switch entry.ArgumentType { + //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) } } @@ -166,13 +197,12 @@ func (g *GameManager) AbilityInvocationsNotify(player *model.Player, payloadMsg func (g *GameManager) ClientAbilityInitFinishNotify(player *model.Player, payloadMsg pb.Message) { //logger.LOG.Debug("user client ability init finish, uid: %v", player.PlayerID) req := payloadMsg.(*proto.ClientAbilityInitFinishNotify) + if player.SceneLoadState != model.SceneEnterDone { + return + } invokeHandler := model.NewInvokeHandler[proto.AbilityInvokeEntry]() for _, entry := range req.Invokes { - //logger.LOG.Debug("AT: %v, FT: %v, UID: %v", entry.ArgumentType, entry.ForwardType, player.PlayerID) - - // 处理能力调用 - g.HandleAbilityInvoke(player, entry) - + logger.LOG.Debug("ClientAbilityInitFinishNotify: %v", entry, player.PlayerID) invokeHandler.AddEntry(entry.ForwardType, entry) } 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) { //logger.LOG.Debug("user client ability change, uid: %v", player.PlayerID) req := payloadMsg.(*proto.ClientAbilityChangeNotify) + if player.SceneLoadState != model.SceneEnterDone { + return + } invokeHandler := model.NewInvokeHandler[proto.AbilityInvokeEntry]() for _, entry := range req.Invokes { + logger.LOG.Debug("ClientAbilityChangeNotify: %v", entry, player.PlayerID) + invokeHandler.AddEntry(entry.ForwardType, entry) } 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) { logger.LOG.Debug("user event do skill success, uid: %v", player.PlayerID) req := payloadMsg.(*proto.EvtDoSkillSuccNotify) + if player.SceneLoadState != model.SceneEnterDone { + return + } logger.LOG.Debug("EvtDoSkillSuccNotify: %v", req) - - // 处理技能开始时的耐力消耗 - g.HandleSkillStartStamina(player, req.SkillId) } func (g *GameManager) EvtAvatarEnterFocusNotify(player *model.Player, payloadMsg pb.Message) { logger.LOG.Debug("user avatar enter focus, uid: %v", player.PlayerID) req := payloadMsg.(*proto.EvtAvatarEnterFocusNotify) + if player.SceneLoadState != model.SceneEnterDone { + return + } logger.LOG.Debug("EvtAvatarEnterFocusNotify: %v", req) world := WORLD_MANAGER.GetWorldByID(player.WorldId) 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) { logger.LOG.Debug("user avatar update focus, uid: %v", player.PlayerID) req := payloadMsg.(*proto.EvtAvatarUpdateFocusNotify) + if player.SceneLoadState != model.SceneEnterDone { + return + } logger.LOG.Debug("EvtAvatarUpdateFocusNotify: %v", req) world := WORLD_MANAGER.GetWorldByID(player.WorldId) 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) { logger.LOG.Debug("user avatar exit focus, uid: %v", player.PlayerID) req := payloadMsg.(*proto.EvtAvatarExitFocusNotify) + if player.SceneLoadState != model.SceneEnterDone { + return + } logger.LOG.Debug("EvtAvatarExitFocusNotify: %v", req) world := WORLD_MANAGER.GetWorldByID(player.WorldId) 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) { logger.LOG.Debug("user entity render change, uid: %v", player.PlayerID) req := payloadMsg.(*proto.EvtEntityRenderersChangedNotify) + if player.SceneLoadState != model.SceneEnterDone { + return + } logger.LOG.Debug("EvtEntityRenderersChangedNotify: %v", req) world := WORLD_MANAGER.GetWorldByID(player.WorldId) 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) { logger.LOG.Debug("user create gadget, uid: %v", player.PlayerID) req := payloadMsg.(*proto.EvtCreateGadgetNotify) + if player.SceneLoadState != model.SceneEnterDone { + return + } logger.LOG.Debug("EvtCreateGadgetNotify: %v", req) world := WORLD_MANAGER.GetWorldByID(player.WorldId) 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) { logger.LOG.Debug("user destroy gadget, uid: %v", player.PlayerID) req := payloadMsg.(*proto.EvtDestroyGadgetNotify) + if player.SceneLoadState != model.SceneEnterDone { + return + } logger.LOG.Debug("EvtDestroyGadgetNotify: %v", req) world := WORLD_MANAGER.GetWorldByID(player.WorldId) scene := world.GetSceneById(player.SceneId) diff --git a/gs/game/user_stamina.go b/gs/game/user_stamina.go index ef4950a2..ccc67b48 100644 --- a/gs/game/user_stamina.go +++ b/gs/game/user_stamina.go @@ -5,30 +5,60 @@ import ( "hk4e/gdconf" "hk4e/gs/constant" "hk4e/gs/model" + "hk4e/pkg/endec" "hk4e/pkg/logger" "hk4e/protocol/cmd" "hk4e/protocol/proto" "time" ) -// HandleAbilityInvoke 处理能力调用 -func (g *GameManager) HandleAbilityInvoke(player *model.Player, entry *proto.AbilityInvokeEntry) { - //logger.LOG.Debug("ability invoke handle, entry: %v", entry.ArgumentType) - +// HandleAbilityStamina 处理来自ability的耐力消耗 +func (g *GameManager) HandleAbilityStamina(player *model.Player, entry *proto.AbilityInvokeEntry) { switch entry.ArgumentType { case proto.AbilityInvokeArgument_ABILITY_INVOKE_ARGUMENT_MIXIN_COST_STAMINA: - // 消耗耐力 - - //costStamina := new(proto.AbilityMixinCostStamina) - //err := pb.Unmarshal(entry.AbilityData, costStamina) - //if err != nil { - // logger.LOG.Error("unmarshal ability data err: %v", err) - // return - //} - - // 处理技能持续时的耐力消耗 + // 大剑重击耐力消耗 + costStamina := new(proto.AbilityMixinCostStamina) + err := pb.Unmarshal(entry.AbilityData, costStamina) + if err != nil { + logger.LOG.Error("unmarshal ability data err: %v", err) + return + } 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() } -// HandleSkillStartStamina 处理技能开始时即时耐力消耗 -func (g *GameManager) HandleSkillStartStamina(player *model.Player, skillId uint32) { - logger.LOG.Error("stamina skill start, skillId: %v", skillId) - avatarSkillConfig, ok := gdconf.CONF.AvatarSkillDataMap[int32(skillId)] - if !ok { - logger.LOG.Error("avatarSkillConfig error, skillId: %v", skillId) - return - } - // 根据配置消耗耐力 - g.UpdateStamina(player, -avatarSkillConfig.CostStamina*100) - - // 记录最后释放的技能 - player.StaminaInfo.LastSkillId = skillId - player.StaminaInfo.LastSkillTime = time.Now().UnixMilli() -} +//// HandleSkillStartStamina 处理技能开始时即时耐力消耗 +//func (g *GameManager) HandleSkillStartStamina(player *model.Player, skillId uint32) { +// logger.LOG.Error("stamina skill start, skillId: %v", skillId) +// avatarSkillConfig, ok := gdconf.CONF.AvatarSkillDataMap[int32(skillId)] +// if !ok { +// logger.LOG.Error("avatarSkillConfig error, skillId: %v", skillId) +// return +// } +// // 根据配置消耗耐力 +// g.UpdateStamina(player, -avatarSkillConfig.CostStamina*100) +// +// // 记录最后释放的技能 +// player.StaminaInfo.LastSkillId = skillId +// player.StaminaInfo.LastSkillTime = time.Now().UnixMilli() +//} // StaminaHandler 处理持续耐力消耗 func (g *GameManager) StaminaHandler(player *model.Player) { diff --git a/gs/game/world_manager.go b/gs/game/world_manager.go index 6e45995b..d3d7f033 100644 --- a/gs/game/world_manager.go +++ b/gs/game/world_manager.go @@ -169,10 +169,17 @@ func (w *World) AddPlayer(player *model.Player, sceneId uint32) { activeAvatarId := player.TeamConfig.GetActiveAvatarId() w.SetPlayerLocalTeam(player, []uint32{activeAvatarId}) } - for _, worldPlayer := range w.playerMap { - w.SetPlayerAvatarIndex(worldPlayer, 0) - } 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.AddPlayer(player) w.InitPlayerTeamEntityId(player) diff --git a/gs/model/player.go b/gs/model/player.go index 80f900dd..d288c216 100644 --- a/gs/model/player.go +++ b/gs/model/player.go @@ -22,7 +22,7 @@ type GameObject interface { } type Player struct { - // 离线数据 + // 离线数据 请尽量不要定义接口等复杂数据结构 ID primitive.ObjectID `bson:"_id,omitempty"` PlayerID uint32 `bson:"playerID"` // 玩家uid NickName string `bson:"nickname"` // 玩家昵称 @@ -52,22 +52,22 @@ type Player struct { MainCharAvatarId uint32 `bson:"mainCharAvatarId"` // 主角id ChatMsgMap map[uint32][]*ChatMsg `bson:"chatMsgMap"` // 聊天信息 IsGM uint8 `bson:"isGM"` // 管理员权限等级 - // 在线数据 - EnterSceneToken uint32 `bson:"-"` // 玩家的世界进入令牌 - DbState int `bson:"-"` // 数据库存档状态 - WorldId uint32 `bson:"-"` // 所在的世界id - GameObjectGuidCounter uint64 `bson:"-"` // 游戏对象guid计数器 - ClientTime uint32 `bson:"-"` // 玩家客户端的本地时钟 - ClientRTT uint32 `bson:"-"` // 玩家客户端往返时延 - GameObjectGuidMap map[uint64]GameObject `bson:"-"` // 游戏对象guid映射表 - Online bool `bson:"-"` // 在线状态 - Pause bool `bson:"-"` // 暂停状态 - SceneLoadState int `bson:"-"` // 场景加载状态 - CoopApplyMap map[uint32]int64 `bson:"-"` // 敲门申请的玩家uid及时间 - StaminaInfo *StaminaInfo `bson:"-"` // 耐力临时数据 - ClientSeq uint32 `bson:"-"` // 客户端发包请求的序号 - CombatInvokeHandler *InvokeHandler[proto.CombatInvokeEntry] `bson:"-"` - AbilityInvokeHandler *InvokeHandler[proto.AbilityInvokeEntry] `bson:"-"` + // 在线数据 请随意 记得加忽略字段的tag + EnterSceneToken uint32 `bson:"-" msgpack:"-"` // 玩家的世界进入令牌 + DbState int `bson:"-" msgpack:"-"` // 数据库存档状态 + WorldId uint32 `bson:"-" msgpack:"-"` // 所在的世界id + GameObjectGuidCounter uint64 `bson:"-" msgpack:"-"` // 游戏对象guid计数器 + ClientTime uint32 `bson:"-" msgpack:"-"` // 玩家客户端的本地时钟 + ClientRTT uint32 `bson:"-" msgpack:"-"` // 玩家客户端往返时延 + GameObjectGuidMap map[uint64]GameObject `bson:"-" msgpack:"-"` // 游戏对象guid映射表 + Online bool `bson:"-" msgpack:"-"` // 在线状态 + Pause bool `bson:"-" msgpack:"-"` // 暂停状态 + SceneLoadState int `bson:"-" msgpack:"-"` // 场景加载状态 + CoopApplyMap map[uint32]int64 `bson:"-" msgpack:"-"` // 敲门申请的玩家uid及时间 + StaminaInfo *StaminaInfo `bson:"-" msgpack:"-"` // 耐力临时数据 + ClientSeq uint32 `bson:"-" msgpack:"-"` // 客户端发包请求的序号 + CombatInvokeHandler *InvokeHandler[proto.CombatInvokeEntry] `bson:"-" msgpack:"-"` // combat转发器 + AbilityInvokeHandler *InvokeHandler[proto.AbilityInvokeEntry] `bson:"-" msgpack:"-"` // ability转发器 } func (p *Player) GetNextGameObjectGuid() uint64 { diff --git a/gs/model/team.go b/gs/model/team.go index c8e43d0d..72c7c773 100644 --- a/gs/model/team.go +++ b/gs/model/team.go @@ -6,8 +6,8 @@ import ( ) type Team struct { - Name string `bson:"name"` - AvatarIdList [4]uint32 `bson:"avatarIdList"` + Name string `bson:"name"` + AvatarIdList []uint32 `bson:"avatarIdList"` } func (t *Team) GetAvatarIdList() []uint32 { @@ -22,7 +22,7 @@ func (t *Team) GetAvatarIdList() []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 { if index >= len(avatarIdList) { break @@ -42,10 +42,10 @@ type TeamInfo struct { func NewTeamInfo() (r *TeamInfo) { r = &TeamInfo{ TeamList: []*Team{ - {Name: "冒险", AvatarIdList: [4]uint32{0, 0, 0, 0}}, - {Name: "委托", AvatarIdList: [4]uint32{0, 0, 0, 0}}, - {Name: "秘境", AvatarIdList: [4]uint32{0, 0, 0, 0}}, - {Name: "联机", AvatarIdList: [4]uint32{0, 0, 0, 0}}, + {Name: "冒险", AvatarIdList: make([]uint32, 4)}, + {Name: "委托", AvatarIdList: make([]uint32, 4)}, + {Name: "秘境", AvatarIdList: make([]uint32, 4)}, + {Name: "联机", AvatarIdList: make([]uint32, 4)}, }, CurrTeamIndex: 0, CurrAvatarIndex: 0, diff --git a/pkg/endec/endec_test.go b/pkg/endec/endec_test.go index 5b049d83..6155b764 100644 --- a/pkg/endec/endec_test.go +++ b/pkg/endec/endec_test.go @@ -27,3 +27,10 @@ func TestAesCFB(t *testing.T) { dec, _ := AesCFBDecrypt(enc, key, key[0:16]) 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) +} diff --git a/pkg/object/object.go b/pkg/object/object.go index 05ff14b5..b247dcb5 100644 --- a/pkg/object/object.go +++ b/pkg/object/object.go @@ -4,14 +4,32 @@ import ( "bytes" "encoding/gob" "fmt" + "github.com/vmihailenco/msgpack/v5" ) -func DeepCopy(src, dest any) error { +func DeepCopy(dst, src any) error { 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 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 {