添加了节点服务器,各个服务器之间支持多对多

This commit is contained in:
flswld committed 2022-12-24 04:14:33 +08:00
1 parent 16dd9c1e87
commit 7e86669628
92 files changed
+1429 -287

No files matched your search

+5 -1
View File
@@ -23,6 +23,10 @@ gen:
--go_out=paths=source_relative:gs/api \
--natsrpc_out=paths=source_relative:gs/api \
gs/api/*.proto
protoc \
--proto_path=node/api \
--go_out=paths=source_relative:node/api \
--natsrpc_out=paths=source_relative:node/api \
node/api/*.proto
#cd protocol/proto && make gen
+9 -8
View File
@@ -4,19 +4,20 @@ hk4e game server
## 开发快速上手
* Go >= 1.19
* Go >= 1.18
1. 首次需要安装工具 `make dev_tool`
1. 生成协议 `make gen`
2. 生成协议 `make gen`
## 快速运行
* mongodb
* nats-server
1. 启动http登录服务器 `cmd/dispatch && go run .`
2. 启动网关服务器 `cd cmd/gate && go run .`
3. 启动游戏服务器 `cd cmd/gs && go run .`
4. 启动游戏管理服务器 `cmd/gm && go run .`
5. 启动战斗服务器 `cmd/fight && go run .`
6. 启动寻路服务器 `cmd/pathfinding && go run .`
1. 启动节点服务器 `cmd/node && go run .`
2. 启动http登录服务器 `cmd/dispatch && go run .`
3. 启动网关服务器 `cd cmd/gate && go run .`
4. 启动战斗服务器 `cmd/fight && go run .`
5. 启动寻路服务器 `cmd/pathfinding && go run .`
6. 启动游戏服务器 `cd cmd/gs && go run .`
7. 启动游戏管理服务器 `cmd/gm && go run .`
+7 -1
View File
@@ -8,6 +8,7 @@ import (
"os"
"hk4e/dispatch/app"
"hk4e/pkg/statsviz_serve"
)
var (
@@ -16,7 +17,12 @@ var (
func main() {
flag.Parse()
// go statsviz_serve.Serve("0.0.0.0:2345")
go func() {
err := statsviz_serve.Serve("0.0.0.0:2345")
if err != nil {
panic(err)
}
}()
err := app.Run(context.TODO(), *config)
if err != nil {
fmt.Println(err)
+4 -1
View File
@@ -8,6 +8,7 @@ import (
"os"
"hk4e/fight/app"
"hk4e/pkg/statsviz_serve"
)
var (
@@ -16,7 +17,9 @@ var (
func main() {
flag.Parse()
// go statsviz_serve.Serve("0.0.0.0:2345")
go func() {
_ = statsviz_serve.Serve("0.0.0.0:5678")
}()
err := app.Run(context.TODO(), *config)
if err != nil {
fmt.Println(err)
+3 -1
View File
@@ -17,7 +17,9 @@ var (
func main() {
flag.Parse()
go statsviz_serve.Serve("0.0.0.0:2345")
go func() {
_ = statsviz_serve.Serve("0.0.0.0:3456")
}()
err := app.Run(context.TODO(), *config)
if err != nil {
fmt.Println(err)
+8
View File
@@ -4,9 +4,11 @@ import (
"context"
"flag"
"fmt"
_ "net/http/pprof"
"os"
"hk4e/gm/app"
"hk4e/pkg/statsviz_serve"
)
var (
@@ -15,6 +17,12 @@ var (
func main() {
flag.Parse()
go func() {
err := statsviz_serve.Serve("0.0.0.0:7890")
if err != nil {
panic(err)
}
}()
err := app.Run(context.TODO(), *config)
if err != nil {
fmt.Println(err)
+3 -1
View File
@@ -17,7 +17,9 @@ var (
func main() {
flag.Parse()
go statsviz_serve.Serve("0.0.0.0:3456")
go func() {
_ = statsviz_serve.Serve("0.0.0.0:4567")
}()
err := app.Run(context.TODO(), *config)
if err != nil {
fmt.Println(err)
+23
View File
@@ -0,0 +1,23 @@
package main
import (
"context"
"hk4e/node/app"
"github.com/spf13/cobra"
)
// NodeCmd 检查配表命令
func NodeCmd() *cobra.Command {
var cfg string
c := &cobra.Command{
Use: "node",
Short: "node server",
RunE: func(cmd *cobra.Command, args []string) error {
return app.Run(context.Background(), cfg)
},
}
c.Flags().StringVar(&cfg, "config", "application.toml", "config file")
return c
}
+12
View File
@@ -0,0 +1,12 @@
[hk4e]
kcp_addr = "127.0.0.1"
kcp_port = 22103
[logger]
level = "DEBUG"
mode = "BOTH"
track = true
max_size = 10485760
[mq]
nats_url = "nats://nats:4222"
+31
View File
@@ -0,0 +1,31 @@
package main
import (
"context"
"flag"
"fmt"
_ "net/http/pprof"
"os"
"hk4e/node/app"
"hk4e/pkg/statsviz_serve"
)
var (
config = flag.String("config", "application.toml", "config file")
)
func main() {
flag.Parse()
go func() {
err := statsviz_serve.Serve("0.0.0.0:1234")
if err != nil {
panic(err)
}
}()
err := app.Run(context.TODO(), *config)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
}
+4 -1
View File
@@ -8,6 +8,7 @@ import (
"os"
"hk4e/pathfinding/app"
"hk4e/pkg/statsviz_serve"
)
var (
@@ -16,7 +17,9 @@ var (
func main() {
flag.Parse()
// go statsviz_serve.Serve("0.0.0.0:2345")
go func() {
_ = statsviz_serve.Serve("0.0.0.0:6789")
}()
err := app.Run(context.TODO(), *config)
if err != nil {
fmt.Println(err)
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
+10
View File
@@ -10,12 +10,20 @@ import (
pb "google.golang.org/protobuf/proto"
)
// 用于服务器之间传输游戏协议
// 仅用于传递数据平面(client<--->server)和控制平面(server<--->server)的消息
// 目前是全部消息都走NATS 之后可以做优化服务器之间socket直连
// 请不要用这个来搞RPC写一大堆异步回调!!!
// 要用RPC有专门的NATSRPC
type MessageQueue struct {
natsConn *nats.Conn
natsMsgChan chan *nats.Msg
netMsgInput chan *NetMsg
netMsgOutput chan *NetMsg
cmdProtoMap *cmd.CmdProtoMap
serverType string
appId string
}
func NewMessageQueue(serverType string, appId string) (r *MessageQueue) {
@@ -35,6 +43,8 @@ func NewMessageQueue(serverType string, appId string) (r *MessageQueue) {
r.netMsgInput = make(chan *NetMsg, 1000)
r.netMsgOutput = make(chan *NetMsg, 1000)
r.cmdProtoMap = cmd.NewCmdProtoMap()
r.serverType = serverType
r.appId = appId
go r.recvHandler()
go r.sendHandler()
return r
+21 -16
View File
@@ -9,12 +9,14 @@ const (
)
type NetMsg struct {
MsgType uint8 `msgpack:"MsgType"`
EventId uint16 `msgpack:"EventId"`
Topic string `msgpack:"-"`
GameMsg *GameMsg `msgpack:"GameMsg"`
FightMsg *FightMsg `msgpack:"FightMsg"`
ConnCtrlMsg *ConnCtrlMsg `msgpack:"ConnCtrlMsg"`
MsgType uint8 `msgpack:"MsgType"`
EventId uint16 `msgpack:"EventId"`
Topic string `msgpack:"-"`
GameMsg *GameMsg `msgpack:"GameMsg"`
FightMsg *FightMsg `msgpack:"FightMsg"`
ConnCtrlMsg *ConnCtrlMsg `msgpack:"ConnCtrlMsg"`
OriginServerType string `msgpack:"OriginServerType"`
OriginServerAppId string `msgpack:"OriginServerAppId"`
}
const (
@@ -33,15 +35,17 @@ type GameMsg struct {
const (
ClientRttNotify = iota
ClientTimeNotify
FightServerSelectNotify
KickPlayerNotify
)
type ConnCtrlMsg struct {
UserId uint32 `msgpack:"UserId"`
ClientRtt uint32 `msgpack:"ClientRtt"`
ClientTime uint32 `msgpack:"ClientTime"`
KickUserId uint32 `msgpack:"KickUserId"`
KickReason uint32 `msgpack:"KickReason"`
UserId uint32 `msgpack:"UserId"`
ClientRtt uint32 `msgpack:"ClientRtt"`
ClientTime uint32 `msgpack:"ClientTime"`
FightServerAppId string `msgpack:"FightServerAppId"`
KickUserId uint32 `msgpack:"KickUserId"`
KickReason uint32 `msgpack:"KickReason"`
}
const (
@@ -52,9 +56,10 @@ const (
)
type FightMsg struct {
FightRoutineId uint32 `msgpack:"FightRoutineId"`
EntityId uint32 `msgpack:"EntityId"`
FightPropMap map[uint32]float32 `msgpack:"FightPropMap"`
Uid uint32 `msgpack:"Uid"`
AvatarGuid uint64 `msgpack:"AvatarGuid"`
FightRoutineId uint32 `msgpack:"FightRoutineId"`
EntityId uint32 `msgpack:"EntityId"`
FightPropMap map[uint32]float32 `msgpack:"FightPropMap"`
Uid uint32 `msgpack:"Uid"`
AvatarGuid uint64 `msgpack:"AvatarGuid"`
GateServerAppId string `msgpack:"GateServerAppId"`
}
+23 -12
View File
@@ -1,37 +1,48 @@
package mq
import (
"strings"
"hk4e/node/api"
)
const (
GATE = "GATE_${APPID}_HK4E"
GS = "GS_${APPID}_HK4E"
FIGHT = "FIGHT_${APPID}_HK4E"
PATHFINDING = "PATHFINDING_${APPID}_HK4E"
)
func (m *MessageQueue) getOriginServer() (originServerType string, originServerAppId string) {
originServerType = m.serverType
originServerAppId = m.appId
return originServerType, originServerAppId
}
func (m *MessageQueue) getTopic(serverType string, appId string) string {
topic := strings.ReplaceAll(serverType, "${APPID}", appId)
topic := serverType + "_" + appId + "_" + "HK4E"
return topic
}
func (m *MessageQueue) SendToGate(appId string, netMsg *NetMsg) {
netMsg.Topic = m.getTopic(GATE, appId)
netMsg.Topic = m.getTopic(api.GATE, appId)
originServerType, originServerAppId := m.getOriginServer()
netMsg.OriginServerType = originServerType
netMsg.OriginServerAppId = originServerAppId
m.netMsgInput <- netMsg
}
func (m *MessageQueue) SendToGs(appId string, netMsg *NetMsg) {
netMsg.Topic = m.getTopic(GS, appId)
netMsg.Topic = m.getTopic(api.GS, appId)
originServerType, originServerAppId := m.getOriginServer()
netMsg.OriginServerType = originServerType
netMsg.OriginServerAppId = originServerAppId
m.netMsgInput <- netMsg
}
func (m *MessageQueue) SendToFight(appId string, netMsg *NetMsg) {
netMsg.Topic = m.getTopic(FIGHT, appId)
netMsg.Topic = m.getTopic(api.FIGHT, appId)
originServerType, originServerAppId := m.getOriginServer()
netMsg.OriginServerType = originServerType
netMsg.OriginServerAppId = originServerAppId
m.netMsgInput <- netMsg
}
func (m *MessageQueue) SendToPathfinding(appId string, netMsg *NetMsg) {
netMsg.Topic = m.getTopic(PATHFINDING, appId)
netMsg.Topic = m.getTopic(api.PATHFINDING, appId)
originServerType, originServerAppId := m.getOriginServer()
netMsg.OriginServerType = originServerType
netMsg.OriginServerAppId = originServerAppId
m.netMsgInput <- netMsg
}
+4 -1
View File
@@ -33,8 +33,11 @@ func LoadRsaKey() (signRsaKey []byte, encRsaKeyMap map[string][]byte, pwdRsaKey
return signRsaKey, encRsaKeyMap, pwdRsaKey
}
func InitRegion(kcpAddr string, kcpPort int32) (*proto.QueryCurrRegionHttpRsp, *proto.QueryRegionListHttpRsp, *random.Ec2b) {
func InitRegion(kcpAddr string, kcpPort int32, ec2b *random.Ec2b) (*proto.QueryCurrRegionHttpRsp, *proto.QueryRegionListHttpRsp, *random.Ec2b) {
dispatchEc2b := random.NewEc2b()
if ec2b != nil {
dispatchEc2b = ec2b
}
dispatchEc2bData := dispatchEc2b.Bytes()
dispatchXorKey := dispatchEc2b.XorKey()
// RegionCurr
+81
View File
@@ -0,0 +1,81 @@
package rpc
import (
"hk4e/common/config"
gsapi "hk4e/gs/api"
nodeapi "hk4e/node/api"
"github.com/nats-io/nats.go"
"github.com/nats-io/nats.go/encoders/protobuf"
)
// Client natsrpc客户端
type Client struct {
conn *nats.Conn
Discovery *DiscoveryClient
GM *GMClient
}
// NewClient 构造
func NewClient() (*Client, error) {
r := new(Client)
conn, err := nats.Connect(config.CONF.MQ.NatsUrl)
if err != nil {
return nil, err
}
r.conn = conn
discoveryClient, err := newDiscoveryClient(conn)
if err != nil {
return nil, err
}
r.Discovery = discoveryClient
gmClient, err := newGmClient(conn)
if err != nil {
return nil, err
}
r.GM = gmClient
return r, nil
}
// Close 销毁
func (c *Client) Close() {
c.conn.Close()
}
// DiscoveryClient node的discovery服务
type DiscoveryClient struct {
nodeapi.DiscoveryNATSRPCClient
}
func newDiscoveryClient(conn *nats.Conn) (*DiscoveryClient, error) {
enc, err := nats.NewEncodedConn(conn, protobuf.PROTOBUF_ENCODER)
if err != nil {
return nil, err
}
cli, err := nodeapi.NewDiscoveryNATSRPCClient(enc)
if err != nil {
return nil, err
}
return &DiscoveryClient{
DiscoveryNATSRPCClient: cli,
}, nil
}
// GMClient gs的gm服务
type GMClient struct {
gsapi.GMNATSRPCClient
}
func newGmClient(conn *nats.Conn) (*GMClient, error) {
enc, err := nats.NewEncodedConn(conn, protobuf.PROTOBUF_ENCODER)
if err != nil {
return nil, err
}
cli, err := gsapi.NewGMNATSRPCClient(enc)
if err != nil {
return nil, err
}
return &GMClient{
GMNATSRPCClient: cli,
}, nil
}
+7 -1
View File
@@ -9,6 +9,7 @@ import (
"time"
"hk4e/common/config"
"hk4e/common/rpc"
"hk4e/dispatch/controller"
"hk4e/dispatch/dao"
"hk4e/pkg/logger"
@@ -23,7 +24,12 @@ func Run(ctx context.Context, configFile string) error {
db := dao.NewDao()
defer db.CloseDao()
_ = controller.NewController(db)
client, err := rpc.NewClient()
if err != nil {
return err
}
_ = controller.NewController(db, client.Discovery)
c := make(chan os.Signal, 1)
signal.Notify(c, syscall.SIGHUP, syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGINT)
+17 -5
View File
@@ -1,13 +1,16 @@
package controller
import (
"context"
"encoding/base64"
"net/http"
"strconv"
"hk4e/common/config"
"hk4e/common/region"
"hk4e/common/rpc"
"hk4e/dispatch/dao"
"hk4e/node/api"
"hk4e/pkg/logger"
"hk4e/pkg/random"
@@ -17,22 +20,32 @@ import (
type Controller struct {
dao *dao.Dao
discovery *rpc.DiscoveryClient
regionListBase64 string
regionCurrBase64 string
signRsaKey []byte
encRsaKeyMap map[string][]byte
pwdRsaKey []byte
dispatchEc2b *random.Ec2b
}
func NewController(dao *dao.Dao) (r *Controller) {
func NewController(dao *dao.Dao, discovery *rpc.DiscoveryClient) (r *Controller) {
r = new(Controller)
r.dao = dao
r.discovery = discovery
r.regionListBase64 = ""
r.regionCurrBase64 = ""
regionCurr, regionList, dispatchEc2b := region.InitRegion(config.CONF.Hk4e.KcpAddr, config.CONF.Hk4e.KcpPort)
r.dispatchEc2b = dispatchEc2b
r.signRsaKey, r.encRsaKeyMap, r.pwdRsaKey = region.LoadRsaKey()
rsp, err := r.discovery.GetRegionEc2B(context.TODO(), &api.NullMsg{})
if err != nil {
logger.Error("get region ec2b error: %v", err)
return nil
}
ec2b, err := random.LoadEc2bKey(rsp.Data)
if err != nil {
logger.Error("parse region ec2b error: %v", err)
return nil
}
regionCurr, regionList, _ := region.InitRegion(config.CONF.Hk4e.KcpAddr, config.CONF.Hk4e.KcpPort, ec2b)
regionCurrModify, err := pb.Marshal(regionCurr)
if err != nil {
logger.Error("Marshal QueryCurrRegionHttpRsp error")
@@ -143,7 +156,6 @@ func (c *Controller) registerRouter() {
}
engine.Use(c.authorize())
engine.POST("/gate/token/verify", c.gateTokenVerify)
engine.GET("/dispatch/ec2b/seed", c.getDispatchEc2bSeed)
port := config.CONF.HttpPort
addr := ":" + strconv.Itoa(int(port))
err := engine.Run(addr)
-11
View File
@@ -49,14 +49,3 @@ func (c *Controller) gateTokenVerify(context *gin.Context) {
PlayerID: uint32(account.PlayerID),
})
}
type DispatchEc2bSeedRsp struct {
Seed string `json:"seed"`
}
func (c *Controller) getDispatchEc2bSeed(context *gin.Context) {
dispatchEc2bSeed := c.dispatchEc2b.Seed()
context.JSON(http.StatusOK, &DispatchEc2bSeedRsp{
Seed: strconv.FormatUint(dispatchEc2bSeed, 10),
})
}
+24 -5
View File
@@ -9,21 +9,40 @@ import (
"time"
"hk4e/common/config"
"hk4e/common/constant"
"hk4e/common/mq"
"hk4e/common/rpc"
"hk4e/fight/engine"
"hk4e/gs/constant"
"hk4e/node/api"
"hk4e/pkg/logger"
)
var APPID string
func Run(ctx context.Context, configFile string) error {
config.InitConfig(configFile)
logger.InitLogger("fight")
logger.Warn("fight start")
// natsrpc client
client, err := rpc.NewClient()
if err != nil {
return err
}
// 注册到节点服务器
rsp, err := client.Discovery.RegisterServer(context.TODO(), &api.RegisterServerReq{
ServerType: api.FIGHT,
})
if err != nil {
return err
}
APPID = rsp.GetAppId()
logger.InitLogger("fight_" + APPID)
logger.Warn("fight start, appid: %v", APPID)
constant.InitConstant()
messageQueue := mq.NewMessageQueue(mq.FIGHT, "1")
messageQueue := mq.NewMessageQueue(api.FIGHT, APPID)
defer messageQueue.Close()
_ = engine.NewFightEngine(messageQueue)
@@ -38,7 +57,7 @@ func Run(ctx context.Context, configFile string) error {
logger.Warn("get a signal %s", s.String())
switch s {
case syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGINT:
logger.Warn("fight exit")
logger.Warn("fight exit, appid: %v", APPID)
time.Sleep(time.Second)
return nil
case syscall.SIGHUP:
+37 -15
View File
@@ -3,8 +3,8 @@ package engine
import (
"time"
"hk4e/common/constant"
"hk4e/common/mq"
"hk4e/gs/constant"
"hk4e/pkg/logger"
"hk4e/protocol/cmd"
"hk4e/protocol/proto"
@@ -29,16 +29,24 @@ func (f *FightEngine) fightHandle() {
userIdFightRoutineIdMap := make(map[uint32]uint32)
for {
netMsg := <-f.messageQueue.GetNetMsg()
// logger.Debug("recv net msg, netMsg: %v", netMsg)
logger.Debug("recv net msg, netMsg: %v", netMsg)
switch netMsg.MsgType {
case mq.MsgTypeGame:
gameMsg := netMsg.GameMsg
if netMsg.EventId != mq.NormalMsg {
continue
}
// logger.Debug("recv game msg, gameMsg: %v", gameMsg)
fightRoutineId := userIdFightRoutineIdMap[gameMsg.UserId]
fightRoutineMsgChan := fightRoutineMsgChanMap[fightRoutineId]
logger.Debug("recv game msg, gameMsg: %v", gameMsg)
fightRoutineId, exist := userIdFightRoutineIdMap[gameMsg.UserId]
if !exist {
logger.Error("could not found fight routine id by uid: %v", gameMsg.UserId)
continue
}
fightRoutineMsgChan, exist := fightRoutineMsgChanMap[fightRoutineId]
if !exist {
logger.Error("could not found fight routine msg chan by fight routine id: %v", fightRoutineId)
continue
}
fightRoutineMsgChan <- netMsg
case mq.MsgTypeFight:
fightMsg := netMsg.FightMsg
@@ -49,21 +57,33 @@ func (f *FightEngine) fightHandle() {
fightRoutineMsgChanMap[fightMsg.FightRoutineId] = fightRoutineMsgChan
fightRoutineCloseChan := make(chan bool, 1)
fightRoutineCloseChanMap[fightMsg.FightRoutineId] = fightRoutineCloseChan
go runFightRoutine(fightMsg.FightRoutineId, fightRoutineMsgChan, fightRoutineCloseChan, f.messageQueue)
go runFightRoutine(fightMsg.FightRoutineId, fightMsg.GateServerAppId, fightRoutineMsgChan, fightRoutineCloseChan, f.messageQueue)
case mq.DelFightRoutine:
fightRoutineCloseChan := fightRoutineCloseChanMap[fightMsg.FightRoutineId]
fightRoutineCloseChan, exist := fightRoutineCloseChanMap[fightMsg.FightRoutineId]
if !exist {
logger.Error("could not found fight routine close chan by fight routine id: %v", fightMsg.FightRoutineId)
continue
}
fightRoutineCloseChan <- true
case mq.FightRoutineAddEntity:
if fightMsg.Uid != 0 {
userIdFightRoutineIdMap[fightMsg.Uid] = fightMsg.FightRoutineId
}
fightRoutineMsgChan := fightRoutineMsgChanMap[fightMsg.FightRoutineId]
fightRoutineMsgChan, exist := fightRoutineMsgChanMap[fightMsg.FightRoutineId]
if !exist {
logger.Error("could not found fight routine msg chan by fight routine id: %v", fightMsg.FightRoutineId)
continue
}
fightRoutineMsgChan <- netMsg
case mq.FightRoutineDelEntity:
if fightMsg.Uid != 0 {
delete(userIdFightRoutineIdMap, fightMsg.Uid)
}
fightRoutineMsgChan := fightRoutineMsgChanMap[fightMsg.FightRoutineId]
fightRoutineMsgChan, exist := fightRoutineMsgChanMap[fightMsg.FightRoutineId]
if !exist {
logger.Error("could not found fight routine msg chan by fight routine id: %v", fightMsg.FightRoutineId)
continue
}
fightRoutineMsgChan <- netMsg
}
}
@@ -71,7 +91,7 @@ func (f *FightEngine) fightHandle() {
}
// SendMsg 发送消息给客户端
func SendMsg(messageQueue *mq.MessageQueue, cmdId uint16, userId uint32, payloadMsg pb.Message) {
func SendMsg(messageQueue *mq.MessageQueue, cmdId uint16, userId uint32, gateAppId string, payloadMsg pb.Message) {
if userId < 100000000 || payloadMsg == nil {
return
}
@@ -86,7 +106,7 @@ func SendMsg(messageQueue *mq.MessageQueue, cmdId uint16, userId uint32, payload
return
}
gameMsg.PayloadMessageData = payloadMessageData
messageQueue.SendToGate("1", &mq.NetMsg{
messageQueue.SendToGate(gateAppId, &mq.NetMsg{
MsgType: mq.MsgTypeGame,
EventId: mq.NormalMsg,
GameMsg: gameMsg,
@@ -106,14 +126,16 @@ type FightRoutine struct {
entityMap map[uint32]*Entity
combatInvokeEntryList []*proto.CombatInvokeEntry
tickCount uint64
gateAppId string
}
func runFightRoutine(fightRoutineId uint32, fightRoutineMsgChan chan *mq.NetMsg, fightRoutineCloseChan chan bool, messageQueue *mq.MessageQueue) {
func runFightRoutine(fightRoutineId uint32, gateAppId string, fightRoutineMsgChan chan *mq.NetMsg, fightRoutineCloseChan chan bool, messageQueue *mq.MessageQueue) {
f := new(FightRoutine)
f.messageQueue = messageQueue
f.entityMap = make(map[uint32]*Entity)
f.combatInvokeEntryList = make([]*proto.CombatInvokeEntry, 0)
f.tickCount = 0
f.gateAppId = gateAppId
logger.Debug("create fight routine, fightRoutineId: %v", fightRoutineId)
ticker := time.NewTicker(time.Millisecond * 10)
for {
@@ -162,7 +184,7 @@ func (f *FightRoutine) onTick50MilliSecond(now int64) {
combatInvocationsNotifyAll := new(proto.CombatInvocationsNotify)
combatInvocationsNotifyAll.InvokeList = f.combatInvokeEntryList
for _, uid := range f.getAllPlayer(f.entityMap) {
SendMsg(f.messageQueue, cmd.CombatInvocationsNotify, uid, combatInvocationsNotifyAll)
SendMsg(f.messageQueue, cmd.CombatInvocationsNotify, uid, f.gateAppId, combatInvocationsNotifyAll)
}
f.combatInvokeEntryList = make([]*proto.CombatInvokeEntry, 0)
}
@@ -180,7 +202,7 @@ func (f *FightRoutine) onTickSecond(now int64) {
AvatarGuid: entity.avatarGuid,
FightPropMap: entity.fightPropMap,
}
SendMsg(f.messageQueue, cmd.AvatarFightPropNotify, entity.uid, avatarFightPropNotify)
SendMsg(f.messageQueue, cmd.AvatarFightPropNotify, entity.uid, f.gateAppId, avatarFightPropNotify)
}
}
@@ -231,7 +253,7 @@ func (f *FightRoutine) attackHandle(gameMsg *mq.GameMsg) {
entityFightPropUpdateNotify.FightPropMap = make(map[uint32]float32)
entityFightPropUpdateNotify.FightPropMap[uint32(constant.FightPropertyConst.FIGHT_PROP_CUR_HP)] = currHp
for _, uid := range f.getAllPlayer(f.entityMap) {
SendMsg(f.messageQueue, cmd.EntityFightPropUpdateNotify, uid, entityFightPropUpdateNotify)
SendMsg(f.messageQueue, cmd.EntityFightPropUpdateNotify, uid, f.gateAppId, entityFightPropUpdateNotify)
}
combatData, err := pb.Marshal(hitInfo)
if err != nil {
+24 -5
View File
@@ -10,19 +10,38 @@ import (
"hk4e/common/config"
"hk4e/common/mq"
"hk4e/common/rpc"
"hk4e/gate/net"
"hk4e/node/api"
"hk4e/pkg/logger"
)
var APPID string
func Run(ctx context.Context, configFile string) error {
config.InitConfig(configFile)
logger.InitLogger("gate")
logger.Warn("gate start")
// natsrpc client
client, err := rpc.NewClient()
if err != nil {
return err
}
messageQueue := mq.NewMessageQueue(mq.GATE, "1")
// 注册到节点服务器
rsp, err := client.Discovery.RegisterServer(context.TODO(), &api.RegisterServerReq{
ServerType: api.GATE,
})
if err != nil {
return err
}
APPID = rsp.GetAppId()
connectManager := net.NewKcpConnectManager(messageQueue)
logger.InitLogger("gate_" + APPID)
logger.Warn("gate start, appid: %v", APPID)
messageQueue := mq.NewMessageQueue(api.GATE, APPID)
connectManager := net.NewKcpConnectManager(messageQueue, client.Discovery)
connectManager.Start()
defer connectManager.Stop()
@@ -43,7 +62,7 @@ func Run(ctx context.Context, configFile string) error {
logger.Warn("get a signal %s", s.String())
switch s {
case syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGINT:
logger.Warn("gate exit")
logger.Warn("gate exit, appid: %v", APPID)
time.Sleep(time.Second)
return nil
case syscall.SIGHUP:
+46 -15
View File
@@ -2,6 +2,7 @@ package net
import (
"bytes"
"context"
"encoding/base64"
"encoding/binary"
"fmt"
@@ -13,6 +14,7 @@ import (
"hk4e/common/mq"
"hk4e/dispatch/controller"
"hk4e/gate/kcp"
"hk4e/node/api"
"hk4e/pkg/endec"
"hk4e/pkg/httpclient"
"hk4e/pkg/logger"
@@ -80,25 +82,25 @@ func (k *KcpConnectManager) recvMsgHandle(protoMsg *ProtoMsg, session *Session)
if connState != ConnActive {
return
}
// 通知GS玩家客户端的本地时钟
connCtrlMsg := new(mq.ConnCtrlMsg)
connCtrlMsg.UserId = userId
connCtrlMsg.ClientTime = pingReq.ClientTime
k.messageQueue.SendToGs("1", &mq.NetMsg{
MsgType: mq.MsgTypeConnCtrl,
EventId: mq.ClientTimeNotify,
ConnCtrlMsg: connCtrlMsg,
})
// 通知GS玩家客户端往返时延
rtt := session.conn.GetSRTT()
connCtrlMsg = new(mq.ConnCtrlMsg)
connCtrlMsg := new(mq.ConnCtrlMsg)
connCtrlMsg.UserId = userId
connCtrlMsg.ClientRtt = uint32(rtt)
k.messageQueue.SendToGs("1", &mq.NetMsg{
k.messageQueue.SendToGs(session.gsServerAppId, &mq.NetMsg{
MsgType: mq.MsgTypeConnCtrl,
EventId: mq.ClientRttNotify,
ConnCtrlMsg: connCtrlMsg,
})
// 通知GS玩家客户端的本地时钟
connCtrlMsg = new(mq.ConnCtrlMsg)
connCtrlMsg.UserId = userId
connCtrlMsg.ClientTime = pingReq.ClientTime
k.messageQueue.SendToGs(session.gsServerAppId, &mq.NetMsg{
MsgType: mq.MsgTypeConnCtrl,
EventId: mq.ClientTimeNotify,
ConnCtrlMsg: connCtrlMsg,
})
default:
if connState != ConnActive && !(protoMsg.CmdId == cmd.PlayerLoginReq || protoMsg.CmdId == cmd.SetPlayerBornDataReq) {
logger.Error("conn not active so drop packet, cmdId: %v, userId: %v, convId: %v", protoMsg.CmdId, userId, protoMsg.ConvId)
@@ -106,12 +108,15 @@ func (k *KcpConnectManager) recvMsgHandle(protoMsg *ProtoMsg, session *Session)
}
// 只转发到寻路服务器
if protoMsg.CmdId == cmd.QueryPathReq || protoMsg.CmdId == cmd.ObstacleModifyNotify {
if session.pathfindingServerAppId == "" {
return
}
gameMsg := new(mq.GameMsg)
gameMsg.UserId = userId
gameMsg.CmdId = protoMsg.CmdId
gameMsg.ClientSeq = protoMsg.HeadMessage.ClientSequenceId
gameMsg.PayloadMessage = protoMsg.PayloadMessage
k.messageQueue.SendToPathfinding("1", &mq.NetMsg{
k.messageQueue.SendToPathfinding(session.pathfindingServerAppId, &mq.NetMsg{
MsgType: mq.MsgTypeGame,
EventId: mq.NormalMsg,
GameMsg: gameMsg,
@@ -119,13 +124,13 @@ func (k *KcpConnectManager) recvMsgHandle(protoMsg *ProtoMsg, session *Session)
return
}
// 同时转发到战斗服务器
if protoMsg.CmdId == cmd.CombatInvocationsNotify {
if protoMsg.CmdId == cmd.CombatInvocationsNotify && session.fightServerAppId != "" {
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{
k.messageQueue.SendToFight(session.fightServerAppId, &mq.NetMsg{
MsgType: mq.MsgTypeGame,
EventId: mq.NormalMsg,
GameMsg: gameMsg,
@@ -137,7 +142,7 @@ func (k *KcpConnectManager) recvMsgHandle(protoMsg *ProtoMsg, session *Session)
gameMsg.CmdId = protoMsg.CmdId
gameMsg.ClientSeq = protoMsg.HeadMessage.ClientSequenceId
gameMsg.PayloadMessage = protoMsg.PayloadMessage
k.messageQueue.SendToGs("1", &mq.NetMsg{
k.messageQueue.SendToGs(session.gsServerAppId, &mq.NetMsg{
MsgType: mq.MsgTypeGame,
EventId: mq.NormalMsg,
GameMsg: gameMsg,
@@ -269,6 +274,32 @@ func (k *KcpConnectManager) getPlayerToken(req *proto.GetPlayerTokenReq, session
session.userId = tokenVerifyRsp.PlayerID
k.SetSession(session, session.conn.GetConv(), session.userId)
k.createSessionChan <- session
// 绑定各个服务器appid
gsServerAppId, err := k.discovery.GetServerAppId(context.TODO(), &api.GetServerAppIdReq{
ServerType: api.GS,
})
if err != nil {
logger.Error("get gs server appid error: %v", err)
return nil
}
session.gsServerAppId = gsServerAppId.AppId
fightServerAppId, err := k.discovery.GetServerAppId(context.TODO(), &api.GetServerAppIdReq{
ServerType: api.FIGHT,
})
if err != nil {
logger.Error("get fight server appid error: %v", err)
}
session.fightServerAppId = fightServerAppId.AppId
pathfindingServerAppId, err := k.discovery.GetServerAppId(context.TODO(), &api.GetServerAppIdReq{
ServerType: api.PATHFINDING,
})
if err != nil {
logger.Error("get pathfinding server appid error: %v", err)
}
session.pathfindingServerAppId = pathfindingServerAppId.AppId
logger.Debug("session gs appid: %v", session.gsServerAppId)
logger.Debug("session fight appid: %v", session.fightServerAppId)
logger.Debug("session pathfinding appid: %v", session.pathfindingServerAppId)
// 返回响应
rsp = new(proto.GetPlayerTokenRsp)
rsp.Uid = tokenVerifyRsp.PlayerID
+33 -19
View File
@@ -2,6 +2,7 @@ package net
import (
"bytes"
"context"
"encoding/binary"
"strconv"
"sync"
@@ -10,9 +11,9 @@ import (
"hk4e/common/config"
"hk4e/common/mq"
"hk4e/common/region"
"hk4e/dispatch/controller"
"hk4e/common/rpc"
"hk4e/gate/kcp"
"hk4e/pkg/httpclient"
"hk4e/node/api"
"hk4e/pkg/logger"
"hk4e/pkg/random"
"hk4e/protocol/cmd"
@@ -21,6 +22,7 @@ import (
const PacketFreqLimit = 1000
type KcpConnectManager struct {
discovery *rpc.DiscoveryClient
openState bool
sessionConvIdMap map[uint64]*Session
sessionUserIdMap map[uint32]*Session
@@ -38,8 +40,9 @@ type KcpConnectManager struct {
encRsaKeyMap map[string][]byte
}
func NewKcpConnectManager(messageQueue *mq.MessageQueue) (r *KcpConnectManager) {
func NewKcpConnectManager(messageQueue *mq.MessageQueue, discovery *rpc.DiscoveryClient) (r *KcpConnectManager) {
r = new(KcpConnectManager)
r.discovery = discovery
r.openState = true
r.sessionConvIdMap = make(map[uint64]*Session)
r.sessionUserIdMap = make(map[uint32]*Session)
@@ -57,20 +60,19 @@ func (k *KcpConnectManager) Start() {
// 读取密钥相关文件
k.signRsaKey, k.encRsaKeyMap, _ = region.LoadRsaKey()
// key
dispatchEc2bSeedRsp, err := httpclient.Get[controller.DispatchEc2bSeedRsp]("http://127.0.0.1:8080/dispatch/ec2b/seed", "")
rsp, err := k.discovery.GetRegionEc2B(context.TODO(), &api.NullMsg{})
if err != nil {
logger.Error("get dispatch ec2b seed error: %v", err)
logger.Error("get region ec2b error: %v", err)
return
}
dispatchEc2bSeed, err := strconv.ParseUint(dispatchEc2bSeedRsp.Seed, 10, 64)
ec2b, err := random.LoadEc2bKey(rsp.Data)
if err != nil {
logger.Error("parse dispatch ec2b seed error: %v", err)
logger.Error("parse region ec2b error: %v", err)
return
}
logger.Debug("get dispatch ec2b seed: %v", dispatchEc2bSeed)
gateDispatchEc2b := random.NewEc2b()
gateDispatchEc2b.SetSeed(dispatchEc2bSeed)
k.dispatchKey = gateDispatchEc2b.XorKey()
regionEc2b := random.NewEc2b()
regionEc2b.SetSeed(ec2b.Seed())
k.dispatchKey = regionEc2b.XorKey()
// kcp
port := strconv.Itoa(int(config.CONF.Hk4e.KcpPort))
listener, err := kcp.ListenWithOptions(config.CONF.Hk4e.KcpAddr+":"+port, nil, 0, 0)
@@ -201,13 +203,16 @@ func (k *KcpConnectManager) enetHandle(listener *kcp.Listener) {
}
type Session struct {
conn *kcp.UDPSession
connState uint8
userId uint32
kcpRawSendChan chan *ProtoMsg
seed uint64
xorKey []byte
changeXorKeyFin bool
conn *kcp.UDPSession
connState uint8
userId uint32
kcpRawSendChan chan *ProtoMsg
seed uint64
xorKey []byte
changeXorKeyFin bool
gsServerAppId string
fightServerAppId string
pathfindingServerAppId string
}
// 接收
@@ -288,6 +293,15 @@ func (k *KcpConnectManager) sendHandle(session *Session) {
if protoMsg.CmdId == cmd.PlayerLoginRsp {
logger.Debug("session active, convId: %v", convId)
session.connState = ConnActive
// 通知GS玩家战斗服务器的appid
connCtrlMsg := new(mq.ConnCtrlMsg)
connCtrlMsg.UserId = session.userId
connCtrlMsg.FightServerAppId = session.fightServerAppId
k.messageQueue.SendToGs(session.gsServerAppId, &mq.NetMsg{
MsgType: mq.MsgTypeConnCtrl,
EventId: mq.FightServerSelectNotify,
ConnCtrlMsg: connCtrlMsg,
})
}
}
}
@@ -328,7 +342,7 @@ func (k *KcpConnectManager) closeKcpConn(session *Session, enetType uint32) {
// 通知GS玩家下线
gameMsg := new(mq.GameMsg)
gameMsg.UserId = session.userId
k.messageQueue.SendToGs("1", &mq.NetMsg{
k.messageQueue.SendToGs(session.gsServerAppId, &mq.NetMsg{
MsgType: mq.MsgTypeGame,
EventId: mq.UserOfflineNotify,
GameMsg: gameMsg,
+3 -11
View File
@@ -8,11 +8,9 @@ import (
"time"
"hk4e/common/config"
"hk4e/common/rpc"
"hk4e/gm/controller"
"hk4e/gm/rpc_client"
"hk4e/pkg/logger"
"github.com/nats-io/nats.go"
)
func Run(ctx context.Context, configFile string) error {
@@ -21,18 +19,12 @@ func Run(ctx context.Context, configFile string) error {
logger.InitLogger("gm")
logger.Warn("gm start")
conn, err := nats.Connect(config.CONF.MQ.NatsUrl)
client, err := rpc.NewClient()
if err != nil {
logger.Error("connect nats error: %v", err)
return err
}
defer conn.Close()
rpc, err := rpc_client.New(conn)
if err != nil {
return err
}
_ = controller.NewController(rpc)
_ = controller.NewController(client.GM)
c := make(chan os.Signal, 1)
signal.Notify(c, syscall.SIGHUP, syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGINT)
+4 -4
View File
@@ -5,19 +5,19 @@ import (
"strconv"
"hk4e/common/config"
"hk4e/gm/rpc_client"
"hk4e/common/rpc"
"hk4e/pkg/logger"
"github.com/gin-gonic/gin"
)
type Controller struct {
rpc *rpc_client.Client
gm *rpc.GMClient
}
func NewController(rpc *rpc_client.Client) (r *Controller) {
func NewController(gm *rpc.GMClient) (r *Controller) {
r = new(Controller)
r.rpc = rpc
r.gm = gm
go r.registerRouter()
return r
}
+1 -1
View File
@@ -20,7 +20,7 @@ func (c *Controller) gmCmd(context *gin.Context) {
if err != nil {
return
}
rep, err := c.rpc.Cmd(context.Request.Context(), &api.CmdRequest{
rep, err := c.gm.Cmd(context.Request.Context(), &api.CmdRequest{
FuncName: gmCmdReq.FuncName,
Param: gmCmdReq.Param,
})
-29
View File
@@ -1,29 +0,0 @@
// Package rpc_client rpc客户端
package rpc_client
import (
"hk4e/gs/api"
"github.com/nats-io/nats.go"
"github.com/nats-io/nats.go/encoders/protobuf"
)
// Client rpc客户端
type Client struct {
api.GMNATSRPCClient
}
// New 构造
func New(conn *nats.Conn) (*Client, error) {
enc, err := nats.NewEncodedConn(conn, protobuf.PROTOBUF_ENCODER)
if err != nil {
return nil, err
}
cli, err := api.NewGMNATSRPCClient(enc)
if err != nil {
return nil, err
}
return &Client{
GMNATSRPCClient: cli,
}, nil
}
+6 -5
View File
@@ -1,6 +1,6 @@
module hk4e
go 1.19
go 1.18
// toml
require github.com/BurntSushi/toml v0.3.1
@@ -44,10 +44,11 @@ require github.com/jszwec/csvutil v1.7.1
// hjson
require github.com/hjson/hjson-go/v4 v4.2.0
require (
github.com/byebyebruce/natsrpc v0.5.5-0.20221125150611-56cd29a4e335
github.com/spf13/cobra v1.6.1
)
// natsrpc
require github.com/byebyebruce/natsrpc v0.5.5-0.20221125150611-56cd29a4e335
// cobra
require github.com/spf13/cobra v1.6.1
require (
github.com/davecgh/go-spew v1.1.1 // indirect
+1 -1
View File
@@ -1,7 +1,7 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.26.0
// protoc v3.14.0
// protoc v3.7.0
// source: api.proto
package api
+33 -15
View File
@@ -9,57 +9,75 @@ import (
"time"
"hk4e/common/config"
"hk4e/common/constant"
"hk4e/common/mq"
"hk4e/common/rpc"
"hk4e/gdconf"
gdc "hk4e/gs/config"
"hk4e/gs/constant"
"hk4e/gs/dao"
"hk4e/gs/game"
"hk4e/gs/service"
"hk4e/node/api"
"hk4e/pkg/logger"
"github.com/nats-io/nats.go"
)
var APPID string
func Run(ctx context.Context, configFile string) error {
config.InitConfig(configFile)
logger.InitLogger("gs")
logger.Warn("gs start")
// natsrpc client
client, err := rpc.NewClient()
if err != nil {
return err
}
// 注册到节点服务器
rsp, err := client.Discovery.RegisterServer(context.TODO(), &api.RegisterServerReq{
ServerType: api.GS,
})
if err != nil {
return err
}
APPID = rsp.GetAppId()
logger.InitLogger("gs_" + APPID)
logger.Warn("gs start, appid: %v", APPID)
constant.InitConstant()
gdc.InitGameDataConfig()
gdconf.InitGameDataConfig()
conn, err := nats.Connect(config.CONF.MQ.NatsUrl)
if err != nil {
logger.Error("connect nats error: %v", err)
return err
}
defer conn.Close()
db, err := dao.NewDao()
if err != nil {
panic(err)
}
defer db.CloseDao()
messageQueue := mq.NewMessageQueue(mq.GS, "1")
messageQueue := mq.NewMessageQueue(api.GS, APPID)
defer messageQueue.Close()
gameManager := game.NewGameManager(db, messageQueue)
defer gameManager.Stop()
c := make(chan os.Signal, 1)
signal.Notify(c, syscall.SIGHUP, syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGINT)
// natsrpc server
conn, err := nats.Connect(config.CONF.MQ.NatsUrl)
if err != nil {
logger.Error("connect nats error: %v", err)
return err
}
defer conn.Close()
s, err := service.NewService(conn)
if err != nil {
return err
}
defer s.Close()
c := make(chan os.Signal, 1)
signal.Notify(c, syscall.SIGHUP, syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGINT)
for {
select {
case <-ctx.Done():
@@ -68,7 +86,7 @@ func Run(ctx context.Context, configFile string) error {
logger.Warn("get a signal %s", s.String())
switch s {
case syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGINT:
logger.Warn("gs exit")
logger.Warn("gs exit, appid: %v", APPID)
time.Sleep(time.Second)
return nil
case syscall.SIGHUP:
+1 -1
View File
@@ -4,7 +4,7 @@ import (
"encoding/json"
"os"
"hk4e/gs/constant"
"hk4e/common/constant"
"hk4e/pkg/logger"
)
+1 -1
View File
@@ -4,7 +4,7 @@ import (
"encoding/json"
"os"
"hk4e/gs/constant"
"hk4e/common/constant"
"hk4e/pkg/endec"
"hk4e/pkg/logger"
)
+1 -1
View File
@@ -4,7 +4,7 @@ import (
"encoding/json"
"os"
"hk4e/gs/constant"
"hk4e/common/constant"
"hk4e/pkg/logger"
)
+1 -1
View File
@@ -4,7 +4,7 @@ import (
"encoding/json"
"os"
"hk4e/gs/constant"
"hk4e/common/constant"
"hk4e/pkg/logger"
)
+1 -1
View File
@@ -1,7 +1,7 @@
package game
import (
"hk4e/gs/constant"
"hk4e/common/constant"
"hk4e/gs/model"
"hk4e/pkg/logger"
)
+2 -1
View File
@@ -47,7 +47,8 @@ func NewCommandManager() *CommandManager {
r := new(CommandManager)
// 创建AI世界
GAME_MANAGER.OnRegOk(false, &proto.SetPlayerBornDataReq{AvatarId: 10000007, NickName: "System"}, 1, 0)
GAME_MANAGER.OnRegOk(false, &proto.SetPlayerBornDataReq{AvatarId: 10000007, NickName: "System"}, 1, 0, "")
GAME_MANAGER.FightServerSelectNotify(1, "")
r.system = USER_MANAGER.GetOnlineUser(1)
r.system.DbState = model.DbNormal
r.system.SceneLoadState = model.SceneEnterDone
+39 -5
View File
@@ -134,17 +134,47 @@ func (g *GameManager) Stop() {
for _, player := range userList {
g.DisconnectPlayer(player.PlayerID, kcp.EnetServerShutdown)
}
time.Sleep(time.Second * 5)
time.Sleep(time.Second * 3)
// 保存玩家数据
LOCAL_EVENT_MANAGER.localEventChan <- &LocalEvent{
EventId: RunUserCopyAndSave,
}
time.Sleep(time.Second * 5)
time.Sleep(time.Second * 3)
}
func (g *GameManager) SendMsgEx(cmdId uint16, userId uint32, clientSeq uint32, gateAppId string, payloadMsg pb.Message) {
if userId < 100000000 {
return
}
if payloadMsg == nil {
logger.Error("payload msg is nil")
return
}
gameMsg := &mq.GameMsg{
UserId: userId,
CmdId: cmdId,
ClientSeq: clientSeq,
PayloadMessage: payloadMsg,
}
g.messageQueue.SendToGate(gateAppId, &mq.NetMsg{
MsgType: mq.MsgTypeGame,
EventId: mq.NormalMsg,
GameMsg: gameMsg,
})
}
// SendMsg 发送消息给客户端
func (g *GameManager) SendMsg(cmdId uint16, userId uint32, clientSeq uint32, payloadMsg pb.Message) {
if userId < 100000000 || payloadMsg == nil {
if userId < 100000000 {
return
}
if payloadMsg == nil {
logger.Error("payload msg is nil")
return
}
player := USER_MANAGER.GetOnlineUser(userId)
if player == nil {
logger.Error("player not exist, uid: %v", userId)
return
}
gameMsg := new(mq.GameMsg)
@@ -158,7 +188,7 @@ func (g *GameManager) SendMsg(cmdId uint16, userId uint32, clientSeq uint32, pay
return
}
gameMsg.PayloadMessageData = payloadMessageData
g.messageQueue.SendToGate("1", &mq.NetMsg{
g.messageQueue.SendToGate(player.GateAppId, &mq.NetMsg{
MsgType: mq.MsgTypeGame,
EventId: mq.NormalMsg,
GameMsg: gameMsg,
@@ -222,7 +252,11 @@ func (g *GameManager) ReconnectPlayer(userId uint32) {
}
func (g *GameManager) DisconnectPlayer(userId uint32, reason uint32) {
g.messageQueue.SendToGate("1", &mq.NetMsg{
player := USER_MANAGER.GetOnlineUser(userId)
if player == nil {
return
}
g.messageQueue.SendToGate(player.GateAppId, &mq.NetMsg{
MsgType: mq.MsgTypeConnCtrl,
EventId: mq.KickPlayerNotify,
ConnCtrlMsg: &mq.ConnCtrlMsg{
+2 -2
View File
@@ -38,10 +38,10 @@ func (l *LocalEventManager) LocalEventHandle(localEvent *LocalEvent) {
if playerLoginInfo.Player != nil {
USER_MANAGER.playerMap[playerLoginInfo.Player.PlayerID] = playerLoginInfo.Player
}
GAME_MANAGER.OnLoginOk(playerLoginInfo.UserId, playerLoginInfo.Player, playerLoginInfo.ClientSeq)
GAME_MANAGER.OnLoginOk(playerLoginInfo.UserId, playerLoginInfo.Player, playerLoginInfo.ClientSeq, playerLoginInfo.GateAppId)
case CheckUserExistOnRegFromDbFinish:
playerRegInfo := localEvent.Msg.(*PlayerRegInfo)
GAME_MANAGER.OnRegOk(playerRegInfo.Exist, playerRegInfo.Req, playerRegInfo.UserId, playerRegInfo.ClientSeq)
GAME_MANAGER.OnRegOk(playerRegInfo.Exist, playerRegInfo.Req, playerRegInfo.UserId, playerRegInfo.ClientSeq, playerRegInfo.GateAppId)
case RunUserCopyAndSave:
startTime := time.Now().UnixNano()
// 拷贝一份数据避免并发访问
+11 -2
View File
@@ -4,6 +4,7 @@ import (
"hk4e/common/mq"
"hk4e/gate/kcp"
"hk4e/gs/model"
"hk4e/node/api"
"hk4e/pkg/logger"
"hk4e/protocol/cmd"
@@ -120,15 +121,18 @@ func (r *RouteManager) InitRoute() {
func (r *RouteManager) RouteHandle(netMsg *mq.NetMsg) {
switch netMsg.MsgType {
case mq.MsgTypeGame:
if netMsg.OriginServerType != api.GATE {
return
}
gameMsg := netMsg.GameMsg
switch netMsg.EventId {
case mq.NormalMsg:
if gameMsg.CmdId == cmd.PlayerLoginReq {
GAME_MANAGER.PlayerLoginReq(gameMsg.UserId, gameMsg.ClientSeq, gameMsg.PayloadMessage)
GAME_MANAGER.PlayerLoginReq(gameMsg.UserId, gameMsg.ClientSeq, netMsg.OriginServerAppId, gameMsg.PayloadMessage)
return
}
if gameMsg.CmdId == cmd.SetPlayerBornDataReq {
GAME_MANAGER.SetPlayerBornDataReq(gameMsg.UserId, gameMsg.ClientSeq, gameMsg.PayloadMessage)
GAME_MANAGER.SetPlayerBornDataReq(gameMsg.UserId, gameMsg.ClientSeq, netMsg.OriginServerAppId, gameMsg.PayloadMessage)
return
}
r.doRoute(gameMsg.CmdId, gameMsg.UserId, gameMsg.ClientSeq, gameMsg.PayloadMessage)
@@ -136,12 +140,17 @@ func (r *RouteManager) RouteHandle(netMsg *mq.NetMsg) {
GAME_MANAGER.OnUserOffline(gameMsg.UserId)
}
case mq.MsgTypeConnCtrl:
if netMsg.OriginServerType != api.GATE {
return
}
connCtrlMsg := netMsg.ConnCtrlMsg
switch netMsg.EventId {
case mq.ClientRttNotify:
GAME_MANAGER.ClientRttNotify(connCtrlMsg.UserId, connCtrlMsg.ClientRtt)
case mq.ClientTimeNotify:
GAME_MANAGER.ClientTimeNotify(connCtrlMsg.UserId, connCtrlMsg.ClientTime)
case mq.FightServerSelectNotify:
GAME_MANAGER.FightServerSelectNotify(connCtrlMsg.UserId, connCtrlMsg.FightServerAppId)
}
}
}
+1 -1
View File
@@ -3,7 +3,7 @@ package game
import (
"time"
"hk4e/gs/constant"
"hk4e/common/constant"
"hk4e/gs/model"
"hk4e/pkg/logger"
"hk4e/pkg/random"
+1 -1
View File
@@ -1,8 +1,8 @@
package game
import (
"hk4e/common/constant"
gdc "hk4e/gs/config"
"hk4e/gs/constant"
"hk4e/gs/model"
"hk4e/pkg/logger"
"hk4e/pkg/object"
+29 -3
View File
@@ -3,6 +3,7 @@ package game
import (
"time"
"hk4e/common/mq"
"hk4e/gs/model"
"hk4e/pkg/logger"
"hk4e/protocol/cmd"
@@ -56,6 +57,16 @@ func (g *GameManager) EntityAiSyncNotify(player *model.Player, payloadMsg pb.Mes
g.SendMsg(cmd.EntityAiSyncNotify, player.PlayerID, player.ClientSeq, entityAiSyncNotify)
}
func (g *GameManager) ClientRttNotify(userId uint32, clientRtt uint32) {
player := USER_MANAGER.GetOnlineUser(userId)
if player == nil {
logger.Error("player is nil, uid: %v", userId)
return
}
logger.Debug("client rtt notify, uid: %v, rtt: %v", userId, clientRtt)
player.ClientRTT = clientRtt
}
func (g *GameManager) ClientTimeNotify(userId uint32, clientTime uint32) {
player := USER_MANAGER.GetOnlineUser(userId)
if player == nil {
@@ -66,14 +77,29 @@ func (g *GameManager) ClientTimeNotify(userId uint32, clientTime uint32) {
player.ClientTime = clientTime
}
func (g *GameManager) ClientRttNotify(userId uint32, clientRtt uint32) {
func (g *GameManager) FightServerSelectNotify(userId uint32, fightAppId string) {
player := USER_MANAGER.GetOnlineUser(userId)
if player == nil {
logger.Error("player is nil, uid: %v", userId)
return
}
logger.Debug("client rtt notify, uid: %v, rtt: %v", userId, clientRtt)
player.ClientRTT = clientRtt
logger.Debug("fight server select notify, uid: %v, fightAppId: %v", userId, fightAppId)
player.FightAppId = fightAppId
// 创建世界
world := WORLD_MANAGER.CreateWorld(player)
GAME_MANAGER.messageQueue.SendToFight(fightAppId, &mq.NetMsg{
MsgType: mq.MsgTypeFight,
EventId: mq.AddFightRoutine,
FightMsg: &mq.FightMsg{
FightRoutineId: world.id,
GateServerAppId: player.GateAppId,
},
})
world.AddPlayer(player, player.SceneId)
player.WorldId = world.id
// 进入场景
player.SceneLoadState = model.SceneNone
g.SendMsg(cmd.PlayerEnterSceneNotify, userId, player.ClientSeq, g.PacketPlayerEnterSceneNotifyLogin(player, proto.EnterType_ENTER_TYPE_SELF))
}
func (g *GameManager) ServerAnnounceNotify(announceId uint32, announceMsg string) {
+1 -1
View File
@@ -1,8 +1,8 @@
package game
import (
"hk4e/common/constant"
gdc "hk4e/gs/config"
"hk4e/gs/constant"
"hk4e/pkg/logger"
"hk4e/protocol/cmd"
"hk4e/protocol/proto"
+20 -26
View File
@@ -3,8 +3,8 @@ package game
import (
"time"
"hk4e/common/constant"
gdc "hk4e/gs/config"
"hk4e/gs/constant"
"hk4e/gs/model"
"hk4e/pkg/logger"
"hk4e/pkg/reflection"
@@ -14,36 +14,38 @@ import (
pb "google.golang.org/protobuf/proto"
)
func (g *GameManager) PlayerLoginReq(userId uint32, clientSeq uint32, payloadMsg pb.Message) {
logger.Info("user login req, uid: %v", userId)
func (g *GameManager) PlayerLoginReq(userId uint32, clientSeq uint32, gateAppId string, payloadMsg pb.Message) {
logger.Info("user login req, uid: %v, gateAppId: %v", userId, gateAppId)
req := payloadMsg.(*proto.PlayerLoginReq)
logger.Debug("login data: %v", req)
g.OnLogin(userId, clientSeq)
g.OnLogin(userId, clientSeq, gateAppId)
}
func (g *GameManager) SetPlayerBornDataReq(userId uint32, clientSeq uint32, payloadMsg pb.Message) {
logger.Info("user reg req, uid: %v", userId)
func (g *GameManager) SetPlayerBornDataReq(userId uint32, clientSeq uint32, gateAppId string, payloadMsg pb.Message) {
logger.Info("user reg req, uid: %v, gateAppId: %v", userId, gateAppId)
req := payloadMsg.(*proto.SetPlayerBornDataReq)
logger.Debug("reg data: %v", req)
g.OnReg(userId, clientSeq, req)
g.OnReg(userId, clientSeq, gateAppId, req)
}
func (g *GameManager) OnLogin(userId uint32, clientSeq uint32) {
func (g *GameManager) OnLogin(userId uint32, clientSeq uint32, gateAppId string) {
logger.Info("user login, uid: %v", userId)
player, asyncWait := USER_MANAGER.OnlineUser(userId, clientSeq)
player, asyncWait := USER_MANAGER.OnlineUser(userId, clientSeq, gateAppId)
if !asyncWait {
g.OnLoginOk(userId, player, clientSeq)
g.OnLoginOk(userId, player, clientSeq, gateAppId)
}
}
func (g *GameManager) OnLoginOk(userId uint32, player *model.Player, clientSeq uint32) {
func (g *GameManager) OnLoginOk(userId uint32, player *model.Player, clientSeq uint32, gateAppId string) {
if player == nil {
g.SendMsg(cmd.DoSetPlayerBornDataNotify, userId, clientSeq, new(proto.DoSetPlayerBornDataNotify))
g.SendMsgEx(cmd.DoSetPlayerBornDataNotify, userId, clientSeq, gateAppId, new(proto.DoSetPlayerBornDataNotify))
return
}
player.OnlineTime = uint32(time.Now().UnixMilli())
player.Online = true
player.GateAppId = gateAppId
// 初始化
player.InitAll()
// player.TeamConfig.UpdateTeam()
@@ -53,32 +55,24 @@ func (g *GameManager) OnLoginOk(userId uint32, player *model.Player, clientSeq u
player.Pos.Y = player.SafePos.Y
player.Pos.Z = player.SafePos.Z
// 创建世界
world := WORLD_MANAGER.CreateWorld(player)
world.AddPlayer(player, player.SceneId)
player.WorldId = world.id
player.CombatInvokeHandler = model.NewInvokeHandler[proto.CombatInvokeEntry]()
player.AbilityInvokeHandler = model.NewInvokeHandler[proto.AbilityInvokeEntry]()
g.LoginNotify(userId, player, clientSeq)
player.SceneLoadState = model.SceneNone
g.SendMsg(cmd.PlayerEnterSceneNotify, userId, clientSeq, g.PacketPlayerEnterSceneNotifyLogin(player, proto.EnterType_ENTER_TYPE_SELF))
}
func (g *GameManager) OnReg(userId uint32, clientSeq uint32, payloadMsg pb.Message) {
func (g *GameManager) OnReg(userId uint32, clientSeq uint32, gateAppId string, payloadMsg pb.Message) {
logger.Debug("user reg, uid: %v", userId)
req := payloadMsg.(*proto.SetPlayerBornDataReq)
logger.Debug("avatar id: %v, nickname: %v", req.AvatarId, req.NickName)
exist, asyncWait := USER_MANAGER.CheckUserExistOnReg(userId, req, clientSeq)
exist, asyncWait := USER_MANAGER.CheckUserExistOnReg(userId, req, clientSeq, gateAppId)
if !asyncWait {
g.OnRegOk(exist, req, userId, clientSeq)
g.OnRegOk(exist, req, userId, clientSeq, gateAppId)
}
}
func (g *GameManager) OnRegOk(exist bool, req *proto.SetPlayerBornDataReq, userId uint32, clientSeq uint32) {
func (g *GameManager) OnRegOk(exist bool, req *proto.SetPlayerBornDataReq, userId uint32, clientSeq uint32, gateAppId string) {
if exist {
logger.Error("recv reg req, but user is already exist, userId: %v", userId)
return
@@ -98,8 +92,8 @@ func (g *GameManager) OnRegOk(exist bool, req *proto.SetPlayerBornDataReq, userI
}
USER_MANAGER.AddUser(player)
g.SendMsg(cmd.SetPlayerBornDataRsp, userId, clientSeq, new(proto.SetPlayerBornDataRsp))
g.OnLogin(userId, clientSeq)
g.SendMsgEx(cmd.SetPlayerBornDataRsp, userId, clientSeq, gateAppId, new(proto.SetPlayerBornDataRsp))
g.OnLogin(userId, clientSeq, gateAppId)
}
func (g *GameManager) OnUserOffline(userId uint32) {
+6 -2
View File
@@ -66,9 +66,10 @@ type PlayerRegInfo struct {
Req *proto.SetPlayerBornDataReq
UserId uint32
ClientSeq uint32
GateAppId string
}
func (u *UserManager) CheckUserExistOnReg(userId uint32, req *proto.SetPlayerBornDataReq, clientSeq uint32) (exist bool, asyncWait bool) {
func (u *UserManager) CheckUserExistOnReg(userId uint32, req *proto.SetPlayerBornDataReq, clientSeq uint32, gateAppId string) (exist bool, asyncWait bool) {
_, exist = u.playerMap[userId]
if exist {
return true, false
@@ -86,6 +87,7 @@ func (u *UserManager) CheckUserExistOnReg(userId uint32, req *proto.SetPlayerBor
Req: req,
UserId: userId,
ClientSeq: clientSeq,
GateAppId: gateAppId,
},
}
}()
@@ -137,9 +139,10 @@ type PlayerLoginInfo struct {
UserId uint32
Player *model.Player
ClientSeq uint32
GateAppId string
}
func (u *UserManager) OnlineUser(userId uint32, clientSeq uint32) (*model.Player, bool) {
func (u *UserManager) OnlineUser(userId uint32, clientSeq uint32, gateAppId string) (*model.Player, bool) {
player, exist := u.playerMap[userId]
if exist {
u.ChangeUserDbState(player, model.DbNormal)
@@ -158,6 +161,7 @@ func (u *UserManager) OnlineUser(userId uint32, clientSeq uint32) (*model.Player
UserId: userId,
Player: player,
ClientSeq: clientSeq,
GateAppId: gateAppId,
},
}
}()
+1 -2
View File
@@ -3,8 +3,7 @@ package game
import (
"strconv"
"hk4e/gs/constant"
"hk4e/common/constant"
gdc "hk4e/gs/config"
"hk4e/gs/model"
"hk4e/pkg/logger"
+9 -1
View File
@@ -3,7 +3,8 @@ package game
import (
"time"
"hk4e/gs/constant"
"hk4e/common/constant"
"hk4e/common/mq"
"hk4e/gs/model"
"hk4e/pkg/logger"
"hk4e/pkg/object"
@@ -320,6 +321,13 @@ func (g *GameManager) UserWorldRemovePlayer(world *World, player *model.Player)
if world.owner.PlayerID == player.PlayerID {
// 房主离开销毁世界
WORLD_MANAGER.DestroyWorld(world.id)
GAME_MANAGER.messageQueue.SendToFight(world.owner.FightAppId, &mq.NetMsg{
MsgType: mq.MsgTypeFight,
EventId: mq.DelFightRoutine,
FightMsg: &mq.FightMsg{
FightRoutineId: world.id,
},
})
return
}
if world.multiplayer && world.GetWorldPlayerNum() > 0 {
+1 -1
View File
@@ -5,8 +5,8 @@ import (
"strconv"
"time"
"hk4e/common/constant"
gdc "hk4e/gs/config"
"hk4e/gs/constant"
"hk4e/gs/model"
"hk4e/pkg/logger"
"hk4e/pkg/object"
+1 -1
View File
@@ -3,7 +3,7 @@ package game
import (
"time"
"hk4e/gs/constant"
"hk4e/common/constant"
"hk4e/gs/model"
"hk4e/pkg/logger"
"hk4e/protocol/cmd"
+1 -1
View File
@@ -5,7 +5,7 @@ import (
"time"
"unicode/utf8"
"hk4e/gs/constant"
"hk4e/common/constant"
"hk4e/gs/model"
"hk4e/pkg/logger"
"hk4e/pkg/object"
+3 -3
View File
@@ -4,8 +4,8 @@ import (
"strings"
"time"
"hk4e/common/constant"
"hk4e/gdconf"
"hk4e/gs/constant"
"hk4e/gs/model"
"hk4e/pkg/endec"
"hk4e/pkg/logger"
@@ -462,7 +462,7 @@ func (g *GameManager) DrownBackHandler(player *model.Player) {
}
// 获取最近角色实体的锚点
// TODO 阻塞优化 16ms我感觉有点慢
//for _, entry := range gdc.CONF.ScenePointEntries {
// for _, entry := range gdc.CONF.ScenePointEntries {
// if entry.PointData == nil || entry.PointData.TranPos == nil {
// continue
// }
@@ -475,7 +475,7 @@ func (g *GameManager) DrownBackHandler(player *model.Player) {
// if player.SafePos.Distance(pointPos) < player.SafePos.Distance(pos) {
// pos = pointPos
// }
//}
// }
// 传送玩家至安全位置
g.TeleportPlayer(player, uint32(constant.EnterReasonConst.Revival), player.SceneId, pos)
}
+1 -1
View File
@@ -1,8 +1,8 @@
package game
import (
"hk4e/common/constant"
gdc "hk4e/gs/config"
"hk4e/gs/constant"
"hk4e/gs/model"
"hk4e/pkg/endec"
"hk4e/pkg/logger"
+1 -1
View File
@@ -1,8 +1,8 @@
package game
import (
"hk4e/common/constant"
gdc "hk4e/gs/config"
"hk4e/gs/constant"
"hk4e/pkg/logger"
"hk4e/protocol/cmd"
"hk4e/protocol/proto"
+4 -18
View File
@@ -4,10 +4,10 @@ import (
"math"
"time"
"hk4e/common/constant"
"hk4e/protocol/cmd"
"hk4e/common/mq"
"hk4e/gs/constant"
"hk4e/gs/game/aoi"
"hk4e/gs/model"
"hk4e/pkg/alg"
@@ -71,13 +71,6 @@ func (w *WorldManager) CreateWorld(owner *model.Player) *World {
}
world.mpLevelEntityId = world.GetNextWorldEntityId(constant.EntityIdTypeConst.MPLEVEL)
w.worldMap[worldId] = world
GAME_MANAGER.messageQueue.SendToFight("1", &mq.NetMsg{
MsgType: mq.MsgTypeFight,
EventId: mq.AddFightRoutine,
FightMsg: &mq.FightMsg{
FightRoutineId: world.id,
},
})
return world
}
@@ -88,13 +81,6 @@ func (w *WorldManager) DestroyWorld(worldId uint32) {
player.WorldId = 0
}
delete(w.worldMap, worldId)
GAME_MANAGER.messageQueue.SendToFight("1", &mq.NetMsg{
MsgType: mq.MsgTypeFight,
EventId: mq.DelFightRoutine,
FightMsg: &mq.FightMsg{
FightRoutineId: world.id,
},
})
}
// GetBigWorld 获取本服务器的AI世界
@@ -715,7 +701,7 @@ func (s *Scene) CreateEntityAvatar(player *model.Player, avatarId uint32) uint32
if avatarId == s.world.GetPlayerActiveAvatarId(player) {
s.world.aoiManager.AddEntityIdToGridByPos(entity.id, float32(entity.pos.X), float32(entity.pos.Y), float32(entity.pos.Z))
}
GAME_MANAGER.messageQueue.SendToFight("1", &mq.NetMsg{
GAME_MANAGER.messageQueue.SendToFight(s.world.owner.FightAppId, &mq.NetMsg{
MsgType: mq.MsgTypeFight,
EventId: mq.FightRoutineAddEntity,
FightMsg: &mq.FightMsg{
@@ -765,7 +751,7 @@ func (s *Scene) CreateEntityMonster(pos *model.Vector, level uint8, fightProp ma
}
s.entityMap[entity.id] = entity
s.world.aoiManager.AddEntityIdToGridByPos(entity.id, float32(entity.pos.X), float32(entity.pos.Y), float32(entity.pos.Z))
GAME_MANAGER.messageQueue.SendToFight("1", &mq.NetMsg{
GAME_MANAGER.messageQueue.SendToFight(s.world.owner.FightAppId, &mq.NetMsg{
MsgType: mq.MsgTypeFight,
EventId: mq.FightRoutineAddEntity,
FightMsg: &mq.FightMsg{
@@ -915,7 +901,7 @@ func (s *Scene) DestroyEntity(entityId uint32) {
}
s.world.aoiManager.RemoveEntityIdFromGridByPos(entity.id, float32(entity.pos.X), float32(entity.pos.Y), float32(entity.pos.Z))
delete(s.entityMap, entityId)
GAME_MANAGER.messageQueue.SendToFight("1", &mq.NetMsg{
GAME_MANAGER.messageQueue.SendToFight(s.world.owner.FightAppId, &mq.NetMsg{
MsgType: mq.MsgTypeFight,
EventId: mq.FightRoutineDelEntity,
FightMsg: &mq.FightMsg{
+1 -1
View File
@@ -1,7 +1,7 @@
package model
import (
"hk4e/gs/constant"
"hk4e/common/constant"
)
type Item struct {
+1 -1
View File
@@ -3,8 +3,8 @@ package model
import (
"time"
"hk4e/common/constant"
gdc "hk4e/gs/config"
"hk4e/gs/constant"
"hk4e/pkg/logger"
)
+2
View File
@@ -71,6 +71,8 @@ type Player struct {
ClientSeq uint32 `bson:"-" msgpack:"-"` // 客户端发包请求的序号
CombatInvokeHandler *InvokeHandler[proto.CombatInvokeEntry] `bson:"-" msgpack:"-"` // combat转发器
AbilityInvokeHandler *InvokeHandler[proto.AbilityInvokeEntry] `bson:"-" msgpack:"-"` // ability转发器
GateAppId string `bson:"-" msgpack:"-"` // 网关服务器的appid
FightAppId string `bson:"-" msgpack:"-"` // 战斗服务器的appid
}
func (p *Player) GetNextGameObjectGuid() uint64 {
+1 -1
View File
@@ -1,7 +1,7 @@
package model
import (
"hk4e/gs/constant"
"hk4e/common/constant"
"hk4e/protocol/proto"
)
+1 -1
View File
@@ -1,8 +1,8 @@
package model
import (
"hk4e/common/constant"
gdc "hk4e/gs/config"
"hk4e/gs/constant"
)
type Team struct {
-1
View File
@@ -30,5 +30,4 @@ func NewService(conn *nats.Conn) (*Service, error) {
// Close 关闭
func (s *Service) Close() {
// TODO
}
+70
View File
@@ -0,0 +1,70 @@
// Code generated by protoc-gen-natsrpc. DO NOT EDIT.
// versions:
// - protoc-gen-natsrpc v0.5.0
// source: api.proto
package api
import (
context "context"
fmt "fmt"
natsrpc "github.com/byebyebruce/natsrpc"
nats_go "github.com/nats-io/nats.go"
proto "google.golang.org/protobuf/proto"
)
var _ = new(context.Context)
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = natsrpc.Version
var _ = nats_go.Version
// 节点服务器注册发现服务
type DiscoveryNATSRPCServer interface {
RegisterServer(ctx context.Context, req *RegisterServerReq) (*RegisterServerRsp, error)
GetServerAppId(ctx context.Context, req *GetServerAppIdReq) (*GetServerAppIdRsp, error)
GetRegionEc2B(ctx context.Context, req *NullMsg) (*RegionEc2B, error)
}
// RegisterDiscoveryNATSRPCServer register Discovery service
func RegisterDiscoveryNATSRPCServer(server *natsrpc.Server, s DiscoveryNATSRPCServer, opts ...natsrpc.ServiceOption) (natsrpc.IService, error) {
return server.Register("hk4e.node.api.Discovery", s, opts...)
}
// 节点服务器注册发现服务
type DiscoveryNATSRPCClient interface {
RegisterServer(ctx context.Context, req *RegisterServerReq, opt ...natsrpc.CallOption) (*RegisterServerRsp, error)
GetServerAppId(ctx context.Context, req *GetServerAppIdReq, opt ...natsrpc.CallOption) (*GetServerAppIdRsp, error)
GetRegionEc2B(ctx context.Context, req *NullMsg, opt ...natsrpc.CallOption) (*RegionEc2B, error)
}
type _DiscoveryNATSRPCClient struct {
c *natsrpc.Client
}
// NewDiscoveryNATSRPCClient
func NewDiscoveryNATSRPCClient(enc *nats_go.EncodedConn, opts ...natsrpc.ClientOption) (DiscoveryNATSRPCClient, error) {
c, err := natsrpc.NewClient(enc, "hk4e.node.api.Discovery", opts...)
if err != nil {
return nil, err
}
ret := &_DiscoveryNATSRPCClient{
c: c,
}
return ret, nil
}
func (c *_DiscoveryNATSRPCClient) RegisterServer(ctx context.Context, req *RegisterServerReq, opt ...natsrpc.CallOption) (*RegisterServerRsp, error) {
rep := &RegisterServerRsp{}
err := c.c.Request(ctx, "RegisterServer", req, rep, opt...)
return rep, err
}
func (c *_DiscoveryNATSRPCClient) GetServerAppId(ctx context.Context, req *GetServerAppIdReq, opt ...natsrpc.CallOption) (*GetServerAppIdRsp, error) {
rep := &GetServerAppIdRsp{}
err := c.c.Request(ctx, "GetServerAppId", req, rep, opt...)
return rep, err
}
func (c *_DiscoveryNATSRPCClient) GetRegionEc2B(ctx context.Context, req *NullMsg, opt ...natsrpc.CallOption) (*RegionEc2B, error) {
rep := &RegionEc2B{}
err := c.c.Request(ctx, "GetRegionEc2B", req, rep, opt...)
return rep, err
}
+466
View File
@@ -0,0 +1,466 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.26.0
// protoc v3.7.0
// source: api.proto
package api
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type NullMsg struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
}
func (x *NullMsg) Reset() {
*x = NullMsg{}
if protoimpl.UnsafeEnabled {
mi := &file_api_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *NullMsg) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NullMsg) ProtoMessage() {}
func (x *NullMsg) ProtoReflect() protoreflect.Message {
mi := &file_api_proto_msgTypes[0]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NullMsg.ProtoReflect.Descriptor instead.
func (*NullMsg) Descriptor() ([]byte, []int) {
return file_api_proto_rawDescGZIP(), []int{0}
}
type GetServerAppIdReq struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
ServerType string `protobuf:"bytes,1,opt,name=server_type,json=serverType,proto3" json:"server_type,omitempty"`
}
func (x *GetServerAppIdReq) Reset() {
*x = GetServerAppIdReq{}
if protoimpl.UnsafeEnabled {
mi := &file_api_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *GetServerAppIdReq) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*GetServerAppIdReq) ProtoMessage() {}
func (x *GetServerAppIdReq) ProtoReflect() protoreflect.Message {
mi := &file_api_proto_msgTypes[1]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use GetServerAppIdReq.ProtoReflect.Descriptor instead.
func (*GetServerAppIdReq) Descriptor() ([]byte, []int) {
return file_api_proto_rawDescGZIP(), []int{1}
}
func (x *GetServerAppIdReq) GetServerType() string {
if x != nil {
return x.ServerType
}
return ""
}
type GetServerAppIdRsp struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
AppId string `protobuf:"bytes,1,opt,name=app_id,json=appId,proto3" json:"app_id,omitempty"`
}
func (x *GetServerAppIdRsp) Reset() {
*x = GetServerAppIdRsp{}
if protoimpl.UnsafeEnabled {
mi := &file_api_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *GetServerAppIdRsp) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*GetServerAppIdRsp) ProtoMessage() {}
func (x *GetServerAppIdRsp) ProtoReflect() protoreflect.Message {
mi := &file_api_proto_msgTypes[2]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use GetServerAppIdRsp.ProtoReflect.Descriptor instead.
func (*GetServerAppIdRsp) Descriptor() ([]byte, []int) {
return file_api_proto_rawDescGZIP(), []int{2}
}
func (x *GetServerAppIdRsp) GetAppId() string {
if x != nil {
return x.AppId
}
return ""
}
type RegisterServerReq struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
ServerType string `protobuf:"bytes,1,opt,name=server_type,json=serverType,proto3" json:"server_type,omitempty"`
}
func (x *RegisterServerReq) Reset() {
*x = RegisterServerReq{}
if protoimpl.UnsafeEnabled {
mi := &file_api_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *RegisterServerReq) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*RegisterServerReq) ProtoMessage() {}
func (x *RegisterServerReq) ProtoReflect() protoreflect.Message {
mi := &file_api_proto_msgTypes[3]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use RegisterServerReq.ProtoReflect.Descriptor instead.
func (*RegisterServerReq) Descriptor() ([]byte, []int) {
return file_api_proto_rawDescGZIP(), []int{3}
}
func (x *RegisterServerReq) GetServerType() string {
if x != nil {
return x.ServerType
}
return ""
}
type RegisterServerRsp struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
AppId string `protobuf:"bytes,1,opt,name=app_id,json=appId,proto3" json:"app_id,omitempty"`
}
func (x *RegisterServerRsp) Reset() {
*x = RegisterServerRsp{}
if protoimpl.UnsafeEnabled {
mi := &file_api_proto_msgTypes[4]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *RegisterServerRsp) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*RegisterServerRsp) ProtoMessage() {}
func (x *RegisterServerRsp) ProtoReflect() protoreflect.Message {
mi := &file_api_proto_msgTypes[4]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use RegisterServerRsp.ProtoReflect.Descriptor instead.
func (*RegisterServerRsp) Descriptor() ([]byte, []int) {
return file_api_proto_rawDescGZIP(), []int{4}
}
func (x *RegisterServerRsp) GetAppId() string {
if x != nil {
return x.AppId
}
return ""
}
type RegionEc2B struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Data []byte `protobuf:"bytes,1,opt,name=data,proto3" json:"data,omitempty"`
}
func (x *RegionEc2B) Reset() {
*x = RegionEc2B{}
if protoimpl.UnsafeEnabled {
mi := &file_api_proto_msgTypes[5]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *RegionEc2B) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*RegionEc2B) ProtoMessage() {}
func (x *RegionEc2B) ProtoReflect() protoreflect.Message {
mi := &file_api_proto_msgTypes[5]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use RegionEc2B.ProtoReflect.Descriptor instead.
func (*RegionEc2B) Descriptor() ([]byte, []int) {
return file_api_proto_rawDescGZIP(), []int{5}
}
func (x *RegionEc2B) GetData() []byte {
if x != nil {
return x.Data
}
return nil
}
var File_api_proto protoreflect.FileDescriptor
var file_api_proto_rawDesc = []byte{
0x0a, 0x09, 0x61, 0x70, 0x69, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x08, 0x6e, 0x6f, 0x64,
0x65, 0x2e, 0x61, 0x70, 0x69, 0x22, 0x09, 0x0a, 0x07, 0x4e, 0x75, 0x6c, 0x6c, 0x4d, 0x73, 0x67,
0x22, 0x34, 0x0a, 0x11, 0x47, 0x65, 0x74, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x41, 0x70, 0x70,
0x49, 0x64, 0x52, 0x65, 0x71, 0x12, 0x1f, 0x0a, 0x0b, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x5f,
0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x73, 0x65, 0x72, 0x76,
0x65, 0x72, 0x54, 0x79, 0x70, 0x65, 0x22, 0x2a, 0x0a, 0x11, 0x47, 0x65, 0x74, 0x53, 0x65, 0x72,
0x76, 0x65, 0x72, 0x41, 0x70, 0x70, 0x49, 0x64, 0x52, 0x73, 0x70, 0x12, 0x15, 0x0a, 0x06, 0x61,
0x70, 0x70, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x61, 0x70, 0x70,
0x49, 0x64, 0x22, 0x34, 0x0a, 0x11, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x53, 0x65,
0x72, 0x76, 0x65, 0x72, 0x52, 0x65, 0x71, 0x12, 0x1f, 0x0a, 0x0b, 0x73, 0x65, 0x72, 0x76, 0x65,
0x72, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x73, 0x65,
0x72, 0x76, 0x65, 0x72, 0x54, 0x79, 0x70, 0x65, 0x22, 0x2a, 0x0a, 0x11, 0x52, 0x65, 0x67, 0x69,
0x73, 0x74, 0x65, 0x72, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x52, 0x73, 0x70, 0x12, 0x15, 0x0a,
0x06, 0x61, 0x70, 0x70, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x61,
0x70, 0x70, 0x49, 0x64, 0x22, 0x20, 0x0a, 0x0a, 0x52, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x45, 0x63,
0x32, 0x62, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c,
0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x32, 0xe3, 0x01, 0x0a, 0x09, 0x44, 0x69, 0x73, 0x63, 0x6f,
0x76, 0x65, 0x72, 0x79, 0x12, 0x4c, 0x0a, 0x0e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72,
0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x12, 0x1b, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x61, 0x70,
0x69, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72,
0x52, 0x65, 0x71, 0x1a, 0x1b, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x52,
0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x52, 0x73, 0x70,
0x22, 0x00, 0x12, 0x4c, 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x41,
0x70, 0x70, 0x49, 0x64, 0x12, 0x1b, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x61, 0x70, 0x69, 0x2e,
0x47, 0x65, 0x74, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x41, 0x70, 0x70, 0x49, 0x64, 0x52, 0x65,
0x71, 0x1a, 0x1b, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x47, 0x65, 0x74,
0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x41, 0x70, 0x70, 0x49, 0x64, 0x52, 0x73, 0x70, 0x22, 0x00,
0x12, 0x3a, 0x0a, 0x0d, 0x47, 0x65, 0x74, 0x52, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x45, 0x63, 0x32,
0x62, 0x12, 0x11, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4e, 0x75, 0x6c,
0x6c, 0x4d, 0x73, 0x67, 0x1a, 0x14, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x61, 0x70, 0x69, 0x2e,
0x52, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x45, 0x63, 0x32, 0x62, 0x22, 0x00, 0x42, 0x13, 0x5a, 0x11,
0x68, 0x6b, 0x34, 0x65, 0x2f, 0x6e, 0x6f, 0x64, 0x65, 0x2f, 0x61, 0x70, 0x69, 0x3b, 0x61, 0x70,
0x69, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
file_api_proto_rawDescOnce sync.Once
file_api_proto_rawDescData = file_api_proto_rawDesc
)
func file_api_proto_rawDescGZIP() []byte {
file_api_proto_rawDescOnce.Do(func() {
file_api_proto_rawDescData = protoimpl.X.CompressGZIP(file_api_proto_rawDescData)
})
return file_api_proto_rawDescData
}
var file_api_proto_msgTypes = make([]protoimpl.MessageInfo, 6)
var file_api_proto_goTypes = []interface{}{
(*NullMsg)(nil), // 0: node.api.NullMsg
(*GetServerAppIdReq)(nil), // 1: node.api.GetServerAppIdReq
(*GetServerAppIdRsp)(nil), // 2: node.api.GetServerAppIdRsp
(*RegisterServerReq)(nil), // 3: node.api.RegisterServerReq
(*RegisterServerRsp)(nil), // 4: node.api.RegisterServerRsp
(*RegionEc2B)(nil), // 5: node.api.RegionEc2b
}
var file_api_proto_depIdxs = []int32{
3, // 0: node.api.Discovery.RegisterServer:input_type -> node.api.RegisterServerReq
1, // 1: node.api.Discovery.GetServerAppId:input_type -> node.api.GetServerAppIdReq
0, // 2: node.api.Discovery.GetRegionEc2b:input_type -> node.api.NullMsg
4, // 3: node.api.Discovery.RegisterServer:output_type -> node.api.RegisterServerRsp
2, // 4: node.api.Discovery.GetServerAppId:output_type -> node.api.GetServerAppIdRsp
5, // 5: node.api.Discovery.GetRegionEc2b:output_type -> node.api.RegionEc2b
3, // [3:6] is the sub-list for method output_type
0, // [0:3] is the sub-list for method input_type
0, // [0:0] is the sub-list for extension type_name
0, // [0:0] is the sub-list for extension extendee
0, // [0:0] is the sub-list for field type_name
}
func init() { file_api_proto_init() }
func file_api_proto_init() {
if File_api_proto != nil {
return
}
if !protoimpl.UnsafeEnabled {
file_api_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*NullMsg); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_api_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*GetServerAppIdReq); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_api_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*GetServerAppIdRsp); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_api_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*RegisterServerReq); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_api_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*RegisterServerRsp); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_api_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*RegionEc2B); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_api_proto_rawDesc,
NumEnums: 0,
NumMessages: 6,
NumExtensions: 0,
NumServices: 1,
},
GoTypes: file_api_proto_goTypes,
DependencyIndexes: file_api_proto_depIdxs,
MessageInfos: file_api_proto_msgTypes,
}.Build()
File_api_proto = out.File
file_api_proto_rawDesc = nil
file_api_proto_goTypes = nil
file_api_proto_depIdxs = nil
}
+34
View File
@@ -0,0 +1,34 @@
syntax = "proto3";
package node.api;
option go_package = "hk4e/node/api;api";
// 节点服务器注册发现服务
service Discovery {
rpc RegisterServer (RegisterServerReq) returns (RegisterServerRsp) {} // 服务器启动注册获取appid
rpc GetServerAppId (GetServerAppIdReq) returns (GetServerAppIdRsp) {} // 随机获取某服务器的appid
rpc GetRegionEc2b (NullMsg) returns (RegionEc2b) {} // 获取区服密钥信息
}
message NullMsg {
}
message GetServerAppIdReq {
string server_type = 1;
}
message GetServerAppIdRsp {
string app_id = 1;
}
message RegisterServerReq {
string server_type = 1;
}
message RegisterServerRsp {
string app_id = 1;
}
message RegionEc2b {
bytes data = 1;
}
+8
View File
@@ -0,0 +1,8 @@
package api
const (
GATE = "GATE"
GS = "GS"
FIGHT = "FIGHT"
PATHFINDING = "PATHFINDING"
)
+56
View File
@@ -0,0 +1,56 @@
package app
import (
"context"
_ "net/http/pprof"
"os"
"os/signal"
"syscall"
"time"
"hk4e/common/config"
"hk4e/node/service"
"hk4e/pkg/logger"
"github.com/nats-io/nats.go"
)
func Run(ctx context.Context, configFile string) error {
config.InitConfig(configFile)
logger.InitLogger("node")
logger.Warn("node start")
// natsrpc server
conn, err := nats.Connect(config.CONF.MQ.NatsUrl)
if err != nil {
logger.Error("connect nats error: %v", err)
return err
}
defer conn.Close()
s, err := service.NewService(conn)
if err != nil {
return err
}
defer s.Close()
c := make(chan os.Signal, 1)
signal.Notify(c, syscall.SIGHUP, syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGINT)
for {
select {
case <-ctx.Done():
return nil
case s := <-c:
logger.Warn("get a signal %s", s.String())
switch s {
case syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGINT:
logger.Warn("node exit")
time.Sleep(time.Second)
return nil
case syscall.SIGHUP:
default:
return nil
}
}
}
}
+94
View File
@@ -0,0 +1,94 @@
package service
import (
"context"
"strings"
"hk4e/common/config"
"hk4e/common/region"
"hk4e/node/api"
"hk4e/pkg/logger"
"hk4e/pkg/random"
"github.com/pkg/errors"
)
var _ api.DiscoveryNATSRPCServer = (*DiscoveryService)(nil)
type ServerInstance struct {
serverType string
appId string
}
type DiscoveryService struct {
regionEc2b *random.Ec2b
// TODO 加锁
serverInstanceMap map[string]map[string]*ServerInstance
serverAppIdMap map[string]bool
}
func NewDiscoveryService() *DiscoveryService {
r := new(DiscoveryService)
_, _, r.regionEc2b = region.InitRegion(config.CONF.Hk4e.KcpAddr, config.CONF.Hk4e.KcpPort, nil)
logger.Info("region ec2b create ok, seed: %v", r.regionEc2b.Seed())
r.serverInstanceMap = map[string]map[string]*ServerInstance{
api.GATE: make(map[string]*ServerInstance),
api.GS: make(map[string]*ServerInstance),
api.FIGHT: make(map[string]*ServerInstance),
api.PATHFINDING: make(map[string]*ServerInstance),
}
r.serverAppIdMap = make(map[string]bool)
return r
}
func (s *DiscoveryService) RegisterServer(ctx context.Context, req *api.RegisterServerReq) (*api.RegisterServerRsp, error) {
logger.Info("register new server, server type: %v", req.ServerType)
instMap, exist := s.serverInstanceMap[req.ServerType]
if !exist {
return nil, errors.New("server type not exist")
}
var appId string
for {
appId = strings.ToLower(random.GetRandomStr(8))
_, exist := s.serverAppIdMap[appId]
if !exist {
s.serverAppIdMap[appId] = true
break
}
}
instMap[appId] = &ServerInstance{
serverType: req.ServerType,
appId: appId,
}
logger.Info("new server appid is: %v", appId)
return &api.RegisterServerRsp{
AppId: appId,
}, nil
}
func (s *DiscoveryService) GetServerAppId(ctx context.Context, req *api.GetServerAppIdReq) (*api.GetServerAppIdRsp, error) {
logger.Info("get server instance, server type: %v", req.ServerType)
instMap, exist := s.serverInstanceMap[req.ServerType]
if !exist {
return nil, errors.New("server type not exist")
}
if len(instMap) == 0 {
return nil, errors.New("no server found")
}
var inst *ServerInstance = nil
for _, v := range instMap {
inst = v
break
}
logger.Info("get server appid is: %v", inst.appId)
return &api.GetServerAppIdRsp{
AppId: inst.appId,
}, nil
}
func (s *DiscoveryService) GetRegionEc2B(ctx context.Context, req *api.NullMsg) (*api.RegionEc2B, error) {
logger.Info("get region ec2b ok")
return &api.RegionEc2B{
Data: s.regionEc2b.Bytes(),
}, nil
}
+32
View File
@@ -0,0 +1,32 @@
package service
import (
"hk4e/node/api"
"github.com/byebyebruce/natsrpc"
"github.com/nats-io/nats.go"
"github.com/nats-io/nats.go/encoders/protobuf"
)
type Service struct {
}
func NewService(conn *nats.Conn) (*Service, error) {
enc, err := nats.NewEncodedConn(conn, protobuf.PROTOBUF_ENCODER)
if err != nil {
return nil, err
}
svr, err := natsrpc.NewServer(enc)
if err != nil {
return nil, err
}
discoveryService := NewDiscoveryService()
_, err = api.RegisterDiscoveryNATSRPCServer(svr, discoveryService)
if err != nil {
return nil, err
}
return &Service{}, nil
}
func (s *Service) Close() {
}
+23 -4
View File
@@ -10,17 +10,36 @@ import (
"hk4e/common/config"
"hk4e/common/mq"
"hk4e/common/rpc"
"hk4e/node/api"
"hk4e/pathfinding/handle"
"hk4e/pkg/logger"
)
var APPID string
func Run(ctx context.Context, configFile string) error {
config.InitConfig(configFile)
logger.InitLogger("pathfinding")
logger.Warn("pathfinding start")
// natsrpc client
client, err := rpc.NewClient()
if err != nil {
return err
}
messageQueue := mq.NewMessageQueue(mq.PATHFINDING, "1")
// 注册到节点服务器
rsp, err := client.Discovery.RegisterServer(context.TODO(), &api.RegisterServerReq{
ServerType: api.PATHFINDING,
})
if err != nil {
return err
}
APPID = rsp.GetAppId()
logger.InitLogger("pathfinding_" + APPID)
logger.Warn("pathfinding start, appid: %v", APPID)
messageQueue := mq.NewMessageQueue(api.PATHFINDING, APPID)
defer messageQueue.Close()
_ = handle.NewHandle(messageQueue)
@@ -35,7 +54,7 @@ func Run(ctx context.Context, configFile string) error {
logger.Warn("get a signal %s", s.String())
switch s {
case syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGINT:
logger.Warn("pathfinding exit")
logger.Warn("pathfinding exit, appid: %v", APPID)
time.Sleep(time.Second)
return nil
case syscall.SIGHUP:
+8 -4
View File
@@ -2,6 +2,7 @@ package handle
import (
"hk4e/common/mq"
"hk4e/node/api"
"hk4e/pathfinding/world"
"hk4e/pkg/logger"
"hk4e/protocol/cmd"
@@ -34,12 +35,15 @@ func (h *Handle) run() {
if netMsg.EventId != mq.NormalMsg {
continue
}
if netMsg.OriginServerType != api.GATE {
continue
}
gameMsg := netMsg.GameMsg
switch gameMsg.CmdId {
case cmd.QueryPathReq:
h.QueryPath(gameMsg.UserId, gameMsg.PayloadMessage)
h.QueryPath(gameMsg.UserId, netMsg.OriginServerAppId, gameMsg.PayloadMessage)
case cmd.ObstacleModifyNotify:
h.ObstacleModifyNotify(gameMsg.UserId, gameMsg.PayloadMessage)
h.ObstacleModifyNotify(gameMsg.UserId, netMsg.OriginServerAppId, gameMsg.PayloadMessage)
}
}
}()
@@ -47,7 +51,7 @@ func (h *Handle) run() {
}
// SendMsg 发送消息给客户端
func (h *Handle) SendMsg(cmdId uint16, userId uint32, payloadMsg pb.Message) {
func (h *Handle) SendMsg(cmdId uint16, userId uint32, gateAppId string, payloadMsg pb.Message) {
if userId < 100000000 || payloadMsg == nil {
return
}
@@ -62,7 +66,7 @@ func (h *Handle) SendMsg(cmdId uint16, userId uint32, payloadMsg pb.Message) {
return
}
gameMsg.PayloadMessageData = payloadMessageData
h.messageQueue.SendToGate("1", &mq.NetMsg{
h.messageQueue.SendToGate(gateAppId, &mq.NetMsg{
MsgType: mq.MsgTypeGame,
EventId: mq.NormalMsg,
GameMsg: gameMsg,
+6 -6
View File
@@ -41,9 +41,9 @@ func (h *Handle) ConvMeshVecListToPbVecList(meshVecList []pfalg.MeshVector) []*p
return ret
}
func (h *Handle) QueryPath(userId uint32, payloadMsg pb.Message) {
func (h *Handle) QueryPath(userId uint32, gateAppId string, payloadMsg pb.Message) {
req := payloadMsg.(*proto.QueryPathReq)
logger.Debug("query path req: %v, uid: %v", req, userId)
logger.Debug("query path req: %v, uid: %v, gateAppId: %v", req, userId, gateAppId)
var ok = false
var path []pfalg.MeshVector = nil
for _, destinationPos := range req.DestinationPos {
@@ -57,7 +57,7 @@ func (h *Handle) QueryPath(userId uint32, payloadMsg pb.Message) {
QueryId: req.QueryId,
QueryStatus: proto.QueryPathRsp_PATH_STATUS_TYPE_FAIL,
}
h.SendMsg(cmd.QueryPathRsp, userId, queryPathRsp)
h.SendMsg(cmd.QueryPathRsp, userId, gateAppId, queryPathRsp)
return
}
queryPathRsp := &proto.QueryPathRsp{
@@ -65,10 +65,10 @@ func (h *Handle) QueryPath(userId uint32, payloadMsg pb.Message) {
QueryStatus: proto.QueryPathRsp_PATH_STATUS_TYPE_SUCC,
Corners: h.ConvMeshVecListToPbVecList(path),
}
h.SendMsg(cmd.QueryPathRsp, userId, queryPathRsp)
h.SendMsg(cmd.QueryPathRsp, userId, gateAppId, queryPathRsp)
}
func (h *Handle) ObstacleModifyNotify(userId uint32, payloadMsg pb.Message) {
func (h *Handle) ObstacleModifyNotify(userId uint32, gateAppId string, payloadMsg pb.Message) {
req := payloadMsg.(*proto.ObstacleModifyNotify)
logger.Debug("obstacle modify req: %v, uid: %v", req, userId)
logger.Debug("obstacle modify req: %v, uid: %v, gateAppId: %v", req, userId, gateAppId)
}
+3 -5
View File
@@ -3,21 +3,19 @@ package statsviz_serve
import (
"net/http"
"hk4e/pkg/logger"
"github.com/arl/statsviz"
)
// Serve 性能检测
// 原生pprof /debug/pprof
// 可视化图表 /debug/statsviz
func Serve(addr string) error {
// 性能检测
err := statsviz.RegisterDefault()
if err != nil {
logger.Error("statsviz init error: %v", err)
return err
}
err = http.ListenAndServe(addr, nil)
if err != nil {
logger.Error("perf debug http start error: %v", err)
return err
}
return nil