mirror of
https://github.com/FlourishingWorld/hk4e.git
synced 2026-02-04 15:42:25 +08:00
558 lines
15 KiB
Go
558 lines
15 KiB
Go
package forward
|
|
|
|
import (
|
|
"hk4e/pkg/random"
|
|
"runtime"
|
|
"sync"
|
|
"time"
|
|
|
|
"hk4e/common/config"
|
|
"hk4e/common/region"
|
|
"hk4e/gate/entity/gm"
|
|
"hk4e/gate/kcp"
|
|
"hk4e/gate/net"
|
|
"hk4e/pkg/logger"
|
|
"hk4e/protocol/cmd"
|
|
"hk4e/protocol/proto"
|
|
)
|
|
|
|
const (
|
|
ConnWaitToken = iota
|
|
ConnWaitLogin
|
|
ConnAlive
|
|
ConnClose
|
|
)
|
|
|
|
type ClientHeadMeta struct {
|
|
seq uint32
|
|
}
|
|
|
|
type ForwardManager struct {
|
|
dao string
|
|
protoMsgInput chan *net.ProtoMsg
|
|
protoMsgOutput chan *net.ProtoMsg
|
|
netMsgInput chan *cmd.NetMsg
|
|
netMsgOutput chan *cmd.NetMsg
|
|
// 玩家登录相关
|
|
connStateMap map[uint64]uint8
|
|
connStateMapLock sync.RWMutex
|
|
// kcpConv -> userID
|
|
convUserIdMap map[uint64]uint32
|
|
convUserIdMapLock sync.RWMutex
|
|
// userID -> kcpConv
|
|
userIdConvMap map[uint32]uint64
|
|
userIdConvMapLock sync.RWMutex
|
|
// kcpConv -> ipAddr
|
|
convAddrMap map[uint64]string
|
|
convAddrMapLock sync.RWMutex
|
|
// kcpConv -> headMeta
|
|
convHeadMetaMap map[uint64]*ClientHeadMeta
|
|
convHeadMetaMapLock sync.RWMutex
|
|
// kcpConv -> seed
|
|
convSeedMap map[uint64]uint64
|
|
convSeedMapLock sync.RWMutex
|
|
kcpEventInput chan *net.KcpEvent
|
|
kcpEventOutput chan *net.KcpEvent
|
|
regionCurr *proto.QueryCurrRegionHttpRsp
|
|
signRsaKey []byte
|
|
encRsaKeyMap map[string][]byte
|
|
}
|
|
|
|
func NewForwardManager(
|
|
protoMsgInput chan *net.ProtoMsg, protoMsgOutput chan *net.ProtoMsg,
|
|
kcpEventInput chan *net.KcpEvent, kcpEventOutput chan *net.KcpEvent,
|
|
netMsgInput chan *cmd.NetMsg, netMsgOutput chan *cmd.NetMsg) (r *ForwardManager) {
|
|
r = new(ForwardManager)
|
|
r.protoMsgInput = protoMsgInput
|
|
r.protoMsgOutput = protoMsgOutput
|
|
r.netMsgInput = netMsgInput
|
|
r.netMsgOutput = netMsgOutput
|
|
r.connStateMap = make(map[uint64]uint8)
|
|
r.convUserIdMap = make(map[uint64]uint32)
|
|
r.userIdConvMap = make(map[uint32]uint64)
|
|
r.convAddrMap = make(map[uint64]string)
|
|
r.convHeadMetaMap = make(map[uint64]*ClientHeadMeta)
|
|
r.convSeedMap = make(map[uint64]uint64)
|
|
r.kcpEventInput = kcpEventInput
|
|
r.kcpEventOutput = kcpEventOutput
|
|
return r
|
|
}
|
|
|
|
func (f *ForwardManager) getHeadMsg(clientSeq uint32) (headMsg *proto.PacketHead) {
|
|
headMsg = new(proto.PacketHead)
|
|
if clientSeq != 0 {
|
|
headMsg.ClientSequenceId = clientSeq
|
|
headMsg.SentMs = uint64(time.Now().UnixMilli())
|
|
}
|
|
return headMsg
|
|
}
|
|
|
|
func (f *ForwardManager) kcpEventHandle() {
|
|
for {
|
|
event := <-f.kcpEventOutput
|
|
logger.LOG.Info("rpc manager recv event, ConvId: %v, EventId: %v", event.ConvId, event.EventId)
|
|
switch event.EventId {
|
|
case net.KcpPacketSendNotify:
|
|
// 发包通知
|
|
// 关闭发包监听
|
|
f.kcpEventInput <- &net.KcpEvent{
|
|
ConvId: event.ConvId,
|
|
EventId: net.KcpPacketSendListen,
|
|
EventMessage: "Disable",
|
|
}
|
|
seed, exist := f.getSeedByConvId(event.ConvId)
|
|
if !exist {
|
|
logger.LOG.Error("can not find seed by convId")
|
|
continue
|
|
}
|
|
keyBlock := random.NewKeyBlock(seed)
|
|
xorKey := keyBlock.XorKey()
|
|
key := make([]byte, 4096)
|
|
copy(key, xorKey[:])
|
|
// 改变密钥
|
|
f.kcpEventInput <- &net.KcpEvent{
|
|
ConvId: event.ConvId,
|
|
EventId: net.KcpXorKeyChange,
|
|
EventMessage: key,
|
|
}
|
|
case net.KcpConnCloseNotify:
|
|
// 连接断开通知
|
|
userId, exist := f.getUserIdByConvId(event.ConvId)
|
|
if !exist {
|
|
logger.LOG.Error("can not find userId by convId")
|
|
continue
|
|
}
|
|
if f.getConnState(event.ConvId) == ConnAlive {
|
|
// 通知GS玩家下线
|
|
netMsg := new(cmd.NetMsg)
|
|
netMsg.UserId = userId
|
|
netMsg.EventId = cmd.UserOfflineNotify
|
|
f.netMsgInput <- netMsg
|
|
logger.LOG.Info("send to gs user offline, ConvId: %v, UserId: %v", event.ConvId, netMsg.UserId)
|
|
}
|
|
// 删除各种map数据
|
|
f.deleteConnState(event.ConvId)
|
|
f.deleteUserIdByConvId(event.ConvId)
|
|
currConvId, currExist := f.getConvIdByUserId(userId)
|
|
if currExist && currConvId == event.ConvId {
|
|
// 防止误删顶号的新连接数据
|
|
f.deleteConvIdByUserId(userId)
|
|
}
|
|
f.deleteAddrByConvId(event.ConvId)
|
|
f.deleteHeadMetaByConvId(event.ConvId)
|
|
f.deleteSeedByConvId(event.ConvId)
|
|
case net.KcpConnEstNotify:
|
|
// 连接建立通知
|
|
addr, ok := event.EventMessage.(string)
|
|
if !ok {
|
|
logger.LOG.Error("event KcpConnEstNotify msg type error")
|
|
continue
|
|
}
|
|
f.setAddrByConvId(event.ConvId, addr)
|
|
case net.KcpConnRttNotify:
|
|
// 客户端往返时延通知
|
|
rtt, ok := event.EventMessage.(int32)
|
|
if !ok {
|
|
logger.LOG.Error("event KcpConnRttNotify msg type error")
|
|
continue
|
|
}
|
|
// 通知GS玩家客户端往返时延
|
|
userId, exist := f.getUserIdByConvId(event.ConvId)
|
|
if !exist {
|
|
logger.LOG.Error("can not find userId by convId")
|
|
continue
|
|
}
|
|
netMsg := new(cmd.NetMsg)
|
|
netMsg.UserId = userId
|
|
netMsg.EventId = cmd.ClientRttNotify
|
|
netMsg.ClientRtt = uint32(rtt)
|
|
f.netMsgInput <- netMsg
|
|
case net.KcpConnAddrChangeNotify:
|
|
// 客户端网络地址改变通知
|
|
f.convAddrMapLock.Lock()
|
|
_, exist := f.convAddrMap[event.ConvId]
|
|
if !exist {
|
|
f.convAddrMapLock.Unlock()
|
|
logger.LOG.Error("conn addr change but conn can not be found")
|
|
continue
|
|
}
|
|
addr := event.EventMessage.(string)
|
|
f.convAddrMap[event.ConvId] = addr
|
|
f.convAddrMapLock.Unlock()
|
|
}
|
|
}
|
|
}
|
|
|
|
func (f *ForwardManager) Start() {
|
|
// 读取密钥相关文件
|
|
f.signRsaKey, f.encRsaKeyMap, _ = region.LoadRsaKey()
|
|
// region
|
|
regionCurr, _, _ := region.InitRegion(config.CONF.Hk4e.KcpAddr, config.CONF.Hk4e.KcpPort)
|
|
f.regionCurr = regionCurr
|
|
// kcp事件监听
|
|
go f.kcpEventHandle()
|
|
go f.recvNetMsgFromGameServer()
|
|
// 接收客户端消息
|
|
cpuCoreNum := runtime.NumCPU()
|
|
_ = cpuCoreNum * 10
|
|
for i := 0; i < 1; i++ {
|
|
go f.sendNetMsgToGameServer()
|
|
}
|
|
}
|
|
|
|
// 发送消息到GS
|
|
func (f *ForwardManager) sendNetMsgToGameServer() {
|
|
for {
|
|
protoMsg := <-f.protoMsgOutput
|
|
if protoMsg.HeadMessage == nil {
|
|
logger.LOG.Error("recv null head msg: %v", protoMsg)
|
|
}
|
|
f.setHeadMetaByConvId(protoMsg.ConvId, &ClientHeadMeta{
|
|
seq: protoMsg.HeadMessage.ClientSequenceId,
|
|
})
|
|
connState := f.getConnState(protoMsg.ConvId)
|
|
// gate本地处理的请求
|
|
switch protoMsg.CmdId {
|
|
case cmd.GetPlayerTokenReq:
|
|
// 获取玩家token请求
|
|
if connState != ConnWaitToken {
|
|
continue
|
|
}
|
|
getPlayerTokenReq := protoMsg.PayloadMessage.(*proto.GetPlayerTokenReq)
|
|
getPlayerTokenRsp := f.getPlayerToken(protoMsg.ConvId, getPlayerTokenReq)
|
|
if getPlayerTokenRsp == nil {
|
|
continue
|
|
}
|
|
// 返回数据到客户端
|
|
resp := new(net.ProtoMsg)
|
|
resp.ConvId = protoMsg.ConvId
|
|
resp.CmdId = cmd.GetPlayerTokenRsp
|
|
resp.HeadMessage = f.getHeadMsg(protoMsg.HeadMessage.ClientSequenceId)
|
|
resp.PayloadMessage = getPlayerTokenRsp
|
|
f.protoMsgInput <- resp
|
|
case cmd.PlayerLoginReq:
|
|
// 玩家登录请求
|
|
if connState != ConnWaitLogin {
|
|
continue
|
|
}
|
|
playerLoginReq := protoMsg.PayloadMessage.(*proto.PlayerLoginReq)
|
|
playerLoginRsp := f.playerLogin(protoMsg.ConvId, playerLoginReq)
|
|
if playerLoginRsp == nil {
|
|
continue
|
|
}
|
|
// 返回数据到客户端
|
|
resp := new(net.ProtoMsg)
|
|
resp.ConvId = protoMsg.ConvId
|
|
resp.CmdId = cmd.PlayerLoginRsp
|
|
resp.HeadMessage = f.getHeadMsg(protoMsg.HeadMessage.ClientSequenceId)
|
|
resp.PayloadMessage = playerLoginRsp
|
|
f.protoMsgInput <- resp
|
|
// 登录成功 通知GS初始化相关数据
|
|
userId, exist := f.getUserIdByConvId(protoMsg.ConvId)
|
|
if !exist {
|
|
logger.LOG.Error("can not find userId by convId")
|
|
continue
|
|
}
|
|
headMeta, exist := f.getHeadMetaByConvId(protoMsg.ConvId)
|
|
if !exist {
|
|
logger.LOG.Error("can not find client head metadata by convId")
|
|
continue
|
|
}
|
|
netMsg := new(cmd.NetMsg)
|
|
netMsg.UserId = userId
|
|
netMsg.EventId = cmd.UserLoginNotify
|
|
netMsg.ClientSeq = headMeta.seq
|
|
f.netMsgInput <- netMsg
|
|
logger.LOG.Info("send to gs user login ok, ConvId: %v, UserId: %v", protoMsg.ConvId, netMsg.UserId)
|
|
case cmd.SetPlayerBornDataReq:
|
|
// 玩家注册请求
|
|
if connState != ConnAlive {
|
|
continue
|
|
}
|
|
userId, exist := f.getUserIdByConvId(protoMsg.ConvId)
|
|
if !exist {
|
|
logger.LOG.Error("can not find userId by convId")
|
|
continue
|
|
}
|
|
netMsg := new(cmd.NetMsg)
|
|
netMsg.UserId = userId
|
|
netMsg.EventId = cmd.UserRegNotify
|
|
netMsg.CmdId = cmd.SetPlayerBornDataReq
|
|
netMsg.ClientSeq = protoMsg.HeadMessage.ClientSequenceId
|
|
netMsg.PayloadMessage = protoMsg.PayloadMessage
|
|
f.netMsgInput <- netMsg
|
|
case cmd.PlayerForceExitRsp:
|
|
// 玩家退出游戏请求
|
|
if connState != ConnAlive {
|
|
continue
|
|
}
|
|
userId, exist := f.getUserIdByConvId(protoMsg.ConvId)
|
|
if !exist {
|
|
logger.LOG.Error("can not find userId by convId")
|
|
continue
|
|
}
|
|
f.setConnState(protoMsg.ConvId, ConnClose)
|
|
info := new(gm.KickPlayerInfo)
|
|
info.UserId = userId
|
|
info.Reason = uint32(kcp.EnetServerKick)
|
|
f.KickPlayer(info)
|
|
case cmd.PingReq:
|
|
// ping请求
|
|
if connState != ConnAlive {
|
|
continue
|
|
}
|
|
pingReq := protoMsg.PayloadMessage.(*proto.PingReq)
|
|
logger.LOG.Debug("user ping req, data: %v", pingReq.String())
|
|
// 返回数据到客户端
|
|
// TODO 记录客户端最后一次ping时间做超时下线处理
|
|
pingRsp := new(proto.PingRsp)
|
|
pingRsp.ClientTime = pingReq.ClientTime
|
|
resp := new(net.ProtoMsg)
|
|
resp.ConvId = protoMsg.ConvId
|
|
resp.CmdId = cmd.PingRsp
|
|
resp.HeadMessage = f.getHeadMsg(protoMsg.HeadMessage.ClientSequenceId)
|
|
resp.PayloadMessage = pingRsp
|
|
f.protoMsgInput <- resp
|
|
// 通知GS玩家客户端的本地时钟
|
|
userId, exist := f.getUserIdByConvId(protoMsg.ConvId)
|
|
if !exist {
|
|
logger.LOG.Error("can not find userId by convId")
|
|
continue
|
|
}
|
|
netMsg := new(cmd.NetMsg)
|
|
netMsg.UserId = userId
|
|
netMsg.EventId = cmd.ClientTimeNotify
|
|
netMsg.ClientTime = pingReq.ClientTime
|
|
f.netMsgInput <- netMsg
|
|
default:
|
|
// 转发到GS
|
|
// 未登录禁止访问GS
|
|
if connState != ConnAlive {
|
|
continue
|
|
}
|
|
netMsg := new(cmd.NetMsg)
|
|
userId, exist := f.getUserIdByConvId(protoMsg.ConvId)
|
|
if exist {
|
|
netMsg.UserId = userId
|
|
} else {
|
|
logger.LOG.Error("can not find userId by convId")
|
|
continue
|
|
}
|
|
netMsg.EventId = cmd.NormalMsg
|
|
netMsg.CmdId = protoMsg.CmdId
|
|
netMsg.ClientSeq = protoMsg.HeadMessage.ClientSequenceId
|
|
netMsg.PayloadMessage = protoMsg.PayloadMessage
|
|
f.netMsgInput <- netMsg
|
|
}
|
|
}
|
|
}
|
|
|
|
// 从GS接收消息
|
|
func (f *ForwardManager) recvNetMsgFromGameServer() {
|
|
for {
|
|
netMsg := <-f.netMsgOutput
|
|
convId, exist := f.getConvIdByUserId(netMsg.UserId)
|
|
if !exist {
|
|
logger.LOG.Error("can not find convId by userId")
|
|
continue
|
|
}
|
|
if netMsg.EventId == cmd.NormalMsg {
|
|
protoMsg := new(net.ProtoMsg)
|
|
protoMsg.ConvId = convId
|
|
protoMsg.CmdId = netMsg.CmdId
|
|
protoMsg.HeadMessage = f.getHeadMsg(netMsg.ClientSeq)
|
|
protoMsg.PayloadMessage = netMsg.PayloadMessage
|
|
f.protoMsgInput <- protoMsg
|
|
} else {
|
|
logger.LOG.Error("recv unknown event from game server, event id: %v", netMsg.EventId)
|
|
}
|
|
}
|
|
}
|
|
|
|
func (f *ForwardManager) getConnState(convId uint64) uint8 {
|
|
f.connStateMapLock.RLock()
|
|
connState, connStateExist := f.connStateMap[convId]
|
|
f.connStateMapLock.RUnlock()
|
|
if !connStateExist {
|
|
connState = ConnWaitToken
|
|
f.connStateMapLock.Lock()
|
|
f.connStateMap[convId] = ConnWaitToken
|
|
f.connStateMapLock.Unlock()
|
|
}
|
|
return connState
|
|
}
|
|
|
|
func (f *ForwardManager) setConnState(convId uint64, state uint8) {
|
|
f.connStateMapLock.Lock()
|
|
f.connStateMap[convId] = state
|
|
f.connStateMapLock.Unlock()
|
|
}
|
|
|
|
func (f *ForwardManager) deleteConnState(convId uint64) {
|
|
f.connStateMapLock.Lock()
|
|
delete(f.connStateMap, convId)
|
|
f.connStateMapLock.Unlock()
|
|
}
|
|
|
|
func (f *ForwardManager) getUserIdByConvId(convId uint64) (userId uint32, exist bool) {
|
|
f.convUserIdMapLock.RLock()
|
|
userId, exist = f.convUserIdMap[convId]
|
|
f.convUserIdMapLock.RUnlock()
|
|
return userId, exist
|
|
}
|
|
|
|
func (f *ForwardManager) setUserIdByConvId(convId uint64, userId uint32) {
|
|
f.convUserIdMapLock.Lock()
|
|
f.convUserIdMap[convId] = userId
|
|
f.convUserIdMapLock.Unlock()
|
|
}
|
|
|
|
func (f *ForwardManager) deleteUserIdByConvId(convId uint64) {
|
|
f.convUserIdMapLock.Lock()
|
|
delete(f.convUserIdMap, convId)
|
|
f.convUserIdMapLock.Unlock()
|
|
}
|
|
|
|
func (f *ForwardManager) getConvIdByUserId(userId uint32) (convId uint64, exist bool) {
|
|
f.userIdConvMapLock.RLock()
|
|
convId, exist = f.userIdConvMap[userId]
|
|
f.userIdConvMapLock.RUnlock()
|
|
return convId, exist
|
|
}
|
|
|
|
func (f *ForwardManager) setConvIdByUserId(userId uint32, convId uint64) {
|
|
f.userIdConvMapLock.Lock()
|
|
f.userIdConvMap[userId] = convId
|
|
f.userIdConvMapLock.Unlock()
|
|
}
|
|
|
|
func (f *ForwardManager) deleteConvIdByUserId(userId uint32) {
|
|
f.userIdConvMapLock.Lock()
|
|
delete(f.userIdConvMap, userId)
|
|
f.userIdConvMapLock.Unlock()
|
|
}
|
|
|
|
func (f *ForwardManager) getAddrByConvId(convId uint64) (addr string, exist bool) {
|
|
f.convAddrMapLock.RLock()
|
|
addr, exist = f.convAddrMap[convId]
|
|
f.convAddrMapLock.RUnlock()
|
|
return addr, exist
|
|
}
|
|
|
|
func (f *ForwardManager) setAddrByConvId(convId uint64, addr string) {
|
|
f.convAddrMapLock.Lock()
|
|
f.convAddrMap[convId] = addr
|
|
f.convAddrMapLock.Unlock()
|
|
}
|
|
|
|
func (f *ForwardManager) deleteAddrByConvId(convId uint64) {
|
|
f.convAddrMapLock.Lock()
|
|
delete(f.convAddrMap, convId)
|
|
f.convAddrMapLock.Unlock()
|
|
}
|
|
|
|
func (f *ForwardManager) getHeadMetaByConvId(convId uint64) (headMeta *ClientHeadMeta, exist bool) {
|
|
f.convHeadMetaMapLock.RLock()
|
|
headMeta, exist = f.convHeadMetaMap[convId]
|
|
f.convHeadMetaMapLock.RUnlock()
|
|
return headMeta, exist
|
|
}
|
|
|
|
func (f *ForwardManager) setHeadMetaByConvId(convId uint64, headMeta *ClientHeadMeta) {
|
|
f.convHeadMetaMapLock.Lock()
|
|
f.convHeadMetaMap[convId] = headMeta
|
|
f.convHeadMetaMapLock.Unlock()
|
|
}
|
|
|
|
func (f *ForwardManager) deleteHeadMetaByConvId(convId uint64) {
|
|
f.convHeadMetaMapLock.Lock()
|
|
delete(f.convHeadMetaMap, convId)
|
|
f.convHeadMetaMapLock.Unlock()
|
|
}
|
|
|
|
func (f *ForwardManager) getSeedByConvId(convId uint64) (seed uint64, exist bool) {
|
|
f.convSeedMapLock.RLock()
|
|
seed, exist = f.convSeedMap[convId]
|
|
f.convSeedMapLock.RUnlock()
|
|
return seed, exist
|
|
}
|
|
|
|
func (f *ForwardManager) setSeedByConvId(convId uint64, seed uint64) {
|
|
f.convSeedMapLock.Lock()
|
|
f.convSeedMap[convId] = seed
|
|
f.convSeedMapLock.Unlock()
|
|
}
|
|
|
|
func (f *ForwardManager) deleteSeedByConvId(convId uint64) {
|
|
f.convSeedMapLock.Lock()
|
|
delete(f.convSeedMap, convId)
|
|
f.convSeedMapLock.Unlock()
|
|
}
|
|
|
|
// 改变网关开放状态
|
|
func (f *ForwardManager) ChangeGateOpenState(isOpen bool) bool {
|
|
f.kcpEventInput <- &net.KcpEvent{
|
|
EventId: net.KcpGateOpenState,
|
|
EventMessage: isOpen,
|
|
}
|
|
logger.LOG.Info("change gate open state to: %v", isOpen)
|
|
return true
|
|
}
|
|
|
|
// 踢出玩家下线
|
|
func (f *ForwardManager) KickPlayer(info *gm.KickPlayerInfo) bool {
|
|
if info == nil {
|
|
return false
|
|
}
|
|
convId, exist := f.getConvIdByUserId(info.UserId)
|
|
if !exist {
|
|
return false
|
|
}
|
|
f.kcpEventInput <- &net.KcpEvent{
|
|
ConvId: convId,
|
|
EventId: net.KcpConnForceClose,
|
|
EventMessage: info.Reason,
|
|
}
|
|
return true
|
|
}
|
|
|
|
// 获取网关在线玩家信息
|
|
func (f *ForwardManager) GetOnlineUser(uid uint32) (list *gm.OnlineUserList) {
|
|
list = &gm.OnlineUserList{
|
|
UserList: make([]*gm.OnlineUserInfo, 0),
|
|
}
|
|
if uid == 0 {
|
|
// 获取全部玩家
|
|
f.convUserIdMapLock.RLock()
|
|
f.convAddrMapLock.RLock()
|
|
for convId, userId := range f.convUserIdMap {
|
|
addr := f.convAddrMap[convId]
|
|
info := &gm.OnlineUserInfo{
|
|
Uid: userId,
|
|
ConvId: convId,
|
|
Addr: addr,
|
|
}
|
|
list.UserList = append(list.UserList, info)
|
|
}
|
|
f.convAddrMapLock.RUnlock()
|
|
f.convUserIdMapLock.RUnlock()
|
|
} else {
|
|
// 获取指定uid玩家
|
|
convId, exist := f.getConvIdByUserId(uid)
|
|
if !exist {
|
|
return list
|
|
}
|
|
addr, exist := f.getAddrByConvId(convId)
|
|
if !exist {
|
|
return list
|
|
}
|
|
info := &gm.OnlineUserInfo{
|
|
Uid: uid,
|
|
ConvId: convId,
|
|
Addr: addr,
|
|
}
|
|
list.UserList = append(list.UserList, info)
|
|
}
|
|
return list
|
|
}
|