From d542647f557d77cc44568b6d3376be847ae3659d Mon Sep 17 00:00:00 2001 From: flswld Date: Tue, 4 Apr 2023 18:09:14 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96=E6=B3=A8=E5=86=8C=E4=B8=8E?= =?UTF-8?q?=E7=99=BB=E5=BD=95=E6=B5=81=E7=A8=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- common/constant/stamina_cost.go | 5 - gate/net/kcp_connect_manager.go | 8 +- gate/net/session.go | 108 ++++---- gdconf/avatar_skill_data.go | 7 +- gdconf/gacha_drop_group_data.go | 4 + gdconf/game_data_config.go | 2 + .../game_data_config/ext/SkillStaminaData.csv | 67 +++++ .../game_data_config/txt/AvatarSkillData.txt | 112 ++++---- gdconf/skill_stamina_data.go | 28 ++ gs/game/game.go | 4 +- gs/game/game_local_event_manager.go | 21 +- gs/game/game_route_manager.go | 7 +- gs/game/game_tick_manager.go | 14 - gs/game/game_user_manager.go | 124 +++------ gs/game/game_world_manager.go | 9 + gs/game/player_common.go | 19 +- gs/game/player_fight_sync.go | 80 +++--- gs/game/player_gacha.go | 8 +- gs/game/player_login.go | 198 +++++++------- gs/game/player_stamina.go | 245 ++++-------------- gs/model/player.go | 1 + gs/model/stamina.go | 3 - 22 files changed, 474 insertions(+), 600 deletions(-) create mode 100644 gdconf/game_data_config/ext/SkillStaminaData.csv create mode 100644 gdconf/skill_stamina_data.go diff --git a/common/constant/stamina_cost.go b/common/constant/stamina_cost.go index d57242d6..87cd2a33 100644 --- a/common/constant/stamina_cost.go +++ b/common/constant/stamina_cost.go @@ -22,9 +22,4 @@ const ( STAMINA_COST_POWERED_SKIFF int32 = 500 // 浪船加速(风圈等) (回复耐力) STAMINA_COST_IN_SKIFF int32 = 500 // 处于浪船中回复角色耐力 (回复耐力) STAMINA_COST_SKIFF_NOBODY int32 = 500 // 浪船无人时回复载具耐力 (回复耐力) - // 武器消耗默认值 - STAMINA_COST_FIGHT_SWORD_ONE_HAND int32 = -2000 // 单手剑 - STAMINA_COST_FIGHT_POLE int32 = -2500 // 长枪 - STAMINA_COST_FIGHT_CATALYST int32 = -5000 // 法器 - STAMINA_COST_FIGHT_CLAYMORE_PER int32 = -4000 // 双手剑 (每秒消耗) ) diff --git a/gate/net/kcp_connect_manager.go b/gate/net/kcp_connect_manager.go index 199583ae..36e695e3 100644 --- a/gate/net/kcp_connect_manager.go +++ b/gate/net/kcp_connect_manager.go @@ -52,8 +52,7 @@ type KcpConnectManager struct { serverCmdProtoMap *cmd.CmdProtoMap clientCmdProtoMap *client_proto.ClientCmdProtoMap // 输入输出管道 - messageQueue *mq.MessageQueue - localMsgOutput chan *ProtoMsg + messageQueue *mq.MessageQueue // 密钥 dispatchKey []byte signRsaKey []byte @@ -77,7 +76,6 @@ func NewKcpConnectManager(messageQueue *mq.MessageQueue, discovery *rpc.Discover r.clientCmdProtoMap = client_proto.NewClientCmdProtoMap() } r.messageQueue = messageQueue - r.localMsgOutput = make(chan *ProtoMsg, 1000) r.run() return r } @@ -166,8 +164,6 @@ func (k *KcpConnectManager) acceptHandle(listener *kcp.Listener) { gsServerAppId: "", anticheatServerAppId: "", pathfindingServerAppId: "", - changeGameServer: false, - joinHostUserId: 0, useMagicSeed: false, } go k.recvHandle(session) @@ -282,8 +278,6 @@ type Session struct { gsServerAppId string anticheatServerAppId string pathfindingServerAppId string - changeGameServer bool - joinHostUserId uint32 useMagicSeed bool } diff --git a/gate/net/session.go b/gate/net/session.go index 37a34ad6..cd738fe2 100644 --- a/gate/net/session.go +++ b/gate/net/session.go @@ -29,6 +29,7 @@ import ( const ( ConnEst = iota + ConnWaitLogin ConnActive ConnClose ) @@ -47,6 +48,7 @@ func (k *KcpConnectManager) recvMsgHandle(protoMsg *ProtoMsg, session *Session) if connState != ConnEst { return } + session.connState = ConnWaitLogin getPlayerTokenReq := protoMsg.PayloadMessage.(*proto.GetPlayerTokenReq) getPlayerTokenRsp := k.getPlayerToken(getPlayerTokenReq, session) if getPlayerTokenRsp == nil { @@ -58,7 +60,7 @@ func (k *KcpConnectManager) recvMsgHandle(protoMsg *ProtoMsg, session *Session) rsp.CmdId = cmd.GetPlayerTokenRsp rsp.HeadMessage = k.getHeadMsg(protoMsg.HeadMessage.ClientSequenceId) rsp.PayloadMessage = getPlayerTokenRsp - k.localMsgOutput <- rsp + session.kcpRawSendChan <- rsp case cmd.PlayerForceExitReq: // 玩家退出游戏请求 if connState != ConnActive { @@ -81,7 +83,7 @@ func (k *KcpConnectManager) recvMsgHandle(protoMsg *ProtoMsg, session *Session) rsp.CmdId = cmd.PingRsp rsp.HeadMessage = k.getHeadMsg(protoMsg.HeadMessage.ClientSequenceId) rsp.PayloadMessage = pingRsp - k.localMsgOutput <- rsp + session.kcpRawSendChan <- rsp logger.Debug("convId: %v, RTO: %v, SRTT: %v, RTTVar: %v", protoMsg.ConvId, session.conn.GetRTO(), session.conn.GetSRTT(), session.conn.GetSRTTVar()) if connState != ConnActive { @@ -106,8 +108,26 @@ func (k *KcpConnectManager) recvMsgHandle(protoMsg *ProtoMsg, session *Session) EventId: mq.ClientTimeNotify, ConnCtrlMsg: connCtrlMsg, }) + case cmd.PlayerLoginReq: + if connState != ConnWaitLogin { + return + } + playerLoginReq := protoMsg.PayloadMessage.(*proto.PlayerLoginReq) + playerLoginReq.TargetUid = 0 + playerLoginReq.TargetHomeOwnerUid = 0 + gameMsg := new(mq.GameMsg) + gameMsg.UserId = userId + gameMsg.CmdId = protoMsg.CmdId + gameMsg.ClientSeq = protoMsg.HeadMessage.ClientSequenceId + gameMsg.PayloadMessage = playerLoginReq + // 转发到GS + k.messageQueue.SendToGs(session.gsServerAppId, &mq.NetMsg{ + MsgType: mq.MsgTypeGame, + EventId: mq.NormalMsg, + GameMsg: gameMsg, + }) default: - if connState != ConnActive && !(protoMsg.CmdId == cmd.PlayerLoginReq || protoMsg.CmdId == cmd.SetPlayerBornDataReq) { + if connState != ConnActive { logger.Error("conn not active so drop packet, cmdId: %v, userId: %v, convId: %v", protoMsg.CmdId, userId, protoMsg.ConvId) return } @@ -161,43 +181,6 @@ func (k *KcpConnectManager) sendMsgHandle() { // 函数栈内缓存 添加删除事件走chan 避免频繁加锁 convSessionMap := make(map[uint64]*Session) userIdConvMap := make(map[uint32]uint64) - // 分发到每个连接具体的发送协程 - sendToClient := func(protoMsg *ProtoMsg) { - session := convSessionMap[protoMsg.ConvId] - if session == nil { - logger.Error("session is nil, convId: %v", protoMsg.ConvId) - return - } - kcpRawSendChan := session.kcpRawSendChan - if kcpRawSendChan == nil { - logger.Error("kcpRawSendChan is nil, convId: %v", protoMsg.ConvId) - return - } - if len(kcpRawSendChan) == 1000 { - logger.Error("kcpRawSendChan is full, convId: %v", protoMsg.ConvId) - return - } - if protoMsg.CmdId == cmd.PlayerLoginRsp { - logger.Debug("session active, convId: %v", protoMsg.ConvId) - session.connState = ConnActive - // 通知GS玩家各个服务器的appid - serverMsg := new(mq.ServerMsg) - serverMsg.UserId = session.userId - if session.changeGameServer { - serverMsg.JoinHostUserId = session.joinHostUserId - session.changeGameServer = false - session.joinHostUserId = 0 - } else { - serverMsg.AnticheatServerAppId = session.anticheatServerAppId - } - k.messageQueue.SendToGs(session.gsServerAppId, &mq.NetMsg{ - MsgType: mq.MsgTypeServer, - EventId: mq.ServerAppidBindNotify, - ServerMsg: serverMsg, - }) - } - kcpRawSendChan <- protoMsg - } // 远程全局顶号注册列表 reLoginRemoteKickRegMap := make(map[uint32]chan bool) for { @@ -212,14 +195,13 @@ func (k *KcpConnectManager) sendMsgHandle() { case remoteKick := <-k.reLoginRemoteKickRegChan: reLoginRemoteKickRegMap[remoteKick.userId] = remoteKick.kickFinishNotifyChan remoteKick.regFinishNotifyChan <- true - case protoMsg := <-k.localMsgOutput: - sendToClient(protoMsg) case netMsg := <-k.messageQueue.GetNetMsg(): switch netMsg.MsgType { case mq.MsgTypeGame: gameMsg := netMsg.GameMsg switch netMsg.EventId { case mq.NormalMsg: + // 分发到每个连接具体的发送协程 convId, exist := userIdConvMap[gameMsg.UserId] if !exist { logger.Error("can not find convId by userId") @@ -230,7 +212,34 @@ func (k *KcpConnectManager) sendMsgHandle() { protoMsg.CmdId = gameMsg.CmdId protoMsg.HeadMessage = k.getHeadMsg(gameMsg.ClientSeq) protoMsg.PayloadMessage = gameMsg.PayloadMessage - sendToClient(protoMsg) + session := convSessionMap[protoMsg.ConvId] + if session == nil { + logger.Error("session is nil, convId: %v", protoMsg.ConvId) + return + } + kcpRawSendChan := session.kcpRawSendChan + if kcpRawSendChan == nil { + logger.Error("kcpRawSendChan is nil, convId: %v", protoMsg.ConvId) + return + } + if len(kcpRawSendChan) == 1000 { + logger.Error("kcpRawSendChan is full, convId: %v", protoMsg.ConvId) + return + } + if protoMsg.CmdId == cmd.PlayerLoginRsp { + logger.Debug("session active, convId: %v", protoMsg.ConvId) + session.connState = ConnActive + // 通知GS玩家各个服务器的appid + serverMsg := new(mq.ServerMsg) + serverMsg.UserId = session.userId + serverMsg.AnticheatServerAppId = session.anticheatServerAppId + k.messageQueue.SendToGs(session.gsServerAppId, &mq.NetMsg{ + MsgType: mq.MsgTypeServer, + EventId: mq.ServerAppidBindNotify, + ServerMsg: serverMsg, + }) + } + kcpRawSendChan <- protoMsg } case mq.MsgTypeConnCtrl: connCtrlMsg := netMsg.ConnCtrlMsg @@ -263,14 +272,15 @@ func (k *KcpConnectManager) sendMsgHandle() { } session.gsServerAppId = serverMsg.GameServerAppId session.anticheatServerAppId = "" - session.changeGameServer = true - session.joinHostUserId = serverMsg.JoinHostUserId // 网关代发登录请求到新的GS gameMsg := new(mq.GameMsg) gameMsg.UserId = serverMsg.UserId gameMsg.CmdId = cmd.PlayerLoginReq gameMsg.ClientSeq = 0 - gameMsg.PayloadMessage = new(proto.PlayerLoginReq) + gameMsg.PayloadMessage = &proto.PlayerLoginReq{ + TargetUid: serverMsg.JoinHostUserId, + TargetHomeOwnerUid: 0, + } k.messageQueue.SendToGs(session.gsServerAppId, &mq.NetMsg{ MsgType: mq.MsgTypeGame, EventId: mq.NormalMsg, @@ -339,10 +349,6 @@ func (k *KcpConnectManager) getPlayerToken(req *proto.GetPlayerTokenReq, session } uid := tokenVerifyRsp.PlayerID loginFailRsp := func(retCode int32, isForbid bool, forbidEndTime uint32) *proto.GetPlayerTokenRsp { - // 关联session信息 不然包发不出去 - session.userId = uid - k.SetSession(session, session.conn.GetConv(), session.userId) - k.createSessionChan <- session rsp := new(proto.GetPlayerTokenRsp) rsp.Uid = uid rsp.IsProficientPlayer = true @@ -397,6 +403,7 @@ func (k *KcpConnectManager) getPlayerToken(req *proto.GetPlayerTokenReq, session loginFailClose() return nil case <-regFinishNotifyChan: + timer.Stop() } oldSession := k.GetSessionByUserId(uid) if oldSession != nil { @@ -426,6 +433,7 @@ func (k *KcpConnectManager) getPlayerToken(req *proto.GetPlayerTokenReq, session loginFailClose() return nil case <-kickFinishNotifyChan: + timer.Stop() } } // 关联玩家uid和连接信息 diff --git a/gdconf/avatar_skill_data.go b/gdconf/avatar_skill_data.go index 5be95349..7854fcc4 100644 --- a/gdconf/avatar_skill_data.go +++ b/gdconf/avatar_skill_data.go @@ -8,10 +8,9 @@ import ( type AvatarSkillData struct { AvatarSkillId int32 `csv:"ID"` AbilityName string `csv:"Ability名称,omitempty"` - // TODO 这个字段实际上并不是拿来直接扣体力的 体力应该由ability来做 但是现在我捋不清所以摆烂了 改了一下表暂时先这么用着 - CostStamina int32 `csv:"消耗体力,omitempty"` - CostElemType int32 `csv:"消耗能量类型,omitempty"` - CostElemVal int32 `csv:"消耗能量值,omitempty"` + CostStamina int32 `csv:"消耗体力,omitempty"` + CostElemType int32 `csv:"消耗能量类型,omitempty"` + CostElemVal int32 `csv:"消耗能量值,omitempty"` } func (g *GameDataConfig) loadAvatarSkillData() { diff --git a/gdconf/gacha_drop_group_data.go b/gdconf/gacha_drop_group_data.go index 83dbab5c..3af77c4e 100644 --- a/gdconf/gacha_drop_group_data.go +++ b/gdconf/gacha_drop_group_data.go @@ -40,3 +40,7 @@ func (g *GameDataConfig) loadGachaDropGroupData() { } logger.Info("GachaDropGroupData count: %v", len(g.GachaDropGroupDataMap)) } + +func GetGachaDropGroupDataByDropId(dropId int32) *GachaDropGroupData { + return CONF.GachaDropGroupDataMap[dropId] +} diff --git a/gdconf/game_data_config.go b/gdconf/game_data_config.go index ba8031f1..01e4a081 100644 --- a/gdconf/game_data_config.go +++ b/gdconf/game_data_config.go @@ -68,6 +68,7 @@ type GameDataConfig struct { GCGCharDataMap map[int32]*GCGCharData // 七圣召唤角色卡牌 GCGSkillDataMap map[int32]*GCGSkillData // 七圣召唤卡牌技能 GachaDropGroupDataMap map[int32]*GachaDropGroupData // 卡池掉落组 临时的 + SkillStaminaDataMap map[int32]*SkillStaminaData // 角色技能消耗体力 临时的 } func InitGameDataConfig() { @@ -168,6 +169,7 @@ func (g *GameDataConfig) load() { g.loadGCGCharData() // 七圣召唤角色卡牌 g.loadGCGSkillData() // 七圣召唤卡牌技能 g.loadGachaDropGroupData() // 卡池掉落组 临时的 + g.loadSkillStaminaData() // 角色技能消耗体力 临时的 } // CSV相关 diff --git a/gdconf/game_data_config/ext/SkillStaminaData.csv b/gdconf/game_data_config/ext/SkillStaminaData.csv new file mode 100644 index 00000000..b64f6651 --- /dev/null +++ b/gdconf/game_data_config/ext/SkillStaminaData.csv @@ -0,0 +1,67 @@ +AvatarSkillId,AbilityName,CostStamina +int32,string,int32 +ID,Ability名称,消耗体力 +10024,Avatar_Ayaka_ExtraAttack,20 +10031,Avatar_Qin_ExtraAttack,20 +10033,Avatar_Qin_VortexSmash,20 +10060,Avatar_Lisa_ExtraAttack,50 +10070,Avatar_Barbara_ExtraAttack,50 +10073,Avatar_Kaeya_ExtraAttack,20 +10160,Avatar_Diluc_ExtraAttack,40 +10201,Avatar_Razor_ExtraAttack,40 +10231,Avatar_Xiangling_ExtraAttack,25 +10241,Avatar_Beidou_ExtraAttack,40 +10261,Avatar_Xiao_ExtraAttack,25 +10271,Avatar_Ningguang_ExtraAttack,50 +10281,Avatar_Prototype_ExtraAttack,999999 +10291,Avatar_Klee_ExtraAttack,50 +10301,Avatar_Zhongli_ExtraAttack,25 +10321,Avatar_Bennett_ExtraAttack,20 +10341,Avatar_Noel_ExtraAttack,40 +10351,Avatar_Qiqi_ExtraAttack,20 +11301,Avatar_Beidou_ExtraAttack,40 +10381,Avatar_Xingqiu_ExtraAttack,20 +10386,Avatar_Albedo_ExtraAttack,20 +10401,Avatar_Beidou_ExtraAttack_Chongyun,40 +10411,Avatar_Mona_ExtraAttack,50 +10421,Avatar_Keqing_ExtraAttack,25 +10431,Avatar_Sucrose_ExtraAttack,50 +10441,Avatar_Xinyan_ExtraAttack,40 +10451,Avatar_Rosaria_ExtraAttack,25 +10461,Avatar_Hutao_ExtraAttack,25 +10471,Avatar_Kazuha_ExtraAttack,20 +10481,Avatar_Feiyan_ExtraAttack,50 +10501,Avatar_Tohma_ExtraAttack,25 +10511,Avatar_Eula_ExtraAttack,40 +10521,Avatar_Shougun_ExtraAttack,25 +10531,Avatar_Sayu_ExtraAttack,40 +10541,Avatar_Kokomi_ExtraAttack,50 +10571,Avatar_Itto_ExtraAttack,20 +10581,Avatar_Yae_ExtraAttack,50 +10591,Avatar_Heizo_ExtraAttack,25 +10631,Avatar_Shenhe_ExtraAttack,25 +10641,Avatar_Yunjin_ExtraAttack,25 +10651,Avatar_Shinobu_ExtraAttack,20 +10661,Avatar_Ayato_ExtraAttack,20 +10681,Avatar_Dori_ExtraAttack,40 +10701,Avatar_Nilou_ExtraAttack,20 +10711,Avatar_Cyno_ExtraAttack,25 +10721,Avatar_Candace_ExtraAttack,25 +10731,Avatar_Nahida_ExtraAttack,50 +10741,Avatar_Layla_ExtraAttack,20 +10751,Avatar_Wanderer_ExtraAttack,50 +10771,Avatar_Yaoyao_ExtraAttack,25 +10781,Avatar_Alhatham_ExtraAttack,20 +10791,Avatar_Dehya_ExtraAttack,40 +10801,Avatar_Mika_ExtraAttack,25 +10821,Avatar_Baizhuer_ExtraAttack,50 +100540,Avatar_PlayerBoy_ExtraAttack_Common,20 +100543,Avatar_PlayerBoy_ExtraAttack_Wind,20 +100545,Avatar_PlayerBoy_ExtraAttack_Rock,20 +100546,Avatar_PlayerBoy_ExtraAttack_Electric,20 +100547,Avatar_PlayerBoy_ExtraAttack_Grass,20 +100550,Avatar_PlayerGirl_ExtraAttack_Common,20 +100553,Avatar_PlayerGirl_ExtraAttack_Wind,20 +100555,Avatar_PlayerGirl_ExtraAttack_Rock,20 +100556,Avatar_PlayerGirl_ExtraAttack_Electric,20 +100557,Avatar_PlayerGirl_ExtraAttack_Grass,20 \ No newline at end of file diff --git a/gdconf/game_data_config/txt/AvatarSkillData.txt b/gdconf/game_data_config/txt/AvatarSkillData.txt index 5698be82..674ac34b 100644 --- a/gdconf/game_data_config/txt/AvatarSkillData.txt +++ b/gdconf/game_data_config/txt/AvatarSkillData.txt @@ -9,7 +9,7 @@ ID Ability名称 是远程 技能CD 无视冷却缩减属性 消耗体力 消耗 10102 10 0 1 0 CircleLockEnemyR5H6HC 1 1 0.3 0 1 0 10111 0 10 1 11 CircleLockEnemy 1 1 0.3 0 1 0 10012 2 0 1 2 CircleLockEnemyR15H10HC 1 1 0.3 0 1 0 -10013 0 15 1 3 CircleLockEnemyR5H6HC 1 1 0.3 0 1 1 233 1 +10013 0 1 1 3 CircleLockEnemyR5H6HC 1 1 0.3 0 1 1 233 1 10014 8 0 4 30 1 5 CircleLockEnemyR15H10HC 1 1 0.3 0 1 0 10015 8 0 1 4 CircleLockEnemyR15H10HC 1 1 0.3 0 1 0 10016 0 0 1 4 CircleLockEnemyR5H6HC 1 1 0.3 0 1 0 @@ -20,10 +20,10 @@ ID Ability名称 是远程 技能CD 无视冷却缩减属性 消耗体力 消耗 10021 15 0 5 60 1 6 CircleLockEnemyR15H10HC 1 1 0.3 0 1 0 10022 Test_CreateSharkTorpedo 5 0 2 0 CircleLockEnemyR10H6HC 1 1 0.3 0 1 0 10023 Test_CreateSteamBang 10 0 1 0 CircleLockEnemyR5H6HC 1 1 0.3 0 1 0 -10024 Avatar_Ayaka_ExtraAttack 0 20 1 0 CircleLockEnemyR5H6HC 1 1 0.3 0 1 231 -10031 Avatar_Qin_ExtraAttack 0 20 1 0 CircleLockEnemyR5H6HC 1 1 0.3 0 1 331 +10024 Avatar_Ayaka_ExtraAttack 0 0 1 0 CircleLockEnemyR5H6HC 1 1 0.3 0 1 231 +10031 Avatar_Qin_ExtraAttack 0 0 1 0 CircleLockEnemyR5H6HC 1 1 0.3 0 1 331 10032 15 0 1 2 CircleLockEnemyR15H10HC 1 1 0.3 0 1 2 1 2132 -10033 Avatar_Qin_VortexSmash 6 20 1 2 CircleLockEnemyR5H6HC 1 1 0.3 0 1 1 332 +10033 Avatar_Qin_VortexSmash 6 0 1 2 CircleLockEnemyR5H6HC 1 1 0.3 0 1 1 332 10034 Avatar_Qin_DandelionWind 20 0 7 80 1 5 CircleLockEnemyR15H10HC 1 1 0.3 0 1 339 10035 15 1 0 1 11 CircleLockEnemyR10 1 1 0.3 0 1 2 1 0 10036 Avatar_Qin_EnterSkill 30 1 0 CircleLockEnemyR10 1 1 0.3 0 0 @@ -42,7 +42,7 @@ ID Ability名称 是远程 技能CD 无视冷却缩减属性 消耗体力 消耗 10057 Avatar_Player_ExtraAttack 0 0 1 0 CircleLockEnemyR5H6HC 1 1 0.3 0 1 0 10058 Avatar_Player_ExtraAttack 0 0 1 0 CircleLockEnemyR5H6HC 1 1 0.3 0 1 0 10059 Avatar_Player_ExtraAttack 0 0 1 0 CircleLockEnemyR5H6HC 1 1 0.3 0 1 0 -10060 Avatar_Lisa_ExtraAttack 0 50 1 0 CircleLockEnemyR15H10HC 1 1 0.3 0 1 431 +10060 Avatar_Lisa_ExtraAttack 0 0 1 0 CircleLockEnemyR15H10HC 1 1 0.3 0 1 431 10061 16 0 1 2 CircleLockEnemyR15H10HC 1 1 0.3 0 1 1 1 432 10062 20 0 4 80 1 5 CircleLockEnemyR15H10HC 1 1 0.3 0 1 439 10063 Test_CreateSharkTorpedo 5 0 2 0 CircleLockEnemyR8H6HC 1 1 0.3 0 1 0 @@ -52,10 +52,10 @@ ID Ability名称 是远程 技能CD 无视冷却缩减属性 消耗体力 消耗 10067 Avatar_Player_UziExplode 1 5 0 1 2 CircleLockEnemyR15H10HC 1 1 0.3 0 1 732 10068 Avatar_Player_WindBreathe 1 15 0 7 60 1 5 CircleLockEnemyR15H10HC 1 1 0.3 0 1 739 10069 0 0 1 1 CircleLockEnemyR5H6HC 1 1 0.3 0 1 0 -10070 Avatar_Barbara_ExtraAttack 0 50 1 0 CircleLockEnemyR15H10HC 1 1 0.3 0 1 1431 +10070 Avatar_Barbara_ExtraAttack 0 0 1 0 CircleLockEnemyR15H10HC 1 1 0.3 0 1 1431 10071 32 0 1 2 CircleLockEnemyR15H10HC 1 1 0.3 0 1 1 1 1432 10072 20 0 2 80 1 5 CircleLockEnemyR15H10HC 1 1 0.3 0 1 1439 -10073 Avatar_Kaeya_ExtraAttack 0 20 1 0 CircleLockEnemyR8H6HC 1 1 0.3 0 1 1531 +10073 Avatar_Kaeya_ExtraAttack 0 0 1 0 CircleLockEnemyR8H6HC 1 1 0.3 0 1 1531 10074 6 0 1 2 CircleLockEnemyR15H10HC 1 1 0.3 0 1 1532 10075 15 0 5 60 1 5 CircleLockEnemyR15H10HC 1 1 0.3 0 1 1539 10076 Avatar_Barbara_ReBorn 900 1 0 1 0 CircleLockEnemyR15H10HC 1 1 0.3 0 1 1 1 Skill_B_Barbara_01 0 1 @@ -68,13 +68,13 @@ ID Ability名称 是远程 技能CD 无视冷却缩减属性 消耗体力 消耗 10083 Avatar_Lsai_TeamTalent_Skill 30 0 1 0 CircleLockEnemyR15H10HC 1 1 0.3 0 1 0 10117 8 0 1 32 CircleLockEnemyR10H6HC 1 1 0.3 0 1 1132 10118 20 0 3 80 1 35 CircleLockEnemyR8H6HC 1 1 0.3 0 1 1139 -10160 Avatar_Diluc_ExtraAttack 0 40 1 0 CircleLockEnemyR5H6HC 1 1 0.3 0 1 1631 +10160 Avatar_Diluc_ExtraAttack 0 0 1 0 CircleLockEnemyR5H6HC 1 1 0.3 0 1 1631 10161 Diluc_Fire_Blade 10 0 1 2 CircleLockEnemyR10H6HC 1 1 0.3 0 1 1632 10162 Diluc_Fire_Blade 2 0 1 3 CircleLockEnemyR10H6HC 1 1 0.3 0 1 0 10163 Diluc_Fire_Blade 2 0 1 4 CircleLockEnemyR10H6HC 1 1 0.3 0 1 0 10165 Diluc_FireCross 12 0 1 40 1 5 CircleLockEnemyR15H10HC 1 1 0.3 0 1 1639 10166 Diluc_EnterSkill 30 0 1 0 CircleLockEnemyR10H6HC 1 1 0.3 0 1 0 -10201 Avatar_Razor_ExtraAttack 0 40 1 0 CircleLockEnemyR5H6HC 1 1 0.3 0 1 2031 +10201 Avatar_Razor_ExtraAttack 0 0 1 0 CircleLockEnemyR5H6HC 1 1 0.3 0 1 2031 10202 Avatar_Razor_ClawMark_Click 6 0 1 2 CircleLockEnemyR15H10HC 1 1 0.3 0 1 2032 10203 Avatar_Razor_LycanMode 20 0 4 80 1 5 CircleLockEnemyR15H10HC 1 1 0.3 0 1 2039 10204 Avatar_Razor_ClawMark_Click 3 0 1 2 CircleLockEnemyR15H10HC 1 1 0.3 0 1 0 @@ -84,10 +84,10 @@ ID Ability名称 是远程 技能CD 无视冷却缩减属性 消耗体力 消耗 10223 1 0 0 1 1 CircleLockEnemyR15H10HC 1 1 0.3 0 1 0 10224 6 0 1 2 CircleLockEnemyR15H10HC 1 1 0.3 0 1 2232 10225 15 0 7 60 1 5 CircleLockEnemyR15H10HC 1 1 0.3 0 1 2239 -10231 Avatar_Xiangling_ExtraAttack 0 25 1 0 CircleLockEnemyR8H6HC 1 1 0.3 0 1 2331 +10231 Avatar_Xiangling_ExtraAttack 0 0 1 0 CircleLockEnemyR8H6HC 1 1 0.3 0 1 2331 10232 12 0 1 2 CircleLockEnemyR15H10HC 1 1 0.3 0 1 2332 10235 20 0 1 80 1 5 CircleLockEnemyR15H10HC 1 1 0.3 0 1 2339 -10241 Avatar_Beidou_ExtraAttack 0 40 1 0 CircleLockEnemyR5H6HC 1 1 0.3 0 1 2431 +10241 Avatar_Beidou_ExtraAttack 0 0 1 0 CircleLockEnemyR5H6HC 1 1 0.3 0 1 2431 10242 Avatar_Beidou_ThunderCounter_Handler 7.5 0 1 2 CircleLockEnemyR8H6HC 1 1 0.3 0 1 2 1 2432 10245 Avatar_Beidou_ThunderShield 20 0 4 80 1 5 CircleLockEnemyR15H10HC 1 1 0.3 0 1 2439 20000 0 0 1 99 CircleLockEnemyR15H10HC 1 1 0.3 0 1 0 @@ -96,24 +96,24 @@ ID Ability名称 是远程 技能CD 无视冷却缩减属性 消耗体力 消耗 10253 1 2 0 1 1 CircleLockEnemyR8H6HC 1 1 0.3 0 1 0 10254 10 0 1 2 CircleLockEnemyR8H6HC 1 1 0.3 0 1 0 10255 15 0 5 60 1 5 CircleLockEnemyR8H6HC 1 1 0.3 0 1 0 -10261 Avatar_Xiao_ExtraAttack 0 25 1 0 CircleLockEnemyR5H6HC 1 1 0.3 0 1 2631 +10261 Avatar_Xiao_ExtraAttack 0 0 1 0 CircleLockEnemyR5H6HC 1 1 0.3 0 1 2631 10262 10 0 2 2 CircleLockEnemyR8H6HC 1 1 0.3 0 1 2632 10263 10 0 2 2 CircleLockEnemyR8H6HC 1 1 0.3 0 1 0 2 10264 0 0 1 11 CircleLockEnemyR5H6HC 1 1 0.3 0 1 0 10265 18 0 7 70 1 5 CircleLockEnemyR8H6HC 1 1 0.3 0 1 2639 -10271 Avatar_Ningguang_ExtraAttack 0 50 1 0 CircleLockEnemyR15H10HC 1 1 0.3 0 1 2731 +10271 Avatar_Ningguang_ExtraAttack 0 0 1 0 CircleLockEnemyR15H10HC 1 1 0.3 0 1 2731 10272 12 0 1 2 CircleLockEnemyR15H10HC 1 1 0.3 0 1 2732 10273 1 0 1 12 CircleLockEnemy 1 1 0.3 0 1 0 10274 12 0 8 40 1 5 CircleLockEnemyR15H10HC 1 1 0.3 0 1 2739 10275 Avatar_Ningguang_Trigger_ElementalArt_CD 1 0 1 0 CircleLockEnemyR15H10HC 1 1 0.3 0 1 0 -10281 Avatar_Prototype_ExtraAttack 0 666666 1 0 CircleLockEnemyR15H10HC 1 1 0.3 0 1 0 +10281 Avatar_Prototype_ExtraAttack 0 0 1 0 CircleLockEnemyR15H10HC 1 1 0.3 0 1 0 10282 0 0 1 2 CircleLockEnemyR5H6HC 1 1 0.3 0 1 0 10283 10 0 1 1 3 CircleLockEnemyR8H6HC 1 1 0.3 0 1 0 -10291 Avatar_Klee_ExtraAttack 0 50 1 0 CircleLockEnemyR15H10HC 1 1 0.3 0 1 2931 +10291 Avatar_Klee_ExtraAttack 0 0 1 0 CircleLockEnemyR15H10HC 1 1 0.3 0 1 2931 10292 20 0 2 2 CircleLockEnemyR15H10HC 1 1 0.3 0 1 2932 10295 15 0 1 60 1 5 CircleLockEnemyR15H10HC 1 1 0.3 0 1 2939 10300 0 0 1 3 CircleLockEnemyR5H6HC 1 1 0.3 0 1 0 -10301 Avatar_Zhongli_ExtraAttack 0 25 1 0 CircleLockEnemyR8H6HC 1 1 0.3 0 1 3031 +10301 Avatar_Zhongli_ExtraAttack 0 0 1 0 CircleLockEnemyR8H6HC 1 1 0.3 0 1 3031 10302 12 0 1 2 CircleLockEnemyR8H6HC 1 1 0.3 0 1 3032 10303 12 0 8 40 1 5 CircleLockEnemyR8H6HC 1 1 0.3 0 1 3039 10311 Avatar_Fischl_PressShoot 1 0 0 1 0 CircleLockEnemyR15H10HC 1 1 0.3 0 1 3131 @@ -122,7 +122,7 @@ ID Ability名称 是远程 技能CD 无视冷却缩减属性 消耗体力 消耗 10314 Avatar_Fischl_AimPressShoot 1 0 0 1 0 CircleLockEnemyR15H10HC 1 1 0.3 0 1 0 10315 1 0 0 1 1 CircleLockEnemyR15H10HC 1 1 0.3 0 1 0 10316 1.5 1 0 1 16 CircleLockEnemyR15H10HC 1 1 0.3 0 1 0 -10321 Avatar_Bennett_ExtraAttack 0 20 1 0 CircleLockEnemyR5H6HC 1 1 0.3 0 1 3231 +10321 Avatar_Bennett_ExtraAttack 0 0 1 0 CircleLockEnemyR5H6HC 1 1 0.3 0 1 3231 10322 Avatar_Bennett_ElementalArt_Handler 5 0 1 2 CircleLockEnemyR10H6HC 1 1 0.3 0 1 3232 10323 15 0 1 60 1 5 CircleLockEnemyR8H6HC 1 1 0.3 0 1 3239 10331 Avatar_Tartaglia_PressShoot 1 0 0 1 0 CircleLockEnemyR15H10HC 1 1 0.3 0 1 3331 @@ -132,11 +132,11 @@ ID Ability名称 是远程 技能CD 无视冷却缩减属性 消耗体力 消耗 10335 1 0 0 1 1 CircleLockEnemyR15H10HC 1 1 0.3 0 1 0 10336 Avatar_Tartaglia_Gandalfr_TriggerOff 8 0 1 0 CircleLockEnemyR8H6HC 1 1 0.3 0 1 0 10337 Avatar_Tartaglia_PressShoot 0 0 1 0 CircleLockEnemyR8H6HC 1 1 0.3 0 1 0 -10341 Avatar_Noel_ExtraAttack 0 40 1 0 CircleLockEnemyR5H6HC 1 1 0.3 0 1 3431 +10341 Avatar_Noel_ExtraAttack 0 0 1 0 CircleLockEnemyR5H6HC 1 1 0.3 0 1 3431 10342 24 0 1 2 CircleLockEnemyR10H6HC 1 1 0.3 0 1 3432 10343 15 0 8 60 1 5 CircleLockEnemyR8H6HC 1 1 0.3 0 1 3439 10344 1 1 0 1 0 CircleLockEnemyR15H10HC 1 1 0.3 0 1 0 -10351 Avatar_Qiqi_ExtraAttack 0 20 1 0 CircleLockEnemyR5H6HC 1 1 0.3 0 1 3531 +10351 Avatar_Qiqi_ExtraAttack 0 0 1 0 CircleLockEnemyR5H6HC 1 1 0.3 0 1 3531 10352 30 0 1 2 CircleLockEnemyR10H6HC 1 1 0.3 0 1 3532 10353 20 0 5 80 1 5 CircleLockEnemyR8H6HC 1 1 0.3 0 1 3539 10355 Avatar_Qiqi_Revive 900 1 0 1 0 CircleLockEnemyR15H10HC 1 1 0.3 0 1 2 1 Skill_B_Barbara_01 0 1 @@ -144,7 +144,7 @@ ID Ability名称 是远程 技能CD 无视冷却缩减属性 消耗体力 消耗 10372 10 0 1 2 CircleLockEnemyR8H6HC 1 1 0.3 0 1 3732 10373 15 0 5 60 1 5 CircleLockEnemyR15H10HC 1 1 0.3 0 1 3739 10374 Avatar_Ganyu_AimPressShoot 1 0 0 1 0 CircleLockEnemyR15H10HC 1 1 0.3 0 1 0 -11301 Avatar_Beidou_ExtraAttack 0 666666 1 0 CircleLockEnemyR5H6HC 1 1 0.3 0 1 0 +11301 Avatar_Beidou_ExtraAttack 0 0 1 0 CircleLockEnemyR5H6HC 1 1 0.3 0 1 0 11302 9 0 1 2 CircleLockEnemyR8H6HC 1 1 0.3 0 1 0 11305 25 0 4 60 1 5 CircleLockEnemyR15H10HC 1 1 0.3 0 1 0 10256 8 0 3 2 CircleLockEnemyR8H6HC 1 1 0.3 0 1 0 @@ -160,10 +160,10 @@ ID Ability名称 是远程 技能CD 无视冷却缩减属性 消耗体力 消耗 11373 15 0 5 60 1 5 CircleLockEnemyR15H10HC 1 1 0.3 0 1 0 11374 1 0 0 1 0 CircleLockEnemyR15H10HC 1 1 0.3 0 1 0 11375 1 0 0 1 1 CircleLockEnemyR15H10HC 1 1 0.3 0 1 0 -10381 Avatar_Xingqiu_ExtraAttack 0 20 1 0 CircleLockEnemyR5H6HC 1 1 0.3 0 1 2531 +10381 Avatar_Xingqiu_ExtraAttack 0 0 1 0 CircleLockEnemyR5H6HC 1 1 0.3 0 1 2531 10382 Avatar_Xingqiu_SkillHoldHandler 21 0 1 2 CircleLockEnemyR8H6HC 1 1 0.3 0 1 2532 10385 20 0 2 80 1 5 CircleLockEnemyR5H6HC 1 1 0.3 0 1 2539 -10386 Avatar_Albedo_ExtraAttack 0 20 1 0 CircleLockEnemyR5H6HC 1 1 0.3 0 1 3831 +10386 Avatar_Albedo_ExtraAttack 0 0 1 0 CircleLockEnemyR5H6HC 1 1 0.3 0 1 3831 10387 4 0 1 2 CircleLockEnemyR5H6HC 1 1 0.3 0 1 3832 10388 12 0 8 40 1 5 CircleLockEnemyR8H6HC 1 1 0.3 0 1 3839 10391 Avatar_Diona_PressShoot 1 0 0 1 0 CircleLockEnemyR15H10HC 1 1 0.3 0 1 3931 @@ -171,58 +171,58 @@ ID Ability名称 是远程 技能CD 无视冷却缩减属性 消耗体力 消耗 10393 Avatar_Diona_AimPressShoot 1 0 0 1 0 CircleLockEnemyR15H10HC 1 1 0.3 0 1 0 10394 1 0 0 1 1 CircleLockEnemyR15H10HC 1 1 0.3 0 1 0 10395 1 20 0 5 80 1 5 CircleLockEnemyR15H10HC 1 1 0.3 0 1 3939 -10401 Avatar_Beidou_ExtraAttack_Chongyun 0 666666 1 0 CircleLockEnemyR5H6HC 1 1 0.3 0 1 3631 +10401 Avatar_Beidou_ExtraAttack_Chongyun 0 0 1 0 CircleLockEnemyR5H6HC 1 1 0.3 0 1 3631 10402 Avatar_Razor_ClawMark_Click 15 0 1 2 CircleLockEnemyR8H6HC 1 1 0.3 0 1 3632 10403 Diluc_FireCross 12 0 5 40 1 5 CircleLockEnemyR15H10HC 1 1 0.3 0 1 3639 -10411 Avatar_Mona_ExtraAttack 0 50 1 0 CircleLockEnemyR15H10HC 1 1 0.3 0 1 4131 +10411 Avatar_Mona_ExtraAttack 0 0 1 0 CircleLockEnemyR15H10HC 1 1 0.3 0 1 4131 10412 12 0 1 2 CircleLockEnemyR15H10HC 1 1 0.3 0 1 4132 -10413 0 15 1 3 CircleLockEnemyR5H6HC 1 1 0.3 0 1 1 4133 1 +10413 0 1 1 3 CircleLockEnemyR5H6HC 1 1 0.3 0 1 1 4133 1 10415 15 0 2 60 1 5 CircleLockEnemyR15H10HC 1 1 0.3 0 1 4139 -10421 Avatar_Keqing_ExtraAttack 0 25 1 0 CircleLockEnemyR5H6HC 1 1 0.3 0 1 4231 +10421 Avatar_Keqing_ExtraAttack 0 0 1 0 CircleLockEnemyR5H6HC 1 1 0.3 0 1 4231 10422 7.5 0 1 2 CircleLockEnemyR15H10HC 1 1 0.3 0 1 4232 10423 0 0 1 3 CircleLockEnemyR15H10HC 1 1 0.3 0 1 0 10425 12 0 4 40 1 5 CircleLockEnemyR5H6HC 1 1 0.3 0 1 4239 -10431 Avatar_Sucrose_ExtraAttack 0 50 1 0 CircleLockEnemyR15H10HC 1 1 0.3 0 1 4331 +10431 Avatar_Sucrose_ExtraAttack 0 0 1 0 CircleLockEnemyR15H10HC 1 1 0.3 0 1 4331 10432 15 0 1 2 CircleLockEnemyR15H10HC 1 1 0.3 0 1 4332 10433 1 5 1 12 CircleLockEnemy 1 1 0.3 0 1 0 10434 0 0 1 0 CircleLockEnemy 1 1 0.3 0 1 0 10435 20 0 7 80 1 5 CircleLockEnemyR15H10HC 1 1 0.3 0 1 4339 -10441 Avatar_Xinyan_ExtraAttack 0 40 1 0 CircleLockEnemyR5H6HC 1 1 0.3 0 1 4431 +10441 Avatar_Xinyan_ExtraAttack 0 0 1 0 CircleLockEnemyR5H6HC 1 1 0.3 0 1 4431 10442 18 0 1 2 CircleLockEnemyR10H6HC 1 1 0.3 0 1 4432 10443 15 0 1 60 1 5 CircleLockEnemyR8H6HC 1 1 0.3 0 1 4439 -10451 Avatar_Rosaria_ExtraAttack 0 25 1 0 CircleLockEnemyR5H6HC 1 1 0.3 0 1 4531 +10451 Avatar_Rosaria_ExtraAttack 0 0 1 0 CircleLockEnemyR5H6HC 1 1 0.3 0 1 4531 10452 6 0 1 2 CircleLockEnemyR15H10HC 1 1 0.3 0 1 4532 10453 15 0 5 60 1 5 CircleLockEnemyR8H6HC 1 1 0.3 0 1 4539 -10461 Avatar_Hutao_ExtraAttack 0 25 1 0 CircleLockEnemyR5H6HC 1 1 0.3 0 1 4631 +10461 Avatar_Hutao_ExtraAttack 0 0 1 0 CircleLockEnemyR5H6HC 1 1 0.3 0 1 4631 10462 16 0 1 2 CircleLockEnemyR5H6HC 1 1 0.3 0 1 4632 10463 15 0 1 60 1 5 CircleLockEnemyR5H6HC 1 1 0.3 0 1 4639 10464 Avatar_Hutao_Constellation_Limbo_Trigger 60 1 0 1 0 CircleLockEnemyR5H6HC 1 1 0.3 0 1 0 1 -10471 Avatar_Kazuha_ExtraAttack 0 20 1 0 CircleLockEnemyR5H6HC 1 1 0.3 0 1 4731 +10471 Avatar_Kazuha_ExtraAttack 0 0 1 0 CircleLockEnemyR5H6HC 1 1 0.3 0 1 4731 10472 6 0 1 2 CircleLockEnemyR8H6HC 1 1 0.3 0 1 4732 10473 6 0 1 3 CircleLockEnemyR8H6HC 1 1 0.3 0 1 0 2 10474 0 0 1 4 CircleLockEnemyR5H10HC 1 1 0.3 0 1 0 10475 15 0 7 60 1 5 CircleLockEnemyR15H10HC 1 1 0.3 0 1 4739 -10481 Avatar_Feiyan_ExtraAttack 0 50 1 0 CircleLockEnemyR15H10HC 1 1 0.3 0 1 4831 +10481 Avatar_Feiyan_ExtraAttack 0 0 1 0 CircleLockEnemyR15H10HC 1 1 0.3 0 1 4831 10482 9 0 1 2 CircleLockEnemyR15H10HC 1 1 0.3 0 1 4832 10485 20 0 1 80 1 5 CircleLockEnemyR5H6HC 1 1 0.3 0 1 4839 10491 Avatar_Yoimiya_PressShoot 1 0 0 1 0 CircleLockEnemyR15H10HC 1 1 0.3 0 1 4931 10492 1 18 0 1 2 CircleLockEnemyR15H10HC 1 1 0.3 0 1 4932 10493 Avatar_Yoimiya_AimPressShoot 1 0 0 1 0 CircleLockEnemyR15H10HC 1 1 0.3 0 1 0 10495 1 15 0 1 60 1 5 CircleLockEnemyR10H6HC 1 1 0.3 0 1 4939 -10501 Avatar_Tohma_ExtraAttack 0 25 1 0 CircleLockEnemyR5H6HC 1 1 0.3 0 1 5031 +10501 Avatar_Tohma_ExtraAttack 0 0 1 0 CircleLockEnemyR5H6HC 1 1 0.3 0 1 5031 10502 15 0 1 2 CircleLockEnemyR8H6HC 1 1 0.3 0 1 5032 10505 20 0 1 80 1 5 CircleLockEnemyR5H6HC 1 1 0.3 0 1 5039 -10511 Avatar_Eula_ExtraAttack 0 40 1 0 CircleLockEnemyR5H6HC 1 1 0.3 0 1 5131 +10511 Avatar_Eula_ExtraAttack 0 0 1 0 CircleLockEnemyR5H6HC 1 1 0.3 0 1 5131 10512 4 0 1 2 CircleLockEnemyR8H6HC 1 1 0.3 0 1 5132 10515 20 0 5 80 1 5 CircleLockEnemyR15H10HC 1 1 0.3 0 1 5139 -10521 Avatar_Shougun_ExtraAttack 0 25 1 0 CircleLockEnemyR5H6HC 1 1 0.3 0 1 5231 +10521 Avatar_Shougun_ExtraAttack 0 0 1 0 CircleLockEnemyR5H6HC 1 1 0.3 0 1 5231 10522 10 0 1 2 CircleLockEnemyR8H6HC 1 1 0.3 0 1 5232 10525 18 0 4 90 1 5 CircleLockEnemyR8H6HC 1 1 0.3 0 1 5239 -10531 Avatar_Sayu_ExtraAttack 0 40 1 0 CircleLockEnemyR5H6HC 1 1 0.3 0 1 5331 +10531 Avatar_Sayu_ExtraAttack 0 0 1 0 CircleLockEnemyR5H6HC 1 1 0.3 0 1 5331 10532 6 0 1 2 CircleLockEnemyR8H6HC 1 1 0.3 0 1 5332 10533 0 0 1 3 CircleLockEnemyR8H6HC 1 1 0.3 0 1 0 10535 20 0 7 80 1 5 CircleLockEnemyR15H10HC 1 1 0.3 0 1 5339 -10541 Avatar_Kokomi_ExtraAttack 0 50 1 0 CircleLockEnemyR15H10HC 1 1 0.3 0 1 5431 +10541 Avatar_Kokomi_ExtraAttack 0 0 1 0 CircleLockEnemyR15H10HC 1 1 0.3 0 1 5431 10542 20 0 1 2 CircleLockEnemyR15H10HC 1 1 0.3 0 1 5432 10545 18 0 2 70 1 5 CircleLockEnemyR15H10HC 1 1 0.3 0 1 5439 10551 Avatar_Gorou_PressShoot 1 0 0 1 0 CircleLockEnemyR15H10HC 1 1 0.3 0 1 5531 @@ -235,14 +235,14 @@ ID Ability名称 是远程 技能CD 无视冷却缩减属性 消耗体力 消耗 10563 Avatar_Sara_AimPressShoot 1 0 0 1 0 CircleLockEnemyR15H10HC 1 1 0.3 0 1 0 10564 1 0 0 1 1 CircleLockEnemyR15H10HC 1 1 0.3 0 1 0 10565 1 20 0 4 80 1 5 CircleLockEnemyR15H10HC 1 1 0.3 0 1 5639 -10571 Avatar_Itto_ExtraAttack 0 20 1 0 CircleLockEnemyR7H6HC 1 1 0.6 0 1 5731 +10571 Avatar_Itto_ExtraAttack 0 0 1 0 CircleLockEnemyR7H6HC 1 1 0.6 0 1 5731 10572 10 0 1 2 CircleLockEnemyR8H6HC 1 1 0.3 0 1 5732 10575 18 0 8 70 1 5 CircleLockEnemyR15H10HC 1 1 0.3 0 1 5739 -10581 Avatar_Yae_ExtraAttack 0 50 1 0 CircleLockEnemyR15H10HC 1 1 0.3 0 1 5831 +10581 Avatar_Yae_ExtraAttack 0 0 1 0 CircleLockEnemyR15H10HC 1 1 0.3 0 1 5831 10582 4 0 3 2 CircleLockEnemyR15H10HC 1 1 0.3 0 1 1 5832 10583 4 0 3 3 CircleLockEnemyR15H10HC 1 1 0.3 0 1 0 10585 22 0 4 90 1 5 CircleLockEnemyR15H10HC 1 1 0.3 0 1 5839 -10591 Avatar_Heizo_ExtraAttack 0 25 1 0 CircleLockEnemyR5H6HC 1 1 0.3 0 1 5931 +10591 Avatar_Heizo_ExtraAttack 0 0 1 0 CircleLockEnemyR5H6HC 1 1 0.3 0 1 5931 10592 10 0 1 2 CircleLockEnemyR8H6HC 1 1 0.3 0 1 5932 10595 12 0 7 40 1 5 CircleLockEnemyR15H10HC 1 1 0.3 0 1 5939 10602 13.5 0 1 22 CircleLockEnemyR15H10HC 1 1 0.3 0 1 1032 @@ -256,19 +256,19 @@ ID Ability名称 是远程 技能CD 无视冷却缩减属性 消耗体力 消耗 10622 20 0 1 2 CircleLockEnemyR15H10HC 1 1 0.3 0 1 6232 10623 Avatar_Aloy_AimPressShoot 1 0 0 1 0 CircleLockEnemyR15H10HC 1 1 0.3 0 1 0 10624 1 0 0 1 1 CircleLockEnemyR15H10HC 1 1 0.3 0 1 0 -10631 Avatar_Shenhe_ExtraAttack 0 25 1 0 CircleLockEnemyR5H6HC 1 1 0.3 0 1 6331 +10631 Avatar_Shenhe_ExtraAttack 0 0 1 0 CircleLockEnemyR5H6HC 1 1 0.3 0 1 6331 10632 10 0 1 2 CircleLockEnemyR8H6HC 1 1 0.3 0 1 6332 10635 20 0 5 80 1 5 CircleLockEnemyR8H6HC 1 1 0.3 0 1 6339 10625 12 0 5 40 1 5 CircleLockEnemyR15H10HC 1 1 0.3 0 1 6239 -10641 Avatar_Yunjin_ExtraAttack 0 25 1 0 CircleLockEnemyR5H6HC 1 1 0.3 0 1 6431 +10641 Avatar_Yunjin_ExtraAttack 0 0 1 0 CircleLockEnemyR5H6HC 1 1 0.3 0 1 6431 10642 9 0 1 2 CircleLockEnemyR8H6HC 1 1 0.3 0 1 6432 10643 15 0 8 60 1 5 CircleLockEnemyR8H6HC 1 1 0.3 0 1 6439 -10651 Avatar_Shinobu_ExtraAttack 0 20 1 0 CircleLockEnemyR5H6HC 1 1 0.3 0 1 6531 +10651 Avatar_Shinobu_ExtraAttack 0 0 1 0 CircleLockEnemyR5H6HC 1 1 0.3 0 1 6531 10652 15 0 1 2 CircleLockEnemyR8H6HC 1 1 0.3 0 1 6532 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 20 1 0 CircleLockEnemyR5H6HC 1 1 0.3 0 1 6631 +10661 Avatar_Ayato_ExtraAttack 0 0 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 @@ -276,14 +276,14 @@ ID Ability名称 是远程 技能CD 无视冷却缩减属性 消耗体力 消耗 10672 12 0 1 2 CircleLockEnemyR15H10HC 1 1 0.3 0 1 6732 10675 15 0 3 60 1 5 CircleLockEnemyR15H10HC 1 1 0.3 0 1 6739 10674 Avatar_Ganyu_AimPressShoot 1 0 0 1 0 CircleLockEnemyR15H10HC 1 1 0.3 0 1 0 -10681 Avatar_Dori_ExtraAttack 0 40 1 0 CircleLockEnemyR5H6HC 1 1 0.3 0 1 6831 +10681 Avatar_Dori_ExtraAttack 0 0 1 0 CircleLockEnemyR5H6HC 1 1 0.3 0 1 6831 10682 9 0 1 2 CircleLockEnemyR15H10HC 1 1 0.3 0 1 6832 10685 20 0 4 80 1 5 CircleLockEnemyR8H6HC 1 1 0.3 0 1 6839 10691 Avatar_Tighnari_PressShoot 1 0 0 1 0 CircleLockEnemyR15H10HC 1 1 0.3 0 1 6931 10692 12 0 1 2 CircleLockEnemyR15H10HC 1 1 0.3 0 1 6932 10693 Avatar_Tighnari_AimPressShoot 1 0 0 1 0 CircleLockEnemyR15H10HC 1 1 0.3 0 1 10695 12 0 3 40 1 5 CircleLockEnemyR15H10HC 1 1 0.3 0 1 6939 -10701 Avatar_Nilou_ExtraAttack 0 20 1 0 CircleLockEnemyR5H6HC 1 1 0.3 0 1 7031 +10701 Avatar_Nilou_ExtraAttack 0 0 1 0 CircleLockEnemyR5H6HC 1 1 0.3 0 1 7031 10702 18 0 1 2 CircleLockEnemyR8H6HC 1 1 0.3 0 1 7032 10703 0 0 1 3 CircleLockEnemyR8H6HC 1 1 0.3 0 1 10704 0 0 1 4 CircleLockEnemyR8H6HC 1 1 0.3 0 1 @@ -291,20 +291,20 @@ ID Ability名称 是远程 技能CD 无视冷却缩减属性 消耗体力 消耗 10707 0 0 1 22 CircleLockEnemyR8H6HC 1 1 0.3 0 1 10705 18 0 2 70 1 5 CircleLockEnemyR15H10HC 1 1 0.3 0 1 7039 10708 0 0 1 23 CircleLockEnemyR8H6HC 1 1 0.3 0 1 -10711 Avatar_Cyno_ExtraAttack 0 25 1 0 CircleLockEnemyR5H6HC 1 1 0.3 0 1 7131 +10711 Avatar_Cyno_ExtraAttack 0 0 1 0 CircleLockEnemyR5H6HC 1 1 0.3 0 1 7131 10712 7.5 0 1 2 CircleLockEnemyR8H6HC 1 1 0.3 0 1 7132 10713 3 0 1 2 CircleLockEnemyR8H6HC 1 1 0.3 0 1 0 2 10715 20 0 4 80 1 5 CircleLockEnemyR8H6HC 1 1 0.3 0 1 7139 -10721 Avatar_Candace_ExtraAttack 0 25 1 0 CircleLockEnemyR5H6HC 1 1 0.3 0 1 7231 +10721 Avatar_Candace_ExtraAttack 0 0 1 0 CircleLockEnemyR5H6HC 1 1 0.3 0 1 7231 10722 · 6 0 1 2 CircleLockEnemyR8H6HC 1 1 0.3 0 1 2 1 7232 10725 15 0 2 60 1 5 CircleLockEnemyR8H6HC 1 1 0.3 0 1 7239 -10731 Avatar_Nahida_ExtraAttack 0 50 1 0 CircleLockEnemyR10H6HC 1 1 0.3 0 1 7331 +10731 Avatar_Nahida_ExtraAttack 0 0 1 0 CircleLockEnemyR10H6HC 1 1 0.3 0 1 7331 10732 · 5 0 1 2 CircleLockEnemyR8H6HC 1 1 0.3 0 1 7332 10735 13.5 0 3 50 1 5 CircleLockEnemyR15H10HC 1 1 0.3 0 1 7339 -10741 Avatar_Layla_ExtraAttack 0 20 1 0 CircleLockEnemyR5H6HC 1 1 0.3 0 1 7431 +10741 Avatar_Layla_ExtraAttack 0 0 1 0 CircleLockEnemyR5H6HC 1 1 0.3 0 1 7431 10742 · 12 0 1 2 CircleLockEnemyR8H6HC 1 1 0.3 0 1 7432 10745 12 0 5 40 1 5 CircleLockEnemyR15H10HC 1 1 0.3 0 1 7439 -10751 Avatar_Wanderer_ExtraAttack 0 50 1 0 CircleLockEnemyR15H10HC 1 1 0.3 0 1 7531 +10751 Avatar_Wanderer_ExtraAttack 0 0 1 0 CircleLockEnemyR15H10HC 1 1 0.3 0 1 7531 10752 6 0 1 2 CircleLockEnemyR15H10HC 1 1 0.3 0 1 7532 10753 15 0 7 60 1 3 CircleLockEnemyR15H10HC 1 1 0.3 0 1 10755 15 0 7 60 1 5 CircleLockEnemyR15H10HC 1 1 0.3 0 1 7539 @@ -316,21 +316,21 @@ ID Ability名称 是远程 技能CD 无视冷却缩减属性 消耗体力 消耗 10762 8 0 1 2 CircleLockEnemyR15H10HC 1 1 0.3 0 1 0 10764 Avatar_Faruzan_AimPressShoot 1 0 0 1 0 CircleLockEnemyR15H10HC 1 1 0.3 0 1 0 10765 12 0 7 40 1 5 CircleLockEnemyR15H10HC 1 1 0.3 0 1 0 -10771 Avatar_Yaoyao_ExtraAttack 0 25 1 0 CircleLockEnemyR5H6HC 1 1 0.3 0 1 0 +10771 Avatar_Yaoyao_ExtraAttack 0 0 1 0 CircleLockEnemyR5H6HC 1 1 0.3 0 1 0 10772 10 0 1 2 CircleLockEnemyR8H6HC 1 1 0.3 0 1 0 10775 20 0 3 80 1 5 CircleLockEnemyR8H6HC 1 1 0.3 0 1 0 -10781 Avatar_Alhatham_ExtraAttack 0 20 1 0 CircleLockEnemyR5H6HC 1 1 0.3 0 1 0 +10781 Avatar_Alhatham_ExtraAttack 0 0 1 0 CircleLockEnemyR5H6HC 1 1 0.3 0 1 0 10782 · 10 0 1 2 CircleLockEnemyR15H10HC 1 1 0.3 0 1 0 10785 15 0 3 60 1 5 CircleLockEnemyR15H10HC 1 1 0.3 0 1 0 -10791 Avatar_Dehya_ExtraAttack 0 666666 1 0 CircleLockEnemyR5H6HC 1 1 0.3 0 1 0 +10791 Avatar_Dehya_ExtraAttack 0 0 1 0 CircleLockEnemyR5H6HC 1 1 0.3 0 1 0 10792 8 0 1 2 CircleLockEnemyR15H10HC 1 1 0.3 0 1 0 10793 0 0 1 3 CircleLockEnemyR15H10HC 1 1 0.3 0 1 0 10794 0.5 0 1 4 CircleLockEnemyR15H10HC 1 1 0.3 0 1 0 10795 15 0 1 60 1 5 CircleLockEnemyR15H10HC 1 1 0.3 0 1 0 -10801 Avatar_Mika_ExtraAttack 0 666666 1 0 CircleLockEnemyR5H6HC 1 1 0.3 0 1 0 +10801 Avatar_Mika_ExtraAttack 0 0 1 0 CircleLockEnemyR5H6HC 1 1 0.3 0 1 0 10802 Avatar_Mika_ElementalArt 10 0 1 2 CircleLockEnemyR8H6HC 1 1 0.3 0 1 0 10805 20 0 5 60 1 5 CircleLockEnemyR5H6HC 1 1 0.3 0 1 0 -10821 Avatar_Baizhuer_ExtraAttack 1 0 666666 1 0 CircleLockEnemyR15H10HC 1 1 0.3 0 1 0 +10821 Avatar_Baizhuer_ExtraAttack 1 0 0 1 0 CircleLockEnemyR15H10HC 1 1 0.3 0 1 0 10822 · 10 0 1 2 CircleLockEnemyR15H10HC 1 1 0.3 0 1 0 10825 15 0 3 60 1 5 CircleLockEnemyR15H10HC 1 1 0.3 0 1 0 20001 Dvalin_S01_AirGun 0 999999 1 0 CircleLockEnemyR10 1 1 0.3 0 1 2 1 0 diff --git a/gdconf/skill_stamina_data.go b/gdconf/skill_stamina_data.go new file mode 100644 index 00000000..98ee0634 --- /dev/null +++ b/gdconf/skill_stamina_data.go @@ -0,0 +1,28 @@ +package gdconf + +import ( + "hk4e/pkg/endec" + "hk4e/pkg/logger" +) + +// 体力应该由ability来做 但是现在我捋不清所以摆烂了 改了一下表暂时先这么用着 + +type SkillStaminaData struct { + AvatarSkillId int32 `csv:"AvatarSkillId"` + AbilityName string `csv:"AbilityName"` + CostStamina int32 `csv:"CostStamina"` +} + +func (g *GameDataConfig) loadSkillStaminaData() { + g.SkillStaminaDataMap = make(map[int32]*SkillStaminaData) + skillStaminaDataList := make([]*SkillStaminaData, 0) + readExtCsv[SkillStaminaData](g.extPrefix+"SkillStaminaData.csv", &skillStaminaDataList) + for _, skillStaminaData := range skillStaminaDataList { + g.SkillStaminaDataMap[endec.Hk4eAbilityHashCode(skillStaminaData.AbilityName)] = skillStaminaData + } + logger.Info("SkillStaminaData count: %v", len(g.SkillStaminaDataMap)) +} + +func GetSkillStaminaDataByAbilityHashCode(abilityHashCode int32) *SkillStaminaData { + return CONF.SkillStaminaDataMap[abilityHashCode] +} diff --git a/gs/game/game.go b/gs/game/game.go index fa63633e..70922527 100644 --- a/gs/game/game.go +++ b/gs/game/game.go @@ -141,10 +141,10 @@ func (g *Game) GetAi() *model.Player { } func (g *Game) CreateRobot(uid uint32, name string, sign string) *model.Player { - GAME.OnRegOk(false, &proto.SetPlayerBornDataReq{AvatarId: 10000007, NickName: name}, uid, 0, "") - GAME.ServerAppidBindNotify(uid, "", 0) + g.OnLogin(uid, 0, "", nil, 0) robot := USER_MANAGER.GetOnlineUser(uid) robot.DbState = model.DbNormal + g.SetPlayerBornDataReq(robot, &proto.SetPlayerBornDataReq{AvatarId: 10000007, NickName: name}) robot.SceneLoadState = model.SceneEnterDone robot.Signature = sign return robot diff --git a/gs/game/game_local_event_manager.go b/gs/game/game_local_event_manager.go index cc6f296b..eae67c6a 100644 --- a/gs/game/game_local_event_manager.go +++ b/gs/game/game_local_event_manager.go @@ -16,13 +16,12 @@ import ( // 本地事件队列管理器 const ( - LoadLoginUserFromDbFinish = iota // 玩家登录从数据库加载完成回调 - CheckUserExistOnRegFromDbFinish // 玩家注册从数据库查询是否已存在完成回调 - RunUserCopyAndSave // 执行一次在线玩家内存数据复制到数据库写入协程 - ExitRunUserCopyAndSave // 停服时执行全部玩家保存操作 - UserOfflineSaveToDbFinish // 玩家离线保存完成 - ReloadGameDataConfig // 执行热更表 - ReloadGameDataConfigFinish // 热更表完成 + LoadLoginUserFromDbFinish = iota // 玩家登录从数据库加载完成回调 + RunUserCopyAndSave // 执行一次在线玩家内存数据复制到数据库写入协程 + ExitRunUserCopyAndSave // 停服时执行全部玩家保存操作 + UserOfflineSaveToDbFinish // 玩家离线保存完成 + ReloadGameDataConfig // 执行热更表 + ReloadGameDataConfigFinish // 热更表完成 ) const ( @@ -66,13 +65,7 @@ func (l *LocalEventManager) LocalEventHandle(localEvent *LocalEvent) { switch localEvent.EventId { case LoadLoginUserFromDbFinish: playerLoginInfo := localEvent.Msg.(*PlayerLoginInfo) - if playerLoginInfo.Player != nil { - USER_MANAGER.AddUser(playerLoginInfo.Player) - } - GAME.OnLoginOk(playerLoginInfo.UserId, playerLoginInfo.ClientSeq, playerLoginInfo.GateAppId, false, playerLoginInfo.Player) - case CheckUserExistOnRegFromDbFinish: - playerRegInfo := localEvent.Msg.(*PlayerRegInfo) - GAME.OnRegOk(playerRegInfo.Exist, playerRegInfo.Req, playerRegInfo.UserId, playerRegInfo.ClientSeq, playerRegInfo.GateAppId) + GAME.OnLogin(playerLoginInfo.UserId, playerLoginInfo.ClientSeq, playerLoginInfo.GateAppId, playerLoginInfo.Player, playerLoginInfo.JoinHostUserId) case ExitRunUserCopyAndSave: fallthrough case RunUserCopyAndSave: diff --git a/gs/game/game_route_manager.go b/gs/game/game_route_manager.go index 9d0d724a..76284d95 100644 --- a/gs/game/game_route_manager.go +++ b/gs/game/game_route_manager.go @@ -54,6 +54,7 @@ func (r *RouteManager) doRoute(cmdId uint16, userId uint32, clientSeq uint32, pa } func (r *RouteManager) initRoute() { + r.registerRouter(cmd.SetPlayerBornDataReq, GAME.SetPlayerBornDataReq) r.registerRouter(cmd.QueryPathReq, GAME.QueryPathReq) r.registerRouter(cmd.UnionCmdNotify, GAME.UnionCmdNotify) r.registerRouter(cmd.MassiveEntityElementOpBatchNotify, GAME.MassiveEntityElementOpBatchNotify) @@ -164,10 +165,6 @@ func (r *RouteManager) RouteHandle(netMsg *mq.NetMsg) { GAME.PlayerLoginReq(gameMsg.UserId, gameMsg.ClientSeq, netMsg.OriginServerAppId, gameMsg.PayloadMessage) return } - if gameMsg.CmdId == cmd.SetPlayerBornDataReq { - GAME.SetPlayerBornDataReq(gameMsg.UserId, gameMsg.ClientSeq, netMsg.OriginServerAppId, gameMsg.PayloadMessage) - return - } r.doRoute(gameMsg.CmdId, gameMsg.UserId, gameMsg.ClientSeq, gameMsg.PayloadMessage) } case mq.MsgTypeConnCtrl: @@ -192,7 +189,7 @@ func (r *RouteManager) RouteHandle(netMsg *mq.NetMsg) { logger.Debug("remote user online state change, uid: %v, online: %v", serverMsg.UserId, serverMsg.IsOnline) USER_MANAGER.SetRemoteUserOnlineState(serverMsg.UserId, serverMsg.IsOnline, netMsg.OriginServerAppId) case mq.ServerAppidBindNotify: - GAME.ServerAppidBindNotify(serverMsg.UserId, serverMsg.AnticheatServerAppId, serverMsg.JoinHostUserId) + GAME.ServerAppidBindNotify(serverMsg.UserId, serverMsg.AnticheatServerAppId) case mq.ServerUserMpReq: GAME.ServerUserMpReq(serverMsg.UserMpInfo, netMsg.OriginServerAppId) case mq.ServerUserMpRsp: diff --git a/gs/game/game_tick_manager.go b/gs/game/game_tick_manager.go index b378126e..348f5d5a 100644 --- a/gs/game/game_tick_manager.go +++ b/gs/game/game_tick_manager.go @@ -152,12 +152,6 @@ func (t *TickManager) OnGameServerTick() { if t.globalTickCount%(60000*60/ServerTickTime) == 0 { t.onTickHour(now) } - if t.globalTickCount%(60000*60*24/ServerTickTime) == 0 { - t.onTickDay(now) - } - if t.globalTickCount%(60000*60*24*7/ServerTickTime) == 0 { - t.onTickWeek(now) - } for userId, userTick := range t.userTickMap { if len(userTick.globalTick.C) == 0 { // 跳过还没到时间的定时器 @@ -184,14 +178,6 @@ func (t *TickManager) OnGameServerTick() { } } -func (t *TickManager) onTickWeek(now int64) { - logger.Info("on tick week, time: %v", now) -} - -func (t *TickManager) onTickDay(now int64) { - logger.Info("on tick day, time: %v", now) -} - func (t *TickManager) onTickHour(now int64) { logger.Info("on tick hour, time: %v", now) } diff --git a/gs/game/game_user_manager.go b/gs/game/game_user_manager.go index 7294aaa1..a18ee6dd 100644 --- a/gs/game/game_user_manager.go +++ b/gs/game/game_user_manager.go @@ -8,14 +8,12 @@ import ( "hk4e/gs/dao" "hk4e/gs/model" "hk4e/pkg/logger" - "hk4e/protocol/proto" "github.com/vmihailenco/msgpack/v5" ) // 玩家管理器 -// 玩家注册 从db查询对应uid是否存在并异步回调返回结果 // 玩家登录 从db查询出来然后写入redis并异步回调返回玩家对象 // 玩家离线 写入db和redis // 玩家定时保存 写入db和redis @@ -78,42 +76,6 @@ func (u *UserManager) GetAllOnlineUserList() map[uint32]*model.Player { return onlinePlayerMap } -type PlayerRegInfo struct { - Exist bool - Req *proto.SetPlayerBornDataReq - UserId uint32 - ClientSeq uint32 - GateAppId string -} - -// CheckUserExistOnReg 玩家注册检查是否已存在 -func (u *UserManager) CheckUserExistOnReg(userId uint32, - req *proto.SetPlayerBornDataReq, clientSeq uint32, gateAppId string) (exist bool, asyncWait bool) { - _, exist = u.playerMap[userId] - if exist { - return true, false - } else { - go func() { - player := u.LoadUserFromDbSync(userId) - exist = false - if player != nil { - exist = true - } - LOCAL_EVENT_MANAGER.GetLocalEventChan() <- &LocalEvent{ - EventId: CheckUserExistOnRegFromDbFinish, - Msg: &PlayerRegInfo{ - Exist: exist, - Req: req, - UserId: userId, - ClientSeq: clientSeq, - GateAppId: gateAppId, - }, - } - }() - return false, true - } -} - // AddUser 向内存玩家数据里添加一个玩家 func (u *UserManager) AddUser(player *model.Player) { if player == nil { @@ -128,55 +90,51 @@ func (u *UserManager) DeleteUser(userId uint32) { } type PlayerLoginInfo struct { - UserId uint32 - Player *model.Player - ClientSeq uint32 - GateAppId string + UserId uint32 + Player *model.Player + ClientSeq uint32 + GateAppId string + JoinHostUserId uint32 } // OnlineUser 玩家上线 -func (u *UserManager) OnlineUser(userId uint32, clientSeq uint32, gateAppId string) (*model.Player, bool) { - player, exist := u.playerMap[userId] - if userId > PlayerBaseUid { - // 正常登录 - if exist { - // 每次玩家上线必须从数据库加载最新的档 如果之前存在于内存则删掉 - u.DeleteUser(userId) - } - go func() { - // 加离线玩家数据分布式锁 - ok := u.dao.DistLockSync(userId) - if !ok { - logger.Error("lock redis offline player data error, uid: %v", userId) - return - } - player := u.LoadUserFromDbSync(userId) - if player != nil { - u.SaveUserToRedisSync(player) - } - // 解离线玩家数据分布式锁 - u.dao.DistUnlock(userId) - if player != nil { - u.ChangeUserDbState(player, model.DbNormal) - player.ChatMsgMap = u.LoadUserChatMsgFromDbSync(userId) - } else { - logger.Error("can not find user from db, uid: %v", userId) - } - LOCAL_EVENT_MANAGER.GetLocalEventChan() <- &LocalEvent{ - EventId: LoadLoginUserFromDbFinish, - Msg: &PlayerLoginInfo{ - UserId: userId, - Player: player, - ClientSeq: clientSeq, - GateAppId: gateAppId, - }, - } - }() - return nil, false - } else { - // 机器人 - return player, true +func (u *UserManager) OnlineUser(userId uint32, clientSeq uint32, gateAppId string, joinHostUserId uint32) { + _, exist := u.playerMap[userId] + // 正常登录 + if exist { + // 每次玩家上线必须从数据库加载最新的档 如果之前存在于内存则删掉 + u.DeleteUser(userId) } + go func() { + // 加离线玩家数据分布式锁 + ok := u.dao.DistLockSync(userId) + if !ok { + logger.Error("lock redis offline player data error, uid: %v", userId) + return + } + player := u.LoadUserFromDbSync(userId) + if player != nil { + u.SaveUserToRedisSync(player) + } + // 解离线玩家数据分布式锁 + u.dao.DistUnlock(userId) + if player != nil { + u.ChangeUserDbState(player, model.DbNormal) + player.ChatMsgMap = u.LoadUserChatMsgFromDbSync(userId) + } else { + logger.Error("can not find user from db, uid: %v", userId) + } + LOCAL_EVENT_MANAGER.GetLocalEventChan() <- &LocalEvent{ + EventId: LoadLoginUserFromDbFinish, + Msg: &PlayerLoginInfo{ + UserId: userId, + Player: player, + ClientSeq: clientSeq, + GateAppId: gateAppId, + JoinHostUserId: joinHostUserId, + }, + } + }() } type ChangeGsInfo struct { diff --git a/gs/game/game_world_manager.go b/gs/game/game_world_manager.go index d66e7ef3..45d18333 100644 --- a/gs/game/game_world_manager.go +++ b/gs/game/game_world_manager.go @@ -421,6 +421,15 @@ func (w *WorldAvatar) GetAbilityList() []*proto.AbilityAppliedAbility { return w.abilityList } +func (w *WorldAvatar) GetAbilityByInstanceId(instanceId uint32) *proto.AbilityAppliedAbility { + for _, ability := range w.abilityList { + if ability.InstancedAbilityId == instanceId { + return ability + } + } + return nil +} + func (w *WorldAvatar) SetAbilityList(abilityList []*proto.AbilityAppliedAbility) { w.abilityList = abilityList } diff --git a/gs/game/player_common.go b/gs/game/player_common.go index f88f71b5..d3aae1aa 100644 --- a/gs/game/player_common.go +++ b/gs/game/player_common.go @@ -119,31 +119,14 @@ func (g *Game) ObstacleModifyNotify(player *model.Player, payloadMsg pb.Message) // logger.Debug("ObstacleModifyNotify: %v, uid: %v", ntf, player.PlayerID) } -func (g *Game) ServerAppidBindNotify(userId uint32, anticheatAppId string, joinHostUserId uint32) { +func (g *Game) ServerAppidBindNotify(userId uint32, anticheatAppId string) { player := USER_MANAGER.GetOnlineUser(userId) if player == nil { logger.Error("player is nil, uid: %v", userId) return } - if joinHostUserId != 0 { - hostPlayer := USER_MANAGER.GetOnlineUser(joinHostUserId) - if hostPlayer == nil { - logger.Error("player is nil, uid: %v", joinHostUserId) - return - } - g.JoinOtherWorld(player, hostPlayer) - return - } logger.Debug("server appid bind notify, uid: %v, anticheatAppId: %v", userId, anticheatAppId) player.AnticheatAppId = anticheatAppId - // 创建世界 - world := WORLD_MANAGER.CreateWorld(player) - world.AddPlayer(player, player.SceneId) - player.WorldId = world.GetId() - // 进入场景 - player.SceneJump = true - player.SceneLoadState = model.SceneNone - g.SendMsg(cmd.PlayerEnterSceneNotify, userId, player.ClientSeq, g.PacketPlayerEnterSceneNotifyLogin(player, proto.EnterType_ENTER_SELF)) } // WorldPlayerRTTNotify 世界里所有玩家的网络延迟广播 diff --git a/gs/game/player_fight_sync.go b/gs/game/player_fight_sync.go index 63247b42..c9b1ab03 100644 --- a/gs/game/player_fight_sync.go +++ b/gs/game/player_fight_sync.go @@ -136,15 +136,9 @@ func (g *Game) CombatInvocationsNotify(player *model.Player, payloadMsg pb.Messa } logger.Debug("[EvtBeingHit] GadgetData: %+v, uid: %v", gadgetDataConfig, player.PlayerID) // TODO 临时的解决方案 - switch gadgetDataConfig.ServerLuaScript { - case "SubfieldDrop_WoodenObject_Broken": - g.KillEntity(player, scene, target.GetId(), proto.PlayerDieType_PLAYER_DIE_GM) - case "SetGadgetState": + if strings.Contains(gadgetDataConfig.ServerLuaScript, "SetGadgetState") { g.ChangeGadgetState(player, target.GetId(), constant.GADGET_STATE_GEAR_START) } - if strings.Contains(gadgetDataConfig.ServerLuaScript, "SubfieldDrop_Ore_") { - g.KillEntity(player, scene, target.GetId(), proto.PlayerDieType_PLAYER_DIE_GM) - } if strings.Contains(gadgetDataConfig.ServerLuaScript, "Controller") { g.ChangeGadgetState(player, target.GetId(), constant.GADGET_STATE_GEAR_START) } @@ -331,12 +325,8 @@ func (g *Game) AbilityInvocationsNotify(player *model.Player, payloadMsg pb.Mess if player.SceneLoadState != model.SceneEnterDone { return } - world := WORLD_MANAGER.GetWorldByID(player.WorldId) - if world == nil { - return - } for _, entry := range req.Invokes { - // logger.Debug("AbilityInvocationsNotify: %v", entry, player.PlayerID) + player.AbilityInvokeHandler.AddEntry(entry.ForwardType, entry) switch entry.ArgumentType { case proto.AbilityInvokeArgument_ABILITY_META_MODIFIER_CHANGE: modifierChange := new(proto.AbilityMetaModifierChange) @@ -345,29 +335,50 @@ func (g *Game) AbilityInvocationsNotify(player *model.Player, payloadMsg pb.Mess logger.Error("parse AbilityMetaModifierChange error: %v", err) continue } - // logger.Error("MC: %v", modifierChange) - worldAvatar := world.GetWorldAvatarByEntityId(entry.EntityId) - if worldAvatar != nil { - for _, ability := range worldAvatar.abilityList { - if ability.InstancedAbilityId == entry.Head.InstancedAbilityId { - // logger.Error("A: %v", ability) - } - } - for _, modifier := range worldAvatar.modifierList { - if modifier.InstancedAbilityId == entry.Head.InstancedAbilityId { - // logger.Error("B: %v", modifier) - } - } - for _, modifier := range worldAvatar.modifierList { - if modifier.InstancedModifierId == entry.Head.InstancedModifierId { - // logger.Error("C: %v", modifier) - } - } + // logger.Debug("entry: %v, ModifierChange: %v", entry, modifierChange) + // 处理耐力消耗 + g.HandleAbilityStamina(player, entry) + 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("entry: %v, MixinCostStamina: %v", entry, costStamina) + // 处理耐力消耗 + g.HandleAbilityStamina(player, entry) + case proto.AbilityInvokeArgument_ABILITY_ACTION_DEDUCT_STAMINA: + deductStamina := new(proto.AbilityActionDeductStamina) + err := pb.Unmarshal(entry.AbilityData, deductStamina) + if err != nil { + logger.Error("parse AbilityActionDeductStamina error: %v", err) + continue + } + logger.Debug("entry: %v, ActionDeductStamina: %v", entry, deductStamina) + // 处理耐力消耗 + 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("entry: %v, DurabilityChange: %v", entry, modifierDurabilityChange) + case proto.AbilityInvokeArgument_ABILITY_META_DURABILITY_IS_ZERO: + durabilityIsZero := new(proto.AbilityMetaDurabilityIsZero) + err := pb.Unmarshal(entry.AbilityData, durabilityIsZero) + if err != nil { + logger.Error("parse AbilityMetaDurabilityIsZero error: %v", err) + continue + } + logger.Debug("entry: %v, DurabilityIsZero: %v", entry, durabilityIsZero) + case proto.AbilityInvokeArgument_ABILITY_MIXIN_ELITE_SHIELD: + case proto.AbilityInvokeArgument_ABILITY_MIXIN_ELEMENT_SHIELD: + case proto.AbilityInvokeArgument_ABILITY_MIXIN_GLOBAL_SHIELD: + case proto.AbilityInvokeArgument_ABILITY_MIXIN_SHIELD_BAR: } - // 处理耐力消耗 - g.HandleAbilityStamina(player, entry) - player.AbilityInvokeHandler.AddEntry(entry.ForwardType, entry) } } @@ -394,13 +405,11 @@ func (g *Game) ClientAbilityChangeNotify(player *model.Player, payloadMsg pb.Mes 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 @@ -453,7 +462,6 @@ func (g *Game) ClientAbilityChangeNotify(player *model.Player, payloadMsg pb.Mes modifierList := worldAvatar.GetModifierList() modifierList = append(modifierList, abilityAppliedModifier) worldAvatar.SetModifierList(modifierList) - default: } } } diff --git a/gs/game/player_gacha.go b/gs/game/player_gacha.go index 780cfd92..5cc5f266 100644 --- a/gs/game/player_gacha.go +++ b/gs/game/player_gacha.go @@ -372,7 +372,7 @@ func (g *Game) doGachaOnce(userId uint32, gachaType uint32, mustGetUpEnable bool return false, 0 } // 找到卡池对应的掉落组 - dropGroupDataConfig := gdconf.CONF.GachaDropGroupDataMap[int32(gachaType)] + dropGroupDataConfig := gdconf.GetGachaDropGroupDataByDropId(int32(gachaType)) if dropGroupDataConfig == nil { logger.Error("drop group not found, drop id: %v", gachaType) return false, 0 @@ -511,7 +511,7 @@ func (g *Game) doGachaOnce(userId uint32, gachaType uint32, mustGetUpEnable bool // 替换本次结果为5星大保底 if gachaPoolInfo.MustGetUpOrange { logger.Debug("trigger must get up orange, uid: %v", userId) - upOrangeDropGroupDataConfig := gdconf.CONF.GachaDropGroupDataMap[upOrangeDropId] + upOrangeDropGroupDataConfig := gdconf.GetGachaDropGroupDataByDropId(upOrangeDropId) if upOrangeDropGroupDataConfig == nil { logger.Error("drop group not found, drop id: %v", upOrangeDropId) return false, 0 @@ -538,7 +538,7 @@ func (g *Game) doGachaOnce(userId uint32, gachaType uint32, mustGetUpEnable bool // 替换本次结果为4星大保底 if gachaPoolInfo.MustGetUpPurple { logger.Debug("trigger must get up purple, uid: %v", userId) - upPurpleDropGroupDataConfig := gdconf.CONF.GachaDropGroupDataMap[upPurpleDropId] + upPurpleDropGroupDataConfig := gdconf.GetGachaDropGroupDataByDropId(upPurpleDropId) if upPurpleDropGroupDataConfig == nil { logger.Error("drop group not found, drop id: %v", upPurpleDropId) return false, 0 @@ -574,7 +574,7 @@ func (g *Game) doGachaRandDropFull(gachaDropGroupDataConfig *gdconf.GachaDropGro return true, drop } // 进行下一步掉落流程 - gachaDropGroupDataConfig = gdconf.CONF.GachaDropGroupDataMap[drop.Result] + gachaDropGroupDataConfig = gdconf.GetGachaDropGroupDataByDropId(drop.Result) if gachaDropGroupDataConfig == nil { logger.Error("drop config error, drop id: %v", drop.Result) return false, nil diff --git a/gs/game/player_login.go b/gs/game/player_login.go index 90f5125d..d57f67ab 100644 --- a/gs/game/player_login.go +++ b/gs/game/player_login.go @@ -19,37 +19,60 @@ func (g *Game) PlayerLoginReq(userId uint32, clientSeq uint32, gateAppId string, logger.Info("user login req, uid: %v, gateAppId: %v", userId, gateAppId) req := payloadMsg.(*proto.PlayerLoginReq) logger.Debug("login data: %v", req) - g.OnLogin(userId, clientSeq, gateAppId, false, nil) + USER_MANAGER.OnlineUser(userId, clientSeq, gateAppId, req.TargetUid) } -func (g *Game) SetPlayerBornDataReq(userId uint32, clientSeq uint32, gateAppId string, payloadMsg pb.Message) { - logger.Info("user reg req, uid: %v, gateAppId: %v", userId, gateAppId) +func (g *Game) SetPlayerBornDataReq(player *model.Player, payloadMsg pb.Message) { req := payloadMsg.(*proto.SetPlayerBornDataReq) - logger.Debug("reg data: %v", req) - if userId < PlayerBaseUid { - logger.Error("uid can not less than player base uid, reg req uid: %v", userId) + logger.Debug("avatar id: %v, nickname: %v", req.AvatarId, req.NickName) + + if player.IsBorn { + logger.Error("player is already born, uid: %v", player.PlayerID) return } - g.OnReg(userId, clientSeq, gateAppId, req) -} -func (g *Game) OnLogin(userId uint32, clientSeq uint32, gateAppId string, isReg bool, regPlayer *model.Player) { - logger.Info("user login, uid: %v", userId) - if isReg { - g.OnLoginOk(userId, clientSeq, gateAppId, true, regPlayer) + mainCharAvatarId := req.AvatarId + if mainCharAvatarId != 10000005 && mainCharAvatarId != 10000007 { + logger.Error("invalid main char avatar id: %v", mainCharAvatarId) return } - player, isRobot := USER_MANAGER.OnlineUser(userId, clientSeq, gateAppId) - if isRobot { - g.OnLoginOk(userId, clientSeq, gateAppId, false, player) + player.NickName = req.NickName + player.HeadImage = mainCharAvatarId + + dbAvatar := player.GetDbAvatar() + dbAvatar.MainCharAvatarId = mainCharAvatarId + // 添加选定的主角 + dbAvatar.AddAvatar(player, dbAvatar.MainCharAvatarId) + // 添加主角初始武器 + avatarDataConfig := gdconf.GetAvatarDataById(int32(dbAvatar.MainCharAvatarId)) + if avatarDataConfig == nil { + logger.Error("get avatar data config is nil, avatarId: %v", dbAvatar.MainCharAvatarId) + return } + weaponId := uint64(g.snowflake.GenId()) + dbWeapon := player.GetDbWeapon() + dbWeapon.AddWeapon(player, uint32(avatarDataConfig.InitialWeapon), weaponId) + weapon := dbWeapon.WeaponMap[weaponId] + dbAvatar.WearWeapon(dbAvatar.MainCharAvatarId, weapon) + dbTeam := player.GetDbTeam() + dbTeam.GetActiveTeam().SetAvatarIdList([]uint32{dbAvatar.MainCharAvatarId}) + + g.AcceptQuest(player, false) + + g.SendMsg(cmd.SetPlayerBornDataRsp, player.PlayerID, player.ClientSeq, new(proto.SetPlayerBornDataRsp)) + + g.LoginNotify(player.PlayerID, player.ClientSeq, player) + + g.SendMsg(cmd.PlayerEnterSceneNotify, player.PlayerID, player.ClientSeq, g.PacketPlayerEnterSceneNotifyLogin(player, proto.EnterType_ENTER_SELF)) } -func (g *Game) OnLoginOk(userId uint32, clientSeq uint32, gateAppId string, isReg bool, player *model.Player) { +func (g *Game) OnLogin(userId uint32, clientSeq uint32, gateAppId string, player *model.Player, joinHostUserId uint32) { if player == nil { - g.SendMsgToGate(cmd.DoSetPlayerBornDataNotify, userId, clientSeq, gateAppId, new(proto.DoSetPlayerBornDataNotify)) - return + player := g.CreatePlayer(userId) + USER_MANAGER.ChangeUserDbState(player, model.DbInsert) } + USER_MANAGER.AddUser(player) + SELF = player player.OnlineTime = uint32(time.Now().UnixMilli()) @@ -67,27 +90,6 @@ func (g *Game) OnLoginOk(userId uint32, clientSeq uint32, gateAppId string, isRe dbItem := player.GetDbItem() dbItem.InitAllItem(player) - if isReg { - // 添加选定的主角 - dbAvatar.AddAvatar(player, dbAvatar.MainCharAvatarId) - // 添加主角初始武器 - avatarDataConfig := gdconf.GetAvatarDataById(int32(dbAvatar.MainCharAvatarId)) - if avatarDataConfig == nil { - logger.Error("get avatar data config is nil, avatarId: %v", dbAvatar.MainCharAvatarId) - return - } - weaponId := uint64(g.snowflake.GenId()) - dbWeapon := player.GetDbWeapon() - dbWeapon.AddWeapon(player, uint32(avatarDataConfig.InitialWeapon), weaponId) - weapon := dbWeapon.WeaponMap[weaponId] - dbAvatar.WearWeapon(dbAvatar.MainCharAvatarId, weapon) - - dbTeam := player.GetDbTeam() - dbTeam.GetActiveTeam().SetAvatarIdList([]uint32{dbAvatar.MainCharAvatarId}) - - g.AcceptQuest(player, false) - } - // 确保玩家位置安全 player.Pos.X = player.SafePos.X player.Pos.Y = player.SafePos.Y @@ -98,12 +100,55 @@ func (g *Game) OnLoginOk(userId uint32, clientSeq uint32, gateAppId string, isRe player.Rot = &model.Vector{X: 0, Y: 307, Z: 0} } + TICK_MANAGER.CreateUserGlobalTick(userId) + TICK_MANAGER.CreateUserTimer(userId, UserTimerActionTest, 100, player.NickName) + + if player.IsBorn { + g.LoginNotify(userId, clientSeq, player) + } + + if joinHostUserId != 0 { + hostPlayer := USER_MANAGER.GetOnlineUser(joinHostUserId) + if hostPlayer == nil { + logger.Error("player is nil, uid: %v", joinHostUserId) + } else { + g.JoinOtherWorld(player, hostPlayer) + } + } else { + // 创建世界 + world := WORLD_MANAGER.CreateWorld(player) + world.AddPlayer(player, player.SceneId) + player.WorldId = world.GetId() + // 进入场景 + player.SceneJump = true + player.SceneLoadState = model.SceneNone + if player.IsBorn { + g.SendMsg(cmd.PlayerEnterSceneNotify, userId, clientSeq, g.PacketPlayerEnterSceneNotifyLogin(player, proto.EnterType_ENTER_SELF)) + } + } + + if !player.IsBorn { + g.SendMsg(cmd.DoSetPlayerBornDataNotify, userId, clientSeq, new(proto.DoSetPlayerBornDataNotify)) + } + + playerLoginRsp := &proto.PlayerLoginRsp{ + IsUseAbilityHash: true, + AbilityHashCode: 0, + IsEnableClientHashDebug: true, + IsScOpen: false, + ScInfo: []byte{}, + TotalTickTime: 0.0, + GameBiz: "hk4e_global", + RegisterCps: "mihoyo", + CountryCode: "US", + Birthday: "2000-01-01", + } + g.SendMsg(cmd.PlayerLoginRsp, userId, clientSeq, playerLoginRsp) + if userId < PlayerBaseUid { return } - g.LoginNotify(userId, player, clientSeq) - MESSAGE_QUEUE.SendToAll(&mq.NetMsg{ MsgType: mq.MsgTypeServer, EventId: mq.ServerUserOnlineStateChangeNotify, @@ -112,53 +157,17 @@ func (g *Game) OnLoginOk(userId uint32, clientSeq uint32, gateAppId string, isRe IsOnline: true, }, }) - - TICK_MANAGER.CreateUserGlobalTick(userId) - TICK_MANAGER.CreateUserTimer(userId, UserTimerActionTest, 100, player.NickName) - atomic.AddInt32(&ONLINE_PLAYER_NUM, 1) SELF = nil } -func (g *Game) OnReg(userId uint32, clientSeq uint32, gateAppId string, payloadMsg pb.Message) { - logger.Debug("user reg, uid: %v", userId) - req := payloadMsg.(*proto.SetPlayerBornDataReq) - logger.Debug("avatar id: %v, nickname: %v", req.AvatarId, req.NickName) - exist, asyncWait := USER_MANAGER.CheckUserExistOnReg(userId, req, clientSeq, gateAppId) - if !asyncWait { - g.OnRegOk(exist, req, userId, clientSeq, gateAppId) - } -} - -func (g *Game) OnRegOk(exist bool, req *proto.SetPlayerBornDataReq, userId uint32, clientSeq uint32, gateAppId string) { - if exist { - logger.Error("recv reg req, but user is already exist, uid: %v", userId) - return - } - nickName := req.NickName - mainCharAvatarId := req.GetAvatarId() - if mainCharAvatarId != 10000005 && mainCharAvatarId != 10000007 { - logger.Error("invalid main char avatar id: %v", mainCharAvatarId) - return - } - player := g.CreatePlayer(userId, nickName, mainCharAvatarId) - if player == nil { - logger.Error("player is nil, uid: %v", userId) - return - } - USER_MANAGER.ChangeUserDbState(player, model.DbInsert) - USER_MANAGER.AddUser(player) - g.SendMsgToGate(cmd.SetPlayerBornDataRsp, userId, clientSeq, gateAppId, new(proto.SetPlayerBornDataRsp)) - g.OnLogin(userId, clientSeq, gateAppId, true, player) -} - -func (g *Game) CreatePlayer(userId uint32, nickName string, mainCharAvatarId uint32) *model.Player { +func (g *Game) CreatePlayer(userId uint32) *model.Player { player := new(model.Player) player.PlayerID = userId - player.NickName = nickName + player.NickName = "" player.Signature = "" - player.HeadImage = mainCharAvatarId + player.HeadImage = 0 player.Birthday = []uint8{0, 0} player.NameCard = 210001 player.NameCardList = make([]uint32, 0) @@ -185,10 +194,13 @@ func (g *Game) CreatePlayer(userId uint32, nickName string, mainCharAvatarId uin player.PropertiesMap[constant.PLAYER_PROP_PLAYER_MP_SETTING_TYPE] = 2 player.PropertiesMap[constant.PLAYER_PROP_IS_MP_MODE_AVAILABLE] = 1 + player.SafePos = new(model.Vector) + player.Pos = new(model.Vector) + player.Rot = new(model.Vector) sceneLuaConfig := gdconf.GetSceneLuaConfigById(int32(player.SceneId)) if sceneLuaConfig == nil { logger.Error("get scene lua config is nil, sceneId: %v, uid: %v", player.SceneId, player.PlayerID) - return nil + return player } player.SafePos = &model.Vector{ X: float64(sceneLuaConfig.SceneConfig.BornPos.X), @@ -206,9 +218,6 @@ func (g *Game) CreatePlayer(userId uint32, nickName string, mainCharAvatarId uin Z: float64(sceneLuaConfig.SceneConfig.BornRot.Z), } - dbAvatar := player.GetDbAvatar() - dbAvatar.MainCharAvatarId = mainCharAvatarId - return player } @@ -231,7 +240,7 @@ func (g *Game) OnUserOffline(userId uint32, changeGsInfo *ChangeGsInfo) { atomic.AddInt32(&ONLINE_PLAYER_NUM, -1) } -func (g *Game) LoginNotify(userId uint32, player *model.Player, clientSeq uint32) { +func (g *Game) LoginNotify(userId uint32, clientSeq uint32, player *model.Player) { g.SendMsg(cmd.PlayerDataNotify, userId, clientSeq, g.PacketPlayerDataNotify(player)) g.SendMsg(cmd.StoreWeightLimitNotify, userId, clientSeq, g.PacketStoreWeightLimitNotify()) g.SendMsg(cmd.PlayerStoreNotify, userId, clientSeq, g.PacketPlayerStoreNotify(player)) @@ -240,25 +249,6 @@ func (g *Game) LoginNotify(userId uint32, player *model.Player, clientSeq uint32 g.SendMsg(cmd.QuestListNotify, userId, clientSeq, g.PacketQuestListNotify(player)) g.SendMsg(cmd.FinishedParentQuestNotify, userId, clientSeq, g.PacketFinishedParentQuestNotify(player)) // g.GCGLogin(player) // 发送GCG登录相关的通知包 - playerLoginRsp := &proto.PlayerLoginRsp{ - IsUseAbilityHash: true, - AbilityHashCode: 0, - IsEnableClientHashDebug: true, - IsScOpen: false, - ScInfo: []byte{}, - TotalTickTime: 0.0, - GameBiz: "hk4e_global", - RegisterCps: "mihoyo", - CountryCode: "US", - Birthday: "2000-01-01", - } - g.SendMsg(cmd.PlayerLoginRsp, userId, clientSeq, playerLoginRsp) - playerTimeNotify := &proto.PlayerTimeNotify{ - IsPaused: player.Pause, - PlayerTime: uint64(player.TotalOnlineTime), - ServerTime: uint64(time.Now().UnixMilli()), - } - g.SendMsg(cmd.PlayerTimeNotify, player.PlayerID, 0, playerTimeNotify) } func (g *Game) PacketPlayerDataNotify(player *model.Player) *proto.PlayerDataNotify { diff --git a/gs/game/player_stamina.go b/gs/game/player_stamina.go index 87b39a36..3d0acbcc 100644 --- a/gs/game/player_stamina.go +++ b/gs/game/player_stamina.go @@ -1,13 +1,11 @@ package game import ( - "strings" "time" "hk4e/common/constant" "hk4e/gdconf" "hk4e/gs/model" - "hk4e/pkg/endec" "hk4e/pkg/logger" "hk4e/protocol/cmd" "hk4e/protocol/proto" @@ -15,68 +13,6 @@ import ( pb "google.golang.org/protobuf/proto" ) -// HandleAbilityStamina 处理来自ability的耐力消耗 -func (g *Game) HandleAbilityStamina(player *model.Player, entry *proto.AbilityInvokeEntry) { - switch entry.ArgumentType { - 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) - return - } - // 处理持续耐力消耗 - g.SkillSustainStamina(player, costStamina.IsSwim) - case proto.AbilityInvokeArgument_ABILITY_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.GetAbilityList() { - if ability.InstancedAbilityId == entry.Head.InstancedAbilityId { - // logger.Error("%v", ability) - abilityNameHashCode = ability.AbilityName.GetHash() - } - } - if abilityNameHashCode == 0 { - return - } - // 根据ability name查找到对应的技能表里的技能配置 - var avatarAbility *gdconf.AvatarSkillData = nil - for _, avatarSkillData := range gdconf.GetAvatarSkillDataMap() { - hashCode := endec.Hk4eAbilityHashCode(avatarSkillData.AbilityName) - if uint32(hashCode) == abilityNameHashCode { - avatarAbility = avatarSkillData - break - } - } - if avatarAbility == nil { - return - } - // 距离技能开始过去的时间 - startPastTime := time.Now().UnixMilli() - player.StaminaInfo.LastSkillTime - // 距离上次技能消耗的时间 - changePastTime := time.Now().UnixMilli() - player.StaminaInfo.LastSkillChargeTime - // 法器角色轻击也会算触发重击消耗 胡桃等角色重击一次会多次消耗 - // 所以通过策略判断 必须距离技能开始过去200ms才算重击 两次技能耐力消耗之间需间隔500ms - - // 暂时就这样实现重击消耗 以后应该还会有更好的办法~ - if player.StaminaInfo.LastSkillId == uint32(avatarAbility.AvatarSkillId) && startPastTime > 200 && changePastTime > 500 { - // 重击对应的耐力消耗 - g.ChargedAttackStamina(player, worldAvatar, avatarAbility) - player.StaminaInfo.LastSkillChargeTime = time.Now().UnixMilli() - } - default: - break - } -} - // SceneAvatarStaminaStepReq 缓慢游泳或缓慢攀爬时消耗耐力 func (g *Game) SceneAvatarStaminaStepReq(player *model.Player, payloadMsg pb.Message) { req := payloadMsg.(*proto.SceneAvatarStaminaStepReq) @@ -115,13 +51,62 @@ func (g *Game) SceneAvatarStaminaStepReq(player *model.Player, payloadMsg pb.Mes g.UpdatePlayerStamina(player, constant.STAMINA_COST_SWIMMING) } - // PacketSceneAvatarStaminaStepRsp sceneAvatarStaminaStepRsp := new(proto.SceneAvatarStaminaStepRsp) sceneAvatarStaminaStepRsp.UseClientRot = true sceneAvatarStaminaStepRsp.Rot = req.Rot g.SendMsg(cmd.SceneAvatarStaminaStepRsp, player.PlayerID, player.ClientSeq, sceneAvatarStaminaStepRsp) } +// HandleAbilityStamina 处理来自ability的耐力消耗 +func (g *Game) HandleAbilityStamina(player *model.Player, entry *proto.AbilityInvokeEntry) { + world := WORLD_MANAGER.GetWorldByID(player.WorldId) + // 获取世界中的角色实体 + worldAvatar := world.GetWorldAvatarByEntityId(entry.EntityId) + if worldAvatar == nil { + return + } + // 查找是不是属于该角色实体的ability id + ability := worldAvatar.GetAbilityByInstanceId(entry.Head.InstancedAbilityId) + abilityNameHashCode := ability.AbilityName.GetHash() + if abilityNameHashCode == 0 { + return + } + // 根据ability name查找到对应的技能表里的技能配置 + staminaDataConfig := gdconf.GetSkillStaminaDataByAbilityHashCode(int32(abilityNameHashCode)) + if staminaDataConfig == nil { + return + } + staminaInfo := player.StaminaInfo + switch entry.ArgumentType { + case proto.AbilityInvokeArgument_ABILITY_META_MODIFIER_CHANGE: + // 普通角色重击耐力消耗 + // 距离技能开始过去的时间 + startPastTime := time.Now().UnixMilli() - staminaInfo.LastSkillTime + // 距离上次技能消耗的时间 + changePastTime := time.Now().UnixMilli() - staminaInfo.LastSkillChargeTime + // 法器角色轻击也会算触发重击消耗 胡桃等角色重击一次会多次消耗 + // 所以通过策略判断 必须距离技能开始过去200ms才算重击 两次技能耐力消耗之间需间隔500ms + // 暂时就这样实现重击消耗 以后应该还会有更好的办法~ + if startPastTime > 200 && changePastTime > 500 { + costStamina := -(staminaDataConfig.CostStamina * 100) + logger.Debug("stamina cost, skillId: %v, cost: %v", staminaDataConfig.AvatarSkillId, costStamina) + g.UpdatePlayerStamina(player, costStamina) + staminaInfo.LastSkillChargeTime = time.Now().UnixMilli() + } + case proto.AbilityInvokeArgument_ABILITY_MIXIN_COST_STAMINA: + // 大剑重击 或 持续技能 耐力消耗 + // 根据配置以及距离上次的时间计算消耗的耐力 + pastTime := time.Now().UnixMilli() - staminaInfo.LastSkillTime + costStamina := -(staminaDataConfig.CostStamina * 100) + costStamina = int32(float64(pastTime) / 1000 * float64(costStamina)) + logger.Debug("stamina cost, skillId: %v, cost: %v", staminaDataConfig.AvatarSkillId, costStamina) + g.UpdatePlayerStamina(player, costStamina) + // 记录最后释放技能的时间 + staminaInfo.LastSkillTime = time.Now().UnixMilli() + case proto.AbilityInvokeArgument_ABILITY_ACTION_DEDUCT_STAMINA: + } +} + // ImmediateStamina 处理即时耐力消耗 func (g *Game) ImmediateStamina(player *model.Player, motionState proto.MotionState) { // 玩家暂停状态不更新耐力 @@ -130,18 +115,14 @@ func (g *Game) ImmediateStamina(player *model.Player, motionState proto.MotionSt } staminaInfo := player.StaminaInfo // logger.Debug("stamina handle, uid: %v, motionState: %v", player.PlayerID, motionState) - // 设置用于持续消耗或恢复耐力的值 staminaInfo.SetStaminaCost(motionState) - // 未改变状态不执行后面 有些仅在动作开始消耗耐力 if motionState == staminaInfo.State { return } - // 记录玩家的动作状态 staminaInfo.State = motionState - // 根据玩家的状态立刻消耗耐力 switch motionState { case proto.MotionState_MOTION_CLIMB: @@ -159,120 +140,10 @@ func (g *Game) ImmediateStamina(player *model.Player, motionState proto.MotionSt } } -// SkillSustainStamina 处理技能持续时的耐力消耗 -func (g *Game) SkillSustainStamina(player *model.Player, isSwim bool) { - staminaInfo := player.StaminaInfo - skillId := staminaInfo.LastSkillId - - // 读取技能配置表 - avatarSkillConfig := gdconf.GetAvatarSkillDataById(int32(skillId)) - if avatarSkillConfig == nil { - logger.Error("avatarSkillConfig error, skillId: %v", skillId) - return - } - // 获取释放技能者的角色Id - world := WORLD_MANAGER.GetWorldByID(player.WorldId) - // 获取世界中的角色实体 - worldAvatar := world.GetWorldAvatarByEntityId(staminaInfo.LastCasterId) - if worldAvatar == nil { - return - } - // 获取现行角色的配置表 - avatarDataConfig := gdconf.GetAvatarDataById(int32(worldAvatar.GetAvatarId())) - if avatarDataConfig == nil { - logger.Error("avatarDataConfig error, avatarId: %v", worldAvatar.GetAvatarId()) - return - } - - // 需要消耗的耐力值 - var costStamina int32 - - // 如果为0代表使用默认值 - if avatarSkillConfig.CostStamina == 0 { - // 大剑持续耐力消耗默认值 - if avatarDataConfig.WeaponType == constant.WEAPON_TYPE_CLAYMORE { - costStamina = constant.STAMINA_COST_FIGHT_CLAYMORE_PER - } - } else { - costStamina = -(avatarSkillConfig.CostStamina * 100) - } - - // 距离上次执行过去的时间 - pastTime := time.Now().UnixMilli() - staminaInfo.LastSkillTime - // 根据配置以及距离上次的时间计算消耗的耐力 - costStamina = int32(float64(pastTime) / 1000 * float64(costStamina)) - logger.Debug("stamina skill sustain, skillId: %v, cost: %v, isSwim: %v", skillId, costStamina, isSwim) - - // 根据配置以及距离上次的时间计算消耗的耐力 - g.UpdatePlayerStamina(player, costStamina) - - // 记录最后释放技能的时间 - player.StaminaInfo.LastSkillTime = time.Now().UnixMilli() -} - -// ChargedAttackStamina 处理重击技能即时耐力消耗 -func (g *Game) ChargedAttackStamina(player *model.Player, worldAvatar *WorldAvatar, skillData *gdconf.AvatarSkillData) { - // 确保技能为重击 - if !strings.Contains(skillData.AbilityName, "ExtraAttack") { - return - } - // 获取现行角色的配置表 - avatarDataConfig := gdconf.GetAvatarDataById(int32(worldAvatar.GetAvatarId())) - if avatarDataConfig == nil { - logger.Error("avatarDataConfig error, avatarId: %v", worldAvatar.GetAvatarId()) - return - } - - // 需要消耗的耐力值 - var costStamina int32 - - // 如果为0代表使用默认值 - if skillData.CostStamina == 0 { - // 使用武器对应默认耐力消耗 - // 双手剑为持续耐力消耗不在这里处理 - switch avatarDataConfig.WeaponType { - case constant.WEAPON_TYPE_SWORD_ONE_HAND: - // 单手剑 - costStamina = constant.STAMINA_COST_FIGHT_SWORD_ONE_HAND - case constant.WEAPON_TYPE_POLE: - // 长枪 - costStamina = constant.STAMINA_COST_FIGHT_POLE - case constant.WEAPON_TYPE_CATALYST: - // 法器 - costStamina = constant.STAMINA_COST_FIGHT_CATALYST - } - } else { - costStamina = -(skillData.CostStamina * 100) - } - logger.Debug("charged attack stamina, skillId: %v, cost: %v", skillData.AvatarSkillId, costStamina) - - // 根据配置消耗耐力 - g.UpdatePlayerStamina(player, costStamina) -} - // SkillStartStamina 处理技能开始时的即时耐力消耗 func (g *Game) SkillStartStamina(player *model.Player, casterId uint32, skillId uint32) { staminaInfo := player.StaminaInfo - - // 获取该技能开始时所需消耗的耐力 - avatarSkillDataConfig := gdconf.GetAvatarSkillDataById(int32(skillId)) - - // 配置表确保存在技能开始对应的耐力消耗 - if avatarSkillDataConfig != nil && avatarSkillDataConfig.CostStamina != 0 { - // 距离上次处理技能开始耐力消耗过去的时间 - pastTime := time.Now().UnixMilli() - staminaInfo.LastSkillStartTime - // 上次触发的技能相同则每400ms触发一次消耗 - if staminaInfo.LastSkillId != skillId || pastTime > 400 { - logger.Debug("skill start stamina, skillId: %v, cost: %v", skillId, avatarSkillDataConfig.CostStamina) - // 根据配置消耗耐力 - g.UpdatePlayerStamina(player, avatarSkillDataConfig.CostStamina) - staminaInfo.LastSkillStartTime = time.Now().UnixMilli() - } - } - // 记录最后释放的技能 - staminaInfo.LastCasterId = casterId - staminaInfo.LastSkillId = skillId staminaInfo.LastSkillTime = time.Now().UnixMilli() } @@ -341,7 +212,6 @@ func (g *Game) SustainStaminaHandler(player *model.Player) { func (g *Game) GetChangeStamina(curStamina int32, maxStamina int32, staminaCost int32) uint32 { // 即将更改为的耐力值 stamina := curStamina + staminaCost - // 确保耐力值不超出范围 if stamina > maxStamina { stamina = maxStamina @@ -371,12 +241,10 @@ func (g *Game) UpdateVehicleStamina(player *model.Player, vehicleEntity *Entity, // logger.Debug("stamina delay reset, restoreDelay: %v", player.StaminaInfo.VehicleRestoreDelay) staminaInfo.VehicleRestoreDelay = 0 } - // 确保载具实体存在 if vehicleEntity == nil { return } - // 因为载具的耐力需要换算 // 这里先*100后面要用的时候再换算 为了确保精度 // 最大耐力值 @@ -384,15 +252,12 @@ func (g *Game) UpdateVehicleStamina(player *model.Player, vehicleEntity *Entity, maxStamina := int32(gadgetEntity.GetGadgetVehicleEntity().GetMaxStamina() * 100) // 现行耐力值 curStamina := int32(gadgetEntity.GetGadgetVehicleEntity().GetCurStamina() * 100) - // 将被变更的耐力 stamina := g.GetChangeStamina(curStamina, maxStamina, staminaCost) - // 当前无变动不要频繁发包 if uint32(curStamina) == stamina { return } - // 更改载具耐力 (换算) g.SetVehicleStamina(player, vehicleEntity, float32(stamina)/100) } @@ -417,23 +282,18 @@ func (g *Game) UpdatePlayerStamina(player *model.Player, staminaCost int32) { // logger.Debug("stamina delay reset, restoreDelay: %v", player.StaminaInfo.RestoreDelay) staminaInfo.PlayerRestoreDelay = 0 } - // 最大耐力值 maxStamina := int32(player.PropertiesMap[constant.PLAYER_PROP_MAX_STAMINA]) // 现行耐力值 curStamina := int32(player.PropertiesMap[constant.PLAYER_PROP_CUR_PERSIST_STAMINA]) - // 将被变更的耐力 stamina := g.GetChangeStamina(curStamina, maxStamina, staminaCost) - // 检测玩家是否没耐力后执行溺水 g.HandleDrown(player, stamina) - // 当前无变动不要频繁发包 if uint32(curStamina) == stamina { return } - // 更改玩家的耐力 g.SetPlayerStamina(player, stamina) } @@ -488,7 +348,6 @@ func (g *Game) HandleDrown(player *model.Player, stamina uint32) { if stamina != 0 || player.StaminaInfo.DrownBackDelay != 0 { return } - // 确保玩家正在游泳 if player.StaminaInfo.State == proto.MotionState_MOTION_SWIM_MOVE || player.StaminaInfo.State == proto.MotionState_MOTION_SWIM_DASH { logger.Debug("player drown, curStamina: %v, state: %v", stamina, player.StaminaInfo.State) @@ -506,7 +365,6 @@ func (g *Game) SetVehicleStamina(player *model.Player, vehicleEntity *Entity, st gadgetEntity.GetGadgetVehicleEntity().SetCurStamina(stamina) // logger.Debug("vehicle stamina set, stamina: %v", stamina) - // PacketVehicleStaminaNotify vehicleStaminaNotify := new(proto.VehicleStaminaNotify) vehicleStaminaNotify.EntityId = vehicleEntity.GetId() vehicleStaminaNotify.CurStamina = stamina @@ -519,13 +377,10 @@ func (g *Game) SetPlayerStamina(player *model.Player, stamina uint32) { prop := constant.PLAYER_PROP_CUR_PERSIST_STAMINA player.PropertiesMap[prop] = stamina // logger.Debug("player stamina set, stamina: %v", stamina) - - // PacketPlayerPropNotify g.PlayerPropNotify(player, prop) } func (g *Game) PlayerPropNotify(player *model.Player, playerPropId uint16) { - // PacketPlayerPropNotify playerPropNotify := new(proto.PlayerPropNotify) playerPropNotify.PropMap = make(map[uint32]*proto.PropValue) playerPropNotify.PropMap[uint32(playerPropId)] = &proto.PropValue{ diff --git a/gs/model/player.go b/gs/model/player.go index f0085459..c55e9d88 100644 --- a/gs/model/player.go +++ b/gs/model/player.go @@ -27,6 +27,7 @@ type Player struct { // 离线数据 请尽量不要定义接口等复杂数据结构 ID primitive.ObjectID `bson:"_id,omitempty"` PlayerID uint32 `bson:"PlayerID"` // 玩家uid + IsBorn bool // 是否完成开场动画 NickName string // 昵称 Signature string // 签名 HeadImage uint32 // 头像 diff --git a/gs/model/stamina.go b/gs/model/stamina.go index 3c7b2bb1..969d37b0 100644 --- a/gs/model/stamina.go +++ b/gs/model/stamina.go @@ -10,10 +10,7 @@ type StaminaInfo struct { CostStamina int32 // 消耗或恢复的耐力 PlayerRestoreDelay uint8 // 玩家耐力回复延时 VehicleRestoreDelay uint8 // 载具耐力回复延时 - LastCasterId uint32 // 最后释放技能者的Id - LastSkillId uint32 // 最后释放的技能Id LastSkillTime int64 // 最后释放技能的时间 - LastSkillStartTime int64 // 最后执行开始技能耐力消耗的时间 LastSkillChargeTime int64 // 最后执行技能耐力消耗的时间 DrownBackDelay uint8 // 溺水返回安全点延时 }