mirror of
https://github.com/FlourishingWorld/hk4e.git
synced 2025-12-19 18:32:23 +08:00
perf与性能优化
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user