性能优化

This commit is contained in:
flswld
2023-04-13 19:46:20 +08:00
parent 0440a6b1ed
commit e7c5723f98
10 changed files with 215 additions and 182 deletions

View File

@@ -33,7 +33,6 @@ type MessageQueue struct {
cmdProtoMap *cmd.CmdProtoMap cmdProtoMap *cmd.CmdProtoMap
serverType string serverType string
appId string appId string
gateTcpMqChan chan []byte
gateTcpMqEventChan chan *GateTcpMqEvent gateTcpMqEventChan chan *GateTcpMqEvent
gateTcpMqDeadEventChan chan string gateTcpMqDeadEventChan chan string
rpcClient *rpc.Client rpcClient *rpc.Client
@@ -63,7 +62,6 @@ func NewMessageQueue(serverType string, appId string, rpcClient *rpc.Client) (r
r.cmdProtoMap = cmd.NewCmdProtoMap() r.cmdProtoMap = cmd.NewCmdProtoMap()
r.serverType = serverType r.serverType = serverType
r.appId = appId r.appId = appId
r.gateTcpMqChan = make(chan []byte, 1000)
r.gateTcpMqEventChan = make(chan *GateTcpMqEvent, 1000) r.gateTcpMqEventChan = make(chan *GateTcpMqEvent, 1000)
r.gateTcpMqDeadEventChan = make(chan string, 1000) r.gateTcpMqDeadEventChan = make(chan string, 1000)
r.rpcClient = rpcClient r.rpcClient = rpcClient
@@ -72,7 +70,7 @@ func NewMessageQueue(serverType string, appId string, rpcClient *rpc.Client) (r
} else if serverType == api.GS || serverType == api.ANTICHEAT || serverType == api.PATHFINDING { } else if serverType == api.GS || serverType == api.ANTICHEAT || serverType == api.PATHFINDING {
go r.runGateTcpMqClient() go r.runGateTcpMqClient()
} }
go r.recvHandler() go r.natsMsgRecvHandler()
go r.sendHandler() go r.sendHandler()
return r return r
} }
@@ -92,50 +90,80 @@ func (m *MessageQueue) GetNetMsg() chan *NetMsg {
return m.netMsgOutput return m.netMsgOutput
} }
func (m *MessageQueue) recvHandler() { func (m *MessageQueue) natsMsgRecvHandler() {
for { for {
var rawData []byte = nil natsMsg := <-m.natsMsgChan
select { rawData := natsMsg.Data
case natsMsg := <-m.natsMsgChan: netMsg := m.parseNetMsg(rawData)
rawData = natsMsg.Data if netMsg == nil {
case gateTcpMqMsg := <-m.gateTcpMqChan:
rawData = gateTcpMqMsg
}
// msgpack NetMsg
netMsg := new(NetMsg)
err := msgpack.Unmarshal(rawData, netMsg)
if err != nil {
logger.Error("parse bin to net msg error: %v", err)
continue continue
} }
// 忽略自己发出的广播消息 // 忽略自己发出的广播消息
if netMsg.OriginServerType == m.serverType && netMsg.OriginServerAppId == m.appId { if netMsg.OriginServerType == m.serverType && netMsg.OriginServerAppId == m.appId {
continue continue
} }
m.netMsgOutput <- netMsg
}
}
func (m *MessageQueue) buildNetMsg(netMsg *NetMsg) []byte {
switch netMsg.MsgType {
case MsgTypeGame:
gameMsg := netMsg.GameMsg
if gameMsg == nil {
logger.Error("send game msg is nil")
return nil
}
if gameMsg.PayloadMessageData == nil {
// protobuf PayloadMessage
payloadMessageData, err := pb.Marshal(gameMsg.PayloadMessage)
if err != nil {
logger.Error("parse payload msg to bin error: %v", err)
return nil
}
gameMsg.PayloadMessageData = payloadMessageData
}
}
// msgpack NetMsg
rawData, err := msgpack.Marshal(netMsg)
if err != nil {
logger.Error("parse net msg to bin error: %v", err)
return nil
}
return rawData
}
func (m *MessageQueue) parseNetMsg(rawData []byte) *NetMsg {
// msgpack NetMsg
netMsg := new(NetMsg)
err := msgpack.Unmarshal(rawData, netMsg)
if err != nil {
logger.Error("parse bin to net msg error: %v", err)
return nil
}
switch netMsg.MsgType { switch netMsg.MsgType {
case MsgTypeGame: case MsgTypeGame:
gameMsg := netMsg.GameMsg gameMsg := netMsg.GameMsg
if gameMsg == nil { if gameMsg == nil {
logger.Error("recv game msg is nil") logger.Error("recv game msg is nil")
continue return nil
} }
if netMsg.EventId == NormalMsg { if netMsg.EventId == NormalMsg {
// protobuf PayloadMessage // protobuf PayloadMessage
payloadMessage := m.cmdProtoMap.GetProtoObjCacheByCmdId(gameMsg.CmdId) payloadMessage := m.cmdProtoMap.GetProtoObjCacheByCmdId(gameMsg.CmdId)
if payloadMessage == nil { if payloadMessage == nil {
logger.Error("get protobuf obj by cmd id error: %v", err) logger.Error("get protobuf obj by cmd id error: %v", err)
continue return nil
} }
err = pb.Unmarshal(gameMsg.PayloadMessageData, payloadMessage) err = pb.Unmarshal(gameMsg.PayloadMessageData, payloadMessage)
if err != nil { if err != nil {
logger.Error("parse bin to payload msg error: %v", err) logger.Error("parse bin to payload msg error: %v", err)
continue return nil
} }
gameMsg.PayloadMessage = payloadMessage gameMsg.PayloadMessage = payloadMessage
} }
} }
m.netMsgOutput <- netMsg return netMsg
}
} }
func (m *MessageQueue) sendHandler() { func (m *MessageQueue) sendHandler() {
@@ -149,34 +177,15 @@ func (m *MessageQueue) sendHandler() {
for { for {
select { select {
case netMsg := <-m.netMsgInput: case netMsg := <-m.netMsgInput:
switch netMsg.MsgType { rawData := m.buildNetMsg(netMsg)
case MsgTypeGame: if rawData == nil {
gameMsg := netMsg.GameMsg
if gameMsg == nil {
logger.Error("send game msg is nil")
continue
}
if gameMsg.PayloadMessageData == nil {
// protobuf PayloadMessage
payloadMessageData, err := pb.Marshal(gameMsg.PayloadMessage)
if err != nil {
logger.Error("parse payload msg to bin error: %v", err)
continue
}
gameMsg.PayloadMessageData = payloadMessageData
}
}
// msgpack NetMsg
netMsgData, err := msgpack.Marshal(netMsg)
if err != nil {
logger.Error("parse net msg to bin error: %v", err)
continue continue
} }
fallbackNatsMqSend := func() { fallbackNatsMqSend := func() {
// 找不到tcp快速通道就fallback回nats // 找不到tcp快速通道就fallback回nats
natsMsg := nats.NewMsg(netMsg.Topic) natsMsg := nats.NewMsg(netMsg.Topic)
natsMsg.Data = netMsgData natsMsg.Data = rawData
err = m.natsConn.PublishMsg(natsMsg) err := m.natsConn.PublishMsg(natsMsg)
if err != nil { if err != nil {
logger.Error("nats publish msg error: %v", err) logger.Error("nats publish msg error: %v", err)
return return
@@ -199,16 +208,13 @@ func (m *MessageQueue) sendHandler() {
fallbackNatsMqSend() fallbackNatsMqSend()
continue continue
} }
// 前4个字节为消息的载荷部分长度 gateTcpMqSend := func(data []byte) bool {
netMsgDataTcp := make([]byte, 4+len(netMsgData)) err := inst.conn.SetWriteDeadline(time.Now().Add(time.Second))
binary.BigEndian.PutUint32(netMsgDataTcp, uint32(len(netMsgData)))
copy(netMsgDataTcp[4:], netMsgData)
err = inst.conn.SetWriteDeadline(time.Now().Add(time.Second))
if err != nil { if err != nil {
fallbackNatsMqSend() fallbackNatsMqSend()
continue return false
} }
_, err = inst.conn.Write(netMsgDataTcp) _, err = inst.conn.Write(data)
if err != nil { if err != nil {
// 发送失败关闭连接fallback回nats // 发送失败关闭连接fallback回nats
logger.Error("gate tcp mq send error: %v", err) logger.Error("gate tcp mq send error: %v", err)
@@ -218,6 +224,19 @@ func (m *MessageQueue) sendHandler() {
inst: inst, inst: inst,
} }
fallbackNatsMqSend() fallbackNatsMqSend()
return false
}
return true
}
// 前4个字节为消息的载荷部分长度
headLenData := make([]byte, 4)
binary.BigEndian.PutUint32(headLenData, uint32(len(rawData)))
ok := gateTcpMqSend(headLenData)
if !ok {
continue
}
ok = gateTcpMqSend(rawData)
if !ok {
continue continue
} }
case gateTcpMqEvent := <-m.gateTcpMqEventChan: case gateTcpMqEvent := <-m.gateTcpMqEventChan:
@@ -381,8 +400,8 @@ func (m *MessageQueue) gateTcpMqConn(gateServerConnAddrMap map[string]bool) {
func (m *MessageQueue) gateTcpMqRecvHandle(inst *GateTcpMqInst) { func (m *MessageQueue) gateTcpMqRecvHandle(inst *GateTcpMqInst) {
dataBuf := make([]byte, 0, 1500) dataBuf := make([]byte, 0, 1500)
recvBuf := make([]byte, 1024*1024)
for { for {
recvBuf := make([]byte, 1500)
recvLen, err := inst.conn.Read(recvBuf) recvLen, err := inst.conn.Read(recvBuf)
if err != nil { if err != nil {
logger.Error("gate tcp mq recv error: %v", err) logger.Error("gate tcp mq recv error: %v", err)
@@ -423,7 +442,11 @@ func (m *MessageQueue) gateTcpMqRecvHandleLoop(data []byte, dataBuf *[]byte) {
*dataBuf = append(*dataBuf, data...) *dataBuf = append(*dataBuf, data...)
return return
} }
m.gateTcpMqChan <- data[4 : 4+msgPayloadLen] rawData := data[4 : 4+msgPayloadLen]
netMsg := m.parseNetMsg(rawData)
if netMsg != nil {
m.netMsgOutput <- netMsg
}
if haveMorePacket { if haveMorePacket {
m.gateTcpMqRecvHandleLoop(data[packetLen:], dataBuf) m.gateTcpMqRecvHandleLoop(data[packetLen:], dataBuf)
} }

View File

@@ -343,8 +343,6 @@ func (s *UDPSession) Close() error {
}) })
if once { if once {
atomic.AddUint64(&DefaultSnmp.CurrEstab, ^uint64(0))
// try best to send all queued messages // try best to send all queued messages
s.mu.Lock() s.mu.Lock()
s.kcp.flush(false) s.kcp.flush(false)

View File

@@ -41,10 +41,10 @@ func (k *KcpConnectManager) recvMsgHandle(protoMsg *ProtoMsg, session *Session)
if protoMsg.HeadMessage == nil { if protoMsg.HeadMessage == nil {
logger.Error("recv null head msg: %v", protoMsg) logger.Error("recv null head msg: %v", protoMsg)
} }
// gate本地处理的请求 // 网关服务器本地处理的请求
switch protoMsg.CmdId { switch protoMsg.CmdId {
case cmd.GetPlayerTokenReq: case cmd.GetPlayerTokenReq:
// 获取玩家token请求 // GATE登录包
if connState != ConnEst { if connState != ConnEst {
return return
} }
@@ -55,14 +55,15 @@ func (k *KcpConnectManager) recvMsgHandle(protoMsg *ProtoMsg, session *Session)
return return
} }
// 返回数据到客户端 // 返回数据到客户端
rsp := new(ProtoMsg) rsp := &ProtoMsg{
rsp.ConvId = protoMsg.ConvId ConvId: protoMsg.ConvId,
rsp.CmdId = cmd.GetPlayerTokenRsp CmdId: cmd.GetPlayerTokenRsp,
rsp.HeadMessage = k.getHeadMsg(protoMsg.HeadMessage.ClientSequenceId) HeadMessage: k.getHeadMsg(protoMsg.HeadMessage.ClientSequenceId),
rsp.PayloadMessage = getPlayerTokenRsp PayloadMessage: getPlayerTokenRsp,
}
session.kcpRawSendChan <- rsp session.kcpRawSendChan <- rsp
case cmd.PlayerForceExitReq: case cmd.PlayerForceExitReq:
// 玩家退出游戏请求 // 退出游戏
if connState != ConnActive { if connState != ConnActive {
return return
} }
@@ -72,17 +73,18 @@ func (k *KcpConnectManager) recvMsgHandle(protoMsg *ProtoMsg, session *Session)
EventMessage: uint32(kcp.EnetClientClose), EventMessage: uint32(kcp.EnetClientClose),
} }
case cmd.PingReq: case cmd.PingReq:
// ping请求 // ping
pingReq := protoMsg.PayloadMessage.(*proto.PingReq) pingReq := protoMsg.PayloadMessage.(*proto.PingReq)
logger.Debug("user ping req, data: %v", pingReq.String()) logger.Debug("user ping req, data: %v", pingReq.String())
// 返回数据到客户端 // 返回数据到客户端
pingRsp := new(proto.PingRsp) pingRsp := new(proto.PingRsp)
pingRsp.ClientTime = pingReq.ClientTime pingRsp.ClientTime = pingReq.ClientTime
rsp := new(ProtoMsg) rsp := &ProtoMsg{
rsp.ConvId = protoMsg.ConvId ConvId: protoMsg.ConvId,
rsp.CmdId = cmd.PingRsp CmdId: cmd.PingRsp,
rsp.HeadMessage = k.getHeadMsg(protoMsg.HeadMessage.ClientSequenceId) HeadMessage: k.getHeadMsg(protoMsg.HeadMessage.ClientSequenceId),
rsp.PayloadMessage = pingRsp PayloadMessage: pingRsp,
}
session.kcpRawSendChan <- rsp session.kcpRawSendChan <- rsp
logger.Debug("convId: %v, RTO: %v, SRTT: %v, RTTVar: %v", logger.Debug("convId: %v, RTO: %v, SRTT: %v, RTTVar: %v",
protoMsg.ConvId, session.conn.GetRTO(), session.conn.GetSRTT(), session.conn.GetSRTTVar()) protoMsg.ConvId, session.conn.GetRTO(), session.conn.GetSRTT(), session.conn.GetSRTTVar())
@@ -91,35 +93,40 @@ func (k *KcpConnectManager) recvMsgHandle(protoMsg *ProtoMsg, session *Session)
} }
// 通知GS玩家客户端往返时延 // 通知GS玩家客户端往返时延
rtt := session.conn.GetSRTT() rtt := session.conn.GetSRTT()
connCtrlMsg := new(mq.ConnCtrlMsg) connCtrlMsg := &mq.ConnCtrlMsg{
connCtrlMsg.UserId = userId UserId: userId,
connCtrlMsg.ClientRtt = uint32(rtt) ClientRtt: uint32(rtt),
ClientTime: 0,
}
k.messageQueue.SendToGs(session.gsServerAppId, &mq.NetMsg{ k.messageQueue.SendToGs(session.gsServerAppId, &mq.NetMsg{
MsgType: mq.MsgTypeConnCtrl, MsgType: mq.MsgTypeConnCtrl,
EventId: mq.ClientRttNotify, EventId: mq.ClientRttNotify,
ConnCtrlMsg: connCtrlMsg, ConnCtrlMsg: connCtrlMsg,
}) })
// 通知GS玩家客户端的本地时钟 // 通知GS玩家客户端的本地时钟
connCtrlMsg = new(mq.ConnCtrlMsg) connCtrlMsg = &mq.ConnCtrlMsg{
connCtrlMsg.UserId = userId UserId: userId,
connCtrlMsg.ClientTime = pingReq.ClientTime ClientTime: pingReq.ClientTime,
}
k.messageQueue.SendToGs(session.gsServerAppId, &mq.NetMsg{ k.messageQueue.SendToGs(session.gsServerAppId, &mq.NetMsg{
MsgType: mq.MsgTypeConnCtrl, MsgType: mq.MsgTypeConnCtrl,
EventId: mq.ClientTimeNotify, EventId: mq.ClientTimeNotify,
ConnCtrlMsg: connCtrlMsg, ConnCtrlMsg: connCtrlMsg,
}) })
case cmd.PlayerLoginReq: case cmd.PlayerLoginReq:
// GS登录包
if connState != ConnWaitLogin { if connState != ConnWaitLogin {
return return
} }
playerLoginReq := protoMsg.PayloadMessage.(*proto.PlayerLoginReq) playerLoginReq := protoMsg.PayloadMessage.(*proto.PlayerLoginReq)
playerLoginReq.TargetUid = 0 playerLoginReq.TargetUid = 0
playerLoginReq.TargetHomeOwnerUid = 0 playerLoginReq.TargetHomeOwnerUid = 0
gameMsg := new(mq.GameMsg) gameMsg := &mq.GameMsg{
gameMsg.UserId = userId UserId: userId,
gameMsg.CmdId = protoMsg.CmdId CmdId: protoMsg.CmdId,
gameMsg.ClientSeq = protoMsg.HeadMessage.ClientSequenceId ClientSeq: protoMsg.HeadMessage.ClientSequenceId,
gameMsg.PayloadMessage = playerLoginReq PayloadMessage: playerLoginReq,
}
// 转发到GS // 转发到GS
k.messageQueue.SendToGs(session.gsServerAppId, &mq.NetMsg{ k.messageQueue.SendToGs(session.gsServerAppId, &mq.NetMsg{
MsgType: mq.MsgTypeGame, MsgType: mq.MsgTypeGame,
@@ -131,10 +138,12 @@ func (k *KcpConnectManager) recvMsgHandle(protoMsg *ProtoMsg, session *Session)
logger.Error("conn not active so drop packet, cmdId: %v, userId: %v, convId: %v", protoMsg.CmdId, userId, protoMsg.ConvId) logger.Error("conn not active so drop packet, cmdId: %v, userId: %v, convId: %v", protoMsg.CmdId, userId, protoMsg.ConvId)
return return
} }
gameMsg := new(mq.GameMsg) gameMsg := &mq.GameMsg{
gameMsg.UserId = userId UserId: userId,
gameMsg.CmdId = protoMsg.CmdId CmdId: protoMsg.CmdId,
gameMsg.ClientSeq = protoMsg.HeadMessage.ClientSequenceId ClientSeq: protoMsg.HeadMessage.ClientSequenceId,
PayloadMessageData: nil,
}
// 在这里直接序列化成二进制数据 终结PayloadMessage的生命周期并回收进缓存池 // 在这里直接序列化成二进制数据 终结PayloadMessage的生命周期并回收进缓存池
payloadMessageData, err := pb.Marshal(protoMsg.PayloadMessage) payloadMessageData, err := pb.Marshal(protoMsg.PayloadMessage)
if err != nil { if err != nil {
@@ -207,32 +216,34 @@ func (k *KcpConnectManager) sendMsgHandle() {
logger.Error("can not find convId by userId") logger.Error("can not find convId by userId")
continue continue
} }
protoMsg := new(ProtoMsg) protoMsg := &ProtoMsg{
protoMsg.ConvId = convId ConvId: convId,
protoMsg.CmdId = gameMsg.CmdId CmdId: gameMsg.CmdId,
protoMsg.HeadMessage = k.getHeadMsg(gameMsg.ClientSeq) HeadMessage: k.getHeadMsg(gameMsg.ClientSeq),
protoMsg.PayloadMessage = gameMsg.PayloadMessage PayloadMessage: gameMsg.PayloadMessage,
}
session := convSessionMap[protoMsg.ConvId] session := convSessionMap[protoMsg.ConvId]
if session == nil { if session == nil {
logger.Error("session is nil, convId: %v", protoMsg.ConvId) logger.Error("session is nil, convId: %v", protoMsg.ConvId)
return continue
} }
kcpRawSendChan := session.kcpRawSendChan kcpRawSendChan := session.kcpRawSendChan
if kcpRawSendChan == nil { if kcpRawSendChan == nil {
logger.Error("kcpRawSendChan is nil, convId: %v", protoMsg.ConvId) logger.Error("kcpRawSendChan is nil, convId: %v", protoMsg.ConvId)
return continue
} }
if len(kcpRawSendChan) == 1000 { if len(kcpRawSendChan) == 1000 {
logger.Error("kcpRawSendChan is full, convId: %v", protoMsg.ConvId) logger.Error("kcpRawSendChan is full, convId: %v", protoMsg.ConvId)
return continue
} }
if protoMsg.CmdId == cmd.PlayerLoginRsp { if protoMsg.CmdId == cmd.PlayerLoginRsp {
logger.Debug("session active, convId: %v", protoMsg.ConvId) logger.Debug("session active, convId: %v", protoMsg.ConvId)
session.connState = ConnActive session.connState = ConnActive
// 通知GS玩家各个服务器的appid // 通知GS玩家各个服务器的appid
serverMsg := new(mq.ServerMsg) serverMsg := &mq.ServerMsg{
serverMsg.UserId = session.userId UserId: session.userId,
serverMsg.AnticheatServerAppId = session.anticheatServerAppId AnticheatServerAppId: session.anticheatServerAppId,
}
k.messageQueue.SendToGs(session.gsServerAppId, &mq.NetMsg{ k.messageQueue.SendToGs(session.gsServerAppId, &mq.NetMsg{
MsgType: mq.MsgTypeServer, MsgType: mq.MsgTypeServer,
EventId: mq.ServerAppidBindNotify, EventId: mq.ServerAppidBindNotify,
@@ -273,13 +284,14 @@ func (k *KcpConnectManager) sendMsgHandle() {
session.gsServerAppId = serverMsg.GameServerAppId session.gsServerAppId = serverMsg.GameServerAppId
session.anticheatServerAppId = "" session.anticheatServerAppId = ""
// 网关代发登录请求到新的GS // 网关代发登录请求到新的GS
gameMsg := new(mq.GameMsg) gameMsg := &mq.GameMsg{
gameMsg.UserId = serverMsg.UserId UserId: serverMsg.UserId,
gameMsg.CmdId = cmd.PlayerLoginReq CmdId: cmd.PlayerLoginReq,
gameMsg.ClientSeq = 0 ClientSeq: 0,
gameMsg.PayloadMessage = &proto.PlayerLoginReq{ PayloadMessage: &proto.PlayerLoginReq{
TargetUid: serverMsg.JoinHostUserId, TargetUid: serverMsg.JoinHostUserId,
TargetHomeOwnerUid: 0, TargetHomeOwnerUid: 0,
},
} }
k.messageQueue.SendToGs(session.gsServerAppId, &mq.NetMsg{ k.messageQueue.SendToGs(session.gsServerAppId, &mq.NetMsg{
MsgType: mq.MsgTypeGame, MsgType: mq.MsgTypeGame,

View File

@@ -369,6 +369,9 @@ func (g *Game) SendMsg(cmdId uint16, userId uint32, clientSeq uint32, payloadMsg
logger.Error("player not exist, uid: %v, stack: %v", userId, logger.Stack()) logger.Error("player not exist, uid: %v, stack: %v", userId, logger.Stack())
return return
} }
if player.NetFreeze {
return
}
gameMsg := new(mq.GameMsg) gameMsg := new(mq.GameMsg)
gameMsg.UserId = userId gameMsg.UserId = userId
gameMsg.CmdId = cmdId gameMsg.CmdId = cmdId

View File

@@ -160,13 +160,13 @@ func (c *CommandManager) TeleportCommand(cmd *CommandMessage) {
c.SendMessage(cmd.Executor, "已将玩家 UID%v 请求加入目标玩家 UID%v 的世界。", player.PlayerID, targetUid) c.SendMessage(cmd.Executor, "已将玩家 UID%v 请求加入目标玩家 UID%v 的世界。", player.PlayerID, targetUid)
} else { } else {
// 传送玩家至目标玩家的位置 // 传送玩家至目标玩家的位置
c.gmCmd.GMTeleportPlayer(player.PlayerID, target.SceneId, 0, target.Pos.X, target.Pos.Y, target.Pos.Z) c.gmCmd.GMTeleportPlayer(player.PlayerID, target.SceneId, target.Pos.X, target.Pos.Y, target.Pos.Z)
// 发送消息给执行者 // 发送消息给执行者
c.SendMessage(cmd.Executor, "已将玩家 UID%v 传送至 目标玩家 UID%v。", player.PlayerID, targetUid) c.SendMessage(cmd.Executor, "已将玩家 UID%v 传送至 目标玩家 UID%v。", player.PlayerID, targetUid)
} }
} else { } else {
// 传送玩家至指定的位置 // 传送玩家至指定的位置
c.gmCmd.GMTeleportPlayer(player.PlayerID, sceneId, 0, pos.X, pos.Y, pos.Z) c.gmCmd.GMTeleportPlayer(player.PlayerID, sceneId, pos.X, pos.Y, pos.Z)
// 发送消息给执行者 // 发送消息给执行者
c.SendMessage(cmd.Executor, "已将玩家 UID%v 传送至 场景:%v, X%.2f, Y%.2f, Z%.2f。", player.PlayerID, sceneId, pos.X, pos.Y, pos.Z) c.SendMessage(cmd.Executor, "已将玩家 UID%v 传送至 场景:%v, X%.2f, Y%.2f, Z%.2f。", player.PlayerID, sceneId, pos.X, pos.Y, pos.Z)
} }

View File

@@ -19,40 +19,20 @@ type GMCmd struct {
// 玩家通用GM指令 // 玩家通用GM指令
// GMTeleportPlayer 传送玩家 // GMTeleportPlayer 传送玩家
func (g *GMCmd) GMTeleportPlayer(userId, sceneId, dungeonId uint32, posX, posY, posZ float64) { func (g *GMCmd) GMTeleportPlayer(userId, sceneId uint32, posX, posY, posZ float64) {
player := USER_MANAGER.GetOnlineUser(userId) player := USER_MANAGER.GetOnlineUser(userId)
if player == nil { if player == nil {
logger.Error("player is nil, uid: %v", userId) logger.Error("player is nil, uid: %v", userId)
return return
} }
dungeonPointId := uint32(0)
if dungeonId != 0 {
end := false
for _, pointData := range gdconf.GetScenePointMapBySceneId(int32(sceneId)) {
if end {
break
}
for _, v := range pointData.DungeonIds {
if uint32(v) == dungeonId {
dungeonPointId = uint32(pointData.Id)
end = true
break
}
}
}
if dungeonPointId == 0 {
logger.Error("dungeon pointid not found, dungeonId: %v, uid: %v", dungeonId, userId)
return
}
}
GAME.TeleportPlayer( GAME.TeleportPlayer(
player, player,
proto.EnterReason_ENTER_REASON_GM, proto.EnterReason_ENTER_REASON_GM,
sceneId, sceneId,
&model.Vector{X: posX, Y: posY, Z: posZ}, &model.Vector{X: posX, Y: posY, Z: posZ},
new(model.Vector), new(model.Vector),
dungeonId, 0,
dungeonPointId, 0,
) )
} }
@@ -106,6 +86,7 @@ func (g *GMCmd) GMAddUserFlycloak(userId, flycloakId uint32) {
// GMAddUserAllItem 给予玩家所有物品 // GMAddUserAllItem 给予玩家所有物品
func (g *GMCmd) GMAddUserAllItem(userId, itemCount uint32) { func (g *GMCmd) GMAddUserAllItem(userId, itemCount uint32) {
g.GMHWOptLogoutPlayer(userId)
itemList := make([]*ChangeItem, 0) itemList := make([]*ChangeItem, 0)
for itemId := range GAME.GetAllItemDataConfig() { for itemId := range GAME.GetAllItemDataConfig() {
itemList = append(itemList, &ChangeItem{ itemList = append(itemList, &ChangeItem{
@@ -125,6 +106,7 @@ func (g *GMCmd) GMAddUserAllWeapon(userId, itemCount uint32) {
// GMAddUserAllReliquary 给予玩家所有圣遗物 // GMAddUserAllReliquary 给予玩家所有圣遗物
func (g *GMCmd) GMAddUserAllReliquary(userId, itemCount uint32) { func (g *GMCmd) GMAddUserAllReliquary(userId, itemCount uint32) {
g.GMHWOptLogoutPlayer(userId)
for itemId := range GAME.GetAllReliquaryDataConfig() { for itemId := range GAME.GetAllReliquaryDataConfig() {
g.GMAddUserReliquary(userId, uint32(itemId), itemCount) g.GMAddUserReliquary(userId, uint32(itemId), itemCount)
} }
@@ -153,6 +135,7 @@ func (g *GMCmd) GMAddUserAllFlycloak(userId uint32) {
// GMAddUserAllEvery 给予玩家所有内容 // GMAddUserAllEvery 给予玩家所有内容
func (g *GMCmd) GMAddUserAllEvery(userId, itemCount uint32) { func (g *GMCmd) GMAddUserAllEvery(userId, itemCount uint32) {
g.GMHWOptLogoutPlayer(userId)
// 给予玩家所有物品 // 给予玩家所有物品
g.GMAddUserAllItem(userId, itemCount) g.GMAddUserAllItem(userId, itemCount)
// 给予玩家所有武器 // 给予玩家所有武器
@@ -165,8 +148,18 @@ func (g *GMCmd) GMAddUserAllEvery(userId, itemCount uint32) {
g.GMAddUserAllCostume(userId) g.GMAddUserAllCostume(userId)
// 给予玩家所有风之翼 // 给予玩家所有风之翼
g.GMAddUserAllFlycloak(userId) g.GMAddUserAllFlycloak(userId)
}
// GMHWOptLogoutPlayer GM重量级操作主动下线玩家
func (g *GMCmd) GMHWOptLogoutPlayer(userId uint32) {
GAME.LogoutPlayer(userId) GAME.LogoutPlayer(userId)
player := USER_MANAGER.GetOnlineUser(userId)
if player == nil {
logger.Error("player is nil, uid: %v", userId)
return
}
// 冻结掉服务器对该玩家的下行 避免大量发包对整个系统造成压力
player.NetFreeze = true
} }
// GMAddQuest 添加任务 // GMAddQuest 添加任务

View File

@@ -47,6 +47,9 @@ func (r *RouteManager) doRoute(cmdId uint16, userId uint32, clientSeq uint32, pa
logger.Error("player not online, uid: %v", userId) logger.Error("player not online, uid: %v", userId)
return return
} }
if player.NetFreeze {
return
}
player.ClientSeq = clientSeq player.ClientSeq = clientSeq
SELF = player SELF = player
handlerFunc(player, payloadMsg) handlerFunc(player, payloadMsg)

View File

@@ -399,8 +399,8 @@ type WorldAvatar struct {
avatarId uint32 avatarId uint32
avatarEntityId uint32 avatarEntityId uint32
weaponEntityId uint32 weaponEntityId uint32
abilityList []*proto.AbilityAppliedAbility abilityMap map[uint32]*proto.AbilityAppliedAbility
modifierList []*proto.AbilityAppliedModifier modifierMap map[uint32]*proto.AbilityAppliedModifier
} }
func (w *WorldAvatar) GetUid() uint32 { func (w *WorldAvatar) GetUid() uint32 {
@@ -424,28 +424,31 @@ func (w *WorldAvatar) SetWeaponEntityId(weaponEntityId uint32) {
} }
func (w *WorldAvatar) GetAbilityList() []*proto.AbilityAppliedAbility { func (w *WorldAvatar) GetAbilityList() []*proto.AbilityAppliedAbility {
return w.abilityList abilityList := make([]*proto.AbilityAppliedAbility, 0)
for _, ability := range w.abilityMap {
abilityList = append(abilityList, ability)
}
return abilityList
} }
func (w *WorldAvatar) GetAbilityByInstanceId(instanceId uint32) *proto.AbilityAppliedAbility { func (w *WorldAvatar) GetAbilityByInstanceId(instanceId uint32) *proto.AbilityAppliedAbility {
for _, ability := range w.abilityList { return w.abilityMap[instanceId]
if ability.InstancedAbilityId == instanceId {
return ability
}
}
return nil
} }
func (w *WorldAvatar) SetAbilityList(abilityList []*proto.AbilityAppliedAbility) { func (w *WorldAvatar) AddAbility(ability *proto.AbilityAppliedAbility) {
w.abilityList = abilityList w.abilityMap[ability.InstancedAbilityId] = ability
} }
func (w *WorldAvatar) GetModifierList() []*proto.AbilityAppliedModifier { func (w *WorldAvatar) GetModifierList() []*proto.AbilityAppliedModifier {
return w.modifierList modifierList := make([]*proto.AbilityAppliedModifier, 0)
for _, modifier := range w.modifierMap {
modifierList = append(modifierList, modifier)
}
return modifierList
} }
func (w *WorldAvatar) SetModifierList(modifierList []*proto.AbilityAppliedModifier) { func (w *WorldAvatar) AddModifier(modifier *proto.AbilityAppliedModifier) {
w.modifierList = modifierList w.modifierMap[modifier.InstancedModifierId] = modifier
} }
// GetWorldAvatarList 获取世界队伍的全部角色列表 // GetWorldAvatarList 获取世界队伍的全部角色列表
@@ -632,8 +635,8 @@ func (w *World) SetPlayerLocalTeam(player *model.Player, avatarIdList []uint32)
avatarId: avatarId, avatarId: avatarId,
avatarEntityId: 0, avatarEntityId: 0,
weaponEntityId: 0, weaponEntityId: 0,
abilityList: make([]*proto.AbilityAppliedAbility, 0), abilityMap: make(map[uint32]*proto.AbilityAppliedAbility),
modifierList: make([]*proto.AbilityAppliedModifier, 0), modifierMap: make(map[uint32]*proto.AbilityAppliedModifier),
} }
} }
w.multiplayerTeam.localTeamMap[player.PlayerID] = newLocalTeam w.multiplayerTeam.localTeamMap[player.PlayerID] = newLocalTeam
@@ -650,8 +653,8 @@ func (w *World) copyLocalTeamToWorld(start int, end int, peerId uint32) {
avatarId: 0, avatarId: 0,
avatarEntityId: 0, avatarEntityId: 0,
weaponEntityId: 0, weaponEntityId: 0,
abilityList: nil, abilityMap: nil,
modifierList: nil, modifierMap: nil,
} }
continue continue
} }

View File

@@ -487,9 +487,7 @@ func (g *Game) ClientAbilityChangeNotify(player *model.Player, payloadMsg pb.Mes
if abilityMetaAddAbility.Ability == nil { if abilityMetaAddAbility.Ability == nil {
continue continue
} }
abilityList := worldAvatar.GetAbilityList() worldAvatar.AddAbility(abilityMetaAddAbility.Ability)
abilityList = append(abilityList, abilityMetaAddAbility.Ability)
worldAvatar.SetAbilityList(abilityList)
case proto.AbilityInvokeArgument_ABILITY_META_MODIFIER_CHANGE: case proto.AbilityInvokeArgument_ABILITY_META_MODIFIER_CHANGE:
abilityMetaModifierChange := new(proto.AbilityMetaModifierChange) abilityMetaModifierChange := new(proto.AbilityMetaModifierChange)
err := pb.Unmarshal(abilityInvokeEntry.AbilityData, abilityMetaModifierChange) err := pb.Unmarshal(abilityInvokeEntry.AbilityData, abilityMetaModifierChange)
@@ -516,9 +514,7 @@ func (g *Game) ClientAbilityChangeNotify(player *model.Player, payloadMsg pb.Mes
if worldAvatar == nil { if worldAvatar == nil {
continue continue
} }
modifierList := worldAvatar.GetModifierList() worldAvatar.AddModifier(abilityAppliedModifier)
modifierList = append(modifierList, abilityAppliedModifier)
worldAvatar.SetModifierList(modifierList)
} }
} }
} }
@@ -738,6 +734,7 @@ func (g *Game) handleGadgetEntityBeHitLow(player *model.Player, entity *Entity,
} }
g.ChangeGadgetState(player, entity.GetId(), constant.GADGET_STATE_GEAR_START) g.ChangeGadgetState(player, entity.GetId(), constant.GADGET_STATE_GEAR_START)
} else if strings.Contains(gadgetDataConfig.ServerLuaScript, "SubfieldDrop_WoodenObject_Broken") { } else if strings.Contains(gadgetDataConfig.ServerLuaScript, "SubfieldDrop_WoodenObject_Broken") {
// 木箱破碎
g.KillEntity(player, scene, entity.GetId(), proto.PlayerDieType_PLAYER_DIE_GM) g.KillEntity(player, scene, entity.GetId(), proto.PlayerDieType_PLAYER_DIE_GM)
} }
} }

View File

@@ -56,21 +56,21 @@ type Player struct {
DbQuest *DbQuest // 任务 DbQuest *DbQuest // 任务
DbWorld *DbWorld // 大世界 DbWorld *DbWorld // 大世界
// 在线数据 请随意 记得加忽略字段的tag // 在线数据 请随意 记得加忽略字段的tag
LastSaveTime uint32 `bson:"-" msgpack:"-"` // 上一次保存时间 LastSaveTime uint32 `bson:"-" msgpack:"-"` // 上一次存档保存时间
DbState int `bson:"-" msgpack:"-"` // 数据库存档状态 DbState int `bson:"-" msgpack:"-"` // 数据库存档状态
WorldId uint32 `bson:"-" msgpack:"-"` // 所在的世界id WorldId uint32 `bson:"-" msgpack:"-"` // 所在的世界id
GameObjectGuidCounter uint64 `bson:"-" msgpack:"-"` // 游戏对象guid计数器 GameObjectGuidCounter uint64 `bson:"-" msgpack:"-"` // 游戏对象guid计数器
LastKeepaliveTime uint32 `bson:"-" msgpack:"-"` // 上一次保持活跃时间 LastKeepaliveTime uint32 `bson:"-" msgpack:"-"` // 上一次保持活跃时间
ClientTime uint32 `bson:"-" msgpack:"-"` // 客户端本地时钟 ClientTime uint32 `bson:"-" msgpack:"-"` // 客户端本地时钟
ClientRTT uint32 `bson:"-" msgpack:"-"` // 客户端往返时延 ClientRTT uint32 `bson:"-" msgpack:"-"` // 客户端网络往返时延
GameObjectGuidMap map[uint64]GameObject `bson:"-" msgpack:"-"` // 游戏对象guid映射表 GameObjectGuidMap map[uint64]GameObject `bson:"-" msgpack:"-"` // 游戏对象guid映射表
Online bool `bson:"-" msgpack:"-"` // 在线状态 Online bool `bson:"-" msgpack:"-"` // 在线状态
Pause bool `bson:"-" msgpack:"-"` // 暂停状态 Pause bool `bson:"-" msgpack:"-"` // 暂停状态
SceneJump bool `bson:"-" msgpack:"-"` // 是否场景切换 SceneJump bool `bson:"-" msgpack:"-"` // 是否场景切换
SceneLoadState int `bson:"-" msgpack:"-"` // 场景加载状态 SceneLoadState int `bson:"-" msgpack:"-"` // 场景加载状态
CoopApplyMap map[uint32]int64 `bson:"-" msgpack:"-"` // 敲门申请的玩家uid及时间 CoopApplyMap map[uint32]int64 `bson:"-" msgpack:"-"` // 敲门申请的玩家uid及时间
StaminaInfo *StaminaInfo `bson:"-" msgpack:"-"` // 耐力临时数据 StaminaInfo *StaminaInfo `bson:"-" msgpack:"-"` // 耐力在线数据
VehicleInfo *VehicleInfo `bson:"-" msgpack:"-"` // 载具临时数据 VehicleInfo *VehicleInfo `bson:"-" msgpack:"-"` // 载具在线数据
ClientSeq uint32 `bson:"-" msgpack:"-"` // 客户端发包请求的序号 ClientSeq uint32 `bson:"-" msgpack:"-"` // 客户端发包请求的序号
CombatInvokeHandler *InvokeHandler[proto.CombatInvokeEntry] `bson:"-" msgpack:"-"` // combat转发器 CombatInvokeHandler *InvokeHandler[proto.CombatInvokeEntry] `bson:"-" msgpack:"-"` // combat转发器
AbilityInvokeHandler *InvokeHandler[proto.AbilityInvokeEntry] `bson:"-" msgpack:"-"` // ability转发器 AbilityInvokeHandler *InvokeHandler[proto.AbilityInvokeEntry] `bson:"-" msgpack:"-"` // ability转发器
@@ -79,6 +79,7 @@ type Player struct {
GCGCurGameGuid uint32 `bson:"-" msgpack:"-"` // GCG玩家所在的游戏guid GCGCurGameGuid uint32 `bson:"-" msgpack:"-"` // GCG玩家所在的游戏guid
GCGInfo *GCGInfo `bson:"-" msgpack:"-"` // 七圣召唤信息 GCGInfo *GCGInfo `bson:"-" msgpack:"-"` // 七圣召唤信息
XLuaDebug bool `bson:"-" msgpack:"-"` // 是否开启客户端XLUA调试 XLuaDebug bool `bson:"-" msgpack:"-"` // 是否开启客户端XLUA调试
NetFreeze bool `bson:"-" msgpack:"-"` // 客户端网络上下行冻结状态
// 特殊数据 // 特殊数据
ChatMsgMap map[uint32][]*ChatMsg `bson:"-" msgpack:"-"` // 聊天信息 数据量偏大 只从db读写 不保存到redis ChatMsgMap map[uint32][]*ChatMsg `bson:"-" msgpack:"-"` // 聊天信息 数据量偏大 只从db读写 不保存到redis
} }