mirror of
https://github.com/FlourishingWorld/hk4e.git
synced 2026-02-04 16:02:26 +08:00
拆分战斗服务器
This commit is contained in:
@@ -9,10 +9,9 @@ import (
|
||||
"time"
|
||||
|
||||
"hk4e/common/config"
|
||||
"hk4e/gate/mq"
|
||||
"hk4e/common/mq"
|
||||
"hk4e/gate/net"
|
||||
"hk4e/pkg/logger"
|
||||
"hk4e/protocol/cmd"
|
||||
)
|
||||
|
||||
func Run(ctx context.Context, configFile string) error {
|
||||
@@ -21,10 +20,9 @@ func Run(ctx context.Context, configFile string) error {
|
||||
logger.InitLogger("gate")
|
||||
logger.Warn("gate start")
|
||||
|
||||
netMsgInput := make(chan *cmd.NetMsg, 10000)
|
||||
netMsgOutput := make(chan *cmd.NetMsg, 10000)
|
||||
messageQueue := mq.NewMessageQueue(mq.GATE, "1")
|
||||
|
||||
connectManager := net.NewKcpConnectManager(netMsgInput, netMsgOutput)
|
||||
connectManager := net.NewKcpConnectManager(messageQueue)
|
||||
connectManager.Start()
|
||||
|
||||
go func() {
|
||||
@@ -34,10 +32,6 @@ func Run(ctx context.Context, configFile string) error {
|
||||
}
|
||||
}()
|
||||
|
||||
messageQueue := mq.NewMessageQueue(netMsgInput, netMsgOutput)
|
||||
messageQueue.Start()
|
||||
defer messageQueue.Close()
|
||||
|
||||
c := make(chan os.Signal, 1)
|
||||
signal.Notify(c, syscall.SIGHUP, syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGINT)
|
||||
for {
|
||||
|
||||
@@ -1,98 +0,0 @@
|
||||
package mq
|
||||
|
||||
import (
|
||||
"hk4e/common/config"
|
||||
"hk4e/pkg/logger"
|
||||
"hk4e/protocol/cmd"
|
||||
|
||||
"github.com/nats-io/nats.go"
|
||||
"github.com/vmihailenco/msgpack/v5"
|
||||
pb "google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
type MessageQueue struct {
|
||||
natsConn *nats.Conn
|
||||
natsMsgChan chan *nats.Msg
|
||||
netMsgInput chan *cmd.NetMsg
|
||||
netMsgOutput chan *cmd.NetMsg
|
||||
cmdProtoMap *cmd.CmdProtoMap
|
||||
}
|
||||
|
||||
func NewMessageQueue(netMsgInput chan *cmd.NetMsg, netMsgOutput chan *cmd.NetMsg) (r *MessageQueue) {
|
||||
r = new(MessageQueue)
|
||||
conn, err := nats.Connect(config.CONF.MQ.NatsUrl)
|
||||
if err != nil {
|
||||
logger.Error("connect nats error: %v", err)
|
||||
return nil
|
||||
}
|
||||
r.natsConn = conn
|
||||
r.natsMsgChan = make(chan *nats.Msg, 10000)
|
||||
_, err = r.natsConn.ChanSubscribe("GATE_CMD_HK4E", r.natsMsgChan)
|
||||
if err != nil {
|
||||
logger.Error("nats subscribe error: %v", err)
|
||||
return nil
|
||||
}
|
||||
r.netMsgInput = netMsgInput
|
||||
r.netMsgOutput = netMsgOutput
|
||||
r.cmdProtoMap = cmd.NewCmdProtoMap()
|
||||
return r
|
||||
}
|
||||
|
||||
func (m *MessageQueue) Start() {
|
||||
go m.startRecvHandler()
|
||||
go m.startSendHandler()
|
||||
}
|
||||
|
||||
func (m *MessageQueue) Close() {
|
||||
m.natsConn.Close()
|
||||
}
|
||||
|
||||
func (m *MessageQueue) startRecvHandler() {
|
||||
for {
|
||||
natsMsg := <-m.natsMsgChan
|
||||
// msgpack NetMsg
|
||||
netMsg := new(cmd.NetMsg)
|
||||
err := msgpack.Unmarshal(natsMsg.Data, netMsg)
|
||||
if err != nil {
|
||||
logger.Error("parse bin to net msg error: %v", err)
|
||||
continue
|
||||
}
|
||||
if netMsg.EventId == cmd.NormalMsg {
|
||||
// protobuf PayloadMessage
|
||||
payloadMessage := m.cmdProtoMap.GetProtoObjByCmdId(netMsg.CmdId)
|
||||
err = pb.Unmarshal(netMsg.PayloadMessageData, payloadMessage)
|
||||
if err != nil {
|
||||
logger.Error("parse bin to payload msg error: %v", err)
|
||||
continue
|
||||
}
|
||||
netMsg.PayloadMessage = payloadMessage
|
||||
}
|
||||
m.netMsgOutput <- netMsg
|
||||
}
|
||||
}
|
||||
|
||||
func (m *MessageQueue) startSendHandler() {
|
||||
for {
|
||||
netMsg := <-m.netMsgInput
|
||||
// protobuf PayloadMessage
|
||||
payloadMessageData, err := pb.Marshal(netMsg.PayloadMessage)
|
||||
if err != nil {
|
||||
logger.Error("parse payload msg to bin error: %v", err)
|
||||
continue
|
||||
}
|
||||
netMsg.PayloadMessageData = payloadMessageData
|
||||
// msgpack NetMsg
|
||||
netMsgData, err := msgpack.Marshal(netMsg)
|
||||
if err != nil {
|
||||
logger.Error("parse net msg to bin error: %v", err)
|
||||
continue
|
||||
}
|
||||
natsMsg := nats.NewMsg("GS_CMD_HK4E")
|
||||
natsMsg.Data = netMsgData
|
||||
err = m.natsConn.PublishMsg(natsMsg)
|
||||
if err != nil {
|
||||
logger.Error("nats publish msg error: %v", err)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"hk4e/common/mq"
|
||||
"hk4e/dispatch/controller"
|
||||
"hk4e/gate/kcp"
|
||||
"hk4e/pkg/endec"
|
||||
@@ -73,24 +74,30 @@ func (k *KcpConnectManager) recvMsgHandle(protoMsg *ProtoMsg, session *Session)
|
||||
rsp.PayloadMessage = playerLoginRsp
|
||||
k.localMsgOutput <- rsp
|
||||
// 登录成功 通知GS初始化相关数据
|
||||
netMsg := new(cmd.NetMsg)
|
||||
netMsg.UserId = userId
|
||||
netMsg.EventId = cmd.UserLoginNotify
|
||||
netMsg.ClientSeq = headMeta.seq
|
||||
k.netMsgInput <- netMsg
|
||||
logger.Info("send to gs user login ok, ConvId: %v, UserId: %v", protoMsg.ConvId, netMsg.UserId)
|
||||
gameMsg := new(mq.GameMsg)
|
||||
gameMsg.UserId = userId
|
||||
gameMsg.ClientSeq = headMeta.seq
|
||||
k.messageQueue.SendToGs("1", &mq.NetMsg{
|
||||
MsgType: mq.MsgTypeGame,
|
||||
EventId: mq.UserLoginNotify,
|
||||
GameMsg: gameMsg,
|
||||
})
|
||||
logger.Info("send to gs user login ok, ConvId: %v, UserId: %v", protoMsg.ConvId, gameMsg.UserId)
|
||||
case cmd.SetPlayerBornDataReq:
|
||||
// 玩家注册请求
|
||||
if connState != ConnAlive {
|
||||
return
|
||||
}
|
||||
netMsg := new(cmd.NetMsg)
|
||||
netMsg.UserId = userId
|
||||
netMsg.EventId = cmd.UserRegNotify
|
||||
netMsg.CmdId = cmd.SetPlayerBornDataReq
|
||||
netMsg.ClientSeq = protoMsg.HeadMessage.ClientSequenceId
|
||||
netMsg.PayloadMessage = protoMsg.PayloadMessage
|
||||
k.netMsgInput <- netMsg
|
||||
gameMsg := new(mq.GameMsg)
|
||||
gameMsg.UserId = userId
|
||||
gameMsg.CmdId = cmd.SetPlayerBornDataReq
|
||||
gameMsg.ClientSeq = protoMsg.HeadMessage.ClientSequenceId
|
||||
gameMsg.PayloadMessage = protoMsg.PayloadMessage
|
||||
k.messageQueue.SendToGs("1", &mq.NetMsg{
|
||||
MsgType: mq.MsgTypeGame,
|
||||
EventId: mq.UserRegNotify,
|
||||
GameMsg: gameMsg,
|
||||
})
|
||||
case cmd.PlayerForceExitReq:
|
||||
// 玩家退出游戏请求
|
||||
if connState != ConnAlive {
|
||||
@@ -119,34 +126,55 @@ func (k *KcpConnectManager) recvMsgHandle(protoMsg *ProtoMsg, session *Session)
|
||||
rsp.PayloadMessage = pingRsp
|
||||
k.localMsgOutput <- rsp
|
||||
// 通知GS玩家客户端的本地时钟
|
||||
netMsg := new(cmd.NetMsg)
|
||||
netMsg.UserId = userId
|
||||
netMsg.EventId = cmd.ClientTimeNotify
|
||||
netMsg.ClientTime = pingReq.ClientTime
|
||||
k.netMsgInput <- netMsg
|
||||
gameMsg := new(mq.GameMsg)
|
||||
gameMsg.UserId = userId
|
||||
gameMsg.ClientTime = pingReq.ClientTime
|
||||
k.messageQueue.SendToGs("1", &mq.NetMsg{
|
||||
MsgType: mq.MsgTypeGame,
|
||||
EventId: mq.ClientTimeNotify,
|
||||
GameMsg: gameMsg,
|
||||
})
|
||||
// RTT
|
||||
logger.Debug("convId: %v, RTO: %v, SRTT: %v, RTTVar: %v", protoMsg.ConvId, session.conn.GetRTO(), session.conn.GetSRTT(), session.conn.GetSRTTVar())
|
||||
// 客户端往返时延通知
|
||||
rtt := session.conn.GetSRTT()
|
||||
// 通知GS玩家客户端往返时延
|
||||
netMsg = new(cmd.NetMsg)
|
||||
netMsg.UserId = userId
|
||||
netMsg.EventId = cmd.ClientRttNotify
|
||||
netMsg.ClientRtt = uint32(rtt)
|
||||
k.netMsgInput <- netMsg
|
||||
gameMsg = new(mq.GameMsg)
|
||||
gameMsg.UserId = userId
|
||||
gameMsg.ClientRtt = uint32(rtt)
|
||||
k.messageQueue.SendToGs("1", &mq.NetMsg{
|
||||
MsgType: mq.MsgTypeGame,
|
||||
EventId: mq.ClientRttNotify,
|
||||
GameMsg: gameMsg,
|
||||
})
|
||||
default:
|
||||
// 转发到GS
|
||||
// 未登录禁止访问GS
|
||||
// 未登录禁止访问
|
||||
if connState != ConnAlive {
|
||||
return
|
||||
}
|
||||
netMsg := new(cmd.NetMsg)
|
||||
netMsg.UserId = userId
|
||||
netMsg.EventId = cmd.NormalMsg
|
||||
netMsg.CmdId = protoMsg.CmdId
|
||||
netMsg.ClientSeq = protoMsg.HeadMessage.ClientSequenceId
|
||||
netMsg.PayloadMessage = protoMsg.PayloadMessage
|
||||
k.netMsgInput <- netMsg
|
||||
// 转发到FIGHT
|
||||
if protoMsg.CmdId == cmd.CombatInvocationsNotify {
|
||||
gameMsg := new(mq.GameMsg)
|
||||
gameMsg.UserId = userId
|
||||
gameMsg.CmdId = protoMsg.CmdId
|
||||
gameMsg.ClientSeq = protoMsg.HeadMessage.ClientSequenceId
|
||||
gameMsg.PayloadMessage = protoMsg.PayloadMessage
|
||||
k.messageQueue.SendToFight("1", &mq.NetMsg{
|
||||
MsgType: mq.MsgTypeGame,
|
||||
EventId: mq.NormalMsg,
|
||||
GameMsg: gameMsg,
|
||||
})
|
||||
}
|
||||
// 转发到GS
|
||||
gameMsg := new(mq.GameMsg)
|
||||
gameMsg.UserId = userId
|
||||
gameMsg.CmdId = protoMsg.CmdId
|
||||
gameMsg.ClientSeq = protoMsg.HeadMessage.ClientSequenceId
|
||||
gameMsg.PayloadMessage = protoMsg.PayloadMessage
|
||||
k.messageQueue.SendToGs("1", &mq.NetMsg{
|
||||
MsgType: mq.MsgTypeGame,
|
||||
EventId: mq.NormalMsg,
|
||||
GameMsg: gameMsg,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -179,22 +207,27 @@ func (k *KcpConnectManager) sendMsgHandle() {
|
||||
close(session.kcpRawSendChan)
|
||||
case protoMsg := <-k.localMsgOutput:
|
||||
sendToClientFn(protoMsg)
|
||||
case netMsg := <-k.netMsgOutput:
|
||||
convId, exist := userIdConvMap[netMsg.UserId]
|
||||
case netMsg := <-k.messageQueue.GetNetMsg():
|
||||
if netMsg.MsgType != mq.MsgTypeGame {
|
||||
logger.Error("recv unknown msg type from game server, msg type: %v", netMsg.MsgType)
|
||||
continue
|
||||
}
|
||||
if netMsg.EventId != mq.NormalMsg {
|
||||
logger.Error("recv unknown event from game server, event id: %v", netMsg.EventId)
|
||||
continue
|
||||
}
|
||||
gameMsg := netMsg.GameMsg
|
||||
convId, exist := userIdConvMap[gameMsg.UserId]
|
||||
if !exist {
|
||||
logger.Error("can not find convId by userId")
|
||||
continue
|
||||
}
|
||||
if netMsg.EventId == cmd.NormalMsg {
|
||||
protoMsg := new(ProtoMsg)
|
||||
protoMsg.ConvId = convId
|
||||
protoMsg.CmdId = netMsg.CmdId
|
||||
protoMsg.HeadMessage = k.getHeadMsg(netMsg.ClientSeq)
|
||||
protoMsg.PayloadMessage = netMsg.PayloadMessage
|
||||
sendToClientFn(protoMsg)
|
||||
} else {
|
||||
logger.Error("recv unknown event from game server, event id: %v", netMsg.EventId)
|
||||
}
|
||||
protoMsg := new(ProtoMsg)
|
||||
protoMsg.ConvId = convId
|
||||
protoMsg.CmdId = gameMsg.CmdId
|
||||
protoMsg.HeadMessage = k.getHeadMsg(gameMsg.ClientSeq)
|
||||
protoMsg.PayloadMessage = gameMsg.PayloadMessage
|
||||
sendToClientFn(protoMsg)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"time"
|
||||
|
||||
"hk4e/common/config"
|
||||
"hk4e/common/mq"
|
||||
"hk4e/common/region"
|
||||
"hk4e/dispatch/controller"
|
||||
"hk4e/gate/kcp"
|
||||
@@ -18,6 +19,8 @@ import (
|
||||
"hk4e/protocol/proto"
|
||||
)
|
||||
|
||||
const PacketFreqLimit = 1000
|
||||
|
||||
type KcpConnectManager struct {
|
||||
openState bool
|
||||
sessionConvIdMap map[uint64]*Session
|
||||
@@ -26,8 +29,7 @@ type KcpConnectManager struct {
|
||||
kcpEventInput chan *KcpEvent
|
||||
kcpEventOutput chan *KcpEvent
|
||||
cmdProtoMap *cmd.CmdProtoMap
|
||||
netMsgInput chan *cmd.NetMsg
|
||||
netMsgOutput chan *cmd.NetMsg
|
||||
messageQueue *mq.MessageQueue
|
||||
localMsgOutput chan *ProtoMsg
|
||||
createSessionChan chan *Session
|
||||
destroySessionChan chan *Session
|
||||
@@ -38,7 +40,7 @@ type KcpConnectManager struct {
|
||||
encRsaKeyMap map[string][]byte
|
||||
}
|
||||
|
||||
func NewKcpConnectManager(netMsgInput chan *cmd.NetMsg, netMsgOutput chan *cmd.NetMsg) (r *KcpConnectManager) {
|
||||
func NewKcpConnectManager(messageQueue *mq.MessageQueue) (r *KcpConnectManager) {
|
||||
r = new(KcpConnectManager)
|
||||
r.openState = true
|
||||
r.sessionConvIdMap = make(map[uint64]*Session)
|
||||
@@ -46,8 +48,7 @@ func NewKcpConnectManager(netMsgInput chan *cmd.NetMsg, netMsgOutput chan *cmd.N
|
||||
r.kcpEventInput = make(chan *KcpEvent, 1000)
|
||||
r.kcpEventOutput = make(chan *KcpEvent, 1000)
|
||||
r.cmdProtoMap = cmd.NewCmdProtoMap()
|
||||
r.netMsgInput = netMsgInput
|
||||
r.netMsgOutput = netMsgOutput
|
||||
r.messageQueue = messageQueue
|
||||
r.localMsgOutput = make(chan *ProtoMsg, 1000)
|
||||
r.createSessionChan = make(chan *Session, 1000)
|
||||
r.destroySessionChan = make(chan *Session, 1000)
|
||||
@@ -245,7 +246,7 @@ func (k *KcpConnectManager) recvHandle(session *Session) {
|
||||
pktFreqLimitCounter++
|
||||
now := time.Now().UnixNano()
|
||||
if now-pktFreqLimitTimer > int64(time.Second) {
|
||||
if pktFreqLimitCounter > 100 {
|
||||
if pktFreqLimitCounter > PacketFreqLimit {
|
||||
logger.Error("exit recv loop, client packet send freq too high, convId: %v, pps: %v", convId, pktFreqLimitCounter)
|
||||
k.closeKcpConn(session, kcp.EnetPacketFreqTooHigh)
|
||||
break
|
||||
@@ -271,8 +272,6 @@ func (k *KcpConnectManager) sendHandle(session *Session) {
|
||||
// 发送
|
||||
conn := session.conn
|
||||
convId := conn.GetConv()
|
||||
pktFreqLimitCounter := 0
|
||||
pktFreqLimitTimer := time.Now().UnixNano()
|
||||
for {
|
||||
protoMsg, ok := <-session.kcpRawSendChan
|
||||
if !ok {
|
||||
@@ -293,19 +292,6 @@ func (k *KcpConnectManager) sendHandle(session *Session) {
|
||||
k.closeKcpConn(session, kcp.EnetServerKick)
|
||||
break
|
||||
}
|
||||
// 发包频率限制
|
||||
pktFreqLimitCounter++
|
||||
now := time.Now().UnixNano()
|
||||
if now-pktFreqLimitTimer > int64(time.Second) {
|
||||
if pktFreqLimitCounter > 100 {
|
||||
logger.Error("exit send loop, server packet send freq too high, convId: %v, pps: %v", convId, pktFreqLimitCounter)
|
||||
k.closeKcpConn(session, kcp.EnetPacketFreqTooHigh)
|
||||
break
|
||||
} else {
|
||||
pktFreqLimitCounter = 0
|
||||
}
|
||||
pktFreqLimitTimer = now
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -332,11 +318,14 @@ func (k *KcpConnectManager) closeKcpConn(session *Session, enetType uint32) {
|
||||
EventId: KcpConnCloseNotify,
|
||||
}
|
||||
// 通知GS玩家下线
|
||||
netMsg := new(cmd.NetMsg)
|
||||
netMsg.UserId = session.userId
|
||||
netMsg.EventId = cmd.UserOfflineNotify
|
||||
k.netMsgInput <- netMsg
|
||||
logger.Info("send to gs user offline, ConvId: %v, UserId: %v", convId, netMsg.UserId)
|
||||
gameMsg := new(mq.GameMsg)
|
||||
gameMsg.UserId = session.userId
|
||||
k.messageQueue.SendToGs("1", &mq.NetMsg{
|
||||
MsgType: mq.MsgTypeGame,
|
||||
EventId: mq.UserOfflineNotify,
|
||||
GameMsg: gameMsg,
|
||||
})
|
||||
logger.Info("send to gs user offline, ConvId: %v, UserId: %v", convId, gameMsg.UserId)
|
||||
k.destroySessionChan <- session
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user