perf与性能优化

This commit is contained in:
flswld
2023-04-15 20:00:37 +08:00
parent 149b773f4b
commit 094ad5add0
26 changed files with 403 additions and 308 deletions

View File

@@ -23,13 +23,13 @@ func Run(ctx context.Context, configFile string) error {
config.InitConfig(configFile)
// natsrpc client
client, err := rpc.NewClient()
discoveryClient, err := rpc.NewDiscoveryClient()
if err != nil {
return err
}
// 注册到节点服务器
rsp, err := client.Discovery.RegisterServer(context.TODO(), &api.RegisterServerReq{
rsp, err := discoveryClient.RegisterServer(context.TODO(), &api.RegisterServerReq{
ServerType: api.ANTICHEAT,
})
if err != nil {
@@ -40,7 +40,7 @@ func Run(ctx context.Context, configFile string) error {
ticker := time.NewTicker(time.Second * 15)
for {
<-ticker.C
_, err := client.Discovery.KeepaliveServer(context.TODO(), &api.KeepaliveServerReq{
_, err := discoveryClient.KeepaliveServer(context.TODO(), &api.KeepaliveServerReq{
ServerType: api.ANTICHEAT,
AppId: APPID,
})
@@ -50,7 +50,7 @@ func Run(ctx context.Context, configFile string) error {
}
}()
defer func() {
_, _ = client.Discovery.CancelServer(context.TODO(), &api.CancelServerReq{
_, _ = discoveryClient.CancelServer(context.TODO(), &api.CancelServerReq{
ServerType: api.ANTICHEAT,
AppId: APPID,
})
@@ -64,7 +64,7 @@ func Run(ctx context.Context, configFile string) error {
gdconf.InitGameDataConfig()
messageQueue := mq.NewMessageQueue(api.ANTICHEAT, APPID, client)
messageQueue := mq.NewMessageQueue(api.ANTICHEAT, APPID, discoveryClient)
defer messageQueue.Close()
handle.NewHandle(messageQueue)

View File

@@ -22,6 +22,7 @@ const (
JumpDistance = 500.0
PointDistance = 10.0
AttackCountLimitEntitySec = 10
KickCheatPlayer = false
)
type MoveVector struct {
@@ -232,7 +233,6 @@ func (h *Handle) CombatInvocationsNotify(userId uint32, gateAppId string, payloa
continue
}
moveSpeed := ctx.GetMoveSpeed()
logger.Debug("player move speed: %v, uid: %v", moveSpeed, userId)
if moveSpeed > MaxMoveSpeed {
logger.Warn("player move overspeed, speed: %v, uid: %v", moveSpeed, userId)
h.KickPlayer(userId, gateAppId)
@@ -286,6 +286,9 @@ func GetDistance(v1 *proto.Vector, v2 *proto.Vector) float32 {
}
func (h *Handle) KickPlayer(userId uint32, gateAppId string) {
if !KickCheatPlayer {
return
}
h.messageQueue.SendToGate(gateAppId, &mq.NetMsg{
MsgType: mq.MsgTypeConnCtrl,
EventId: mq.KickPlayerNotify,

View File

@@ -35,10 +35,10 @@ type MessageQueue struct {
appId string
gateTcpMqEventChan chan *GateTcpMqEvent
gateTcpMqDeadEventChan chan string
rpcClient *rpc.Client
discoveryClient *rpc.DiscoveryClient
}
func NewMessageQueue(serverType string, appId string, rpcClient *rpc.Client) (r *MessageQueue) {
func NewMessageQueue(serverType string, appId string, discoveryClient *rpc.DiscoveryClient) (r *MessageQueue) {
r = new(MessageQueue)
conn, err := nats.Connect(config.GetConfig().MQ.NatsUrl)
if err != nil {
@@ -64,7 +64,7 @@ func NewMessageQueue(serverType string, appId string, rpcClient *rpc.Client) (r
r.appId = appId
r.gateTcpMqEventChan = make(chan *GateTcpMqEvent, 1000)
r.gateTcpMqDeadEventChan = make(chan string, 1000)
r.rpcClient = rpcClient
r.discoveryClient = discoveryClient
if serverType == api.GATE {
go r.runGateTcpMqServer()
} else if serverType == api.GS || serverType == api.ANTICHEAT || serverType == api.PATHFINDING {
@@ -355,7 +355,7 @@ func (m *MessageQueue) runGateTcpMqClient() {
}
func (m *MessageQueue) gateTcpMqConn(gateServerConnAddrMap map[string]bool) {
rsp, err := m.rpcClient.Discovery.GetAllGateServerInfoList(context.TODO(), new(api.NullMsg))
rsp, err := m.discoveryClient.GetAllGateServerInfoList(context.TODO(), new(api.NullMsg))
if err != nil {
logger.Error("gate tcp mq get gate list error: %v", err)
return

View File

@@ -5,48 +5,30 @@ import (
gsapi "hk4e/gs/api"
nodeapi "hk4e/node/api"
"github.com/byebyebruce/natsrpc"
"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.GetConfig().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()
}
// natsrpc客户端
// DiscoveryClient node的discovery服务
type DiscoveryClient struct {
nodeapi.DiscoveryNATSRPCClient
}
func NewDiscoveryClient() (*DiscoveryClient, error) {
conn, err := nats.Connect(config.GetConfig().MQ.NatsUrl)
if err != nil {
return nil, err
}
discoveryClient, err := newDiscoveryClient(conn)
if err != nil {
return nil, err
}
return discoveryClient, nil
}
func newDiscoveryClient(conn *nats.Conn) (*DiscoveryClient, error) {
enc, err := nats.NewEncodedConn(conn, protobuf.PROTOBUF_ENCODER)
if err != nil {
@@ -66,12 +48,24 @@ type GMClient struct {
gsapi.GMNATSRPCClient
}
func newGmClient(conn *nats.Conn) (*GMClient, error) {
func NewGMClient(gsId uint32) (*GMClient, error) {
conn, err := nats.Connect(config.GetConfig().MQ.NatsUrl)
if err != nil {
return nil, err
}
gmClient, err := newGmClient(conn, gsId)
if err != nil {
return nil, err
}
return gmClient, nil
}
func newGmClient(conn *nats.Conn, gsId uint32) (*GMClient, error) {
enc, err := nats.NewEncodedConn(conn, protobuf.PROTOBUF_ENCODER)
if err != nil {
return nil, err
}
cli, err := gsapi.NewGMNATSRPCClient(enc)
cli, err := gsapi.NewGMNATSRPCClient(enc, natsrpc.WithClientID(gsId))
if err != nil {
return nil, err
}

View File

@@ -27,12 +27,12 @@ func Run(ctx context.Context, configFile string) error {
defer db.CloseDao()
// natsrpc client
client, err := rpc.NewClient()
discoveryClient, err := rpc.NewDiscoveryClient()
if err != nil {
return err
}
_ = controller.NewController(db, client.Discovery)
_ = controller.NewController(db, discoveryClient)
c := make(chan os.Signal, 1)
signal.Notify(c, syscall.SIGHUP, syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGINT)

View File

@@ -24,13 +24,13 @@ func Run(ctx context.Context, configFile string) error {
config.InitConfig(configFile)
// natsrpc client
client, err := rpc.NewClient()
discoveryClient, err := rpc.NewDiscoveryClient()
if err != nil {
return err
}
// 注册到节点服务器
rsp, err := client.Discovery.RegisterServer(context.TODO(), &api.RegisterServerReq{
rsp, err := discoveryClient.RegisterServer(context.TODO(), &api.RegisterServerReq{
ServerType: api.GATE,
GateServerAddr: &api.GateServerAddr{
KcpAddr: config.GetConfig().Hk4e.KcpAddr,
@@ -48,7 +48,7 @@ func Run(ctx context.Context, configFile string) error {
ticker := time.NewTicker(time.Second * 15)
for {
<-ticker.C
_, err := client.Discovery.KeepaliveServer(context.TODO(), &api.KeepaliveServerReq{
_, err := discoveryClient.KeepaliveServer(context.TODO(), &api.KeepaliveServerReq{
ServerType: api.GATE,
AppId: APPID,
LoadCount: uint32(atomic.LoadInt32(&net.CLIENT_CONN_NUM)),
@@ -59,7 +59,7 @@ func Run(ctx context.Context, configFile string) error {
}
}()
defer func() {
_, _ = client.Discovery.CancelServer(context.TODO(), &api.CancelServerReq{
_, _ = discoveryClient.CancelServer(context.TODO(), &api.CancelServerReq{
ServerType: api.GATE,
AppId: APPID,
})
@@ -71,10 +71,10 @@ func Run(ctx context.Context, configFile string) error {
logger.CloseLogger()
}()
messageQueue := mq.NewMessageQueue(api.GATE, APPID, client)
messageQueue := mq.NewMessageQueue(api.GATE, APPID, discoveryClient)
defer messageQueue.Close()
connectManager := net.NewKcpConnectManager(messageQueue, client.Discovery)
connectManager := net.NewKcpConnectManager(messageQueue, discoveryClient)
defer connectManager.Close()
go func() {

View File

@@ -7,7 +7,6 @@ import (
"syscall"
"hk4e/common/config"
"hk4e/common/rpc"
"hk4e/gm/controller"
"hk4e/pkg/logger"
)
@@ -21,13 +20,7 @@ func Run(ctx context.Context, configFile string) error {
logger.CloseLogger()
}()
// natsrpc client
client, err := rpc.NewClient()
if err != nil {
return err
}
_ = controller.NewController(client.GM)
_ = controller.NewController()
c := make(chan os.Signal, 1)
signal.Notify(c, syscall.SIGHUP, syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGINT)

View File

@@ -3,6 +3,7 @@ package controller
import (
"net/http"
"strconv"
"sync"
"hk4e/common/config"
"hk4e/common/rpc"
@@ -12,12 +13,13 @@ import (
)
type Controller struct {
gm *rpc.GMClient
gmClientMap map[uint32]*rpc.GMClient
gmClientMapLock sync.RWMutex
}
func NewController(gm *rpc.GMClient) (r *Controller) {
func NewController() (r *Controller) {
r = new(Controller)
r.gm = gm
r.gmClientMap = make(map[uint32]*rpc.GMClient)
go r.registerRouter()
return r
}

View File

@@ -3,6 +3,7 @@ package controller
import (
"net/http"
"hk4e/common/rpc"
"hk4e/gs/api"
"hk4e/pkg/logger"
@@ -10,8 +11,9 @@ import (
)
type GmCmdReq struct {
FuncName string `json:"func_name"`
Param []string `json:"param"`
FuncName string `json:"func_name"`
ParamList []string `json:"param_list"`
GsId uint32 `json:"gs_id"`
}
func (c *Controller) gmCmd(context *gin.Context) {
@@ -21,14 +23,28 @@ func (c *Controller) gmCmd(context *gin.Context) {
logger.Error("parse json error: %v", err)
return
}
rep, err := c.gm.Cmd(context.Request.Context(), &api.CmdRequest{
FuncName: gmCmdReq.FuncName,
Param: gmCmdReq.Param,
logger.Info("GmCmdReq: %v", gmCmdReq)
c.gmClientMapLock.RLock()
gmClient, exist := c.gmClientMap[gmCmdReq.GsId]
c.gmClientMapLock.RUnlock()
if !exist {
var err error = nil
gmClient, err = rpc.NewGMClient(gmCmdReq.GsId)
if err != nil {
logger.Error("new gm client error: %v", err)
return
}
c.gmClientMapLock.Lock()
c.gmClientMap[gmCmdReq.GsId] = gmClient
c.gmClientMapLock.Unlock()
}
rep, err := gmClient.Cmd(context.Request.Context(), &api.CmdRequest{
FuncName: gmCmdReq.FuncName,
ParamList: gmCmdReq.ParamList,
})
if err != nil {
context.JSON(http.StatusInternalServerError, err)
return
}
context.JSON(http.StatusOK, rep)
logger.Info("%v", gmCmdReq)
}

View File

@@ -3,17 +3,14 @@ syntax = "proto3";
package gs.api;
option go_package = "hk4e/gs/api;api";
//import "natsrpc.proto";
//import "testdata.proto";
// GM 服务
service GM {
rpc Cmd (CmdRequest) returns (CmdReply) {}
}
message CmdRequest {
string func_name = 1;
repeated string param = 2;
string func_name = 1;
repeated string param_list = 2;
}
message CmdReply {

View File

@@ -29,13 +29,13 @@ func Run(ctx context.Context, configFile string) error {
config.InitConfig(configFile)
// natsrpc client
client, err := rpc.NewClient()
discoveryClient, err := rpc.NewDiscoveryClient()
if err != nil {
return err
}
// 注册到节点服务器
rsp, err := client.Discovery.RegisterServer(context.TODO(), &api.RegisterServerReq{
rsp, err := discoveryClient.RegisterServer(context.TODO(), &api.RegisterServerReq{
ServerType: api.GS,
})
if err != nil {
@@ -46,7 +46,7 @@ func Run(ctx context.Context, configFile string) error {
ticker := time.NewTicker(time.Second * 15)
for {
<-ticker.C
_, err := client.Discovery.KeepaliveServer(context.TODO(), &api.KeepaliveServerReq{
_, err := discoveryClient.KeepaliveServer(context.TODO(), &api.KeepaliveServerReq{
ServerType: api.GS,
AppId: APPID,
LoadCount: uint32(atomic.LoadInt32(&game.ONLINE_PLAYER_NUM)),
@@ -58,12 +58,12 @@ func Run(ctx context.Context, configFile string) error {
}()
GSID = rsp.GetGsId()
defer func() {
_, _ = client.Discovery.CancelServer(context.TODO(), &api.CancelServerReq{
_, _ = discoveryClient.CancelServer(context.TODO(), &api.CancelServerReq{
ServerType: api.GS,
AppId: APPID,
})
}()
mainGsAppid, err := client.Discovery.GetMainGameServerAppId(context.TODO(), &api.NullMsg{})
mainGsAppid, err := discoveryClient.GetMainGameServerAppId(context.TODO(), &api.NullMsg{})
if err != nil {
return err
}
@@ -82,11 +82,11 @@ func Run(ctx context.Context, configFile string) error {
}
defer db.CloseDao()
messageQueue := mq.NewMessageQueue(api.GS, APPID, client)
messageQueue := mq.NewMessageQueue(api.GS, APPID, discoveryClient)
defer messageQueue.Close()
gameManager := game.NewGameManager(db, messageQueue, GSID, APPID, mainGsAppid.AppId, client.Discovery)
defer gameManager.Close()
gameCore := game.NewGameCore(db, messageQueue, GSID, APPID, mainGsAppid.AppId, discoveryClient)
defer gameCore.Close()
// natsrpc server
conn, err := nats.Connect(config.GetConfig().MQ.NatsUrl)
@@ -95,7 +95,7 @@ func Run(ctx context.Context, configFile string) error {
return err
}
defer conn.Close()
s, err := service.NewService(conn)
s, err := service.NewService(conn, GSID)
if err != nil {
return err
}

View File

@@ -2,17 +2,16 @@ package game
import (
"runtime"
"strconv"
"time"
"hk4e/common/mq"
"hk4e/common/rpc"
"hk4e/gate/kcp"
"hk4e/gdconf"
"hk4e/gs/dao"
"hk4e/gs/model"
"hk4e/pkg/alg"
"hk4e/pkg/logger"
"hk4e/pkg/random"
"hk4e/pkg/reflection"
"hk4e/protocol/cmd"
"hk4e/protocol/proto"
@@ -55,7 +54,7 @@ type Game struct {
ai *model.Player // 本服的Ai玩家对象
}
func NewGameManager(dao *dao.Dao, messageQueue *mq.MessageQueue, gsId uint32, gsAppid string, mainGsAppid string, discovery *rpc.DiscoveryClient) (r *Game) {
func NewGameCore(dao *dao.Dao, messageQueue *mq.MessageQueue, gsId uint32, gsAppid string, mainGsAppid string, discovery *rpc.DiscoveryClient) (r *Game) {
r = new(Game)
r.discovery = discovery
r.dao = dao
@@ -76,7 +75,7 @@ func NewGameManager(dao *dao.Dao, messageQueue *mq.MessageQueue, gsId uint32, gs
// 创建本服的Ai世界
uid := AiBaseUid + gsId
name := AiName
sign := AiSign
sign := AiSign + " GS:" + strconv.Itoa(int(gsId))
if r.IsMainGs() {
// 约定MainGameServer的Ai的AiWorld叫BigWorld
// 此世界会出现在全服的在线玩家列表中 所有的玩家都可以进入到此世界里来
@@ -89,72 +88,6 @@ func NewGameManager(dao *dao.Dao, messageQueue *mq.MessageQueue, gsId uint32, gs
COMMAND_MANAGER.SetSystem(r.ai)
COMMAND_MANAGER.gmCmd.GMUnlockAllPoint(r.ai.PlayerID, 3)
USER_MANAGER.SetRemoteUserOnlineState(BigWorldAiUid, true, mainGsAppid)
aiWorld := WORLD_MANAGER.GetAiWorld()
if r.IsMainGs() {
// TODO 测试
for i := 1; i < 100; i++ {
uid := 1000000 + uint32(i)
avatarId := uint32(0)
for _, avatarData := range gdconf.GetAvatarDataMap() {
avatarId = uint32(avatarData.AvatarId)
break
}
robot := r.CreateRobot(uid, random.GetRandomStr(8), random.GetRandomStr(10))
r.AddUserAvatar(uid, avatarId)
dbAvatar := robot.GetDbAvatar()
r.SetUpAvatarTeamReq(robot, &proto.SetUpAvatarTeamReq{
TeamId: 1,
AvatarTeamGuidList: []uint64{dbAvatar.AvatarMap[avatarId].Guid},
CurAvatarGuid: dbAvatar.AvatarMap[avatarId].Guid,
})
r.JoinPlayerSceneReq(robot, &proto.JoinPlayerSceneReq{
TargetUid: r.ai.PlayerID,
})
r.EnterSceneReadyReq(robot, &proto.EnterSceneReadyReq{
EnterSceneToken: aiWorld.GetEnterSceneToken(),
})
r.SceneInitFinishReq(robot, &proto.SceneInitFinishReq{
EnterSceneToken: aiWorld.GetEnterSceneToken(),
})
r.EnterSceneDoneReq(robot, &proto.EnterSceneDoneReq{
EnterSceneToken: aiWorld.GetEnterSceneToken(),
})
r.PostEnterSceneReq(robot, &proto.PostEnterSceneReq{
EnterSceneToken: aiWorld.GetEnterSceneToken(),
})
activeAvatarId := aiWorld.GetPlayerActiveAvatarId(robot)
entityMoveInfo := &proto.EntityMoveInfo{
EntityId: aiWorld.GetPlayerWorldAvatarEntityId(robot, activeAvatarId),
MotionInfo: &proto.MotionInfo{
Pos: &proto.Vector{
X: float32(1800.0 + random.GetRandomFloat64(-100.0, 100.0)),
Y: float32(195.0 + random.GetRandomFloat64(0.0, 5.0)),
Z: float32(-1500.0 + random.GetRandomFloat64(-100.0, 100.0)),
},
Rot: &proto.Vector{
X: 0,
Y: float32(random.GetRandomFloat64(0.0, 360.0)),
Z: 0,
},
State: proto.MotionState_MOTION_STANDBY,
},
SceneTime: 0,
ReliableSeq: 0,
}
combatData, err := pb.Marshal(entityMoveInfo)
if err != nil {
continue
}
r.CombatInvocationsNotify(robot, &proto.CombatInvocationsNotify{
InvokeList: []*proto.CombatInvokeEntry{{
CombatData: combatData,
ForwardType: proto.ForwardType_FORWARD_TO_ALL_EXCEPT_CUR,
ArgumentType: proto.CombatTypeArgument_ENTITY_MOVE,
}},
})
r.UnionCmdNotify(robot, &proto.UnionCmdNotify{})
}
}
r.run()
return r
}
@@ -237,6 +170,8 @@ func (g *Game) gameMainLoop() {
localEventCost := int64(0)
commandCost := int64(0)
routeCount := int64(0)
maxRouteCost := int64(0)
maxRouteCmdId := uint16(0)
runtime.LockOSThread()
for {
// 消耗CPU时间性能统计
@@ -246,6 +181,7 @@ func (g *Game) gameMainLoop() {
tickCost /= 1e6
localEventCost /= 1e6
commandCost /= 1e6
maxRouteCost /= 1e6
logger.Info("[GAME MAIN LOOP] cpu time cost detail, routeCost: %v ms, tickCost: %v ms, localEventCost: %v ms, commandCost: %v ms",
routeCost, tickCost, localEventCost, commandCost)
totalCost := routeCost + tickCost + localEventCost + commandCost
@@ -258,13 +194,20 @@ func (g *Game) gameMainLoop() {
totalCost)
logger.Info("[GAME MAIN LOOP] total cpu time cost percent, totalCost: %v%%",
float32(totalCost)/float32(intervalTime/1e6)*100.0)
logger.Info("[GAME MAIN LOOP] avg route cost: %v ms", float32(routeCost)/float32(routeCount))
avgRouteCost := float32(0)
if routeCount != 0 {
avgRouteCost = float32(routeCost) / float32(routeCount)
}
logger.Info("[GAME MAIN LOOP] avg route cost: %v ms", avgRouteCost)
logger.Info("[GAME MAIN LOOP] max route cost: %v ms, cmdId: %v", maxRouteCost, maxRouteCmdId)
lastTime = now
routeCost = 0
tickCost = 0
localEventCost = 0
commandCost = 0
routeCount = 0
maxRouteCost = 0
maxRouteCmdId = 0
}
select {
case netMsg := <-MESSAGE_QUEUE.GetNetMsg():
@@ -272,6 +215,10 @@ func (g *Game) gameMainLoop() {
start := time.Now().UnixNano()
ROUTE_MANAGER.RouteHandle(netMsg)
end := time.Now().UnixNano()
if netMsg.MsgType == mq.MsgTypeGame && (end-start) > maxRouteCost {
maxRouteCost = end - start
maxRouteCmdId = netMsg.GameMsg.CmdId
}
routeCost += end - start
routeCount++
case <-TICK_MANAGER.GetGlobalTick().C:
@@ -369,6 +316,9 @@ func (g *Game) SendMsg(cmdId uint16, userId uint32, clientSeq uint32, payloadMsg
logger.Error("player not exist, uid: %v, stack: %v", userId, logger.Stack())
return
}
if !player.Online {
return
}
if player.NetFreeze {
return
}

View File

@@ -6,8 +6,12 @@ import (
"hk4e/gdconf"
"hk4e/gs/model"
"hk4e/pkg/logger"
"hk4e/pkg/random"
"hk4e/protocol/cmd"
"hk4e/protocol/proto"
"google.golang.org/protobuf/encoding/protojson"
pb "google.golang.org/protobuf/proto"
)
// GM函数模块
@@ -166,6 +170,23 @@ func (g *GMCmd) GMAddQuest(userId uint32, questId uint32) {
GAME.SendMsg(cmd.QuestListUpdateNotify, player.PlayerID, player.ClientSeq, ntf)
}
// GMFinishQuest 完成任务
func (g *GMCmd) GMFinishQuest(userId uint32, questId uint32) {
player := USER_MANAGER.GetOnlineUser(userId)
if player == nil {
logger.Error("player is nil, uid: %v", userId)
return
}
dbQuest := player.GetDbQuest()
dbQuest.ForceFinishQuest(questId)
ntf := &proto.QuestListUpdateNotify{
QuestList: make([]*proto.Quest, 0),
}
ntf.QuestList = append(ntf.QuestList, GAME.PacketQuest(player, questId))
GAME.SendMsg(cmd.QuestListUpdateNotify, player.PlayerID, player.ClientSeq, ntf)
GAME.AcceptQuest(player, true)
}
// GMForceFinishAllQuest 强制完成当前所有任务
func (g *GMCmd) GMForceFinishAllQuest(userId uint32) {
player := USER_MANAGER.GetOnlineUser(userId)
@@ -279,3 +300,110 @@ func (g *GMCmd) PlayAudio() {
func (g *GMCmd) UpdateFrame(rgb bool) {
UpdateFrame(rgb)
}
var RobotUidCounter uint32 = 0
func (g *GMCmd) CreateRobotInBigWorld(uid uint32, name string, avatarId uint32) {
if !GAME.IsMainGs() {
return
}
if uid == 0 {
RobotUidCounter++
uid = 1000000 + RobotUidCounter
}
if name == "" {
name = random.GetRandomStr(8)
}
if avatarId == 0 {
for _, avatarData := range gdconf.GetAvatarDataMap() {
avatarId = uint32(avatarData.AvatarId)
break
}
}
aiWorld := WORLD_MANAGER.GetAiWorld()
robot := GAME.CreateRobot(uid, name, name)
GAME.AddUserAvatar(uid, avatarId)
dbAvatar := robot.GetDbAvatar()
GAME.SetUpAvatarTeamReq(robot, &proto.SetUpAvatarTeamReq{
TeamId: 1,
AvatarTeamGuidList: []uint64{dbAvatar.AvatarMap[avatarId].Guid},
CurAvatarGuid: dbAvatar.AvatarMap[avatarId].Guid,
})
GAME.SetPlayerHeadImageReq(robot, &proto.SetPlayerHeadImageReq{
AvatarId: avatarId,
})
GAME.JoinPlayerSceneReq(robot, &proto.JoinPlayerSceneReq{
TargetUid: aiWorld.owner.PlayerID,
})
GAME.EnterSceneReadyReq(robot, &proto.EnterSceneReadyReq{
EnterSceneToken: aiWorld.GetEnterSceneToken(),
})
GAME.SceneInitFinishReq(robot, &proto.SceneInitFinishReq{
EnterSceneToken: aiWorld.GetEnterSceneToken(),
})
GAME.EnterSceneDoneReq(robot, &proto.EnterSceneDoneReq{
EnterSceneToken: aiWorld.GetEnterSceneToken(),
})
GAME.PostEnterSceneReq(robot, &proto.PostEnterSceneReq{
EnterSceneToken: aiWorld.GetEnterSceneToken(),
})
activeAvatarId := aiWorld.GetPlayerActiveAvatarId(robot)
pos := new(model.Vector)
rot := new(model.Vector)
for _, targetPlayer := range aiWorld.GetAllPlayer() {
if targetPlayer.PlayerID < PlayerBaseUid {
continue
}
pos = &model.Vector{X: targetPlayer.Pos.X, Y: targetPlayer.Pos.Y, Z: targetPlayer.Pos.Z}
rot = &model.Vector{X: targetPlayer.Rot.X, Y: targetPlayer.Rot.Y, Z: targetPlayer.Rot.Z}
}
entityMoveInfo := &proto.EntityMoveInfo{
EntityId: aiWorld.GetPlayerWorldAvatarEntityId(robot, activeAvatarId),
MotionInfo: &proto.MotionInfo{
Pos: &proto.Vector{X: float32(pos.X), Y: float32(pos.Y), Z: float32(pos.Z)},
Rot: &proto.Vector{X: float32(rot.X), Y: float32(rot.Y), Z: float32(rot.Z)},
State: proto.MotionState_MOTION_STANDBY,
},
SceneTime: 0,
ReliableSeq: 0,
}
combatData, err := pb.Marshal(entityMoveInfo)
if err != nil {
return
}
GAME.CombatInvocationsNotify(robot, &proto.CombatInvocationsNotify{
InvokeList: []*proto.CombatInvokeEntry{{
CombatData: combatData,
ForwardType: proto.ForwardType_FORWARD_TO_ALL_EXCEPT_CUR,
ArgumentType: proto.CombatTypeArgument_ENTITY_MOVE,
}},
})
GAME.UnionCmdNotify(robot, &proto.UnionCmdNotify{})
}
func (g *GMCmd) ServerAnnounce(announceId uint32, announceMsg string, isRevoke bool) {
if !isRevoke {
GAME.ServerAnnounceNotify(announceId, announceMsg)
} else {
GAME.ServerAnnounceRevokeNotify(announceId)
}
}
func (g *GMCmd) SendMsgToPlayer(cmdName string, userId uint32, msgJson string) {
cmdId := cmdProtoMap.GetCmdIdByCmdName(cmdName)
if cmdId == 0 {
logger.Error("cmd name not found")
return
}
if cmdId == cmd.WindSeedClientNotify {
logger.Error("what are you doing ???")
return
}
msg := cmdProtoMap.GetProtoObjByCmdId(cmdId)
err := protojson.Unmarshal([]byte(msgJson), msg)
if err != nil {
logger.Error("parse msg error: %v", err)
return
}
GAME.SendMsg(cmdId, userId, 0, msg)
}

View File

@@ -27,14 +27,16 @@ type CommandFunc func(*CommandMessage)
// CommandMessage 命令消息
// 给下层执行命令时提供数据
type CommandMessage struct {
// 玩家聊天GM
// executor 玩家为 model.Player 类型
// GM等为 string 类型
Executor any // 执行者
Text string // 命令原始文本
Name string // 命令前缀
Args map[string]string // 命令参数
FuncName string // 函数名
Param []string // 函数参数列表
// 系统GM
FuncName string // 函数
ParamList []string // 函数参数列表
}
// CommandManager 命令管理器
@@ -120,17 +122,8 @@ func (c *CommandManager) PlayerInputCommand(player *model.Player, targetUid uint
if targetUid != c.system.PlayerID {
return
}
// 输入命令进行处理
c.InputCommand(player, text)
}
// InputCommand 输入要处理的命令
func (c *CommandManager) InputCommand(executor any, text string) {
// 留着这个主要还是为了万一以后要对接要别的地方
logger.Debug("input command, uid: %v text: %v", c.GetExecutorId(executor), text)
// 输入的命令将在其他协程中处理
c.commandTextInput <- &CommandMessage{Executor: executor, Text: text}
// 输入命令将在主协程中处理
c.commandTextInput <- &CommandMessage{Executor: player, Text: text}
}
func (c *CommandManager) CallGMCmd(funcName string, paramList []string) bool {
@@ -239,11 +232,11 @@ func (c *CommandManager) CallGMCmd(funcName string, paramList []string) bool {
// HandleCommand 处理命令
// 主协程接收到命令消息后执行
func (c *CommandManager) HandleCommand(cmd *CommandMessage) {
// 直接执行GM函数
// 系统GM 直接执行GM函数
if cmd.FuncName != "" {
logger.Info("run gm cmd, FuncName: %v, Param: %v", cmd.FuncName, cmd.Param)
logger.Info("run gm cmd, FuncName: %v, ParamList: %v", cmd.FuncName, cmd.ParamList)
// 反射调用command_gm.go中的函数并反射解析传入参数类型
c.CallGMCmd(cmd.FuncName, cmd.Param)
c.CallGMCmd(cmd.FuncName, cmd.ParamList)
return
}

View File

@@ -13,49 +13,6 @@ import (
// 接口路由管理器
type HandlerFunc func(player *model.Player, payloadMsg pb.Message)
type RouteManager struct {
// k:cmdId v:HandlerFunc
handlerFuncRouteMap map[uint16]HandlerFunc
}
func NewRouteManager() (r *RouteManager) {
r = new(RouteManager)
r.handlerFuncRouteMap = make(map[uint16]HandlerFunc)
r.initRoute()
return r
}
func (r *RouteManager) registerRouter(cmdId uint16, handlerFunc HandlerFunc) {
r.handlerFuncRouteMap[cmdId] = handlerFunc
}
func (r *RouteManager) doRoute(cmdId uint16, userId uint32, clientSeq uint32, payloadMsg pb.Message) {
handlerFunc, ok := r.handlerFuncRouteMap[cmdId]
if !ok {
logger.Error("no route for msg, cmdId: %v", cmdId)
return
}
player := USER_MANAGER.GetOnlineUser(userId)
if player == nil {
logger.Error("player is nil, uid: %v", userId)
GAME.KickPlayer(userId, kcp.EnetNotFoundSession)
return
}
if !player.Online {
logger.Error("player not online, uid: %v", userId)
return
}
if player.NetFreeze {
return
}
player.ClientSeq = clientSeq
SELF = player
handlerFunc(player, payloadMsg)
SELF = nil
}
func (r *RouteManager) initRoute() {
r.registerRouter(cmd.SetPlayerBornDataReq, GAME.SetPlayerBornDataReq)
r.registerRouter(cmd.QueryPathReq, GAME.QueryPathReq)
@@ -155,6 +112,49 @@ func (r *RouteManager) initRoute() {
r.registerRouter(cmd.GadgetInteractReq, GAME.GadgetInteractReq)
}
type HandlerFunc func(player *model.Player, payloadMsg pb.Message)
type RouteManager struct {
// k:cmdId v:HandlerFunc
handlerFuncRouteMap map[uint16]HandlerFunc
}
func NewRouteManager() (r *RouteManager) {
r = new(RouteManager)
r.handlerFuncRouteMap = make(map[uint16]HandlerFunc)
r.initRoute()
return r
}
func (r *RouteManager) registerRouter(cmdId uint16, handlerFunc HandlerFunc) {
r.handlerFuncRouteMap[cmdId] = handlerFunc
}
func (r *RouteManager) doRoute(cmdId uint16, userId uint32, clientSeq uint32, payloadMsg pb.Message) {
handlerFunc, ok := r.handlerFuncRouteMap[cmdId]
if !ok {
logger.Error("no route for msg, cmdId: %v", cmdId)
return
}
player := USER_MANAGER.GetOnlineUser(userId)
if player == nil {
logger.Error("player is nil, uid: %v", userId)
GAME.KickPlayer(userId, kcp.EnetNotFoundSession)
return
}
if !player.Online {
logger.Error("player not online, uid: %v", userId)
return
}
if player.NetFreeze {
return
}
player.ClientSeq = clientSeq
SELF = player
handlerFunc(player, payloadMsg)
SELF = nil
}
func (r *RouteManager) RouteHandle(netMsg *mq.NetMsg) {
switch netMsg.MsgType {
case mq.MsgTypeGame:

View File

@@ -6,7 +6,6 @@ import (
"hk4e/gdconf"
"hk4e/gs/model"
"hk4e/pkg/logger"
"hk4e/pkg/random"
"hk4e/protocol/cmd"
"hk4e/protocol/proto"
)
@@ -19,9 +18,9 @@ const (
)
type UserTimer struct {
timer *time.Timer
action int
data []any
timeout int64
action int
data []any
}
type UserTick struct {
@@ -76,9 +75,9 @@ func (t *TickManager) CreateUserTimer(userId uint32, action int, delay uint32, d
}
userTick.timerIdCounter++
userTick.timerMap[userTick.timerIdCounter] = &UserTimer{
timer: time.NewTimer(time.Second * time.Duration(delay)),
action: action,
data: data,
timeout: int64(delay * 1000),
action: action,
data: data,
}
logger.Debug("create user timer, uid: %v, action: %v, time: %v",
userId, action, time.Now().Add(time.Second*time.Duration(delay)).Format("2006-01-02 15:04:05"))
@@ -170,12 +169,10 @@ func (t *TickManager) OnGameServerTick() {
t.onUserTickMinute(userId, now)
}
for timerId, timer := range userTick.timerMap {
if len(timer.timer.C) == 0 {
if now < timer.timeout {
// 跳过还没到时间的定时器
continue
}
<-timer.timer.C
timer.timer.Stop()
delete(userTick.timerMap, timerId)
t.userTimerHandle(userId, timer.action, timer.data)
}
@@ -187,33 +184,7 @@ func (t *TickManager) onTickHour(now int64) {
}
func (t *TickManager) onTickMinute(now int64) {
// GAME.ServerAnnounceNotify(100, "test123")
gdconf.LuaStateLruRemove()
for _, world := range WORLD_MANAGER.GetAllWorld() {
for _, player := range world.GetAllPlayer() {
if player.SceneLoadState == model.SceneEnterDone {
// 随机物品
allItemDataConfig := GAME.GetAllItemDataConfig()
count := random.GetRandomInt32(0, 4)
i := int32(0)
for itemId := range allItemDataConfig {
num := random.GetRandomInt32(1, 9)
GAME.AddUserItem(player.PlayerID, []*ChangeItem{{ItemId: uint32(itemId), ChangeCount: uint32(num)}}, true, 0)
i++
if i > count {
break
}
}
GAME.AddUserItem(player.PlayerID, []*ChangeItem{{ItemId: 102, ChangeCount: 30}}, true, 0)
GAME.AddUserItem(player.PlayerID, []*ChangeItem{{ItemId: 201, ChangeCount: 10}}, true, 0)
GAME.AddUserItem(player.PlayerID, []*ChangeItem{{ItemId: 202, ChangeCount: 100}}, true, 0)
GAME.AddUserItem(player.PlayerID, []*ChangeItem{{ItemId: 203, ChangeCount: 10}}, true, 0)
// 蓝球粉球
GAME.AddUserItem(player.PlayerID, []*ChangeItem{{ItemId: 223, ChangeCount: 1}}, true, 0)
GAME.AddUserItem(player.PlayerID, []*ChangeItem{{ItemId: 224, ChangeCount: 1}}, true, 0)
}
}
}
}
func (t *TickManager) onTick10Second(now int64) {

View File

@@ -74,6 +74,7 @@ func (w *WorldManager) CreateWorld(owner *model.Player) *World {
aoiManager.Init3DRectAoiManager(1200, 12, 1200)
world.bigWorldAoi = aoiManager
}
logger.Info("big world aoi init finish")
return world
}

View File

@@ -260,17 +260,20 @@ func (g *Game) SceneBlockAoiPlayerMove(player *model.Player, world *World, scene
if !world.GetMultiplayer() {
// 单人世界直接卸载group
g.RemoveSceneGroup(player, scene, groupConfig)
} else if !WORLD_MANAGER.IsBigWorld(world) {
} else {
// 多人世界group附近没有任何玩家则卸载
remove := true
for _, otherPlayer := range scene.GetAllPlayer() {
for otherPlayerGroupId := range g.GetNeighborGroup(otherPlayer.SceneId, otherPlayer.Pos) {
if otherPlayerGroupId == groupId {
remove = false
break
}
dx := int32(otherPlayer.Pos.X) - int32(groupConfig.Pos.X)
if dx < 0 {
dx *= -1
}
if !remove {
dy := int32(otherPlayer.Pos.Z) - int32(groupConfig.Pos.Z)
if dy < 0 {
dy *= -1
}
if dx <= GROUP_LOAD_DISTANCE || dy <= GROUP_LOAD_DISTANCE {
remove = false
break
}
}

View File

@@ -20,9 +20,10 @@ import (
// 场景模块 场景组 小组 实体 管理相关
const (
ENTITY_MAX_BATCH_SEND_NUM = 1000 // 单次同步的最大实体数量
ENTITY_VISION_DISTANCE = 100 // 实体视野距离
GROUP_LOAD_DISTANCE = 250 // 场景组加载距离
ENTITY_MAX_BATCH_SEND_NUM = 1000 // 单次同步客户端的最大实体数量
BLOCK_SIZE = 1024 // 区块大小
GROUP_LOAD_DISTANCE = 250 // 场景组加载距离 取值范围(0,BLOCK_SIZE)
ENTITY_VISION_DISTANCE = 100 // 实体视野距离 取值范围(0,GROUP_LOAD_DISTANCE)
)
func (g *Game) EnterSceneReadyReq(player *model.Player, payloadMsg pb.Message) {
@@ -56,21 +57,24 @@ func (g *Game) EnterSceneReadyReq(player *model.Player, payloadMsg pb.Message) {
}
g.RemoveSceneEntityNotifyToPlayer(player, proto.VisionType_VISION_MISS, delEntityIdList)
// 卸载旧位置附近的group
for groupId, groupConfig := range g.GetNeighborGroup(ctx.OldSceneId, ctx.OldPos) {
for _, groupConfig := range g.GetNeighborGroup(ctx.OldSceneId, ctx.OldPos) {
if !world.GetMultiplayer() {
// 单人世界直接卸载group
g.RemoveSceneGroup(player, oldScene, groupConfig)
} else if !WORLD_MANAGER.IsBigWorld(world) {
} else {
// 多人世界group附近没有任何玩家则卸载
remove := true
for _, otherPlayer := range oldScene.GetAllPlayer() {
for otherPlayerGroupId := range g.GetNeighborGroup(otherPlayer.SceneId, otherPlayer.Pos) {
if otherPlayerGroupId == groupId {
remove = false
break
}
dx := int32(otherPlayer.Pos.X) - int32(groupConfig.Pos.X)
if dx < 0 {
dx *= -1
}
if !remove {
dy := int32(otherPlayer.Pos.Z) - int32(groupConfig.Pos.Z)
if dy < 0 {
dy *= -1
}
if dx <= GROUP_LOAD_DISTANCE || dy <= GROUP_LOAD_DISTANCE {
remove = false
break
}
}
@@ -665,10 +669,19 @@ func (g *Game) ChangeGadgetState(player *model.Player, entityId uint32, state ui
// GetVisionEntity 获取某位置视野内的全部实体
func (g *Game) GetVisionEntity(scene *Scene, pos *model.Vector) map[uint32]*Entity {
visionEntity := make(map[uint32]*Entity)
for _, entity := range scene.GetAllEntity() {
if math.Abs(pos.X-entity.pos.X) > ENTITY_VISION_DISTANCE ||
math.Abs(pos.Z-entity.pos.Z) > ENTITY_VISION_DISTANCE {
allEntityMap := scene.GetAllEntity()
ratio := float32(ENTITY_VISION_DISTANCE*ENTITY_VISION_DISTANCE) / float32(GROUP_LOAD_DISTANCE*GROUP_LOAD_DISTANCE)
visionEntity := make(map[uint32]*Entity, int(float32(len(allEntityMap))*ratio))
for _, entity := range allEntityMap {
dx := int32(pos.X) - int32(entity.pos.X)
if dx < 0 {
dx *= -1
}
dy := int32(pos.Z) - int32(entity.pos.Z)
if dy < 0 {
dy *= -1
}
if dx > ENTITY_VISION_DISTANCE || dy > ENTITY_VISION_DISTANCE {
continue
}
visionEntity[entity.GetId()] = entity
@@ -684,11 +697,19 @@ func (g *Game) GetNeighborGroup(sceneId uint32, pos *model.Vector) map[uint32]*g
return nil
}
objectList := aoiManager.GetObjectListByPos(float32(pos.X), 0.0, float32(pos.Z))
neighborGroup := make(map[uint32]*gdconf.Group)
ratio := float32(GROUP_LOAD_DISTANCE*GROUP_LOAD_DISTANCE) / float32(BLOCK_SIZE*BLOCK_SIZE*9)
neighborGroup := make(map[uint32]*gdconf.Group, int(float32(len(objectList))*ratio))
for _, groupAny := range objectList {
groupConfig := groupAny.(*gdconf.Group)
if math.Abs(pos.X-float64(groupConfig.Pos.X)) > GROUP_LOAD_DISTANCE ||
math.Abs(pos.Z-float64(groupConfig.Pos.Z)) > GROUP_LOAD_DISTANCE {
dx := int32(pos.X) - int32(groupConfig.Pos.X)
if dx < 0 {
dx *= -1
}
dy := int32(pos.Z) - int32(groupConfig.Pos.Z)
if dy < 0 {
dy *= -1
}
if dx > GROUP_LOAD_DISTANCE || dy > GROUP_LOAD_DISTANCE {
continue
}
if groupConfig.DynamicLoad {

View File

@@ -191,7 +191,7 @@ func (g *Game) ChangeMpTeamAvatarReq(player *model.Player, payloadMsg pb.Message
logger.Error("get world is nil, worldId: %v, uid: %v", player.WorldId, player.PlayerID)
return
}
if WORLD_MANAGER.IsBigWorld(world) || !world.GetMultiplayer() || len(avatarGuidList) == 0 || len(avatarGuidList) > 4 {
if !world.GetMultiplayer() || len(avatarGuidList) == 0 || len(avatarGuidList) > 4 {
g.SendError(cmd.ChangeMpTeamAvatarRsp, player, &proto.ChangeMpTeamAvatarRsp{})
return
}

View File

@@ -525,6 +525,15 @@ func (g *Game) TeleportPlayer(
sceneId uint32, pos, rot *model.Vector,
dungeonId, dungeonPointId uint32,
) {
world := WORLD_MANAGER.GetWorldByID(player.WorldId)
if world == nil {
logger.Error("get world is nil, worldId: %v, uid: %v", player.WorldId, player.PlayerID)
return
}
if WORLD_MANAGER.IsBigWorld(world) && sceneId != 3 {
logger.Error("big world scene not support now, sceneId: %v, uid: %v", sceneId, player.PlayerID)
return
}
newSceneId := sceneId
oldSceneId := player.SceneId
oldPos := &model.Vector{X: player.Pos.X, Y: player.Pos.Y, Z: player.Pos.Z}
@@ -533,11 +542,6 @@ func (g *Game) TeleportPlayer(
jumpScene = true
}
player.SceneJump = jumpScene
world := WORLD_MANAGER.GetWorldByID(player.WorldId)
if world == nil {
logger.Error("get world is nil, worldId: %v, uid: %v", player.WorldId, player.PlayerID)
return
}
oldScene := world.GetSceneById(oldSceneId)
activeAvatarId := world.GetPlayerActiveAvatarId(player)
g.RemoveSceneEntityNotifyBroadcast(oldScene, proto.VisionType_VISION_REMOVE, []uint32{world.GetPlayerWorldAvatarEntityId(player, activeAvatarId)}, false, 0)

View File

@@ -16,8 +16,8 @@ type GMService struct {
func (s *GMService) Cmd(ctx context.Context, req *api.CmdRequest) (*api.CmdReply, error) {
commandTextInput := game.COMMAND_MANAGER.GetCommandTextInput()
commandTextInput <- &game.CommandMessage{
FuncName: req.FuncName,
Param: req.Param,
FuncName: req.FuncName,
ParamList: req.ParamList,
}
return &api.CmdReply{
Message: "OK",

View File

@@ -10,7 +10,7 @@ import (
type Service struct{}
func NewService(conn *nats.Conn) (*Service, error) {
func NewService(conn *nats.Conn, gsId uint32) (*Service, error) {
enc, err := nats.NewEncodedConn(conn, protobuf.PROTOBUF_ENCODER)
if err != nil {
return nil, err
@@ -20,7 +20,7 @@ func NewService(conn *nats.Conn) (*Service, error) {
return nil, err
}
gs := &GMService{}
_, err = api.RegisterGMNATSRPCServer(svr, gs)
_, err = api.RegisterGMNATSRPCServer(svr, gs, natsrpc.WithServiceID(gsId))
if err != nil {
return nil, err
}

View File

@@ -22,13 +22,13 @@ func Run(ctx context.Context, configFile string) error {
config.InitConfig(configFile)
// natsrpc client
client, err := rpc.NewClient()
discoveryClient, err := rpc.NewDiscoveryClient()
if err != nil {
return err
}
// 注册到节点服务器
rsp, err := client.Discovery.RegisterServer(context.TODO(), &api.RegisterServerReq{
rsp, err := discoveryClient.RegisterServer(context.TODO(), &api.RegisterServerReq{
ServerType: api.PATHFINDING,
})
if err != nil {
@@ -39,7 +39,7 @@ func Run(ctx context.Context, configFile string) error {
ticker := time.NewTicker(time.Second * 15)
for {
<-ticker.C
_, err := client.Discovery.KeepaliveServer(context.TODO(), &api.KeepaliveServerReq{
_, err := discoveryClient.KeepaliveServer(context.TODO(), &api.KeepaliveServerReq{
ServerType: api.PATHFINDING,
AppId: APPID,
})
@@ -49,7 +49,7 @@ func Run(ctx context.Context, configFile string) error {
}
}()
defer func() {
_, _ = client.Discovery.CancelServer(context.TODO(), &api.CancelServerReq{
_, _ = discoveryClient.CancelServer(context.TODO(), &api.CancelServerReq{
ServerType: api.PATHFINDING,
AppId: APPID,
})
@@ -61,7 +61,7 @@ func Run(ctx context.Context, configFile string) error {
logger.CloseLogger()
}()
messageQueue := mq.NewMessageQueue(api.PATHFINDING, APPID, client)
messageQueue := mq.NewMessageQueue(api.PATHFINDING, APPID, discoveryClient)
defer messageQueue.Close()
_ = handle.NewHandle(messageQueue)

View File

@@ -55,7 +55,8 @@ func (h *Handle) QueryPath(userId uint32, gateAppId string, payloadMsg pb.Messag
if !ok {
queryPathRsp := &proto.QueryPathRsp{
QueryId: req.QueryId,
QueryStatus: proto.QueryPathRsp_STATUS_FAIL,
QueryStatus: proto.QueryPathRsp_STATUS_SUCC,
Corners: []*proto.Vector{req.DestinationPos[0]},
}
h.SendMsg(cmd.QueryPathRsp, userId, gateAppId, queryPathRsp)
return

View File

@@ -93,24 +93,32 @@ func (a *AoiManager) IsValidAoiPos(x, y, z float32) bool {
}
// GetSurrGridListByGid 根据格子的gid得到当前周边的格子信息
func (a *AoiManager) GetSurrGridListByGid(gid uint32) (gridList []*Grid) {
gridList = make([]*Grid, 0)
func (a *AoiManager) GetSurrGridListByGid(gid uint32) []*Grid {
gridList := make([]*Grid, 0, 27)
// 判断grid是否存在
grid, exist := a.gridMap[gid]
if !exist {
return gridList
}
// 添加自己
gridList = append(gridList, grid)
if grid != nil {
gridList = append(gridList, grid)
}
// 根据gid得到当前格子所在的x轴编号
idx := int16(gid % (uint32(a.numX) * uint32(a.numZ)) % uint32(a.numX))
// 判断当前格子左边是否还有格子
if idx > 0 {
gridList = append(gridList, a.gridMap[gid-1])
grid = a.gridMap[gid-1]
if grid != nil {
gridList = append(gridList, grid)
}
}
// 判断当前格子右边是否还有格子
if idx < a.numX-1 {
gridList = append(gridList, a.gridMap[gid+1])
grid = a.gridMap[gid+1]
if grid != nil {
gridList = append(gridList, grid)
}
}
// 将x轴当前的格子都取出进行遍历 再分别得到每个格子的平面上下是否有格子
// 得到当前x轴的格子id集合
@@ -124,11 +132,17 @@ func (a *AoiManager) GetSurrGridListByGid(gid uint32) (gridList []*Grid) {
idz := int16(v % (uint32(a.numX) * uint32(a.numZ)) / uint32(a.numX))
// 判断当前格子平面上方是否还有格子
if idz > 0 {
gridList = append(gridList, a.gridMap[v-uint32(a.numX)])
grid = a.gridMap[v-uint32(a.numX)]
if grid != nil {
gridList = append(gridList, grid)
}
}
// 判断当前格子平面下方是否还有格子
if idz < a.numZ-1 {
gridList = append(gridList, a.gridMap[v+uint32(a.numX)])
grid = a.gridMap[v+uint32(a.numX)]
if grid != nil {
gridList = append(gridList, grid)
}
}
}
// 将xoz平面当前的格子都取出进行遍历 再分别得到每个格子的空间上下是否有格子
@@ -143,21 +157,20 @@ func (a *AoiManager) GetSurrGridListByGid(gid uint32) (gridList []*Grid) {
idy := int16(v / (uint32(a.numX) * uint32(a.numZ)))
// 判断当前格子空间上方是否还有格子
if idy > 0 {
gridList = append(gridList, a.gridMap[v-uint32(a.numX)*uint32(a.numZ)])
grid = a.gridMap[v-uint32(a.numX)*uint32(a.numZ)]
if grid != nil {
gridList = append(gridList, grid)
}
}
// 判断当前格子空间下方是否还有格子
if idy < a.numY-1 {
gridList = append(gridList, a.gridMap[v+uint32(a.numX)*uint32(a.numZ)])
grid = a.gridMap[v+uint32(a.numX)*uint32(a.numZ)]
if grid != nil {
gridList = append(gridList, grid)
}
}
}
retGridList := make([]*Grid, 0)
for _, v := range gridList {
if v == nil {
continue
}
retGridList = append(retGridList, v)
}
return retGridList
return gridList
}
// GetObjectListByPos 通过坐标得到周边格子内的全部object
@@ -166,7 +179,12 @@ func (a *AoiManager) GetObjectListByPos(x, y, z float32) map[int64]any {
gid := a.GetGidByPos(x, y, z)
// 根据格子id得到周边格子的信息
gridList := a.GetSurrGridListByGid(gid)
objectList := make(map[int64]any)
objectListLen := 0
for _, v := range gridList {
tmp := v.GetObjectList()
objectListLen += len(tmp)
}
objectList := make(map[int64]any, objectListLen)
for _, v := range gridList {
tmp := v.GetObjectList()
for kk, vv := range tmp {