mirror of
https://github.com/FlourishingWorld/hk4e.git
synced 2026-02-04 12:52:31 +08:00
优化注册与登录流程
This commit is contained in:
@@ -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 // 双手剑 (每秒消耗)
|
||||
)
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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和连接信息
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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]
|
||||
}
|
||||
|
||||
@@ -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相关
|
||||
|
||||
67
gdconf/game_data_config/ext/SkillStaminaData.csv
Normal file
67
gdconf/game_data_config/ext/SkillStaminaData.csv
Normal file
@@ -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
|
||||
|
@@ -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
|
||||
|
||||
28
gdconf/skill_stamina_data.go
Normal file
28
gdconf/skill_stamina_data.go
Normal file
@@ -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]
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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 世界里所有玩家的网络延迟广播
|
||||
|
||||
@@ -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:
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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{
|
||||
|
||||
@@ -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 // 头像
|
||||
|
||||
@@ -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 // 溺水返回安全点延时
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user