mirror of
https://github.com/FlourishingWorld/hk4e.git
synced 2026-02-04 15:42:25 +08:00
寻路服务器
This commit is contained in:
@@ -14,6 +14,9 @@ hk4e game server
|
|||||||
* mongodb
|
* mongodb
|
||||||
* nats-server
|
* nats-server
|
||||||
|
|
||||||
1. 启动dispatch `cmd/dispatch && go run .`
|
1. 启动http登录服务器 `cmd/dispatch && go run .`
|
||||||
1. 启动gate `cd cmd/gate && go run .`
|
2. 启动网关服务器 `cd cmd/gate && go run .`
|
||||||
1. 启动gs `cd cmd/gs && go run .`
|
3. 启动游戏服务器 `cd cmd/gs && go run .`
|
||||||
|
4. 启动游戏管理服务器 `cmd/gm && go run .`
|
||||||
|
5. 启动战斗服务器 `cmd/fight && go run .`
|
||||||
|
6. 启动寻路服务器 `cmd/pathfinding && go run .`
|
||||||
|
|||||||
23
cmd/hk4e/pathfinding.go
Normal file
23
cmd/hk4e/pathfinding.go
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"hk4e/pathfinding/app"
|
||||||
|
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
)
|
||||||
|
|
||||||
|
// PathfindingCmd 检查配表命令
|
||||||
|
func PathfindingCmd() *cobra.Command {
|
||||||
|
var cfg string
|
||||||
|
c := &cobra.Command{
|
||||||
|
Use: "pathfinding",
|
||||||
|
Short: "pathfinding 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
|
||||||
|
}
|
||||||
8
cmd/pathfinding/application.toml
Normal file
8
cmd/pathfinding/application.toml
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
[logger]
|
||||||
|
level = "DEBUG"
|
||||||
|
mode = "BOTH"
|
||||||
|
track = true
|
||||||
|
max_size = 10485760
|
||||||
|
|
||||||
|
[mq]
|
||||||
|
nats_url = "nats://nats:4222"
|
||||||
25
cmd/pathfinding/main.go
Normal file
25
cmd/pathfinding/main.go
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
_ "net/http/pprof"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"hk4e/pathfinding/app"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
config = flag.String("config", "application.toml", "config file")
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
flag.Parse()
|
||||||
|
// go statsviz_serve.Serve("0.0.0.0:2345")
|
||||||
|
err := app.Run(context.TODO(), *config)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -5,9 +5,10 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
GATE = "GATE_${APPID}_HK4E"
|
GATE = "GATE_${APPID}_HK4E"
|
||||||
GS = "GS_${APPID}_HK4E"
|
GS = "GS_${APPID}_HK4E"
|
||||||
FIGHT = "FIGHT_${APPID}_HK4E"
|
FIGHT = "FIGHT_${APPID}_HK4E"
|
||||||
|
PATHFINDING = "PATHFINDING_${APPID}_HK4E"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (m *MessageQueue) getTopic(serverType string, appId string) string {
|
func (m *MessageQueue) getTopic(serverType string, appId string) string {
|
||||||
@@ -29,3 +30,8 @@ func (m *MessageQueue) SendToFight(appId string, netMsg *NetMsg) {
|
|||||||
netMsg.Topic = m.getTopic(FIGHT, appId)
|
netMsg.Topic = m.getTopic(FIGHT, appId)
|
||||||
m.netMsgInput <- netMsg
|
m.netMsgInput <- netMsg
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *MessageQueue) SendToPathfinding(appId string, netMsg *NetMsg) {
|
||||||
|
netMsg.Topic = m.getTopic(PATHFINDING, appId)
|
||||||
|
m.netMsgInput <- netMsg
|
||||||
|
}
|
||||||
|
|||||||
@@ -104,18 +104,21 @@ func (k *KcpConnectManager) recvMsgHandle(protoMsg *ProtoMsg, session *Session)
|
|||||||
logger.Error("conn not active so drop packet, cmdId: %v, userId: %v, convId: %v", protoMsg.CmdId, userId, protoMsg.ConvId)
|
logger.Error("conn not active so drop packet, cmdId: %v, userId: %v, convId: %v", protoMsg.CmdId, userId, protoMsg.ConvId)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// 转发到GS
|
// 只转发到寻路服务器
|
||||||
gameMsg := new(mq.GameMsg)
|
if protoMsg.CmdId == cmd.QueryPathReq || protoMsg.CmdId == cmd.ObstacleModifyNotify {
|
||||||
gameMsg.UserId = userId
|
gameMsg := new(mq.GameMsg)
|
||||||
gameMsg.CmdId = protoMsg.CmdId
|
gameMsg.UserId = userId
|
||||||
gameMsg.ClientSeq = protoMsg.HeadMessage.ClientSequenceId
|
gameMsg.CmdId = protoMsg.CmdId
|
||||||
gameMsg.PayloadMessage = protoMsg.PayloadMessage
|
gameMsg.ClientSeq = protoMsg.HeadMessage.ClientSequenceId
|
||||||
k.messageQueue.SendToGs("1", &mq.NetMsg{
|
gameMsg.PayloadMessage = protoMsg.PayloadMessage
|
||||||
MsgType: mq.MsgTypeGame,
|
k.messageQueue.SendToPathfinding("1", &mq.NetMsg{
|
||||||
EventId: mq.NormalMsg,
|
MsgType: mq.MsgTypeGame,
|
||||||
GameMsg: gameMsg,
|
EventId: mq.NormalMsg,
|
||||||
})
|
GameMsg: gameMsg,
|
||||||
// 转发到FIGHT
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// 同时转发到战斗服务器
|
||||||
if protoMsg.CmdId == cmd.CombatInvocationsNotify {
|
if protoMsg.CmdId == cmd.CombatInvocationsNotify {
|
||||||
gameMsg := new(mq.GameMsg)
|
gameMsg := new(mq.GameMsg)
|
||||||
gameMsg.UserId = userId
|
gameMsg.UserId = userId
|
||||||
@@ -128,6 +131,17 @@ func (k *KcpConnectManager) recvMsgHandle(protoMsg *ProtoMsg, session *Session)
|
|||||||
GameMsg: gameMsg,
|
GameMsg: gameMsg,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
// 转发到GS
|
||||||
|
gameMsg := new(mq.GameMsg)
|
||||||
|
gameMsg.UserId = userId
|
||||||
|
gameMsg.CmdId = protoMsg.CmdId
|
||||||
|
gameMsg.ClientSeq = protoMsg.HeadMessage.ClientSequenceId
|
||||||
|
gameMsg.PayloadMessage = protoMsg.PayloadMessage
|
||||||
|
k.messageQueue.SendToGs("1", &mq.NetMsg{
|
||||||
|
MsgType: mq.MsgTypeGame,
|
||||||
|
EventId: mq.NormalMsg,
|
||||||
|
GameMsg: gameMsg,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -95,42 +95,3 @@ func (g *GameDataConfig) loadAll() {
|
|||||||
g.excelBinPrefix += "/"
|
g.excelBinPrefix += "/"
|
||||||
g.load()
|
g.load()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *GameDataConfig) ReadWorldTerrain() []byte {
|
|
||||||
resourcePath := g.getResourcePathPrefix()
|
|
||||||
dirInfo, err := os.Stat(resourcePath)
|
|
||||||
if err != nil || !dirInfo.IsDir() {
|
|
||||||
logger.Error("open game data config dir error: %v", err)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
dirInfo, err = os.Stat(resourcePath + "/WorldStatic")
|
|
||||||
if err != nil || !dirInfo.IsDir() {
|
|
||||||
logger.Error("open game data world static dir error: %v", err)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
data, err := os.ReadFile(resourcePath + "/WorldStatic/world_terrain.bin")
|
|
||||||
if err != nil {
|
|
||||||
logger.Error("read world terrain file error: %v", err)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return data
|
|
||||||
}
|
|
||||||
|
|
||||||
func (g *GameDataConfig) WriteWorldTerrain(data []byte) {
|
|
||||||
resourcePath := g.getResourcePathPrefix()
|
|
||||||
dirInfo, err := os.Stat(resourcePath)
|
|
||||||
if err != nil || !dirInfo.IsDir() {
|
|
||||||
logger.Error("open game data config dir error: %v", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
dirInfo, err = os.Stat(resourcePath + "/WorldStatic")
|
|
||||||
if err != nil || !dirInfo.IsDir() {
|
|
||||||
logger.Error("open game data world static dir error: %v", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
err = os.WriteFile(resourcePath+"/WorldStatic/world_terrain.bin", data, 0644)
|
|
||||||
if err != nil {
|
|
||||||
logger.Error("write world terrain file error: %v", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -140,7 +140,6 @@ func (g *GameManager) Stop() {
|
|||||||
EventId: RunUserCopyAndSave,
|
EventId: RunUserCopyAndSave,
|
||||||
}
|
}
|
||||||
time.Sleep(time.Second * 5)
|
time.Sleep(time.Second * 5)
|
||||||
// g.worldManager.worldStatic.SaveTerrain()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// SendMsg 发送消息给客户端
|
// SendMsg 发送消息给客户端
|
||||||
|
|||||||
@@ -66,7 +66,6 @@ func (r *RouteManager) InitRoute() {
|
|||||||
r.registerRouter(cmd.ChooseCurAvatarTeamReq, GAME_MANAGER.ChooseCurAvatarTeamReq)
|
r.registerRouter(cmd.ChooseCurAvatarTeamReq, GAME_MANAGER.ChooseCurAvatarTeamReq)
|
||||||
r.registerRouter(cmd.GetGachaInfoReq, GAME_MANAGER.GetGachaInfoReq)
|
r.registerRouter(cmd.GetGachaInfoReq, GAME_MANAGER.GetGachaInfoReq)
|
||||||
r.registerRouter(cmd.DoGachaReq, GAME_MANAGER.DoGachaReq)
|
r.registerRouter(cmd.DoGachaReq, GAME_MANAGER.DoGachaReq)
|
||||||
r.registerRouter(cmd.QueryPathReq, GAME_MANAGER.QueryPathReq)
|
|
||||||
r.registerRouter(cmd.CombatInvocationsNotify, GAME_MANAGER.CombatInvocationsNotify)
|
r.registerRouter(cmd.CombatInvocationsNotify, GAME_MANAGER.CombatInvocationsNotify)
|
||||||
r.registerRouter(cmd.AbilityInvocationsNotify, GAME_MANAGER.AbilityInvocationsNotify)
|
r.registerRouter(cmd.AbilityInvocationsNotify, GAME_MANAGER.AbilityInvocationsNotify)
|
||||||
r.registerRouter(cmd.ClientAbilityInitFinishNotify, GAME_MANAGER.ClientAbilityInitFinishNotify)
|
r.registerRouter(cmd.ClientAbilityInitFinishNotify, GAME_MANAGER.ClientAbilityInitFinishNotify)
|
||||||
|
|||||||
@@ -209,19 +209,19 @@ func (t *TickManager) onTickSecond(now int64) {
|
|||||||
worldPlayerRTTNotify.PlayerRttList = append(worldPlayerRTTNotify.PlayerRttList, playerRTTInfo)
|
worldPlayerRTTNotify.PlayerRttList = append(worldPlayerRTTNotify.PlayerRttList, playerRTTInfo)
|
||||||
}
|
}
|
||||||
GAME_MANAGER.SendMsg(cmd.WorldPlayerRTTNotify, player.PlayerID, 0, worldPlayerRTTNotify)
|
GAME_MANAGER.SendMsg(cmd.WorldPlayerRTTNotify, player.PlayerID, 0, worldPlayerRTTNotify)
|
||||||
}
|
|
||||||
if !world.IsBigWorld() && world.owner.SceneLoadState == model.SceneEnterDone {
|
|
||||||
// 刷怪
|
// 刷怪
|
||||||
scene := world.GetSceneById(3)
|
if !world.IsBigWorld() && world.owner.SceneLoadState == model.SceneEnterDone {
|
||||||
monsterEntityCount := 0
|
scene := world.GetSceneById(3)
|
||||||
for _, entity := range scene.entityMap {
|
monsterEntityCount := 0
|
||||||
if entity.entityType == uint32(proto.ProtEntityType_PROT_ENTITY_TYPE_MONSTER) {
|
for _, entity := range scene.entityMap {
|
||||||
monsterEntityCount++
|
if entity.entityType == uint32(proto.ProtEntityType_PROT_ENTITY_TYPE_MONSTER) {
|
||||||
|
monsterEntityCount++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if monsterEntityCount < 30 {
|
||||||
|
monsterEntityId := t.createMonster(world.owner, scene)
|
||||||
|
GAME_MANAGER.AddSceneEntityNotify(world.owner, proto.VisionType_VISION_TYPE_BORN, []uint32{monsterEntityId}, true, false)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if monsterEntityCount < 30 {
|
|
||||||
monsterEntityId := t.createMonster(scene)
|
|
||||||
GAME_MANAGER.AddSceneEntityNotify(world.owner, proto.VisionType_VISION_TYPE_BORN, []uint32{monsterEntityId}, true, false)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -241,7 +241,7 @@ func (t *TickManager) onTick200MilliSecond(now int64) {
|
|||||||
func (t *TickManager) onTick100MilliSecond(now int64) {
|
func (t *TickManager) onTick100MilliSecond(now int64) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *TickManager) createMonster(scene *Scene) uint32 {
|
func (t *TickManager) createMonster(player *model.Player, scene *Scene) uint32 {
|
||||||
pos := &model.Vector{
|
pos := &model.Vector{
|
||||||
X: 2747,
|
X: 2747,
|
||||||
Y: 194,
|
Y: 194,
|
||||||
|
|||||||
@@ -108,6 +108,13 @@ func (g *GameManager) ToTheMoonEnterSceneReq(player *model.Player, payloadMsg pb
|
|||||||
g.SendMsg(cmd.ToTheMoonEnterSceneRsp, player.PlayerID, player.ClientSeq, new(proto.ToTheMoonEnterSceneRsp))
|
g.SendMsg(cmd.ToTheMoonEnterSceneRsp, player.PlayerID, player.ClientSeq, new(proto.ToTheMoonEnterSceneRsp))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (g *GameManager) PathfindingEnterSceneReq(player *model.Player, payloadMsg pb.Message) {
|
||||||
|
logger.Debug("user pf enter scene, uid: %v", player.PlayerID)
|
||||||
|
req := payloadMsg.(*proto.PathfindingEnterSceneReq)
|
||||||
|
_ = req
|
||||||
|
g.SendMsg(cmd.PathfindingEnterSceneRsp, player.PlayerID, player.ClientSeq, new(proto.PathfindingEnterSceneRsp))
|
||||||
|
}
|
||||||
|
|
||||||
func (g *GameManager) SetEntityClientDataNotify(player *model.Player, payloadMsg pb.Message) {
|
func (g *GameManager) SetEntityClientDataNotify(player *model.Player, payloadMsg pb.Message) {
|
||||||
logger.Debug("user set entity client data, uid: %v", player.PlayerID)
|
logger.Debug("user set entity client data, uid: %v", player.PlayerID)
|
||||||
ntf := payloadMsg.(*proto.SetEntityClientDataNotify)
|
ntf := payloadMsg.(*proto.SetEntityClientDataNotify)
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
package game
|
package game
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"hk4e/gs/constant"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
|
"hk4e/gs/constant"
|
||||||
|
|
||||||
gdc "hk4e/gs/config"
|
gdc "hk4e/gs/config"
|
||||||
"hk4e/gs/model"
|
"hk4e/gs/model"
|
||||||
"hk4e/pkg/logger"
|
"hk4e/pkg/logger"
|
||||||
@@ -108,23 +109,6 @@ func (g *GameManager) TeleportPlayer(player *model.Player, enterReason uint32, s
|
|||||||
g.SendMsg(cmd.PlayerEnterSceneNotify, player.PlayerID, player.ClientSeq, playerEnterSceneNotify)
|
g.SendMsg(cmd.PlayerEnterSceneNotify, player.PlayerID, player.ClientSeq, playerEnterSceneNotify)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *GameManager) PathfindingEnterSceneReq(player *model.Player, payloadMsg pb.Message) {
|
|
||||||
logger.Debug("user pathfinding enter scene, uid: %v", player.PlayerID)
|
|
||||||
g.SendMsg(cmd.PathfindingEnterSceneRsp, player.PlayerID, player.ClientSeq, new(proto.PathfindingEnterSceneRsp))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (g *GameManager) QueryPathReq(player *model.Player, payloadMsg pb.Message) {
|
|
||||||
// logger.Debug("user query path, uid: %v", player.PlayerID)
|
|
||||||
req := payloadMsg.(*proto.QueryPathReq)
|
|
||||||
|
|
||||||
queryPathRsp := &proto.QueryPathRsp{
|
|
||||||
Corners: []*proto.Vector{req.DestinationPos[0]},
|
|
||||||
QueryId: req.QueryId,
|
|
||||||
QueryStatus: proto.QueryPathRsp_PATH_STATUS_TYPE_SUCC,
|
|
||||||
}
|
|
||||||
g.SendMsg(cmd.QueryPathRsp, player.PlayerID, player.ClientSeq, queryPathRsp)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (g *GameManager) GetScenePointReq(player *model.Player, payloadMsg pb.Message) {
|
func (g *GameManager) GetScenePointReq(player *model.Player, payloadMsg pb.Message) {
|
||||||
logger.Debug("user get scene point, uid: %v", player.PlayerID)
|
logger.Debug("user get scene point, uid: %v", player.PlayerID)
|
||||||
req := payloadMsg.(*proto.GetScenePointReq)
|
req := payloadMsg.(*proto.GetScenePointReq)
|
||||||
|
|||||||
@@ -18,20 +18,15 @@ import (
|
|||||||
// 世界管理器
|
// 世界管理器
|
||||||
|
|
||||||
type WorldManager struct {
|
type WorldManager struct {
|
||||||
worldMap map[uint32]*World
|
worldMap map[uint32]*World
|
||||||
snowflake *alg.SnowflakeWorker
|
snowflake *alg.SnowflakeWorker
|
||||||
worldStatic *WorldStatic
|
bigWorld *World
|
||||||
bigWorld *World
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewWorldManager(snowflake *alg.SnowflakeWorker) (r *WorldManager) {
|
func NewWorldManager(snowflake *alg.SnowflakeWorker) (r *WorldManager) {
|
||||||
r = new(WorldManager)
|
r = new(WorldManager)
|
||||||
r.worldMap = make(map[uint32]*World)
|
r.worldMap = make(map[uint32]*World)
|
||||||
r.snowflake = snowflake
|
r.snowflake = snowflake
|
||||||
r.worldStatic = NewWorldStatic()
|
|
||||||
r.worldStatic.InitTerrain()
|
|
||||||
// r.worldStatic.Pathfinding()
|
|
||||||
// r.worldStatic.ConvPathVectorListToAiMoveVectorList()
|
|
||||||
return r
|
return r
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,163 +0,0 @@
|
|||||||
package game
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"encoding/gob"
|
|
||||||
"unsafe"
|
|
||||||
|
|
||||||
gdc "hk4e/gs/config"
|
|
||||||
"hk4e/gs/model"
|
|
||||||
"hk4e/pkg/alg"
|
|
||||||
"hk4e/pkg/logger"
|
|
||||||
)
|
|
||||||
|
|
||||||
// 世界的静态资源坐标点数据
|
|
||||||
|
|
||||||
type MeshMapPos struct {
|
|
||||||
X int16
|
|
||||||
Y int16
|
|
||||||
Z int16
|
|
||||||
}
|
|
||||||
|
|
||||||
type WorldStatic struct {
|
|
||||||
// x y z -> if terrain exist
|
|
||||||
terrain map[MeshMapPos]bool
|
|
||||||
// x y z -> gather id
|
|
||||||
gather map[MeshMapPos]uint32
|
|
||||||
pathfindingStartPos MeshMapPos
|
|
||||||
pathfindingEndPos MeshMapPos
|
|
||||||
pathVectorList []MeshMapPos
|
|
||||||
aiMoveMeshSpeedParam int
|
|
||||||
aiMoveVectorList []*model.Vector
|
|
||||||
aiMoveCurrIndex int
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewWorldStatic() (r *WorldStatic) {
|
|
||||||
r = new(WorldStatic)
|
|
||||||
r.terrain = make(map[MeshMapPos]bool)
|
|
||||||
r.gather = make(map[MeshMapPos]uint32)
|
|
||||||
r.InitGather()
|
|
||||||
r.pathfindingStartPos = MeshMapPos{
|
|
||||||
X: 2747,
|
|
||||||
Y: 194,
|
|
||||||
Z: -1719,
|
|
||||||
}
|
|
||||||
r.pathfindingEndPos = MeshMapPos{
|
|
||||||
X: 2588,
|
|
||||||
Y: 211,
|
|
||||||
Z: -1349,
|
|
||||||
}
|
|
||||||
r.pathVectorList = make([]MeshMapPos, 0)
|
|
||||||
r.aiMoveMeshSpeedParam = 3
|
|
||||||
r.aiMoveVectorList = make([]*model.Vector, 0)
|
|
||||||
r.aiMoveCurrIndex = 0
|
|
||||||
return r
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *WorldStatic) InitTerrain() bool {
|
|
||||||
data := gdc.CONF.ReadWorldTerrain()
|
|
||||||
decoder := gob.NewDecoder(bytes.NewReader(data))
|
|
||||||
err := decoder.Decode(&w.terrain)
|
|
||||||
if err != nil {
|
|
||||||
logger.Error("unmarshal world terrain data error: %v", err)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *WorldStatic) SaveTerrain() bool {
|
|
||||||
var buffer bytes.Buffer
|
|
||||||
encoder := gob.NewEncoder(&buffer)
|
|
||||||
err := encoder.Encode(w.terrain)
|
|
||||||
if err != nil {
|
|
||||||
logger.Error("marshal world terrain data error: %v", err)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
gdc.CONF.WriteWorldTerrain(buffer.Bytes())
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *WorldStatic) GetTerrain(x int16, y int16, z int16) (exist bool) {
|
|
||||||
pos := MeshMapPos{
|
|
||||||
X: x,
|
|
||||||
Y: y,
|
|
||||||
Z: z,
|
|
||||||
}
|
|
||||||
exist = w.terrain[pos]
|
|
||||||
return exist
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *WorldStatic) SetTerrain(x int16, y int16, z int16) {
|
|
||||||
pos := MeshMapPos{
|
|
||||||
X: x,
|
|
||||||
Y: y,
|
|
||||||
Z: z,
|
|
||||||
}
|
|
||||||
w.terrain[pos] = true
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *WorldStatic) InitGather() {
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *WorldStatic) GetGather(x int16, y int16, z int16) (gatherId uint32, exist bool) {
|
|
||||||
pos := MeshMapPos{
|
|
||||||
X: x,
|
|
||||||
Y: y,
|
|
||||||
Z: z,
|
|
||||||
}
|
|
||||||
gatherId, exist = w.gather[pos]
|
|
||||||
return gatherId, exist
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *WorldStatic) SetGather(x int16, y int16, z int16, gatherId uint32) {
|
|
||||||
pos := MeshMapPos{
|
|
||||||
X: x,
|
|
||||||
Y: y,
|
|
||||||
Z: z,
|
|
||||||
}
|
|
||||||
w.gather[pos] = gatherId
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *WorldStatic) ConvWSTMapToPFMap() map[alg.MeshMapPos]bool {
|
|
||||||
return *(*map[alg.MeshMapPos]bool)(unsafe.Pointer(&w.terrain))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *WorldStatic) ConvWSPosToPFPos(v MeshMapPos) alg.MeshMapPos {
|
|
||||||
return alg.MeshMapPos(v)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *WorldStatic) ConvPFPVLToWSPVL(v []alg.MeshMapPos) []MeshMapPos {
|
|
||||||
return *(*[]MeshMapPos)(unsafe.Pointer(&v))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *WorldStatic) Pathfinding() {
|
|
||||||
bfs := alg.NewBFS()
|
|
||||||
bfs.InitMap(
|
|
||||||
w.ConvWSTMapToPFMap(),
|
|
||||||
w.ConvWSPosToPFPos(w.pathfindingStartPos),
|
|
||||||
w.ConvWSPosToPFPos(w.pathfindingEndPos),
|
|
||||||
100,
|
|
||||||
)
|
|
||||||
pathVectorList := bfs.Pathfinding()
|
|
||||||
if pathVectorList == nil {
|
|
||||||
logger.Error("could not find path")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
logger.Debug("find path success, path: %v", pathVectorList)
|
|
||||||
w.pathVectorList = w.ConvPFPVLToWSPVL(pathVectorList)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *WorldStatic) ConvPathVectorListToAiMoveVectorList() {
|
|
||||||
for index, currPathVector := range w.pathVectorList {
|
|
||||||
if index > 0 {
|
|
||||||
lastPathVector := w.pathVectorList[index-1]
|
|
||||||
for i := 0; i < w.aiMoveMeshSpeedParam; i++ {
|
|
||||||
w.aiMoveVectorList = append(w.aiMoveVectorList, &model.Vector{
|
|
||||||
X: float64(lastPathVector.X) + float64(currPathVector.X-lastPathVector.X)/float64(w.aiMoveMeshSpeedParam)*float64(i),
|
|
||||||
Y: float64(lastPathVector.Y) + float64(currPathVector.Y-lastPathVector.Y)/float64(w.aiMoveMeshSpeedParam)*float64(i),
|
|
||||||
Z: float64(lastPathVector.Z) + float64(currPathVector.Z-lastPathVector.Z)/float64(w.aiMoveMeshSpeedParam)*float64(i),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
47
pathfinding/app/app.go
Normal file
47
pathfinding/app/app.go
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
package app
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
_ "net/http/pprof"
|
||||||
|
"os"
|
||||||
|
"os/signal"
|
||||||
|
"syscall"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"hk4e/common/config"
|
||||||
|
"hk4e/common/mq"
|
||||||
|
"hk4e/pathfinding/handle"
|
||||||
|
"hk4e/pkg/logger"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Run(ctx context.Context, configFile string) error {
|
||||||
|
config.InitConfig(configFile)
|
||||||
|
|
||||||
|
logger.InitLogger("pathfinding")
|
||||||
|
logger.Warn("pathfinding start")
|
||||||
|
|
||||||
|
messageQueue := mq.NewMessageQueue(mq.PATHFINDING, "1")
|
||||||
|
defer messageQueue.Close()
|
||||||
|
|
||||||
|
_ = handle.NewHandle(messageQueue)
|
||||||
|
|
||||||
|
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("pathfinding exit")
|
||||||
|
time.Sleep(time.Second)
|
||||||
|
return nil
|
||||||
|
case syscall.SIGHUP:
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
70
pathfinding/handle/handle.go
Normal file
70
pathfinding/handle/handle.go
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
package handle
|
||||||
|
|
||||||
|
import (
|
||||||
|
"hk4e/common/mq"
|
||||||
|
"hk4e/pathfinding/world"
|
||||||
|
"hk4e/pkg/logger"
|
||||||
|
"hk4e/protocol/cmd"
|
||||||
|
|
||||||
|
pb "google.golang.org/protobuf/proto"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Handle struct {
|
||||||
|
worldStatic *world.WorldStatic
|
||||||
|
messageQueue *mq.MessageQueue
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewHandle(messageQueue *mq.MessageQueue) (r *Handle) {
|
||||||
|
r = new(Handle)
|
||||||
|
r.worldStatic = world.NewWorldStatic()
|
||||||
|
r.worldStatic.InitTerrain()
|
||||||
|
r.messageQueue = messageQueue
|
||||||
|
go r.run()
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Handle) run() {
|
||||||
|
for i := 0; i < 4; i++ {
|
||||||
|
go func() {
|
||||||
|
for {
|
||||||
|
netMsg := <-h.messageQueue.GetNetMsg()
|
||||||
|
if netMsg.MsgType != mq.MsgTypeGame {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if netMsg.EventId != mq.NormalMsg {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
gameMsg := netMsg.GameMsg
|
||||||
|
switch gameMsg.CmdId {
|
||||||
|
case cmd.QueryPathReq:
|
||||||
|
h.QueryPath(gameMsg.UserId, gameMsg.PayloadMessage)
|
||||||
|
case cmd.ObstacleModifyNotify:
|
||||||
|
h.ObstacleModifyNotify(gameMsg.UserId, gameMsg.PayloadMessage)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// SendMsg 发送消息给客户端
|
||||||
|
func (h *Handle) SendMsg(cmdId uint16, userId uint32, payloadMsg pb.Message) {
|
||||||
|
if userId < 100000000 || payloadMsg == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
gameMsg := new(mq.GameMsg)
|
||||||
|
gameMsg.UserId = userId
|
||||||
|
gameMsg.CmdId = cmdId
|
||||||
|
gameMsg.ClientSeq = 0
|
||||||
|
// 在这里直接序列化成二进制数据 防止发送的消息内包含各种游戏数据指针 而造成并发读写的问题
|
||||||
|
payloadMessageData, err := pb.Marshal(payloadMsg)
|
||||||
|
if err != nil {
|
||||||
|
logger.Error("parse payload msg to bin error: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
gameMsg.PayloadMessageData = payloadMessageData
|
||||||
|
h.messageQueue.SendToGate("1", &mq.NetMsg{
|
||||||
|
MsgType: mq.MsgTypeGame,
|
||||||
|
EventId: mq.NormalMsg,
|
||||||
|
GameMsg: gameMsg,
|
||||||
|
})
|
||||||
|
}
|
||||||
74
pathfinding/handle/query_path.go
Normal file
74
pathfinding/handle/query_path.go
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
package handle
|
||||||
|
|
||||||
|
import (
|
||||||
|
"hk4e/pathfinding/pfalg"
|
||||||
|
"hk4e/pkg/logger"
|
||||||
|
"hk4e/protocol/cmd"
|
||||||
|
"hk4e/protocol/proto"
|
||||||
|
|
||||||
|
pb "google.golang.org/protobuf/proto"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (h *Handle) ConvPbVecToMeshVec(pbVec *proto.Vector) pfalg.MeshVector {
|
||||||
|
return pfalg.MeshVector{
|
||||||
|
X: int16(pbVec.X),
|
||||||
|
Y: int16(pbVec.Y),
|
||||||
|
Z: int16(pbVec.Z),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Handle) ConvMeshVecToPbVec(meshVec pfalg.MeshVector) *proto.Vector {
|
||||||
|
return &proto.Vector{
|
||||||
|
X: float32(meshVec.X),
|
||||||
|
Y: float32(meshVec.Y),
|
||||||
|
Z: float32(meshVec.Z),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Handle) ConvPbVecListToMeshVecList(pbVecList []*proto.Vector) []pfalg.MeshVector {
|
||||||
|
ret := make([]pfalg.MeshVector, 0)
|
||||||
|
for _, pbVec := range pbVecList {
|
||||||
|
ret = append(ret, h.ConvPbVecToMeshVec(pbVec))
|
||||||
|
}
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Handle) ConvMeshVecListToPbVecList(meshVecList []pfalg.MeshVector) []*proto.Vector {
|
||||||
|
ret := make([]*proto.Vector, 0)
|
||||||
|
for _, meshVec := range meshVecList {
|
||||||
|
ret = append(ret, h.ConvMeshVecToPbVec(meshVec))
|
||||||
|
}
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Handle) QueryPath(userId uint32, payloadMsg pb.Message) {
|
||||||
|
req := payloadMsg.(*proto.QueryPathReq)
|
||||||
|
logger.Debug("query path req: %v, uid: %v", req, userId)
|
||||||
|
var ok = false
|
||||||
|
var path []pfalg.MeshVector = nil
|
||||||
|
for _, destinationPos := range req.DestinationPos {
|
||||||
|
ok, path = h.worldStatic.Pathfinding(h.ConvPbVecToMeshVec(req.SourcePos), h.ConvPbVecToMeshVec(destinationPos))
|
||||||
|
if ok {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !ok {
|
||||||
|
queryPathRsp := &proto.QueryPathRsp{
|
||||||
|
QueryId: req.QueryId,
|
||||||
|
QueryStatus: proto.QueryPathRsp_PATH_STATUS_TYPE_FAIL,
|
||||||
|
}
|
||||||
|
h.SendMsg(cmd.QueryPathRsp, userId, queryPathRsp)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
queryPathRsp := &proto.QueryPathRsp{
|
||||||
|
QueryId: req.QueryId,
|
||||||
|
QueryStatus: proto.QueryPathRsp_PATH_STATUS_TYPE_SUCC,
|
||||||
|
Corners: h.ConvMeshVecListToPbVecList(path),
|
||||||
|
}
|
||||||
|
h.SendMsg(cmd.QueryPathRsp, userId, queryPathRsp)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Handle) ObstacleModifyNotify(userId uint32, payloadMsg pb.Message) {
|
||||||
|
req := payloadMsg.(*proto.ObstacleModifyNotify)
|
||||||
|
logger.Debug("obstacle modify req: %v, uid: %v", req, userId)
|
||||||
|
}
|
||||||
@@ -1,4 +1,8 @@
|
|||||||
package alg
|
package pfalg
|
||||||
|
|
||||||
|
import (
|
||||||
|
"hk4e/pkg/alg"
|
||||||
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
NODE_NONE = iota
|
NODE_NONE = iota
|
||||||
@@ -27,7 +31,7 @@ func NewBFS() (r *BFS) {
|
|||||||
return r
|
return r
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *BFS) InitMap(terrain map[MeshMapPos]bool, start MeshMapPos, end MeshMapPos, extR int16) {
|
func (b *BFS) InitMap(terrain map[MeshVector]bool, start MeshVector, end MeshVector, extR int16) {
|
||||||
xLen := end.X - start.X
|
xLen := end.X - start.X
|
||||||
yLen := end.Y - start.Y
|
yLen := end.Y - start.Y
|
||||||
zLen := end.Z - start.Z
|
zLen := end.Z - start.Z
|
||||||
@@ -58,7 +62,7 @@ func (b *BFS) InitMap(terrain map[MeshMapPos]bool, start MeshMapPos, end MeshMap
|
|||||||
} else if x == end.X && y == end.Y && z == end.Z {
|
} else if x == end.X && y == end.Y && z == end.Z {
|
||||||
state = NODE_END
|
state = NODE_END
|
||||||
} else {
|
} else {
|
||||||
_, exist := terrain[MeshMapPos{
|
_, exist := terrain[MeshVector{
|
||||||
X: x,
|
X: x,
|
||||||
Y: y,
|
Y: y,
|
||||||
Z: z,
|
Z: z,
|
||||||
@@ -161,8 +165,8 @@ func (b *BFS) GetPath() []*PathNode {
|
|||||||
return path
|
return path
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *BFS) Pathfinding() []MeshMapPos {
|
func (b *BFS) Pathfinding() []MeshVector {
|
||||||
queue := NewALQueue[*PathNode]()
|
queue := alg.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 {
|
||||||
@@ -183,10 +187,10 @@ func (b *BFS) Pathfinding() []MeshMapPos {
|
|||||||
if path == nil {
|
if path == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
pathVectorList := make([]MeshMapPos, 0)
|
pathVectorList := make([]MeshVector, 0)
|
||||||
for i := len(path) - 1; i >= 0; i-- {
|
for i := len(path) - 1; i >= 0; i-- {
|
||||||
node := path[i]
|
node := path[i]
|
||||||
pathVectorList = append(pathVectorList, MeshMapPos{
|
pathVectorList = append(pathVectorList, MeshVector{
|
||||||
X: node.x,
|
X: node.x,
|
||||||
Y: node.y,
|
Y: node.y,
|
||||||
Z: node.z,
|
Z: node.z,
|
||||||
7
pathfinding/pfalg/mesh_vector.go
Normal file
7
pathfinding/pfalg/mesh_vector.go
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
package pfalg
|
||||||
|
|
||||||
|
type MeshVector struct {
|
||||||
|
X int16
|
||||||
|
Y int16
|
||||||
|
Z int16
|
||||||
|
}
|
||||||
88
pathfinding/world/world_static.go
Normal file
88
pathfinding/world/world_static.go
Normal file
@@ -0,0 +1,88 @@
|
|||||||
|
package world
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/gob"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"hk4e/pathfinding/pfalg"
|
||||||
|
"hk4e/pkg/logger"
|
||||||
|
)
|
||||||
|
|
||||||
|
type WorldStatic struct {
|
||||||
|
// x y z -> if terrain exist
|
||||||
|
terrain map[pfalg.MeshVector]bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewWorldStatic() (r *WorldStatic) {
|
||||||
|
r = new(WorldStatic)
|
||||||
|
r.terrain = make(map[pfalg.MeshVector]bool)
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *WorldStatic) InitTerrain() bool {
|
||||||
|
data, err := os.ReadFile("./world_terrain.bin")
|
||||||
|
if err != nil {
|
||||||
|
logger.Error("read world terrain file error: %v", err)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
decoder := gob.NewDecoder(bytes.NewReader(data))
|
||||||
|
err = decoder.Decode(&w.terrain)
|
||||||
|
if err != nil {
|
||||||
|
logger.Error("unmarshal world terrain data error: %v", err)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *WorldStatic) SaveTerrain() bool {
|
||||||
|
var buffer bytes.Buffer
|
||||||
|
encoder := gob.NewEncoder(&buffer)
|
||||||
|
err := encoder.Encode(w.terrain)
|
||||||
|
if err != nil {
|
||||||
|
logger.Error("marshal world terrain data error: %v", err)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
err = os.WriteFile("./world_terrain.bin", buffer.Bytes(), 0644)
|
||||||
|
if err != nil {
|
||||||
|
logger.Error("write world terrain file error: %v", err)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *WorldStatic) GetTerrain(x int16, y int16, z int16) (exist bool) {
|
||||||
|
pos := pfalg.MeshVector{
|
||||||
|
X: x,
|
||||||
|
Y: y,
|
||||||
|
Z: z,
|
||||||
|
}
|
||||||
|
exist = w.terrain[pos]
|
||||||
|
return exist
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *WorldStatic) SetTerrain(x int16, y int16, z int16) {
|
||||||
|
pos := pfalg.MeshVector{
|
||||||
|
X: x,
|
||||||
|
Y: y,
|
||||||
|
Z: z,
|
||||||
|
}
|
||||||
|
w.terrain[pos] = true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *WorldStatic) Pathfinding(startPos pfalg.MeshVector, endPos pfalg.MeshVector) (bool, []pfalg.MeshVector) {
|
||||||
|
bfs := pfalg.NewBFS()
|
||||||
|
bfs.InitMap(
|
||||||
|
w.terrain,
|
||||||
|
startPos,
|
||||||
|
endPos,
|
||||||
|
100,
|
||||||
|
)
|
||||||
|
pathVectorList := bfs.Pathfinding()
|
||||||
|
if pathVectorList == nil {
|
||||||
|
logger.Error("could not find path")
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
logger.Debug("find path success, path: %v", pathVectorList)
|
||||||
|
return true, pathVectorList
|
||||||
|
}
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
package alg
|
|
||||||
|
|
||||||
type MeshMapPos struct {
|
|
||||||
X int16
|
|
||||||
Y int16
|
|
||||||
Z int16
|
|
||||||
}
|
|
||||||
@@ -100,6 +100,7 @@ func (c *CmdProtoMap) registerAllMessage() {
|
|||||||
c.registerMessage(LifeStateChangeNotify, &proto.LifeStateChangeNotify{}) // 实体存活状态改变通知
|
c.registerMessage(LifeStateChangeNotify, &proto.LifeStateChangeNotify{}) // 实体存活状态改变通知
|
||||||
c.registerMessage(SceneEntityDrownReq, &proto.SceneEntityDrownReq{}) // 场景实体溺水请求
|
c.registerMessage(SceneEntityDrownReq, &proto.SceneEntityDrownReq{}) // 场景实体溺水请求
|
||||||
c.registerMessage(SceneEntityDrownRsp, &proto.SceneEntityDrownRsp{}) // 场景实体溺水响应
|
c.registerMessage(SceneEntityDrownRsp, &proto.SceneEntityDrownRsp{}) // 场景实体溺水响应
|
||||||
|
c.registerMessage(ObstacleModifyNotify, &proto.ObstacleModifyNotify{}) // 寻路阻挡变动通知
|
||||||
|
|
||||||
// 战斗与同步
|
// 战斗与同步
|
||||||
c.registerMessage(AvatarFightPropNotify, &proto.AvatarFightPropNotify{}) // 角色战斗属性通知
|
c.registerMessage(AvatarFightPropNotify, &proto.AvatarFightPropNotify{}) // 角色战斗属性通知
|
||||||
@@ -254,7 +255,6 @@ func (c *CmdProtoMap) registerAllMessage() {
|
|||||||
// c.registerMessage(EntityConfigHashNotify, &proto.EntityConfigHashNotify{})
|
// c.registerMessage(EntityConfigHashNotify, &proto.EntityConfigHashNotify{})
|
||||||
// c.registerMessage(MonsterAIConfigHashNotify, &proto.MonsterAIConfigHashNotify{})
|
// c.registerMessage(MonsterAIConfigHashNotify, &proto.MonsterAIConfigHashNotify{})
|
||||||
// c.registerMessage(GetRegionSearchReq, &proto.GetRegionSearchReq{})
|
// c.registerMessage(GetRegionSearchReq, &proto.GetRegionSearchReq{})
|
||||||
// c.registerMessage(ObstacleModifyNotify, &proto.ObstacleModifyNotify{})
|
|
||||||
|
|
||||||
// 空消息
|
// 空消息
|
||||||
c.registerMessage(65535, &proto.NullMsg{})
|
c.registerMessage(65535, &proto.NullMsg{})
|
||||||
|
|||||||
Reference in New Issue
Block a user