mirror of
https://github.com/FlourishingWorld/hk4e.git
synced 2026-02-04 17:02:26 +08:00
服务器玩家在线信息同步
This commit is contained in:
@@ -8,6 +8,7 @@ import (
|
|||||||
"syscall"
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"hk4e/anticheat/handle"
|
||||||
"hk4e/common/config"
|
"hk4e/common/config"
|
||||||
"hk4e/common/mq"
|
"hk4e/common/mq"
|
||||||
"hk4e/common/rpc"
|
"hk4e/common/rpc"
|
||||||
@@ -63,6 +64,8 @@ func Run(ctx context.Context, configFile string) error {
|
|||||||
messageQueue := mq.NewMessageQueue(api.ANTICHEAT, APPID, client)
|
messageQueue := mq.NewMessageQueue(api.ANTICHEAT, APPID, client)
|
||||||
defer messageQueue.Close()
|
defer messageQueue.Close()
|
||||||
|
|
||||||
|
handle.NewHandle(messageQueue)
|
||||||
|
|
||||||
c := make(chan os.Signal, 1)
|
c := make(chan os.Signal, 1)
|
||||||
signal.Notify(c, syscall.SIGHUP, syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGINT)
|
signal.Notify(c, syscall.SIGHUP, syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGINT)
|
||||||
for {
|
for {
|
||||||
|
|||||||
71
anticheat/handle/handle.go
Normal file
71
anticheat/handle/handle.go
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
package handle
|
||||||
|
|
||||||
|
import (
|
||||||
|
"hk4e/common/mq"
|
||||||
|
"hk4e/gate/kcp"
|
||||||
|
"hk4e/node/api"
|
||||||
|
"hk4e/protocol/cmd"
|
||||||
|
"hk4e/protocol/proto"
|
||||||
|
|
||||||
|
pb "google.golang.org/protobuf/proto"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Handle struct {
|
||||||
|
messageQueue *mq.MessageQueue
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewHandle(messageQueue *mq.MessageQueue) (r *Handle) {
|
||||||
|
r = new(Handle)
|
||||||
|
r.messageQueue = messageQueue
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Handle) run() {
|
||||||
|
go func() {
|
||||||
|
for {
|
||||||
|
netMsg := <-h.messageQueue.GetNetMsg()
|
||||||
|
if netMsg.MsgType != mq.MsgTypeGame {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if netMsg.EventId != mq.NormalMsg {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if netMsg.OriginServerType != api.GATE {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
gameMsg := netMsg.GameMsg
|
||||||
|
switch gameMsg.CmdId {
|
||||||
|
case cmd.CombatInvocationsNotify:
|
||||||
|
h.CombatInvocationsNotify(gameMsg.UserId, netMsg.OriginServerAppId, gameMsg.PayloadMessage)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Handle) CombatInvocationsNotify(userId uint32, gateAppId string, payloadMsg pb.Message) {
|
||||||
|
req := payloadMsg.(*proto.CombatInvocationsNotify)
|
||||||
|
for _, entry := range req.InvokeList {
|
||||||
|
switch entry.ArgumentType {
|
||||||
|
case proto.CombatTypeArgument_ENTITY_MOVE:
|
||||||
|
entityMoveInfo := new(proto.EntityMoveInfo)
|
||||||
|
err := pb.Unmarshal(entry.CombatData, entityMoveInfo)
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if entityMoveInfo.MotionInfo.Pos.Y > 3000.0 {
|
||||||
|
h.KickPlayer(userId, gateAppId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Handle) KickPlayer(userId uint32, gateAppId string) {
|
||||||
|
h.messageQueue.SendToGate(gateAppId, &mq.NetMsg{
|
||||||
|
MsgType: mq.MsgTypeConnCtrl,
|
||||||
|
EventId: mq.KickPlayerNotify,
|
||||||
|
ConnCtrlMsg: &mq.ConnCtrlMsg{
|
||||||
|
KickUserId: userId,
|
||||||
|
KickReason: kcp.EnetServerKillClient,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -69,7 +69,7 @@ func NewMessageQueue(serverType string, appId string, rpcClient *rpc.Client) (r
|
|||||||
r.rpcClient = rpcClient
|
r.rpcClient = rpcClient
|
||||||
if serverType == api.GATE {
|
if serverType == api.GATE {
|
||||||
go r.runGateTcpMqServer()
|
go r.runGateTcpMqServer()
|
||||||
} else {
|
} else if serverType == api.GS || serverType == api.ANTICHEAT || serverType == api.PATHFINDING {
|
||||||
go r.runGateTcpMqClient()
|
go r.runGateTcpMqClient()
|
||||||
}
|
}
|
||||||
go r.recvHandler()
|
go r.recvHandler()
|
||||||
|
|||||||
@@ -111,6 +111,8 @@ func (k *KcpConnectManager) run() {
|
|||||||
go k.sendMsgHandle()
|
go k.sendMsgHandle()
|
||||||
go k.acceptHandle(listener)
|
go k.acceptHandle(listener)
|
||||||
go k.gateNetInfo()
|
go k.gateNetInfo()
|
||||||
|
k.syncGlobalGsOnlineMap()
|
||||||
|
go k.autoSyncGlobalGsOnlineMap()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (k *KcpConnectManager) Close() {
|
func (k *KcpConnectManager) Close() {
|
||||||
@@ -268,7 +270,7 @@ func (k *KcpConnectManager) enetHandle(listener *kcp.Listener) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Session 连接会话结构
|
// Session 连接会话结构 只允许定义并发安全或者简单的基础数据结构
|
||||||
type Session struct {
|
type Session struct {
|
||||||
conn *kcp.UDPSession
|
conn *kcp.UDPSession
|
||||||
connState uint8
|
connState uint8
|
||||||
@@ -467,3 +469,28 @@ func (k *KcpConnectManager) DeleteSession(convId uint64, userId uint32) {
|
|||||||
delete(k.sessionUserIdMap, userId)
|
delete(k.sessionUserIdMap, userId)
|
||||||
k.sessionMapLock.Unlock()
|
k.sessionMapLock.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (k *KcpConnectManager) autoSyncGlobalGsOnlineMap() {
|
||||||
|
ticker := time.NewTicker(time.Second * 60)
|
||||||
|
for {
|
||||||
|
<-ticker.C
|
||||||
|
k.syncGlobalGsOnlineMap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (k *KcpConnectManager) syncGlobalGsOnlineMap() {
|
||||||
|
rsp, err := k.discovery.GetGlobalGsOnlineMap(context.TODO(), nil)
|
||||||
|
if err != nil {
|
||||||
|
logger.Error("get global gs online map error: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
copyMap := make(map[uint32]string)
|
||||||
|
for k, v := range rsp.GlobalGsOnlineMap {
|
||||||
|
copyMap[k] = v
|
||||||
|
}
|
||||||
|
copyMapLen := len(copyMap)
|
||||||
|
k.globalGsOnlineMapLock.Lock()
|
||||||
|
k.globalGsOnlineMap = copyMap
|
||||||
|
k.globalGsOnlineMapLock.Unlock()
|
||||||
|
logger.Info("sync global gs online map finish, len: %v", copyMapLen)
|
||||||
|
}
|
||||||
|
|||||||
@@ -85,7 +85,7 @@ func Run(ctx context.Context, configFile string) error {
|
|||||||
messageQueue := mq.NewMessageQueue(api.GS, APPID, client)
|
messageQueue := mq.NewMessageQueue(api.GS, APPID, client)
|
||||||
defer messageQueue.Close()
|
defer messageQueue.Close()
|
||||||
|
|
||||||
gameManager := game.NewGameManager(db, messageQueue, GSID, APPID, mainGsAppid.AppId)
|
gameManager := game.NewGameManager(db, messageQueue, GSID, APPID, mainGsAppid.AppId, client.Discovery)
|
||||||
defer gameManager.Close()
|
defer gameManager.Close()
|
||||||
|
|
||||||
// natsrpc server
|
// natsrpc server
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"hk4e/common/mq"
|
"hk4e/common/mq"
|
||||||
|
"hk4e/common/rpc"
|
||||||
"hk4e/gate/kcp"
|
"hk4e/gate/kcp"
|
||||||
"hk4e/gdconf"
|
"hk4e/gdconf"
|
||||||
"hk4e/gs/dao"
|
"hk4e/gs/dao"
|
||||||
@@ -46,6 +47,7 @@ var ONLINE_PLAYER_NUM int32 = 0 // 当前在线玩家数
|
|||||||
var SELF *model.Player
|
var SELF *model.Player
|
||||||
|
|
||||||
type GameManager struct {
|
type GameManager struct {
|
||||||
|
discovery *rpc.DiscoveryClient // node服务器客户端
|
||||||
dao *dao.Dao
|
dao *dao.Dao
|
||||||
snowflake *alg.SnowflakeWorker
|
snowflake *alg.SnowflakeWorker
|
||||||
gsId uint32
|
gsId uint32
|
||||||
@@ -54,8 +56,9 @@ type GameManager struct {
|
|||||||
ai *model.Player // 本服的Ai玩家对象
|
ai *model.Player // 本服的Ai玩家对象
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewGameManager(dao *dao.Dao, messageQueue *mq.MessageQueue, gsId uint32, gsAppid string, mainGsAppid string) (r *GameManager) {
|
func NewGameManager(dao *dao.Dao, messageQueue *mq.MessageQueue, gsId uint32, gsAppid string, mainGsAppid string, discovery *rpc.DiscoveryClient) (r *GameManager) {
|
||||||
r = new(GameManager)
|
r = new(GameManager)
|
||||||
|
r.discovery = discovery
|
||||||
r.dao = dao
|
r.dao = dao
|
||||||
MESSAGE_QUEUE = messageQueue
|
MESSAGE_QUEUE = messageQueue
|
||||||
r.snowflake = alg.NewSnowflakeWorker(int64(gsId))
|
r.snowflake = alg.NewSnowflakeWorker(int64(gsId))
|
||||||
|
|||||||
@@ -242,12 +242,14 @@ func (g *GameManager) LoginNotify(userId uint32, player *model.Player, clientSeq
|
|||||||
playerLoginRsp := &proto.PlayerLoginRsp{
|
playerLoginRsp := &proto.PlayerLoginRsp{
|
||||||
IsUseAbilityHash: true,
|
IsUseAbilityHash: true,
|
||||||
AbilityHashCode: 0,
|
AbilityHashCode: 0,
|
||||||
GameBiz: "hk4e_global",
|
IsEnableClientHashDebug: true,
|
||||||
IsScOpen: false,
|
IsScOpen: false,
|
||||||
RegisterCps: "mihoyo",
|
ScInfo: []byte{},
|
||||||
CountryCode: "CN",
|
|
||||||
Birthday: "2000-01-01",
|
|
||||||
TotalTickTime: 0.0,
|
TotalTickTime: 0.0,
|
||||||
|
GameBiz: "hk4e_global",
|
||||||
|
RegisterCps: "mihoyo",
|
||||||
|
CountryCode: "US",
|
||||||
|
Birthday: "2000-01-01",
|
||||||
}
|
}
|
||||||
g.SendMsg(cmd.PlayerLoginRsp, userId, clientSeq, playerLoginRsp)
|
g.SendMsg(cmd.PlayerLoginRsp, userId, clientSeq, playerLoginRsp)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
package game
|
package game
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"hk4e/gs/dao"
|
"hk4e/gs/dao"
|
||||||
@@ -23,6 +25,7 @@ type UserManager struct {
|
|||||||
playerMap map[uint32]*model.Player // 内存玩家数据
|
playerMap map[uint32]*model.Player // 内存玩家数据
|
||||||
saveUserChan chan *SaveUserData // 用于主协程发送玩家数据给定时保存协程
|
saveUserChan chan *SaveUserData // 用于主协程发送玩家数据给定时保存协程
|
||||||
remotePlayerMap map[uint32]string // 远程玩家 key:userId value:玩家所在gs的appid
|
remotePlayerMap map[uint32]string // 远程玩家 key:userId value:玩家所在gs的appid
|
||||||
|
remotePlayerMapLock sync.RWMutex
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewUserManager(dao *dao.Dao) (r *UserManager) {
|
func NewUserManager(dao *dao.Dao) (r *UserManager) {
|
||||||
@@ -32,6 +35,8 @@ func NewUserManager(dao *dao.Dao) (r *UserManager) {
|
|||||||
r.saveUserChan = make(chan *SaveUserData) // 无缓冲区chan 避免主协程在写入时被迫加锁
|
r.saveUserChan = make(chan *SaveUserData) // 无缓冲区chan 避免主协程在写入时被迫加锁
|
||||||
r.remotePlayerMap = make(map[uint32]string)
|
r.remotePlayerMap = make(map[uint32]string)
|
||||||
go r.saveUserHandle()
|
go r.saveUserHandle()
|
||||||
|
r.syncRemotePlayerMap()
|
||||||
|
go r.autoSyncRemotePlayerMap()
|
||||||
return r
|
return r
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -251,8 +256,39 @@ func (u *UserManager) ChangeUserDbState(player *model.Player, state int) {
|
|||||||
|
|
||||||
// 远程玩家相关操作
|
// 远程玩家相关操作
|
||||||
|
|
||||||
|
func (u *UserManager) autoSyncRemotePlayerMap() {
|
||||||
|
ticker := time.NewTicker(time.Second * 60)
|
||||||
|
for {
|
||||||
|
<-ticker.C
|
||||||
|
u.syncRemotePlayerMap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *UserManager) syncRemotePlayerMap() {
|
||||||
|
rsp, err := GAME_MANAGER.discovery.GetGlobalGsOnlineMap(context.TODO(), nil)
|
||||||
|
if err != nil {
|
||||||
|
logger.Error("get global gs online map error: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
copyMap := make(map[uint32]string)
|
||||||
|
for k, v := range rsp.GlobalGsOnlineMap {
|
||||||
|
player, exist := u.playerMap[k]
|
||||||
|
if exist && player.Online {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
copyMap[k] = v
|
||||||
|
}
|
||||||
|
copyMapLen := len(copyMap)
|
||||||
|
u.remotePlayerMapLock.Lock()
|
||||||
|
u.remotePlayerMap = copyMap
|
||||||
|
u.remotePlayerMapLock.Unlock()
|
||||||
|
logger.Info("sync remote player map finish, len: %v", copyMapLen)
|
||||||
|
}
|
||||||
|
|
||||||
func (u *UserManager) GetRemoteUserOnlineState(userId uint32) bool {
|
func (u *UserManager) GetRemoteUserOnlineState(userId uint32) bool {
|
||||||
|
u.remotePlayerMapLock.RLock()
|
||||||
_, exist := u.remotePlayerMap[userId]
|
_, exist := u.remotePlayerMap[userId]
|
||||||
|
u.remotePlayerMapLock.RUnlock()
|
||||||
if !exist {
|
if !exist {
|
||||||
return false
|
return false
|
||||||
} else {
|
} else {
|
||||||
@@ -261,7 +297,9 @@ func (u *UserManager) GetRemoteUserOnlineState(userId uint32) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (u *UserManager) GetRemoteUserGsAppId(userId uint32) string {
|
func (u *UserManager) GetRemoteUserGsAppId(userId uint32) string {
|
||||||
|
u.remotePlayerMapLock.RLock()
|
||||||
appId, exist := u.remotePlayerMap[userId]
|
appId, exist := u.remotePlayerMap[userId]
|
||||||
|
u.remotePlayerMapLock.RUnlock()
|
||||||
if !exist {
|
if !exist {
|
||||||
return ""
|
return ""
|
||||||
} else {
|
} else {
|
||||||
@@ -270,12 +308,14 @@ func (u *UserManager) GetRemoteUserGsAppId(userId uint32) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (u *UserManager) SetRemoteUserOnlineState(userId uint32, isOnline bool, appId string) {
|
func (u *UserManager) SetRemoteUserOnlineState(userId uint32, isOnline bool, appId string) {
|
||||||
|
u.remotePlayerMapLock.Lock()
|
||||||
if isOnline {
|
if isOnline {
|
||||||
u.remotePlayerMap[userId] = appId
|
u.remotePlayerMap[userId] = appId
|
||||||
} else {
|
} else {
|
||||||
delete(u.remotePlayerMap, userId)
|
delete(u.remotePlayerMap, userId)
|
||||||
u.DeleteUser(userId)
|
u.DeleteUser(userId)
|
||||||
}
|
}
|
||||||
|
u.remotePlayerMapLock.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetRemoteOnlineUserList 获取指定数量的远程在线玩家 玩家数据只读禁止修改
|
// GetRemoteOnlineUserList 获取指定数量的远程在线玩家 玩家数据只读禁止修改
|
||||||
@@ -285,16 +325,22 @@ func (u *UserManager) GetRemoteOnlineUserList(total int) map[uint32]*model.Playe
|
|||||||
}
|
}
|
||||||
onlinePlayerMap := make(map[uint32]*model.Player)
|
onlinePlayerMap := make(map[uint32]*model.Player)
|
||||||
count := 0
|
count := 0
|
||||||
|
userIdList := make([]uint32, 0)
|
||||||
|
u.remotePlayerMapLock.RLock()
|
||||||
for userId := range u.remotePlayerMap {
|
for userId := range u.remotePlayerMap {
|
||||||
|
userIdList = append(userIdList, userId)
|
||||||
|
count++
|
||||||
|
if count >= total {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
u.remotePlayerMapLock.RUnlock()
|
||||||
|
for _, userId := range userIdList {
|
||||||
player := u.LoadTempOfflineUser(userId, false)
|
player := u.LoadTempOfflineUser(userId, false)
|
||||||
if player == nil {
|
if player == nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
onlinePlayerMap[player.PlayerID] = player
|
onlinePlayerMap[player.PlayerID] = player
|
||||||
count++
|
|
||||||
if count >= total {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return onlinePlayerMap
|
return onlinePlayerMap
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,6 +21,8 @@ service Discovery {
|
|||||||
rpc GetAllGateServerInfoList (NullMsg) returns (GateServerInfoList) {}
|
rpc GetAllGateServerInfoList (NullMsg) returns (GateServerInfoList) {}
|
||||||
// 获取主游戏服务器的appid
|
// 获取主游戏服务器的appid
|
||||||
rpc GetMainGameServerAppId (NullMsg) returns (GetMainGameServerAppIdRsp) {}
|
rpc GetMainGameServerAppId (NullMsg) returns (GetMainGameServerAppIdRsp) {}
|
||||||
|
// 获取全服玩家GS在线列表
|
||||||
|
rpc GetGlobalGsOnlineMap (NullMsg) returns (GetGlobalGsOnlineMapRsp) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
message NullMsg {
|
message NullMsg {
|
||||||
@@ -84,3 +86,7 @@ message GateServerInfo {
|
|||||||
message GateServerInfoList {
|
message GateServerInfoList {
|
||||||
repeated GateServerInfo gate_server_info_list = 1;
|
repeated GateServerInfo gate_server_info_list = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
message GetGlobalGsOnlineMapRsp {
|
||||||
|
map<uint32, string> GlobalGsOnlineMap = 1;
|
||||||
|
}
|
||||||
|
|||||||
@@ -5,4 +5,5 @@ const (
|
|||||||
GS = "GS"
|
GS = "GS"
|
||||||
ANTICHEAT = "ANTICHEAT"
|
ANTICHEAT = "ANTICHEAT"
|
||||||
PATHFINDING = "PATHFINDING"
|
PATHFINDING = "PATHFINDING"
|
||||||
|
NODE = "NODE"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -8,6 +8,8 @@ import (
|
|||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
"hk4e/common/config"
|
"hk4e/common/config"
|
||||||
|
"hk4e/common/mq"
|
||||||
|
"hk4e/node/api"
|
||||||
"hk4e/node/service"
|
"hk4e/node/service"
|
||||||
"hk4e/pkg/logger"
|
"hk4e/pkg/logger"
|
||||||
|
|
||||||
@@ -30,7 +32,12 @@ func Run(ctx context.Context, configFile string) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
defer conn.Close()
|
defer conn.Close()
|
||||||
s, err := service.NewService(conn)
|
|
||||||
|
// 只用来监听全服广播
|
||||||
|
messageQueue := mq.NewMessageQueue(api.NODE, "node", nil)
|
||||||
|
defer messageQueue.Close()
|
||||||
|
|
||||||
|
s, err := service.NewService(conn, messageQueue)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -53,6 +53,8 @@ type DiscoveryService struct {
|
|||||||
regionEc2b *random.Ec2b // 全局区服密钥信息
|
regionEc2b *random.Ec2b // 全局区服密钥信息
|
||||||
serverInstanceMap map[string]*sync.Map // 全部服务器实例集合 key:服务器类型 value:服务器实例集合 -> key:appid value:服务器实例
|
serverInstanceMap map[string]*sync.Map // 全部服务器实例集合 key:服务器类型 value:服务器实例集合 -> key:appid value:服务器实例
|
||||||
serverAppIdMap *sync.Map // 服务器appid集合 key:appid value:是否存在
|
serverAppIdMap *sync.Map // 服务器appid集合 key:appid value:是否存在
|
||||||
|
globalGsOnlineMap map[uint32]string
|
||||||
|
globalGsOnlineMapLock sync.RWMutex
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewDiscoveryService() *DiscoveryService {
|
func NewDiscoveryService() *DiscoveryService {
|
||||||
@@ -65,6 +67,7 @@ func NewDiscoveryService() *DiscoveryService {
|
|||||||
r.serverInstanceMap[api.ANTICHEAT] = new(sync.Map)
|
r.serverInstanceMap[api.ANTICHEAT] = new(sync.Map)
|
||||||
r.serverInstanceMap[api.PATHFINDING] = new(sync.Map)
|
r.serverInstanceMap[api.PATHFINDING] = new(sync.Map)
|
||||||
r.serverAppIdMap = new(sync.Map)
|
r.serverAppIdMap = new(sync.Map)
|
||||||
|
r.globalGsOnlineMap = make(map[uint32]string)
|
||||||
go r.removeDeadServer()
|
go r.removeDeadServer()
|
||||||
return r
|
return r
|
||||||
}
|
}
|
||||||
@@ -281,6 +284,19 @@ func (s *DiscoveryService) GetMainGameServerAppId(ctx context.Context, req *api.
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetGlobalGsOnlineMap 获取全服玩家GS在线列表
|
||||||
|
func (s *DiscoveryService) GetGlobalGsOnlineMap(ctx context.Context, req *api.NullMsg) (*api.GetGlobalGsOnlineMapRsp, error) {
|
||||||
|
copyMap := make(map[uint32]string)
|
||||||
|
s.globalGsOnlineMapLock.RLock()
|
||||||
|
for k, v := range s.globalGsOnlineMap {
|
||||||
|
copyMap[k] = v
|
||||||
|
}
|
||||||
|
s.globalGsOnlineMapLock.RUnlock()
|
||||||
|
return &api.GetGlobalGsOnlineMapRsp{
|
||||||
|
GlobalGsOnlineMap: copyMap,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (s *DiscoveryService) getRandomServerInstance(instMap *sync.Map) *ServerInstance {
|
func (s *DiscoveryService) getRandomServerInstance(instMap *sync.Map) *ServerInstance {
|
||||||
instList := make(ServerInstanceSortList, 0)
|
instList := make(ServerInstanceSortList, 0)
|
||||||
instMap.Range(func(key, value any) bool {
|
instMap.Range(func(key, value any) bool {
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package service
|
package service
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"hk4e/common/mq"
|
||||||
"hk4e/node/api"
|
"hk4e/node/api"
|
||||||
|
|
||||||
"github.com/byebyebruce/natsrpc"
|
"github.com/byebyebruce/natsrpc"
|
||||||
@@ -9,9 +10,11 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type Service struct {
|
type Service struct {
|
||||||
|
messageQueue *mq.MessageQueue
|
||||||
|
discoveryService *DiscoveryService
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewService(conn *nats.Conn) (*Service, error) {
|
func NewService(conn *nats.Conn, messageQueue *mq.MessageQueue) (*Service, error) {
|
||||||
enc, err := nats.NewEncodedConn(conn, protobuf.PROTOBUF_ENCODER)
|
enc, err := nats.NewEncodedConn(conn, protobuf.PROTOBUF_ENCODER)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -25,8 +28,36 @@ func NewService(conn *nats.Conn) (*Service, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return &Service{}, nil
|
s := &Service{
|
||||||
|
messageQueue: messageQueue,
|
||||||
|
discoveryService: discoveryService,
|
||||||
|
}
|
||||||
|
go s.BroadcastReceiver()
|
||||||
|
return s, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Service) Close() {
|
func (s *Service) Close() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Service) BroadcastReceiver() {
|
||||||
|
for {
|
||||||
|
netMsg := <-s.messageQueue.GetNetMsg()
|
||||||
|
if netMsg.MsgType != mq.MsgTypeServer {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if netMsg.EventId != mq.ServerUserOnlineStateChangeNotify {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if netMsg.OriginServerType != api.GS {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
serverMsg := netMsg.ServerMsg
|
||||||
|
s.discoveryService.globalGsOnlineMapLock.Lock()
|
||||||
|
if serverMsg.IsOnline {
|
||||||
|
s.discoveryService.globalGsOnlineMap[serverMsg.UserId] = netMsg.OriginServerAppId
|
||||||
|
} else {
|
||||||
|
delete(s.discoveryService.globalGsOnlineMap, serverMsg.UserId)
|
||||||
|
}
|
||||||
|
s.discoveryService.globalGsOnlineMapLock.Unlock()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -25,7 +25,6 @@ func NewHandle(messageQueue *mq.MessageQueue) (r *Handle) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (h *Handle) run() {
|
func (h *Handle) run() {
|
||||||
for i := 0; i < 1; i++ {
|
|
||||||
go func() {
|
go func() {
|
||||||
for {
|
for {
|
||||||
netMsg := <-h.messageQueue.GetNetMsg()
|
netMsg := <-h.messageQueue.GetNetMsg()
|
||||||
@@ -48,11 +47,10 @@ func (h *Handle) run() {
|
|||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// SendMsg 发送消息给客户端
|
// SendMsg 发送消息给客户端
|
||||||
func (h *Handle) SendMsg(cmdId uint16, userId uint32, gateAppId string, payloadMsg pb.Message) {
|
func (h *Handle) SendMsg(cmdId uint16, userId uint32, gateAppId string, payloadMsg pb.Message) {
|
||||||
if userId < 100000000 || payloadMsg == nil {
|
if payloadMsg == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
gameMsg := new(mq.GameMsg)
|
gameMsg := new(mq.GameMsg)
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
package handle
|
package handle
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"hk4e/pathfinding/pfalg"
|
"hk4e/pkg/alg"
|
||||||
"hk4e/pkg/logger"
|
"hk4e/pkg/logger"
|
||||||
"hk4e/protocol/cmd"
|
"hk4e/protocol/cmd"
|
||||||
"hk4e/protocol/proto"
|
"hk4e/protocol/proto"
|
||||||
@@ -9,15 +9,15 @@ import (
|
|||||||
pb "google.golang.org/protobuf/proto"
|
pb "google.golang.org/protobuf/proto"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (h *Handle) ConvPbVecToMeshVec(pbVec *proto.Vector) pfalg.MeshVector {
|
func (h *Handle) ConvPbVecToMeshVec(pbVec *proto.Vector) alg.MeshVector {
|
||||||
return pfalg.MeshVector{
|
return alg.MeshVector{
|
||||||
X: int16(pbVec.X),
|
X: int16(pbVec.X),
|
||||||
Y: int16(pbVec.Y),
|
Y: int16(pbVec.Y),
|
||||||
Z: int16(pbVec.Z),
|
Z: int16(pbVec.Z),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Handle) ConvMeshVecToPbVec(meshVec pfalg.MeshVector) *proto.Vector {
|
func (h *Handle) ConvMeshVecToPbVec(meshVec alg.MeshVector) *proto.Vector {
|
||||||
return &proto.Vector{
|
return &proto.Vector{
|
||||||
X: float32(meshVec.X),
|
X: float32(meshVec.X),
|
||||||
Y: float32(meshVec.Y),
|
Y: float32(meshVec.Y),
|
||||||
@@ -25,15 +25,15 @@ func (h *Handle) ConvMeshVecToPbVec(meshVec pfalg.MeshVector) *proto.Vector {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Handle) ConvPbVecListToMeshVecList(pbVecList []*proto.Vector) []pfalg.MeshVector {
|
func (h *Handle) ConvPbVecListToMeshVecList(pbVecList []*proto.Vector) []alg.MeshVector {
|
||||||
ret := make([]pfalg.MeshVector, 0)
|
ret := make([]alg.MeshVector, 0)
|
||||||
for _, pbVec := range pbVecList {
|
for _, pbVec := range pbVecList {
|
||||||
ret = append(ret, h.ConvPbVecToMeshVec(pbVec))
|
ret = append(ret, h.ConvPbVecToMeshVec(pbVec))
|
||||||
}
|
}
|
||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Handle) ConvMeshVecListToPbVecList(meshVecList []pfalg.MeshVector) []*proto.Vector {
|
func (h *Handle) ConvMeshVecListToPbVecList(meshVecList []alg.MeshVector) []*proto.Vector {
|
||||||
ret := make([]*proto.Vector, 0)
|
ret := make([]*proto.Vector, 0)
|
||||||
for _, meshVec := range meshVecList {
|
for _, meshVec := range meshVecList {
|
||||||
ret = append(ret, h.ConvMeshVecToPbVec(meshVec))
|
ret = append(ret, h.ConvMeshVecToPbVec(meshVec))
|
||||||
@@ -45,7 +45,7 @@ func (h *Handle) QueryPath(userId uint32, gateAppId string, payloadMsg pb.Messag
|
|||||||
req := payloadMsg.(*proto.QueryPathReq)
|
req := payloadMsg.(*proto.QueryPathReq)
|
||||||
logger.Debug("query path req: %v, uid: %v, gateAppId: %v", req, userId, gateAppId)
|
logger.Debug("query path req: %v, uid: %v, gateAppId: %v", req, userId, gateAppId)
|
||||||
var ok = false
|
var ok = false
|
||||||
var path []pfalg.MeshVector = nil
|
var path []alg.MeshVector = nil
|
||||||
for _, destinationPos := range req.DestinationPos {
|
for _, destinationPos := range req.DestinationPos {
|
||||||
ok, path = h.worldStatic.Pathfinding(h.ConvPbVecToMeshVec(req.SourcePos), h.ConvPbVecToMeshVec(destinationPos))
|
ok, path = h.worldStatic.Pathfinding(h.ConvPbVecToMeshVec(req.SourcePos), h.ConvPbVecToMeshVec(destinationPos))
|
||||||
if ok {
|
if ok {
|
||||||
|
|||||||
@@ -1,7 +0,0 @@
|
|||||||
package pfalg
|
|
||||||
|
|
||||||
type MeshVector struct {
|
|
||||||
X int16
|
|
||||||
Y int16
|
|
||||||
Z int16
|
|
||||||
}
|
|
||||||
@@ -5,18 +5,18 @@ import (
|
|||||||
"encoding/gob"
|
"encoding/gob"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"hk4e/pathfinding/pfalg"
|
"hk4e/pkg/alg"
|
||||||
"hk4e/pkg/logger"
|
"hk4e/pkg/logger"
|
||||||
)
|
)
|
||||||
|
|
||||||
type WorldStatic struct {
|
type WorldStatic struct {
|
||||||
// x y z -> if terrain exist
|
// x y z -> if terrain exist
|
||||||
terrain map[pfalg.MeshVector]bool
|
terrain map[alg.MeshVector]bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewWorldStatic() (r *WorldStatic) {
|
func NewWorldStatic() (r *WorldStatic) {
|
||||||
r = new(WorldStatic)
|
r = new(WorldStatic)
|
||||||
r.terrain = make(map[pfalg.MeshVector]bool)
|
r.terrain = make(map[alg.MeshVector]bool)
|
||||||
return r
|
return r
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -52,7 +52,7 @@ func (w *WorldStatic) SaveTerrain() bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (w *WorldStatic) GetTerrain(x int16, y int16, z int16) (exist bool) {
|
func (w *WorldStatic) GetTerrain(x int16, y int16, z int16) (exist bool) {
|
||||||
pos := pfalg.MeshVector{
|
pos := alg.MeshVector{
|
||||||
X: x,
|
X: x,
|
||||||
Y: y,
|
Y: y,
|
||||||
Z: z,
|
Z: z,
|
||||||
@@ -62,7 +62,7 @@ func (w *WorldStatic) GetTerrain(x int16, y int16, z int16) (exist bool) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (w *WorldStatic) SetTerrain(x int16, y int16, z int16) {
|
func (w *WorldStatic) SetTerrain(x int16, y int16, z int16) {
|
||||||
pos := pfalg.MeshVector{
|
pos := alg.MeshVector{
|
||||||
X: x,
|
X: x,
|
||||||
Y: y,
|
Y: y,
|
||||||
Z: z,
|
Z: z,
|
||||||
@@ -70,13 +70,13 @@ func (w *WorldStatic) SetTerrain(x int16, y int16, z int16) {
|
|||||||
w.terrain[pos] = true
|
w.terrain[pos] = true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *WorldStatic) Pathfinding(startPos pfalg.MeshVector, endPos pfalg.MeshVector) (bool, []pfalg.MeshVector) {
|
func (w *WorldStatic) Pathfinding(startPos alg.MeshVector, endPos alg.MeshVector) (bool, []alg.MeshVector) {
|
||||||
bfs := pfalg.NewBFS()
|
bfs := alg.NewBFS()
|
||||||
bfs.InitMap(
|
bfs.InitMap(
|
||||||
w.terrain,
|
w.terrain,
|
||||||
startPos,
|
startPos,
|
||||||
endPos,
|
endPos,
|
||||||
100,
|
0,
|
||||||
)
|
)
|
||||||
pathVectorList := bfs.Pathfinding()
|
pathVectorList := bfs.Pathfinding()
|
||||||
if pathVectorList == nil {
|
if pathVectorList == nil {
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
package pfalg
|
package alg
|
||||||
|
|
||||||
import (
|
// 广度优先搜索寻路
|
||||||
"hk4e/pkg/alg"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
const (
|
||||||
NODE_NONE = iota
|
NODE_NONE = iota
|
||||||
@@ -166,7 +164,7 @@ func (b *BFS) GetPath() []*PathNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (b *BFS) Pathfinding() []MeshVector {
|
func (b *BFS) Pathfinding() []MeshVector {
|
||||||
queue := alg.NewALQueue[*PathNode]()
|
queue := NewALQueue[*PathNode]()
|
||||||
b.startPathNode.visit = true
|
b.startPathNode.visit = true
|
||||||
queue.EnQueue(b.startPathNode)
|
queue.EnQueue(b.startPathNode)
|
||||||
for queue.Len() > 0 {
|
for queue.Len() > 0 {
|
||||||
@@ -65,3 +65,10 @@ func Vector3CrossProd(v1 *Vector3, v2 *Vector3) *Vector3 {
|
|||||||
v3.Z = v1.X*v2.Y - v2.X*v1.Y
|
v3.Z = v1.X*v2.Y - v2.X*v1.Y
|
||||||
return v3
|
return v3
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MeshVector 网格向量
|
||||||
|
type MeshVector struct {
|
||||||
|
X int16
|
||||||
|
Y int16
|
||||||
|
Z int16
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user