mirror of
https://github.com/FlourishingWorld/hk4e.git
synced 2026-03-01 00:35:36 +08:00
完善登录流程的错误处理
This commit is contained in:
@@ -6,6 +6,7 @@ import (
|
|||||||
"net"
|
"net"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
"hk4e/common/config"
|
"hk4e/common/config"
|
||||||
"hk4e/common/rpc"
|
"hk4e/common/rpc"
|
||||||
@@ -25,16 +26,17 @@ import (
|
|||||||
// 要用RPC有专门的NATSRPC
|
// 要用RPC有专门的NATSRPC
|
||||||
|
|
||||||
type MessageQueue struct {
|
type MessageQueue struct {
|
||||||
natsConn *nats.Conn
|
natsConn *nats.Conn
|
||||||
natsMsgChan chan *nats.Msg
|
natsMsgChan chan *nats.Msg
|
||||||
netMsgInput chan *NetMsg
|
netMsgInput chan *NetMsg
|
||||||
netMsgOutput chan *NetMsg
|
netMsgOutput chan *NetMsg
|
||||||
cmdProtoMap *cmd.CmdProtoMap
|
cmdProtoMap *cmd.CmdProtoMap
|
||||||
serverType string
|
serverType string
|
||||||
appId string
|
appId string
|
||||||
gateTcpMqChan chan []byte
|
gateTcpMqChan chan []byte
|
||||||
gateTcpMqEventChan chan *GateTcpMqEvent
|
gateTcpMqEventChan chan *GateTcpMqEvent
|
||||||
rpcClient *rpc.Client
|
gateTcpMqDeadEventChan chan string
|
||||||
|
rpcClient *rpc.Client
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewMessageQueue(serverType string, appId string, rpcClient *rpc.Client) (r *MessageQueue) {
|
func NewMessageQueue(serverType string, appId string, rpcClient *rpc.Client) (r *MessageQueue) {
|
||||||
@@ -63,11 +65,12 @@ func NewMessageQueue(serverType string, appId string, rpcClient *rpc.Client) (r
|
|||||||
r.appId = appId
|
r.appId = appId
|
||||||
r.gateTcpMqChan = make(chan []byte, 1000)
|
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.rpcClient = rpcClient
|
r.rpcClient = rpcClient
|
||||||
if serverType == api.GATE {
|
if serverType == api.GATE {
|
||||||
r.initGateTcpMqServer()
|
go r.runGateTcpMqServer()
|
||||||
} else {
|
} else {
|
||||||
r.initGateTcpMqClient()
|
go r.runGateTcpMqClient()
|
||||||
}
|
}
|
||||||
go r.recvHandler()
|
go r.recvHandler()
|
||||||
go r.sendHandler()
|
go r.sendHandler()
|
||||||
@@ -75,6 +78,13 @@ func NewMessageQueue(serverType string, appId string, rpcClient *rpc.Client) (r
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (m *MessageQueue) Close() {
|
func (m *MessageQueue) Close() {
|
||||||
|
// 等待所有待发送的消息发送完毕
|
||||||
|
for {
|
||||||
|
if len(m.netMsgInput) == 0 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
time.Sleep(time.Millisecond * 100)
|
||||||
|
}
|
||||||
m.natsConn.Close()
|
m.natsConn.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -98,6 +108,10 @@ func (m *MessageQueue) recvHandler() {
|
|||||||
logger.Error("parse bin to net msg error: %v", err)
|
logger.Error("parse bin to net msg error: %v", err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
// 忽略自己发出的广播消息
|
||||||
|
if netMsg.OriginServerType == m.serverType && netMsg.OriginServerAppId == m.appId {
|
||||||
|
continue
|
||||||
|
}
|
||||||
switch netMsg.MsgType {
|
switch netMsg.MsgType {
|
||||||
case MsgTypeGame:
|
case MsgTypeGame:
|
||||||
gameMsg := netMsg.GameMsg
|
gameMsg := netMsg.GameMsg
|
||||||
@@ -168,9 +182,15 @@ func (m *MessageQueue) sendHandler() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// 广播消息只能走nats
|
||||||
|
if netMsg.ServerType == "ALL_SERVER_HK4E" {
|
||||||
|
fallbackNatsMqSend()
|
||||||
|
continue
|
||||||
|
}
|
||||||
// 有tcp快速通道就走快速通道
|
// 有tcp快速通道就走快速通道
|
||||||
instMap, exist := gateTcpMqInstMap[netMsg.ServerType]
|
instMap, exist := gateTcpMqInstMap[netMsg.ServerType]
|
||||||
if !exist {
|
if !exist {
|
||||||
|
logger.Error("unknown server type: %v", netMsg.ServerType)
|
||||||
fallbackNatsMqSend()
|
fallbackNatsMqSend()
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@@ -204,6 +224,7 @@ func (m *MessageQueue) sendHandler() {
|
|||||||
case EventDisconnect:
|
case EventDisconnect:
|
||||||
logger.Warn("gate tcp mq disconnect, addr: %v, server type: %v, appid: %v", inst.conn.RemoteAddr().String(), inst.serverType, inst.appId)
|
logger.Warn("gate tcp mq disconnect, addr: %v, server type: %v, appid: %v", inst.conn.RemoteAddr().String(), inst.serverType, inst.appId)
|
||||||
delete(gateTcpMqInstMap[inst.serverType], inst.appId)
|
delete(gateTcpMqInstMap[inst.serverType], inst.appId)
|
||||||
|
m.gateTcpMqDeadEventChan <- inst.conn.RemoteAddr().String()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -225,7 +246,7 @@ type GateTcpMqEvent struct {
|
|||||||
inst *GateTcpMqInst
|
inst *GateTcpMqInst
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *MessageQueue) initGateTcpMqServer() {
|
func (m *MessageQueue) runGateTcpMqServer() {
|
||||||
addr, err := net.ResolveTCPAddr("tcp4", "0.0.0.0:"+strconv.Itoa(int(config.CONF.Hk4e.GateTcpMqPort)))
|
addr, err := net.ResolveTCPAddr("tcp4", "0.0.0.0:"+strconv.Itoa(int(config.CONF.Hk4e.GateTcpMqPort)))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error("gate tcp mq parse port error: %v", err)
|
logger.Error("gate tcp mq parse port error: %v", err)
|
||||||
@@ -236,17 +257,13 @@ func (m *MessageQueue) initGateTcpMqServer() {
|
|||||||
logger.Error("gate tcp mq listen error: %v", err)
|
logger.Error("gate tcp mq listen error: %v", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
go m.gateTcpMqAcceptHandle(listener)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *MessageQueue) gateTcpMqAcceptHandle(listener *net.TCPListener) {
|
|
||||||
for {
|
for {
|
||||||
conn, err := listener.Accept()
|
conn, err := listener.Accept()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error("gate tcp mq accept error: %v", err)
|
logger.Error("gate tcp mq accept error: %v", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
logger.Info("server connect gate tcp mq, addr: %v", conn.RemoteAddr().String())
|
logger.Info("accept gate tcp mq, server addr: %v", conn.RemoteAddr().String())
|
||||||
go m.gateTcpMqHandshake(conn)
|
go m.gateTcpMqHandshake(conn)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -296,14 +313,37 @@ func (m *MessageQueue) gateTcpMqHandshake(conn net.Conn) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *MessageQueue) initGateTcpMqClient() {
|
func (m *MessageQueue) runGateTcpMqClient() {
|
||||||
|
// 已存在的GATE连接列表
|
||||||
|
gateServerConnAddrMap := make(map[string]bool)
|
||||||
|
m.gateTcpMqConn(gateServerConnAddrMap)
|
||||||
|
ticker := time.NewTicker(time.Minute)
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case addr := <-m.gateTcpMqDeadEventChan:
|
||||||
|
// GATE连接断开
|
||||||
|
delete(gateServerConnAddrMap, addr)
|
||||||
|
case <-ticker.C:
|
||||||
|
// 定时获取全部GATE实例地址并建立连接
|
||||||
|
m.gateTcpMqConn(gateServerConnAddrMap)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MessageQueue) gateTcpMqConn(gateServerConnAddrMap map[string]bool) {
|
||||||
rsp, err := m.rpcClient.Discovery.GetAllGateServerInfoList(context.TODO(), new(api.NullMsg))
|
rsp, err := m.rpcClient.Discovery.GetAllGateServerInfoList(context.TODO(), new(api.NullMsg))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error("gate tcp mq get gate list error: %v", err)
|
logger.Error("gate tcp mq get gate list error: %v", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
for _, gateServerInfo := range rsp.GateServerInfoList {
|
for _, gateServerInfo := range rsp.GateServerInfoList {
|
||||||
addr, err := net.ResolveTCPAddr("tcp4", gateServerInfo.MqAddr+":"+strconv.Itoa(int(gateServerInfo.MqPort)))
|
gateServerAddr := gateServerInfo.MqAddr + ":" + strconv.Itoa(int(gateServerInfo.MqPort))
|
||||||
|
_, exist := gateServerConnAddrMap[gateServerAddr]
|
||||||
|
// GATE连接已存在
|
||||||
|
if exist {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
addr, err := net.ResolveTCPAddr("tcp4", gateServerAddr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error("gate tcp mq parse addr error: %v", err)
|
logger.Error("gate tcp mq parse addr error: %v", err)
|
||||||
return
|
return
|
||||||
@@ -323,11 +363,13 @@ func (m *MessageQueue) initGateTcpMqClient() {
|
|||||||
serverType: api.GATE,
|
serverType: api.GATE,
|
||||||
appId: gateServerInfo.AppId,
|
appId: gateServerInfo.AppId,
|
||||||
}
|
}
|
||||||
go m.gateTcpMqRecvHandle(inst)
|
|
||||||
m.gateTcpMqEventChan <- &GateTcpMqEvent{
|
m.gateTcpMqEventChan <- &GateTcpMqEvent{
|
||||||
event: EventConnect,
|
event: EventConnect,
|
||||||
inst: inst,
|
inst: inst,
|
||||||
}
|
}
|
||||||
|
gateServerConnAddrMap[gateServerAddr] = true
|
||||||
|
logger.Info("connect gate tcp mq, gate addr: %v", conn.RemoteAddr().String())
|
||||||
|
go m.gateTcpMqRecvHandle(inst)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -17,9 +17,9 @@ func (m *MessageQueue) getTopic(serverType string, appId string) string {
|
|||||||
|
|
||||||
func (m *MessageQueue) SendToGate(appId string, netMsg *NetMsg) {
|
func (m *MessageQueue) SendToGate(appId string, netMsg *NetMsg) {
|
||||||
netMsg.Topic = m.getTopic(api.GATE, appId)
|
netMsg.Topic = m.getTopic(api.GATE, appId)
|
||||||
originServerType, originServerAppId := m.getOriginServer()
|
|
||||||
netMsg.ServerType = api.GATE
|
netMsg.ServerType = api.GATE
|
||||||
netMsg.AppId = appId
|
netMsg.AppId = appId
|
||||||
|
originServerType, originServerAppId := m.getOriginServer()
|
||||||
netMsg.OriginServerType = originServerType
|
netMsg.OriginServerType = originServerType
|
||||||
netMsg.OriginServerAppId = originServerAppId
|
netMsg.OriginServerAppId = originServerAppId
|
||||||
m.netMsgInput <- netMsg
|
m.netMsgInput <- netMsg
|
||||||
@@ -27,9 +27,9 @@ func (m *MessageQueue) SendToGate(appId string, netMsg *NetMsg) {
|
|||||||
|
|
||||||
func (m *MessageQueue) SendToGs(appId string, netMsg *NetMsg) {
|
func (m *MessageQueue) SendToGs(appId string, netMsg *NetMsg) {
|
||||||
netMsg.Topic = m.getTopic(api.GS, appId)
|
netMsg.Topic = m.getTopic(api.GS, appId)
|
||||||
originServerType, originServerAppId := m.getOriginServer()
|
|
||||||
netMsg.ServerType = api.GS
|
netMsg.ServerType = api.GS
|
||||||
netMsg.AppId = appId
|
netMsg.AppId = appId
|
||||||
|
originServerType, originServerAppId := m.getOriginServer()
|
||||||
netMsg.OriginServerType = originServerType
|
netMsg.OriginServerType = originServerType
|
||||||
netMsg.OriginServerAppId = originServerAppId
|
netMsg.OriginServerAppId = originServerAppId
|
||||||
m.netMsgInput <- netMsg
|
m.netMsgInput <- netMsg
|
||||||
@@ -37,9 +37,9 @@ func (m *MessageQueue) SendToGs(appId string, netMsg *NetMsg) {
|
|||||||
|
|
||||||
func (m *MessageQueue) SendToFight(appId string, netMsg *NetMsg) {
|
func (m *MessageQueue) SendToFight(appId string, netMsg *NetMsg) {
|
||||||
netMsg.Topic = m.getTopic(api.FIGHT, appId)
|
netMsg.Topic = m.getTopic(api.FIGHT, appId)
|
||||||
originServerType, originServerAppId := m.getOriginServer()
|
|
||||||
netMsg.ServerType = api.FIGHT
|
netMsg.ServerType = api.FIGHT
|
||||||
netMsg.AppId = appId
|
netMsg.AppId = appId
|
||||||
|
originServerType, originServerAppId := m.getOriginServer()
|
||||||
netMsg.OriginServerType = originServerType
|
netMsg.OriginServerType = originServerType
|
||||||
netMsg.OriginServerAppId = originServerAppId
|
netMsg.OriginServerAppId = originServerAppId
|
||||||
m.netMsgInput <- netMsg
|
m.netMsgInput <- netMsg
|
||||||
@@ -47,9 +47,9 @@ func (m *MessageQueue) SendToFight(appId string, netMsg *NetMsg) {
|
|||||||
|
|
||||||
func (m *MessageQueue) SendToPathfinding(appId string, netMsg *NetMsg) {
|
func (m *MessageQueue) SendToPathfinding(appId string, netMsg *NetMsg) {
|
||||||
netMsg.Topic = m.getTopic(api.PATHFINDING, appId)
|
netMsg.Topic = m.getTopic(api.PATHFINDING, appId)
|
||||||
originServerType, originServerAppId := m.getOriginServer()
|
|
||||||
netMsg.ServerType = api.PATHFINDING
|
netMsg.ServerType = api.PATHFINDING
|
||||||
netMsg.AppId = appId
|
netMsg.AppId = appId
|
||||||
|
originServerType, originServerAppId := m.getOriginServer()
|
||||||
netMsg.OriginServerType = originServerType
|
netMsg.OriginServerType = originServerType
|
||||||
netMsg.OriginServerAppId = originServerAppId
|
netMsg.OriginServerAppId = originServerAppId
|
||||||
m.netMsgInput <- netMsg
|
m.netMsgInput <- netMsg
|
||||||
@@ -57,6 +57,7 @@ func (m *MessageQueue) SendToPathfinding(appId string, netMsg *NetMsg) {
|
|||||||
|
|
||||||
func (m *MessageQueue) SendToAll(netMsg *NetMsg) {
|
func (m *MessageQueue) SendToAll(netMsg *NetMsg) {
|
||||||
netMsg.Topic = "ALL_SERVER_HK4E"
|
netMsg.Topic = "ALL_SERVER_HK4E"
|
||||||
|
netMsg.ServerType = "ALL_SERVER_HK4E"
|
||||||
originServerType, originServerAppId := m.getOriginServer()
|
originServerType, originServerAppId := m.getOriginServer()
|
||||||
netMsg.OriginServerType = originServerType
|
netMsg.OriginServerType = originServerType
|
||||||
netMsg.OriginServerAppId = originServerAppId
|
netMsg.OriginServerAppId = originServerAppId
|
||||||
|
|||||||
@@ -22,42 +22,42 @@ type TokenVerifyRsp struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *Controller) gateTokenVerify(context *gin.Context) {
|
func (c *Controller) gateTokenVerify(context *gin.Context) {
|
||||||
VerifyFail := func() {
|
verifyFail := func(playerID uint32) {
|
||||||
context.JSON(http.StatusOK, &TokenVerifyRsp{
|
context.JSON(http.StatusOK, &TokenVerifyRsp{
|
||||||
Valid: false,
|
Valid: false,
|
||||||
Forbid: false,
|
Forbid: false,
|
||||||
ForbidEndTime: 0,
|
ForbidEndTime: 0,
|
||||||
PlayerID: 0,
|
PlayerID: playerID,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
tokenVerifyReq := new(TokenVerifyReq)
|
tokenVerifyReq := new(TokenVerifyReq)
|
||||||
err := context.ShouldBindJSON(tokenVerifyReq)
|
err := context.ShouldBindJSON(tokenVerifyReq)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
VerifyFail()
|
verifyFail(0)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
logger.Info("gate token verify, req: %v", tokenVerifyReq)
|
logger.Info("gate token verify, req: %v", tokenVerifyReq)
|
||||||
accountId, err := strconv.ParseUint(tokenVerifyReq.AccountId, 10, 64)
|
accountId, err := strconv.ParseUint(tokenVerifyReq.AccountId, 10, 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
VerifyFail()
|
verifyFail(0)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
account, err := c.dao.QueryAccountByField("accountID", accountId)
|
account, err := c.dao.QueryAccountByField("accountID", accountId)
|
||||||
if err != nil || account == nil {
|
if err != nil || account == nil {
|
||||||
VerifyFail()
|
verifyFail(0)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if tokenVerifyReq.AccountToken != account.ComboToken {
|
if tokenVerifyReq.AccountToken != account.ComboToken {
|
||||||
VerifyFail()
|
verifyFail(uint32(account.PlayerID))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if account.ComboTokenUsed {
|
if account.ComboTokenUsed {
|
||||||
VerifyFail()
|
verifyFail(uint32(account.PlayerID))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
_, err = c.dao.UpdateAccountFieldByFieldName("accountID", account.AccountID, "comboTokenUsed", true)
|
_, err = c.dao.UpdateAccountFieldByFieldName("accountID", account.AccountID, "comboTokenUsed", true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
VerifyFail()
|
verifyFail(uint32(account.PlayerID))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
context.JSON(http.StatusOK, &TokenVerifyRsp{
|
context.JSON(http.StatusOK, &TokenVerifyRsp{
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ const (
|
|||||||
PacketMaxLen = 343 * 1024 // 最大应用层包长度
|
PacketMaxLen = 343 * 1024 // 最大应用层包长度
|
||||||
ConnRecvTimeout = 30 // 收包超时时间 秒
|
ConnRecvTimeout = 30 // 收包超时时间 秒
|
||||||
ConnSendTimeout = 10 // 发包超时时间 秒
|
ConnSendTimeout = 10 // 发包超时时间 秒
|
||||||
MaxClientConnNumLimit = 100 // 最大客户端连接数限制
|
MaxClientConnNumLimit = 2 // 最大客户端连接数限制
|
||||||
)
|
)
|
||||||
|
|
||||||
var CLIENT_CONN_NUM int32 = 0 // 当前客户端连接数
|
var CLIENT_CONN_NUM int32 = 0 // 当前客户端连接数
|
||||||
@@ -37,14 +37,17 @@ type KcpConnectManager struct {
|
|||||||
discovery *rpc.DiscoveryClient // node服务器客户端
|
discovery *rpc.DiscoveryClient // node服务器客户端
|
||||||
openState bool // 网关开放状态
|
openState bool // 网关开放状态
|
||||||
// 会话
|
// 会话
|
||||||
sessionConvIdMap map[uint64]*Session
|
sessionConvIdMap map[uint64]*Session
|
||||||
sessionUserIdMap map[uint32]*Session
|
sessionUserIdMap map[uint32]*Session
|
||||||
sessionMapLock sync.RWMutex
|
sessionMapLock sync.RWMutex
|
||||||
createSessionChan chan *Session
|
createSessionChan chan *Session
|
||||||
destroySessionChan chan *Session
|
destroySessionChan chan *Session
|
||||||
|
globalGsOnlineMap map[uint32]string
|
||||||
|
globalGsOnlineMapLock sync.RWMutex
|
||||||
// 连接事件
|
// 连接事件
|
||||||
kcpEventInput chan *KcpEvent
|
kcpEventInput chan *KcpEvent
|
||||||
kcpEventOutput chan *KcpEvent
|
kcpEventOutput chan *KcpEvent
|
||||||
|
reLoginRemoteKickRegChan chan *RemoteKick
|
||||||
// 协议
|
// 协议
|
||||||
serverCmdProtoMap *cmd.CmdProtoMap
|
serverCmdProtoMap *cmd.CmdProtoMap
|
||||||
clientCmdProtoMap *client_proto.ClientCmdProtoMap
|
clientCmdProtoMap *client_proto.ClientCmdProtoMap
|
||||||
@@ -65,8 +68,10 @@ func NewKcpConnectManager(messageQueue *mq.MessageQueue, discovery *rpc.Discover
|
|||||||
r.sessionUserIdMap = make(map[uint32]*Session)
|
r.sessionUserIdMap = make(map[uint32]*Session)
|
||||||
r.createSessionChan = make(chan *Session, 1000)
|
r.createSessionChan = make(chan *Session, 1000)
|
||||||
r.destroySessionChan = make(chan *Session, 1000)
|
r.destroySessionChan = make(chan *Session, 1000)
|
||||||
|
r.globalGsOnlineMap = make(map[uint32]string)
|
||||||
r.kcpEventInput = make(chan *KcpEvent, 1000)
|
r.kcpEventInput = make(chan *KcpEvent, 1000)
|
||||||
r.kcpEventOutput = make(chan *KcpEvent, 1000)
|
r.kcpEventOutput = make(chan *KcpEvent, 1000)
|
||||||
|
r.reLoginRemoteKickRegChan = make(chan *RemoteKick, 1000)
|
||||||
r.serverCmdProtoMap = cmd.NewCmdProtoMap()
|
r.serverCmdProtoMap = cmd.NewCmdProtoMap()
|
||||||
if config.CONF.Hk4e.ClientProtoProxyEnable {
|
if config.CONF.Hk4e.ClientProtoProxyEnable {
|
||||||
r.clientCmdProtoMap = client_proto.NewClientCmdProtoMap()
|
r.clientCmdProtoMap = client_proto.NewClientCmdProtoMap()
|
||||||
@@ -110,8 +115,6 @@ func (k *KcpConnectManager) run() {
|
|||||||
|
|
||||||
func (k *KcpConnectManager) Close() {
|
func (k *KcpConnectManager) Close() {
|
||||||
k.closeAllKcpConn()
|
k.closeAllKcpConn()
|
||||||
// 等待所有连接关闭时需要发送的消息发送完毕
|
|
||||||
time.Sleep(time.Second * 3)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (k *KcpConnectManager) gateNetInfo() {
|
func (k *KcpConnectManager) gateNetInfo() {
|
||||||
@@ -145,13 +148,6 @@ func (k *KcpConnectManager) acceptHandle(listener *kcp.Listener) {
|
|||||||
_ = conn.Close()
|
_ = conn.Close()
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
clientConnNum := atomic.AddInt32(&CLIENT_CONN_NUM, 1)
|
|
||||||
if clientConnNum > MaxClientConnNumLimit {
|
|
||||||
logger.Error("gate conn num limit, convId: %v", convId)
|
|
||||||
_ = conn.Close()
|
|
||||||
atomic.AddInt32(&CLIENT_CONN_NUM, -1)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
conn.SetACKNoDelay(true)
|
conn.SetACKNoDelay(true)
|
||||||
conn.SetWriteDelay(false)
|
conn.SetWriteDelay(false)
|
||||||
logger.Info("client connect, convId: %v", convId)
|
logger.Info("client connect, convId: %v", convId)
|
||||||
|
|||||||
@@ -61,13 +61,7 @@ func (k *KcpConnectManager) eventHandle() {
|
|||||||
k.closeAllKcpConn()
|
k.closeAllKcpConn()
|
||||||
}
|
}
|
||||||
case KcpConnRelogin:
|
case KcpConnRelogin:
|
||||||
kickFinishNotifyChan, ok := event.EventMessage.(chan bool)
|
|
||||||
if !ok {
|
|
||||||
logger.Error("event KcpConnRelogin msg type error")
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
k.forceCloseKcpConn(event.ConvId, kcp.EnetServerRelogin)
|
k.forceCloseKcpConn(event.ConvId, kcp.EnetServerRelogin)
|
||||||
kickFinishNotifyChan <- true
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import (
|
|||||||
"math/rand"
|
"math/rand"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"hk4e/common/config"
|
"hk4e/common/config"
|
||||||
@@ -148,13 +149,14 @@ func (k *KcpConnectManager) recvMsgHandle(protoMsg *ProtoMsg, session *Session)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 从GS接收消息
|
// 接收来自其他服务器的消息
|
||||||
func (k *KcpConnectManager) sendMsgHandle() {
|
func (k *KcpConnectManager) sendMsgHandle() {
|
||||||
logger.Debug("send msg handle start")
|
logger.Debug("send msg handle start")
|
||||||
|
// 函数栈内缓存 添加删除事件走chan 避免频繁加锁
|
||||||
convSessionMap := make(map[uint64]*Session)
|
convSessionMap := make(map[uint64]*Session)
|
||||||
userIdConvMap := make(map[uint32]uint64)
|
userIdConvMap := make(map[uint32]uint64)
|
||||||
|
// 分发到每个连接具体的发送协程
|
||||||
sendToClientFn := func(protoMsg *ProtoMsg) {
|
sendToClientFn := func(protoMsg *ProtoMsg) {
|
||||||
// 分发到每个连接具体的发送协程
|
|
||||||
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)
|
||||||
@@ -212,6 +214,8 @@ func (k *KcpConnectManager) sendMsgHandle() {
|
|||||||
}
|
}
|
||||||
kcpRawSendChan <- protoMsg
|
kcpRawSendChan <- protoMsg
|
||||||
}
|
}
|
||||||
|
// 远程全局顶号注册列表
|
||||||
|
reLoginRemoteKickRegMap := make(map[uint32]chan bool)
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case session := <-k.createSessionChan:
|
case session := <-k.createSessionChan:
|
||||||
@@ -221,6 +225,8 @@ func (k *KcpConnectManager) sendMsgHandle() {
|
|||||||
delete(convSessionMap, session.conn.GetConv())
|
delete(convSessionMap, session.conn.GetConv())
|
||||||
delete(userIdConvMap, session.userId)
|
delete(userIdConvMap, session.userId)
|
||||||
close(session.kcpRawSendChan)
|
close(session.kcpRawSendChan)
|
||||||
|
case remoteKick := <-k.reLoginRemoteKickRegChan:
|
||||||
|
reLoginRemoteKickRegMap[remoteKick.userId] = remoteKick.kickFinishNotifyChan
|
||||||
case protoMsg := <-k.localMsgOutput:
|
case protoMsg := <-k.localMsgOutput:
|
||||||
sendToClientFn(protoMsg)
|
sendToClientFn(protoMsg)
|
||||||
case netMsg := <-k.messageQueue.GetNetMsg():
|
case netMsg := <-k.messageQueue.GetNetMsg():
|
||||||
@@ -268,7 +274,7 @@ func (k *KcpConnectManager) sendMsgHandle() {
|
|||||||
session := convSessionMap[convId]
|
session := convSessionMap[convId]
|
||||||
if session == nil {
|
if session == nil {
|
||||||
logger.Error("session is nil, convId: %v", convId)
|
logger.Error("session is nil, convId: %v", convId)
|
||||||
return
|
continue
|
||||||
}
|
}
|
||||||
session.gsServerAppId = serverMsg.GameServerAppId
|
session.gsServerAppId = serverMsg.GameServerAppId
|
||||||
session.fightServerAppId = ""
|
session.fightServerAppId = ""
|
||||||
@@ -285,6 +291,22 @@ func (k *KcpConnectManager) sendMsgHandle() {
|
|||||||
EventId: mq.NormalMsg,
|
EventId: mq.NormalMsg,
|
||||||
GameMsg: gameMsg,
|
GameMsg: gameMsg,
|
||||||
})
|
})
|
||||||
|
case mq.ServerUserOnlineStateChangeNotify:
|
||||||
|
// 收到GS玩家离线完成通知 唤醒存在的顶号登录流程
|
||||||
|
if serverMsg.IsOnline {
|
||||||
|
k.globalGsOnlineMapLock.Lock()
|
||||||
|
k.globalGsOnlineMap[serverMsg.UserId] = netMsg.OriginServerAppId
|
||||||
|
k.globalGsOnlineMapLock.Unlock()
|
||||||
|
} else {
|
||||||
|
k.globalGsOnlineMapLock.Lock()
|
||||||
|
delete(k.globalGsOnlineMap, serverMsg.UserId)
|
||||||
|
k.globalGsOnlineMapLock.Unlock()
|
||||||
|
kickFinishNotifyChan, exist := reLoginRemoteKickRegMap[serverMsg.UserId]
|
||||||
|
if !exist {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
kickFinishNotifyChan <- true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -300,8 +322,13 @@ func (k *KcpConnectManager) getHeadMsg(clientSeq uint32) (headMsg *proto.PacketH
|
|||||||
return headMsg
|
return headMsg
|
||||||
}
|
}
|
||||||
|
|
||||||
func (k *KcpConnectManager) getPlayerToken(req *proto.GetPlayerTokenReq, session *Session) (rsp *proto.GetPlayerTokenRsp) {
|
type RemoteKick struct {
|
||||||
loginFail := func() {
|
userId uint32
|
||||||
|
kickFinishNotifyChan chan bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (k *KcpConnectManager) getPlayerToken(req *proto.GetPlayerTokenReq, session *Session) *proto.GetPlayerTokenRsp {
|
||||||
|
loginFailClose := func() {
|
||||||
k.kcpEventInput <- &KcpEvent{
|
k.kcpEventInput <- &KcpEvent{
|
||||||
ConvId: session.conn.GetConv(),
|
ConvId: session.conn.GetConv(),
|
||||||
EventId: KcpConnForceClose,
|
EventId: KcpConnForceClose,
|
||||||
@@ -313,26 +340,26 @@ func (k *KcpConnectManager) getPlayerToken(req *proto.GetPlayerTokenReq, session
|
|||||||
AccountToken: req.AccountToken,
|
AccountToken: req.AccountToken,
|
||||||
}, "")
|
}, "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error("verify token error: %v", err)
|
logger.Error("verify token error: %v, account uid: %v", err, req.AccountUid)
|
||||||
loginFail()
|
loginFailClose()
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
if !tokenVerifyRsp.Valid {
|
uid := tokenVerifyRsp.PlayerID
|
||||||
logger.Error("token error")
|
loginFailRsp := func(retCode int32, isForbid bool, forbidEndTime uint32) *proto.GetPlayerTokenRsp {
|
||||||
loginFail()
|
// 关联session信息 不然包发不出去
|
||||||
return nil
|
session.userId = uid
|
||||||
}
|
k.SetSession(session, session.conn.GetConv(), session.userId)
|
||||||
// comboToken验证成功
|
k.createSessionChan <- session
|
||||||
if tokenVerifyRsp.Forbid {
|
rsp := new(proto.GetPlayerTokenRsp)
|
||||||
// 封号通知
|
rsp.Uid = uid
|
||||||
rsp = new(proto.GetPlayerTokenRsp)
|
|
||||||
rsp.Uid = tokenVerifyRsp.PlayerID
|
|
||||||
rsp.IsProficientPlayer = true
|
rsp.IsProficientPlayer = true
|
||||||
rsp.Retcode = int32(proto.Retcode_RET_BLACK_UID)
|
rsp.Retcode = retCode
|
||||||
rsp.Msg = "FORBID_CHEATING_PLUGINS"
|
if isForbid {
|
||||||
rsp.BlackUidEndTime = tokenVerifyRsp.ForbidEndTime
|
rsp.Msg = "FORBID_CHEATING_PLUGINS"
|
||||||
if rsp.BlackUidEndTime == 0 {
|
rsp.BlackUidEndTime = forbidEndTime
|
||||||
rsp.BlackUidEndTime = 2051193600 // 2035-01-01 00:00:00
|
if rsp.BlackUidEndTime == 0 {
|
||||||
|
rsp.BlackUidEndTime = 2051193600 // 2035-01-01 00:00:00
|
||||||
|
}
|
||||||
}
|
}
|
||||||
rsp.RegPlatform = 3
|
rsp.RegPlatform = 3
|
||||||
rsp.CountryCode = "US"
|
rsp.CountryCode = "US"
|
||||||
@@ -341,31 +368,57 @@ func (k *KcpConnectManager) getPlayerToken(req *proto.GetPlayerTokenReq, session
|
|||||||
rsp.ClientIpStr = split[0]
|
rsp.ClientIpStr = split[0]
|
||||||
return rsp
|
return rsp
|
||||||
}
|
}
|
||||||
oldSession := k.GetSessionByUserId(tokenVerifyRsp.PlayerID)
|
if !tokenVerifyRsp.Valid {
|
||||||
|
logger.Error("token error, uid: %v", uid)
|
||||||
|
return loginFailRsp(int32(proto.Retcode_RET_TOKEN_ERROR), false, 0)
|
||||||
|
}
|
||||||
|
// comboToken验证成功
|
||||||
|
if tokenVerifyRsp.Forbid {
|
||||||
|
// 封号通知
|
||||||
|
return loginFailRsp(int32(proto.Retcode_RET_BLACK_UID), true, tokenVerifyRsp.ForbidEndTime)
|
||||||
|
}
|
||||||
|
clientConnNum := atomic.AddInt32(&CLIENT_CONN_NUM, 1)
|
||||||
|
if clientConnNum > MaxClientConnNumLimit {
|
||||||
|
logger.Error("gate conn num limit, uid: %v", uid)
|
||||||
|
return loginFailRsp(int32(proto.Retcode_RET_MAX_PLAYER), false, 0)
|
||||||
|
}
|
||||||
|
oldSession := k.GetSessionByUserId(uid)
|
||||||
if oldSession != nil {
|
if oldSession != nil {
|
||||||
// 本地顶号
|
// 本地顶号
|
||||||
kickFinishNotifyChan := make(chan bool)
|
|
||||||
k.kcpEventInput <- &KcpEvent{
|
k.kcpEventInput <- &KcpEvent{
|
||||||
ConvId: oldSession.conn.GetConv(),
|
ConvId: oldSession.conn.GetConv(),
|
||||||
EventId: KcpConnRelogin,
|
EventId: KcpConnRelogin,
|
||||||
EventMessage: kickFinishNotifyChan,
|
}
|
||||||
|
kickFinishNotifyChan := make(chan bool)
|
||||||
|
k.reLoginRemoteKickRegChan <- &RemoteKick{
|
||||||
|
userId: uid,
|
||||||
|
kickFinishNotifyChan: kickFinishNotifyChan,
|
||||||
}
|
}
|
||||||
<-kickFinishNotifyChan
|
<-kickFinishNotifyChan
|
||||||
} else {
|
}
|
||||||
|
k.globalGsOnlineMapLock.RLock()
|
||||||
|
_, exist := k.globalGsOnlineMap[uid]
|
||||||
|
k.globalGsOnlineMapLock.RUnlock()
|
||||||
|
if exist {
|
||||||
// 远程全局顶号
|
// 远程全局顶号
|
||||||
connCtrlMsg := new(mq.ConnCtrlMsg)
|
connCtrlMsg := new(mq.ConnCtrlMsg)
|
||||||
connCtrlMsg.KickUserId = tokenVerifyRsp.PlayerID
|
connCtrlMsg.KickUserId = uid
|
||||||
connCtrlMsg.KickReason = kcp.EnetServerRelogin
|
connCtrlMsg.KickReason = kcp.EnetServerRelogin
|
||||||
k.messageQueue.SendToAll(&mq.NetMsg{
|
k.messageQueue.SendToAll(&mq.NetMsg{
|
||||||
MsgType: mq.MsgTypeConnCtrl,
|
MsgType: mq.MsgTypeConnCtrl,
|
||||||
EventId: mq.KickPlayerNotify,
|
EventId: mq.KickPlayerNotify,
|
||||||
ConnCtrlMsg: connCtrlMsg,
|
ConnCtrlMsg: connCtrlMsg,
|
||||||
})
|
})
|
||||||
// TODO 确保旧连接已下线 已通知GS已保存好数据
|
// 注册回调通知
|
||||||
time.Sleep(time.Second)
|
kickFinishNotifyChan := make(chan bool)
|
||||||
|
k.reLoginRemoteKickRegChan <- &RemoteKick{
|
||||||
|
userId: uid,
|
||||||
|
kickFinishNotifyChan: kickFinishNotifyChan,
|
||||||
|
}
|
||||||
|
<-kickFinishNotifyChan
|
||||||
}
|
}
|
||||||
// 关联玩家uid和连接信息
|
// 关联玩家uid和连接信息
|
||||||
session.userId = tokenVerifyRsp.PlayerID
|
session.userId = uid
|
||||||
k.SetSession(session, session.conn.GetConv(), session.userId)
|
k.SetSession(session, session.conn.GetConv(), session.userId)
|
||||||
k.createSessionChan <- session
|
k.createSessionChan <- session
|
||||||
// 绑定各个服务器appid
|
// 绑定各个服务器appid
|
||||||
@@ -373,8 +426,8 @@ func (k *KcpConnectManager) getPlayerToken(req *proto.GetPlayerTokenReq, session
|
|||||||
ServerType: api.GS,
|
ServerType: api.GS,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error("get gs server appid error: %v", err)
|
logger.Error("get gs server appid error: %v, uid: %v", err, uid)
|
||||||
loginFail()
|
loginFailClose()
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
session.gsServerAppId = gsServerAppId.AppId
|
session.gsServerAppId = gsServerAppId.AppId
|
||||||
@@ -382,22 +435,22 @@ func (k *KcpConnectManager) getPlayerToken(req *proto.GetPlayerTokenReq, session
|
|||||||
ServerType: api.FIGHT,
|
ServerType: api.FIGHT,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error("get fight server appid error: %v", err)
|
logger.Error("get fight server appid error: %v, uid: %v", err, uid)
|
||||||
}
|
}
|
||||||
session.fightServerAppId = fightServerAppId.AppId
|
session.fightServerAppId = fightServerAppId.AppId
|
||||||
pathfindingServerAppId, err := k.discovery.GetServerAppId(context.TODO(), &api.GetServerAppIdReq{
|
pathfindingServerAppId, err := k.discovery.GetServerAppId(context.TODO(), &api.GetServerAppIdReq{
|
||||||
ServerType: api.PATHFINDING,
|
ServerType: api.PATHFINDING,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error("get pathfinding server appid error: %v", err)
|
logger.Error("get pathfinding server appid error: %v, uid: %v", err, uid)
|
||||||
}
|
}
|
||||||
session.pathfindingServerAppId = pathfindingServerAppId.AppId
|
session.pathfindingServerAppId = pathfindingServerAppId.AppId
|
||||||
logger.Debug("session gs appid: %v", session.gsServerAppId)
|
logger.Debug("session gs appid: %v, uid: %v", session.gsServerAppId, uid)
|
||||||
logger.Debug("session fight appid: %v", session.fightServerAppId)
|
logger.Debug("session fight appid: %v, uid: %v", session.fightServerAppId, uid)
|
||||||
logger.Debug("session pathfinding appid: %v", session.pathfindingServerAppId)
|
logger.Debug("session pathfinding appid: %v, uid: %v", session.pathfindingServerAppId, uid)
|
||||||
// 返回响应
|
// 返回响应
|
||||||
rsp = new(proto.GetPlayerTokenRsp)
|
rsp := new(proto.GetPlayerTokenRsp)
|
||||||
rsp.Uid = tokenVerifyRsp.PlayerID
|
rsp.Uid = uid
|
||||||
rsp.AccountUid = req.AccountUid
|
rsp.AccountUid = req.AccountUid
|
||||||
rsp.Token = req.AccountToken
|
rsp.Token = req.AccountToken
|
||||||
data := make([]byte, 16+32)
|
data := make([]byte, 16+32)
|
||||||
@@ -418,66 +471,66 @@ func (k *KcpConnectManager) getPlayerToken(req *proto.GetPlayerTokenReq, session
|
|||||||
serverSeedUint64 := timeRand.Uint64()
|
serverSeedUint64 := timeRand.Uint64()
|
||||||
session.seed = serverSeedUint64
|
session.seed = serverSeedUint64
|
||||||
if req.GetKeyId() != 0 {
|
if req.GetKeyId() != 0 {
|
||||||
logger.Debug("do hk4e 2.8 rsa logic")
|
logger.Debug("do hk4e 2.8 rsa logic, uid: %v", uid)
|
||||||
session.useMagicSeed = true
|
session.useMagicSeed = true
|
||||||
keyId := strconv.Itoa(int(req.GetKeyId()))
|
keyId := strconv.Itoa(int(req.GetKeyId()))
|
||||||
encPubPrivKey, exist := k.encRsaKeyMap[keyId]
|
encPubPrivKey, exist := k.encRsaKeyMap[keyId]
|
||||||
if !exist {
|
if !exist {
|
||||||
logger.Error("can not found key id: %v", keyId)
|
logger.Error("can not found key id: %v, uid: %v", keyId, uid)
|
||||||
loginFail()
|
loginFailClose()
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
pubKey, err := endec.RsaParsePubKeyByPrivKey(encPubPrivKey)
|
pubKey, err := endec.RsaParsePubKeyByPrivKey(encPubPrivKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error("parse rsa pub key error: %v", err)
|
logger.Error("parse rsa pub key error: %v, uid: %v", err, uid)
|
||||||
loginFail()
|
loginFailClose()
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
signPrivkey, err := endec.RsaParsePrivKey(k.signRsaKey)
|
signPrivkey, err := endec.RsaParsePrivKey(k.signRsaKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error("parse rsa priv key error: %v", err)
|
logger.Error("parse rsa priv key error: %v, uid: %v", err, uid)
|
||||||
loginFail()
|
loginFailClose()
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
clientSeedBase64 := req.GetClientRandKey()
|
clientSeedBase64 := req.GetClientRandKey()
|
||||||
clientSeedEnc, err := base64.StdEncoding.DecodeString(clientSeedBase64)
|
clientSeedEnc, err := base64.StdEncoding.DecodeString(clientSeedBase64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error("parse client seed base64 error: %v", err)
|
logger.Error("parse client seed base64 error: %v, uid: %v", err, uid)
|
||||||
loginFail()
|
loginFailClose()
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
clientSeed, err := endec.RsaDecrypt(clientSeedEnc, signPrivkey)
|
clientSeed, err := endec.RsaDecrypt(clientSeedEnc, signPrivkey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error("rsa dec error: %v", err)
|
logger.Error("rsa dec error: %v, uid: %v", err, uid)
|
||||||
loginFail()
|
loginFailClose()
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
clientSeedUint64 := uint64(0)
|
clientSeedUint64 := uint64(0)
|
||||||
err = binary.Read(bytes.NewReader(clientSeed), binary.BigEndian, &clientSeedUint64)
|
err = binary.Read(bytes.NewReader(clientSeed), binary.BigEndian, &clientSeedUint64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error("parse client seed to uint64 error: %v", err)
|
logger.Error("parse client seed to uint64 error: %v, uid: %v", err, uid)
|
||||||
loginFail()
|
loginFailClose()
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
seedUint64 := serverSeedUint64 ^ clientSeedUint64
|
seedUint64 := serverSeedUint64 ^ clientSeedUint64
|
||||||
seedBuf := new(bytes.Buffer)
|
seedBuf := new(bytes.Buffer)
|
||||||
err = binary.Write(seedBuf, binary.BigEndian, seedUint64)
|
err = binary.Write(seedBuf, binary.BigEndian, seedUint64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error("conv seed uint64 to bytes error: %v", err)
|
logger.Error("conv seed uint64 to bytes error: %v, uid: %v", err, uid)
|
||||||
loginFail()
|
loginFailClose()
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
seed := seedBuf.Bytes()
|
seed := seedBuf.Bytes()
|
||||||
seedEnc, err := endec.RsaEncrypt(seed, pubKey)
|
seedEnc, err := endec.RsaEncrypt(seed, pubKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error("rsa enc error: %v", err)
|
logger.Error("rsa enc error: %v, uid: %v", err, uid)
|
||||||
loginFail()
|
loginFailClose()
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
seedSign, err := endec.RsaSign(seed, signPrivkey)
|
seedSign, err := endec.RsaSign(seed, signPrivkey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error("rsa sign error: %v", err)
|
logger.Error("rsa sign error: %v, uid: %v", err, uid)
|
||||||
loginFail()
|
loginFailClose()
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
rsp.KeyId = req.KeyId
|
rsp.KeyId = req.KeyId
|
||||||
|
|||||||
@@ -21,13 +21,17 @@ func (d *Dao) GetRedisPlayerKey(userId uint32) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (d *Dao) GetRedisPlayer(userId uint32) *model.Player {
|
func (d *Dao) GetRedisPlayer(userId uint32) *model.Player {
|
||||||
|
startTime := time.Now().UnixNano()
|
||||||
playerDataLz4, err := d.redis.Get(context.TODO(), d.GetRedisPlayerKey(userId)).Result()
|
playerDataLz4, err := d.redis.Get(context.TODO(), d.GetRedisPlayerKey(userId)).Result()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error("get player from redis error: %v", err)
|
logger.Error("get player from redis error: %v", err)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
endTime := time.Now().UnixNano()
|
||||||
|
costTime := endTime - startTime
|
||||||
|
logger.Debug("get player from redis cost time: %v ns", costTime)
|
||||||
// 解压
|
// 解压
|
||||||
startTime := time.Now().UnixNano()
|
startTime = time.Now().UnixNano()
|
||||||
in := bytes.NewReader([]byte(playerDataLz4))
|
in := bytes.NewReader([]byte(playerDataLz4))
|
||||||
out := new(bytes.Buffer)
|
out := new(bytes.Buffer)
|
||||||
lz4Reader := lz4.NewReader(in)
|
lz4Reader := lz4.NewReader(in)
|
||||||
@@ -37,8 +41,8 @@ func (d *Dao) GetRedisPlayer(userId uint32) *model.Player {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
playerData := out.Bytes()
|
playerData := out.Bytes()
|
||||||
endTime := time.Now().UnixNano()
|
endTime = time.Now().UnixNano()
|
||||||
costTime := endTime - startTime
|
costTime = endTime - startTime
|
||||||
logger.Debug("lz4 decode cost time: %v ns, before len: %v, after len: %v, ratio lz4/raw: %v",
|
logger.Debug("lz4 decode cost time: %v ns, before len: %v, after len: %v, ratio lz4/raw: %v",
|
||||||
costTime, len(playerDataLz4), len(playerData), float64(len(playerDataLz4))/float64(len(playerData)))
|
costTime, len(playerDataLz4), len(playerData), float64(len(playerDataLz4))/float64(len(playerData)))
|
||||||
player := new(model.Player)
|
player := new(model.Player)
|
||||||
@@ -76,11 +80,15 @@ func (d *Dao) SetRedisPlayer(player *model.Player) {
|
|||||||
costTime := endTime - startTime
|
costTime := endTime - startTime
|
||||||
logger.Debug("lz4 encode cost time: %v ns, before len: %v, after len: %v, ratio lz4/raw: %v",
|
logger.Debug("lz4 encode cost time: %v ns, before len: %v, after len: %v, ratio lz4/raw: %v",
|
||||||
costTime, len(playerData), len(playerDataLz4), float64(len(playerDataLz4))/float64(len(playerData)))
|
costTime, len(playerData), len(playerDataLz4), float64(len(playerDataLz4))/float64(len(playerData)))
|
||||||
|
startTime = time.Now().UnixNano()
|
||||||
err = d.redis.Set(context.TODO(), d.GetRedisPlayerKey(player.PlayerID), playerDataLz4, time.Hour*24*30).Err()
|
err = d.redis.Set(context.TODO(), d.GetRedisPlayerKey(player.PlayerID), playerDataLz4, time.Hour*24*30).Err()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error("set player to redis error: %v", err)
|
logger.Error("set player to redis error: %v", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
endTime = time.Now().UnixNano()
|
||||||
|
costTime = endTime - startTime
|
||||||
|
logger.Debug("set player to redis cost time: %v ns", costTime)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *Dao) SetRedisPlayerList(playerList []*model.Player) {
|
func (d *Dao) SetRedisPlayerList(playerList []*model.Player) {
|
||||||
|
|||||||
@@ -185,6 +185,7 @@ func (g *GameManager) gameMainLoop() {
|
|||||||
tickCost := int64(0)
|
tickCost := int64(0)
|
||||||
localEventCost := int64(0)
|
localEventCost := int64(0)
|
||||||
commandCost := int64(0)
|
commandCost := int64(0)
|
||||||
|
routeCount := int64(0)
|
||||||
runtime.LockOSThread()
|
runtime.LockOSThread()
|
||||||
for {
|
for {
|
||||||
// 消耗CPU时间性能统计
|
// 消耗CPU时间性能统计
|
||||||
@@ -194,7 +195,7 @@ func (g *GameManager) gameMainLoop() {
|
|||||||
tickCost /= 1e6
|
tickCost /= 1e6
|
||||||
localEventCost /= 1e6
|
localEventCost /= 1e6
|
||||||
commandCost /= 1e6
|
commandCost /= 1e6
|
||||||
logger.Info("[GAME MAIN LOOP] cpu time cost detail, routeCost: %vms, tickCost: %vms, localEventCost: %vms, commandCost: %vms",
|
logger.Info("[GAME MAIN LOOP] cpu time cost detail, routeCost: %v ms, tickCost: %v ms, localEventCost: %v ms, commandCost: %v ms",
|
||||||
routeCost, tickCost, localEventCost, commandCost)
|
routeCost, tickCost, localEventCost, commandCost)
|
||||||
totalCost := routeCost + tickCost + localEventCost + commandCost
|
totalCost := routeCost + tickCost + localEventCost + commandCost
|
||||||
logger.Info("[GAME MAIN LOOP] cpu time cost percent, routeCost: %v%%, tickCost: %v%%, localEventCost: %v%%, commandCost: %v%%",
|
logger.Info("[GAME MAIN LOOP] cpu time cost percent, routeCost: %v%%, tickCost: %v%%, localEventCost: %v%%, commandCost: %v%%",
|
||||||
@@ -202,15 +203,17 @@ func (g *GameManager) gameMainLoop() {
|
|||||||
float32(tickCost)/float32(totalCost)*100.0,
|
float32(tickCost)/float32(totalCost)*100.0,
|
||||||
float32(localEventCost)/float32(totalCost)*100.0,
|
float32(localEventCost)/float32(totalCost)*100.0,
|
||||||
float32(commandCost)/float32(totalCost)*100.0)
|
float32(commandCost)/float32(totalCost)*100.0)
|
||||||
logger.Info("[GAME MAIN LOOP] total cpu time cost detail, totalCost: %vms",
|
logger.Info("[GAME MAIN LOOP] total cpu time cost detail, totalCost: %v ms",
|
||||||
totalCost)
|
totalCost)
|
||||||
logger.Info("[GAME MAIN LOOP] total cpu time cost percent, totalCost: %v%%",
|
logger.Info("[GAME MAIN LOOP] total cpu time cost percent, totalCost: %v%%",
|
||||||
float32(totalCost)/float32(intervalTime/1e6)*100.0)
|
float32(totalCost)/float32(intervalTime/1e6)*100.0)
|
||||||
|
logger.Info("[GAME MAIN LOOP] avg route cost: %v ms", float32(routeCost)/float32(routeCount))
|
||||||
lastTime = now
|
lastTime = now
|
||||||
routeCost = 0
|
routeCost = 0
|
||||||
tickCost = 0
|
tickCost = 0
|
||||||
localEventCost = 0
|
localEventCost = 0
|
||||||
commandCost = 0
|
commandCost = 0
|
||||||
|
routeCount = 0
|
||||||
}
|
}
|
||||||
select {
|
select {
|
||||||
case netMsg := <-MESSAGE_QUEUE.GetNetMsg():
|
case netMsg := <-MESSAGE_QUEUE.GetNetMsg():
|
||||||
@@ -219,6 +222,7 @@ func (g *GameManager) gameMainLoop() {
|
|||||||
ROUTE_MANAGER.RouteHandle(netMsg)
|
ROUTE_MANAGER.RouteHandle(netMsg)
|
||||||
end := time.Now().UnixNano()
|
end := time.Now().UnixNano()
|
||||||
routeCost += end - start
|
routeCost += end - start
|
||||||
|
routeCount++
|
||||||
case <-TICK_MANAGER.GetGlobalTick().C:
|
case <-TICK_MANAGER.GetGlobalTick().C:
|
||||||
// 游戏服务器定时帧
|
// 游戏服务器定时帧
|
||||||
start := time.Now().UnixNano()
|
start := time.Now().UnixNano()
|
||||||
@@ -232,12 +236,12 @@ func (g *GameManager) gameMainLoop() {
|
|||||||
end := time.Now().UnixNano()
|
end := time.Now().UnixNano()
|
||||||
localEventCost += end - start
|
localEventCost += end - start
|
||||||
case command := <-COMMAND_MANAGER.GetCommandTextInput():
|
case command := <-COMMAND_MANAGER.GetCommandTextInput():
|
||||||
// 处理传入的命令(普通玩家 GM命令)
|
// 处理GM命令
|
||||||
start := time.Now().UnixNano()
|
start := time.Now().UnixNano()
|
||||||
COMMAND_MANAGER.HandleCommand(command)
|
COMMAND_MANAGER.HandleCommand(command)
|
||||||
end := time.Now().UnixNano()
|
end := time.Now().UnixNano()
|
||||||
commandCost += end - start
|
commandCost += end - start
|
||||||
logger.Info("run gm cmd cost: %v ns", commandCost)
|
logger.Info("run gm cmd cost: %v ns", end-start)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"hk4e/common/mq"
|
"hk4e/common/mq"
|
||||||
|
"hk4e/gate/kcp"
|
||||||
"hk4e/gs/model"
|
"hk4e/gs/model"
|
||||||
"hk4e/pkg/logger"
|
"hk4e/pkg/logger"
|
||||||
"hk4e/protocol/cmd"
|
"hk4e/protocol/cmd"
|
||||||
@@ -87,6 +88,13 @@ func (g *GameManager) ClientTimeNotify(userId uint32, clientTime uint32) {
|
|||||||
}
|
}
|
||||||
logger.Debug("client time notify, uid: %v, time: %v", userId, clientTime)
|
logger.Debug("client time notify, uid: %v, time: %v", userId, clientTime)
|
||||||
player.ClientTime = clientTime
|
player.ClientTime = clientTime
|
||||||
|
now := time.Now().Unix()
|
||||||
|
// 客户端与服务器时间相差太过严重
|
||||||
|
if now-int64(player.ClientTime) > 60 || int64(player.ClientTime)-now > 60 {
|
||||||
|
g.KickPlayer(player.PlayerID, kcp.EnetServerKick)
|
||||||
|
logger.Error("abs of client time and server time above 60, uid: %v", userId)
|
||||||
|
}
|
||||||
|
player.LastKeepaliveTime = uint32(now)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *GameManager) ServerAnnounceNotify(announceId uint32, announceMsg string) {
|
func (g *GameManager) ServerAnnounceNotify(announceId uint32, announceMsg string) {
|
||||||
|
|||||||
@@ -85,6 +85,17 @@ func (t *TickManager) onUserTickSecond(userId uint32, now int64) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (t *TickManager) onUserTickMinute(userId uint32, now int64) {
|
func (t *TickManager) onUserTickMinute(userId uint32, now int64) {
|
||||||
|
player := USER_MANAGER.GetOnlineUser(userId)
|
||||||
|
if player == nil {
|
||||||
|
logger.Error("player is nil, uid: %v", userId)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if uint32(now/1000)-player.LastKeepaliveTime > 60 {
|
||||||
|
logger.Error("remove keepalive timeout user, uid: %v", userId)
|
||||||
|
GAME_MANAGER.OnUserOffline(userId, &ChangeGsInfo{
|
||||||
|
IsChangeGs: false,
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 玩家定时任务常量
|
// 玩家定时任务常量
|
||||||
@@ -182,15 +193,6 @@ func (t *TickManager) onTickMinute(now int64) {
|
|||||||
count := random.GetRandomInt32(0, 4)
|
count := random.GetRandomInt32(0, 4)
|
||||||
i := int32(0)
|
i := int32(0)
|
||||||
for itemId := range allItemDataConfig {
|
for itemId := range allItemDataConfig {
|
||||||
itemDataConfig, ok := allItemDataConfig[itemId]
|
|
||||||
if !ok {
|
|
||||||
logger.Error("config is nil, itemId: %v", itemId)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
// TODO 3.0.0REL版本中 发送某些无效家具 可能会导致客户端背包家具界面卡死
|
|
||||||
if uint16(itemDataConfig.Type) == constant.ITEM_TYPE_FURNITURE {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
num := random.GetRandomInt32(1, 9)
|
num := random.GetRandomInt32(1, 9)
|
||||||
GAME_MANAGER.AddUserItem(player.PlayerID, []*UserItem{{ItemId: uint32(itemId), ChangeCount: uint32(num)}}, true, 0)
|
GAME_MANAGER.AddUserItem(player.PlayerID, []*UserItem{{ItemId: uint32(itemId), ChangeCount: uint32(num)}}, true, 0)
|
||||||
i++
|
i++
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ import (
|
|||||||
const (
|
const (
|
||||||
ENTITY_NUM_UNLIMIT = false // 是否不限制场景内实体数量
|
ENTITY_NUM_UNLIMIT = false // 是否不限制场景内实体数量
|
||||||
ENTITY_MAX_SEND_NUM = 200 // 场景内最大实体数量
|
ENTITY_MAX_SEND_NUM = 200 // 场景内最大实体数量
|
||||||
MAX_MULTIPLAYER_WORLD_NUM = 10 // 本服务器最大多人世界数量
|
MAX_MULTIPLAYER_WORLD_NUM = 2 // 本服务器最大多人世界数量
|
||||||
)
|
)
|
||||||
|
|
||||||
type WorldManager struct {
|
type WorldManager struct {
|
||||||
|
|||||||
@@ -27,12 +27,12 @@ type Avatar struct {
|
|||||||
FetterLevel uint8 `bson:"fetterLevel"` // 好感度等级
|
FetterLevel uint8 `bson:"fetterLevel"` // 好感度等级
|
||||||
FetterExp uint32 `bson:"fetterExp"` // 好感度经验
|
FetterExp uint32 `bson:"fetterExp"` // 好感度经验
|
||||||
PromoteRewardMap map[uint32]bool `bson:"promoteRewardMap"` // 突破奖励 map[突破等级]是否已被领取
|
PromoteRewardMap map[uint32]bool `bson:"promoteRewardMap"` // 突破奖励 map[突破等级]是否已被领取
|
||||||
Guid uint64 `bson:"-"`
|
Guid uint64 `bson:"-" msgpack:"-"`
|
||||||
EquipGuidMap map[uint64]uint64 `bson:"-"`
|
EquipGuidMap map[uint64]uint64 `bson:"-" msgpack:"-"`
|
||||||
EquipWeapon *Weapon `bson:"-"`
|
EquipWeapon *Weapon `bson:"-" msgpack:"-"`
|
||||||
EquipReliquaryList []*Reliquary `bson:"-"`
|
EquipReliquaryList []*Reliquary `bson:"-" msgpack:"-"`
|
||||||
FightPropMap map[uint32]float32 `bson:"-"`
|
FightPropMap map[uint32]float32 `bson:"-" msgpack:"-"`
|
||||||
ExtraAbilityEmbryos map[string]bool `bson:"-"`
|
ExtraAbilityEmbryos map[string]bool `bson:"-" msgpack:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Player) InitAllAvatar() {
|
func (p *Player) InitAllAvatar() {
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import "hk4e/common/constant"
|
|||||||
type Item struct {
|
type Item struct {
|
||||||
ItemId uint32 `bson:"itemId"` // 道具id
|
ItemId uint32 `bson:"itemId"` // 道具id
|
||||||
Count uint32 `bson:"count"` // 道具数量
|
Count uint32 `bson:"count"` // 道具数量
|
||||||
Guid uint64 `bson:"-"`
|
Guid uint64 `bson:"-" msgpack:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Player) InitAllItem() {
|
func (p *Player) InitAllItem() {
|
||||||
|
|||||||
@@ -62,6 +62,7 @@ type Player struct {
|
|||||||
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:"-"` // 上一次保持活跃时间
|
||||||
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映射表
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ type Reliquary struct {
|
|||||||
AffixIdList []uint32 `bson:"affixIdList"` // 词缀
|
AffixIdList []uint32 `bson:"affixIdList"` // 词缀
|
||||||
MainPropId uint32 `bson:"mainPropId"` // 主词条id
|
MainPropId uint32 `bson:"mainPropId"` // 主词条id
|
||||||
AvatarId uint32 `bson:"avatarId"` // 装备角色id
|
AvatarId uint32 `bson:"avatarId"` // 装备角色id
|
||||||
Guid uint64 `bson:"-"`
|
Guid uint64 `bson:"-" msgpack:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Player) InitReliquary(reliquary *Reliquary) {
|
func (p *Player) InitReliquary(reliquary *Reliquary) {
|
||||||
|
|||||||
@@ -36,8 +36,8 @@ type TeamInfo struct {
|
|||||||
TeamList []*Team `bson:"teamList"`
|
TeamList []*Team `bson:"teamList"`
|
||||||
CurrTeamIndex uint8 `bson:"currTeamIndex"`
|
CurrTeamIndex uint8 `bson:"currTeamIndex"`
|
||||||
CurrAvatarIndex uint8 `bson:"currAvatarIndex"`
|
CurrAvatarIndex uint8 `bson:"currAvatarIndex"`
|
||||||
TeamResonances map[uint16]bool `bson:"-"`
|
TeamResonances map[uint16]bool `bson:"-" msgpack:"-"`
|
||||||
TeamResonancesConfig map[int32]bool `bson:"-"`
|
TeamResonancesConfig map[int32]bool `bson:"-" msgpack:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewTeamInfo() (r *TeamInfo) {
|
func NewTeamInfo() (r *TeamInfo) {
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ type Weapon struct {
|
|||||||
AffixIdList []uint32 `bson:"affixIdList"` // 词缀
|
AffixIdList []uint32 `bson:"affixIdList"` // 词缀
|
||||||
Refinement uint8 `bson:"refinement"` // 精炼等阶
|
Refinement uint8 `bson:"refinement"` // 精炼等阶
|
||||||
AvatarId uint32 `bson:"avatarId"` // 装备角色id
|
AvatarId uint32 `bson:"avatarId"` // 装备角色id
|
||||||
Guid uint64 `bson:"-"`
|
Guid uint64 `bson:"-" msgpack:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Player) InitWeapon(weapon *Weapon) {
|
func (p *Player) InitWeapon(weapon *Weapon) {
|
||||||
|
|||||||
Reference in New Issue
Block a user