大量优化

This commit is contained in:
flswld
2023-01-05 01:29:00 +08:00
parent f991480192
commit 27f16d9063
226 changed files with 2651 additions and 2484 deletions

View File

@@ -67,8 +67,6 @@ type FightMsg struct {
const (
ServerAppidBindNotify = iota // 玩家连接绑定的各个服务器appid通知
ServerUserOnlineStateChangeNotify // 广播玩家上线和离线状态以及所在GS的appid
ServerUserBaseInfoReq // 跨服玩家基础数据请求
ServerUserBaseInfoRsp // 跨服玩家基础数据响应
ServerUserGsChangeNotify // 跨服玩家迁移通知
ServerUserMpReq // 跨服多人世界相关请求
ServerUserMpRsp // 跨服多人世界相关响应
@@ -80,7 +78,6 @@ type ServerMsg struct {
FightServerAppId string `msgpack:"FightServerAppId"`
UserId uint32 `msgpack:"UserId"`
IsOnline bool `msgpack:"IsOnline"`
UserBaseInfo *UserBaseInfo `msgpack:"UserBaseInfo"`
GameServerAppId string `msgpack:"GameServerAppId"`
JoinHostUserId uint32 `msgpack:"JoinHostUserId"`
UserMpInfo *UserMpInfo `msgpack:"UserMpInfo"`
@@ -94,17 +91,15 @@ type OriginInfo struct {
}
type UserBaseInfo struct {
OriginInfo *OriginInfo `msgpack:"OriginInfo"`
UserId uint32 `msgpack:"UserId"`
Nickname string `msgpack:"Nickname"`
PlayerLevel uint32 `msgpack:"PlayerLevel"`
MpSettingType uint8 `msgpack:"MpSettingType"`
NameCardId uint32 `msgpack:"NameCardId"`
Signature string `msgpack:"Signature"`
HeadImageId uint32 `msgpack:"HeadImageId"`
WorldPlayerNum uint32 `msgpack:"WorldPlayerNum"`
WorldLevel uint32 `msgpack:"WorldLevel"`
Birthday []uint8 `msgpack:"Birthday"`
UserId uint32 `msgpack:"UserId"`
Nickname string `msgpack:"Nickname"`
PlayerLevel uint32 `msgpack:"PlayerLevel"`
MpSettingType uint8 `msgpack:"MpSettingType"`
NameCardId uint32 `msgpack:"NameCardId"`
Signature string `msgpack:"Signature"`
HeadImageId uint32 `msgpack:"HeadImageId"`
WorldPlayerNum uint32 `msgpack:"WorldPlayerNum"`
WorldLevel uint32 `msgpack:"WorldLevel"`
}
type UserMpInfo struct {

View File

@@ -1,8 +1,8 @@
package api
type ComboTokenReq struct {
AppID int `json:"app_id"`
ChannelID int `json:"channel_id"`
AppID any `json:"app_id"`
ChannelID any `json:"channel_id"`
Data string `json:"data"`
Device string `json:"device"`
Sign string `json:"sign"`

View File

@@ -1,6 +1,6 @@
package api
type ComboTokenRes struct {
type ComboTokenRsp struct {
Message string `json:"message"`
Retcode int `json:"retcode"`
Data LoginData `json:"data"`
@@ -16,8 +16,8 @@ type LoginData struct {
FatigueRemind any `json:"fatigue_remind"`
}
func NewComboTokenRes() (r *ComboTokenRes) {
r = &ComboTokenRes{
func NewComboTokenRsp() (r *ComboTokenRsp) {
r = &ComboTokenRsp{
Message: "",
Retcode: 0,
Data: LoginData{

View File

@@ -44,21 +44,25 @@ func (c *Controller) getClientVersionByName(versionName string) (int, string) {
}
versionSlice := reg.FindAllString(versionName, -1)
version := 0
for index := 0; index < len(versionSlice); index++ {
v, err := strconv.Atoi(versionSlice[index])
for index, value := range versionSlice {
v, err := strconv.Atoi(value)
if err != nil {
logger.Error("parse client version error: %v", err)
return 0, ""
}
for i := 0; i < len(versionSlice)-1-index; i++ {
if v >= 10 {
// 测试版本
if index != 2 {
logger.Error("invalid client version")
return 0, ""
}
v /= 10
}
for i := 0; i < 2-index; i++ {
v *= 10
}
version += v
}
if version >= 1000 {
// 测试版本
version /= 10
}
return version, strconv.Itoa(version)
}

View File

@@ -208,7 +208,7 @@ func (c *Controller) v2Login(context *gin.Context) {
logger.Error("ParseInt uid error: %v", err)
return
}
responseData := api.NewComboTokenRes()
responseData := api.NewComboTokenRsp()
account, err := c.dao.QueryAccountByField("accountID", uid)
if account == nil || account.Token != loginData.Token {
responseData.Retcode = -201

Binary file not shown.

Before

Width:  |  Height:  |  Size: 224 KiB

After

Width:  |  Height:  |  Size: 220 KiB

View File

@@ -304,10 +304,16 @@ func initClientCmdProtoMap() {
func GetClientProtoObjByName(protoObjName string) pb.Message {
if !config.CONF.Hk4e.ClientProtoProxyEnable {
return &proto.NullMsg{}
logger.Error("client proto proxy func not enable")
return nil
}
clientProtoObj := ClientCmdProtoMapRefValue.MethodByName(
"GetClientProtoObjByName",
).Call([]reflect.Value{reflect.ValueOf(protoObjName)})[0].Interface().(pb.Message)
fn := ClientCmdProtoMapRefValue.MethodByName("GetClientProtoObjByName")
ret := fn.Call([]reflect.Value{reflect.ValueOf(protoObjName)})
obj := ret[0].Interface()
if obj == nil {
logger.Error("try to get a not exist proto obj, protoObjName: %v", protoObjName)
return nil
}
clientProtoObj := obj.(pb.Message)
return clientProtoObj
}

View File

@@ -13,11 +13,14 @@ func TestClientProtoGen(t *testing.T) {
}
nameList := make([]string, 0)
for _, entry := range dir {
split := strings.Split(entry.Name(), ".")
if len(split) != 2 || split[1] != "proto" {
if entry.IsDir() {
continue
}
nameList = append(nameList, split[0])
split := strings.Split(entry.Name(), ".")
if len(split) < 2 || split[len(split)-1] != "proto" {
continue
}
nameList = append(nameList, split[len(split)-2])
}
fileData := "package client_proto\n"

View File

@@ -129,6 +129,7 @@ func (k *KcpConnectManager) acceptHandle(listener *kcp.Listener) {
pathfindingServerAppId: "",
changeGameServer: false,
joinHostUserId: 0,
useMagicSeed: false,
}
go k.recvHandle(session)
go k.sendHandle(session)
@@ -228,6 +229,7 @@ type Session struct {
pathfindingServerAppId string
changeGameServer bool
joinHostUserId uint32
useMagicSeed bool
}
// 接收
@@ -297,33 +299,15 @@ func (k *KcpConnectManager) sendHandle(session *Session) {
break
}
if session.changeXorKeyFin == false && protoMsg.CmdId == cmd.GetPlayerTokenRsp {
// XOR密钥切换
logger.Debug("change session xor key, convId: %v", convId)
session.changeXorKeyFin = true
keyBlock := random.NewKeyBlock(session.seed)
keyBlock := random.NewKeyBlock(session.seed, session.useMagicSeed)
xorKey := keyBlock.XorKey()
key := make([]byte, 4096)
copy(key, xorKey[:])
session.xorKey = key
}
if protoMsg.CmdId == cmd.PlayerLoginRsp {
logger.Debug("session active, convId: %v", convId)
session.connState = ConnActive
// 通知GS玩家各个服务器的appid
serverMsg := new(mq.ServerMsg)
serverMsg.UserId = session.userId
if session.changeGameServer {
serverMsg.JoinHostUserId = session.joinHostUserId
session.changeGameServer = false
session.joinHostUserId = 0
} else {
serverMsg.FightServerAppId = session.fightServerAppId
}
k.messageQueue.SendToGs(session.gsServerAppId, &mq.NetMsg{
MsgType: mq.MsgTypeServer,
EventId: mq.ServerAppidBindNotify,
ServerMsg: serverMsg,
})
}
}
}

View File

@@ -295,8 +295,13 @@ func (k *KcpConnectManager) encodeProtoToPayload(protoObj pb.Message) (cmdId uin
}
func (k *KcpConnectManager) getClientProtoObjByName(protoObjName string) pb.Message {
clientProtoObj := k.clientCmdProtoMapRefValue.MethodByName(
"GetClientProtoObjByName",
).Call([]reflect.Value{reflect.ValueOf(protoObjName)})[0].Interface().(pb.Message)
fn := k.clientCmdProtoMapRefValue.MethodByName("GetClientProtoObjByName")
ret := fn.Call([]reflect.Value{reflect.ValueOf(protoObjName)})
obj := ret[0].Interface()
if obj == nil {
logger.Error("try to get a not exist proto obj, protoObjName: %v", protoObjName)
return nil
}
clientProtoObj := obj.(pb.Message)
return clientProtoObj
}

View File

@@ -164,13 +164,32 @@ func (k *KcpConnectManager) sendMsgHandle() {
}
kcpRawSendChan := session.kcpRawSendChan
if kcpRawSendChan == nil {
logger.Error("kcpRawSendChan is nil, session: %v", session)
logger.Error("kcpRawSendChan is nil, convId: %v", protoMsg.ConvId)
return
}
select {
case kcpRawSendChan <- protoMsg:
default:
logger.Error("kcpRawSendChan is full, session: %v", session)
if len(kcpRawSendChan) == 1000 {
logger.Error("kcpRawSendChan is full, convId: %v", protoMsg.ConvId)
return
}
kcpRawSendChan <- protoMsg
if protoMsg.CmdId == cmd.PlayerLoginRsp {
logger.Debug("session active, convId: %v", protoMsg.ConvId)
session.connState = ConnActive
// 通知GS玩家各个服务器的appid
serverMsg := new(mq.ServerMsg)
serverMsg.UserId = session.userId
if session.changeGameServer {
serverMsg.JoinHostUserId = session.joinHostUserId
session.changeGameServer = false
session.joinHostUserId = 0
} else {
serverMsg.FightServerAppId = session.fightServerAppId
}
k.messageQueue.SendToGs(session.gsServerAppId, &mq.NetMsg{
MsgType: mq.MsgTypeServer,
EventId: mq.ServerAppidBindNotify,
ServerMsg: serverMsg,
})
}
}
for {
@@ -280,7 +299,7 @@ func (k *KcpConnectManager) getPlayerToken(req *proto.GetPlayerTokenReq, session
rsp = new(proto.GetPlayerTokenRsp)
rsp.Uid = tokenVerifyRsp.PlayerID
rsp.IsProficientPlayer = true
rsp.Retcode = 21
rsp.Retcode = int32(proto.Retcode_RET_BLACK_UID)
rsp.Msg = "FORBID_CHEATING_PLUGINS"
rsp.BlackUidEndTime = tokenVerifyRsp.ForbidEndTime
if rsp.BlackUidEndTime == 0 {
@@ -365,8 +384,12 @@ func (k *KcpConnectManager) getPlayerToken(req *proto.GetPlayerTokenReq, session
addr := session.conn.RemoteAddr().String()
split := strings.Split(addr, ":")
rsp.ClientIpStr = split[0]
timeRand := random.GetTimeRand()
serverSeedUint64 := timeRand.Uint64()
session.seed = serverSeedUint64
if req.GetKeyId() != 0 {
logger.Debug("do hk4e 2.8 rsa logic")
session.useMagicSeed = true
keyId := strconv.Itoa(int(req.GetKeyId()))
encPubPrivKey, exist := k.encRsaKeyMap[keyId]
if !exist {
@@ -400,9 +423,6 @@ func (k *KcpConnectManager) getPlayerToken(req *proto.GetPlayerTokenReq, session
logger.Error("parse client seed to uint64 error: %v", err)
return rsp
}
timeRand := random.GetTimeRand()
serverSeedUint64 := timeRand.Uint64()
session.seed = serverSeedUint64
seedUint64 := serverSeedUint64 ^ clientSeedUint64
seedBuf := new(bytes.Buffer)
err = binary.Write(seedBuf, binary.BigEndian, seedUint64)
@@ -424,6 +444,10 @@ func (k *KcpConnectManager) getPlayerToken(req *proto.GetPlayerTokenReq, session
rsp.KeyId = req.KeyId
rsp.ServerRandKey = base64.StdEncoding.EncodeToString(seedEnc)
rsp.Sign = base64.StdEncoding.EncodeToString(seedSign)
} else {
session.useMagicSeed = false
rsp.SecretKeySeed = serverSeedUint64
rsp.SecretKey = fmt.Sprintf("%03x-%012x", data[:3], data[4:16])
}
return rsp
}

View File

@@ -1,9 +1,10 @@
package game
import (
"hk4e/gs/model"
"strconv"
"strings"
"hk4e/gs/model"
)
// HelpCommand 帮助命令

View File

@@ -60,8 +60,6 @@ func NewGameManager(dao *dao.Dao, messageQueue *mq.MessageQueue, gsId uint32) (r
}
func (g *GameManager) run() {
ROUTE_MANAGER.InitRoute()
USER_MANAGER.StartAutoSaveUser()
go g.gameMainLoopD()
}
@@ -123,7 +121,7 @@ func (g *GameManager) gameMainLoop() {
ROUTE_MANAGER.RouteHandle(netMsg)
end := time.Now().UnixNano()
routeCost += end - start
case <-TICK_MANAGER.ticker.C:
case <-TICK_MANAGER.globalTick.C:
// 游戏服务器定时帧
start := time.Now().UnixNano()
TICK_MANAGER.OnGameServerTick()
@@ -153,13 +151,20 @@ func (g *GameManager) Stop() {
}
time.Sleep(time.Second * 3)
// 保存玩家数据
onlinePlayerMap := USER_MANAGER.GetAllOnlineUserList()
saveUserIdList := make([]uint32, 0, len(onlinePlayerMap))
for userId := range onlinePlayerMap {
saveUserIdList = append(saveUserIdList, userId)
}
LOCAL_EVENT_MANAGER.localEventChan <- &LocalEvent{
EventId: RunUserCopyAndSave,
Msg: saveUserIdList,
}
time.Sleep(time.Second * 3)
}
func (g *GameManager) SendMsgEx(cmdId uint16, userId uint32, clientSeq uint32, gateAppId string, payloadMsg pb.Message) {
// SendMsgToGate 发送消息给客户端 指定网关
func (g *GameManager) SendMsgToGate(cmdId uint16, userId uint32, clientSeq uint32, gateAppId string, payloadMsg pb.Message) {
if userId < 100000000 {
return
}
@@ -245,12 +250,14 @@ func (g *GameManager) CommonRetSucc(cmdId uint16, player *model.Player, rsp pb.M
g.SendMsg(cmdId, player.PlayerID, player.ClientSeq, rsp)
}
// SendToWorldA 给世界内所有玩家发消息
func (g *GameManager) SendToWorldA(world *World, cmdId uint16, seq uint32, msg pb.Message) {
for _, v := range world.playerMap {
GAME_MANAGER.SendMsg(cmdId, v.PlayerID, seq, msg)
}
}
// SendToWorldAEC 给世界内除自己以外的所有玩家发消息
func (g *GameManager) SendToWorldAEC(world *World, cmdId uint16, seq uint32, msg pb.Message, uid uint32) {
for _, v := range world.playerMap {
if uid == v.PlayerID {
@@ -260,6 +267,7 @@ func (g *GameManager) SendToWorldAEC(world *World, cmdId uint16, seq uint32, msg
}
}
// SendToWorldH 给世界房主发消息
func (g *GameManager) SendToWorldH(world *World, cmdId uint16, seq uint32, msg pb.Message) {
GAME_MANAGER.SendMsg(cmdId, world.owner.PlayerID, seq, msg)
}
@@ -286,10 +294,16 @@ func (g *GameManager) DisconnectPlayer(userId uint32, reason uint32) {
func (g *GameManager) GetClientProtoObjByName(protoObjName string) pb.Message {
if !appConfig.CONF.Hk4e.ClientProtoProxyEnable {
return &proto.NullMsg{}
logger.Error("client proto proxy func not enable")
return nil
}
clientProtoObj := g.clientCmdProtoMapRefValue.MethodByName(
"GetClientProtoObjByName",
).Call([]reflect.Value{reflect.ValueOf(protoObjName)})[0].Interface().(pb.Message)
fn := g.clientCmdProtoMapRefValue.MethodByName("GetClientProtoObjByName")
ret := fn.Call([]reflect.Value{reflect.ValueOf(protoObjName)})
obj := ret[0].Interface()
if obj == nil {
logger.Error("try to get a not exist proto obj, protoObjName: %v", protoObjName)
return nil
}
clientProtoObj := obj.(pb.Message)
return clientProtoObj
}

View File

@@ -85,10 +85,10 @@ func (g *GCGManager) JoinGame(game *GCGGame, player *model.Player) {
game.controllerMap[game.controllerIdCounter] = controller
}
//// CreateGameCardInfo 生成操控者卡牌信息
//func (g *GCGManager) CreateGameCardInfo(controller *GCGController, gcgDeck *model.GCGDeck) *GCGCardInfo {
// // CreateGameCardInfo 生成操控者卡牌信息
// func (g *GCGManager) CreateGameCardInfo(controller *GCGController, gcgDeck *model.GCGDeck) *GCGCardInfo {
//
//}
// }
// GetGameControllerByUserId 通过玩家Id获取GCGController对象
func (g *GCGManager) GetGameControllerByUserId(game *GCGGame, userId uint32) *GCGController {

View File

@@ -45,11 +45,17 @@ func (l *LocalEventManager) LocalEventHandle(localEvent *LocalEvent) {
playerRegInfo := localEvent.Msg.(*PlayerRegInfo)
GAME_MANAGER.OnRegOk(playerRegInfo.Exist, playerRegInfo.Req, playerRegInfo.UserId, playerRegInfo.ClientSeq, playerRegInfo.GateAppId)
case RunUserCopyAndSave:
saveUserIdList := localEvent.Msg.([]uint32)
startTime := time.Now().UnixNano()
// 拷贝一份数据避免并发访问
insertPlayerList := make([]*model.Player, 0)
updatePlayerList := make([]*model.Player, 0)
for uid, player := range USER_MANAGER.playerMap {
for _, uid := range saveUserIdList {
player := USER_MANAGER.GetOnlineUser(uid)
if player == nil {
logger.Error("try to save but user not exist or online, uid: %v", uid)
continue
}
if uid < 100000000 {
continue
}

View File

@@ -23,6 +23,7 @@ type RouteManager struct {
func NewRouteManager() (r *RouteManager) {
r = new(RouteManager)
r.handlerFuncRouteMap = make(map[uint16]HandlerFunc)
r.initRoute()
return r
}
@@ -52,7 +53,7 @@ func (r *RouteManager) doRoute(cmdId uint16, userId uint32, clientSeq uint32, pa
SELF = nil
}
func (r *RouteManager) InitRoute() {
func (r *RouteManager) initRoute() {
r.registerRouter(cmd.UnionCmdNotify, GAME_MANAGER.UnionCmdNotify)
r.registerRouter(cmd.MassiveEntityElementOpBatchNotify, GAME_MANAGER.MassiveEntityElementOpBatchNotify)
r.registerRouter(cmd.ToTheMoonEnterSceneReq, GAME_MANAGER.ToTheMoonEnterSceneReq)
@@ -169,10 +170,6 @@ func (r *RouteManager) RouteHandle(netMsg *mq.NetMsg) {
USER_MANAGER.SetRemoteUserOnlineState(serverMsg.UserId, serverMsg.IsOnline, netMsg.OriginServerAppId)
case mq.ServerAppidBindNotify:
GAME_MANAGER.ServerAppidBindNotify(serverMsg.UserId, serverMsg.FightServerAppId, serverMsg.JoinHostUserId)
case mq.ServerUserBaseInfoReq:
GAME_MANAGER.ServerUserBaseInfoReq(serverMsg.UserBaseInfo, netMsg.OriginServerAppId)
case mq.ServerUserBaseInfoRsp:
GAME_MANAGER.ServerUserBaseInfoRsp(serverMsg.UserBaseInfo)
case mq.ServerUserMpReq:
GAME_MANAGER.ServerUserMpReq(serverMsg.UserMpInfo, netMsg.OriginServerAppId)
case mq.ServerUserMpRsp:

View File

@@ -13,49 +13,148 @@ import (
// 游戏服务器定时帧管理器
type UserTimer struct {
timer *time.Timer
action int
}
type UserTick struct {
globalTick *time.Ticker
globalTickCount uint64
timerIdCounter uint64
timerMap map[uint64]*UserTimer
}
type TickManager struct {
ticker *time.Ticker
tickCount uint64
globalTick *time.Ticker
globalTickCount uint64
userTickMap map[uint32]*UserTick
}
func NewTickManager() (r *TickManager) {
r = new(TickManager)
r.ticker = time.NewTicker(time.Millisecond * 100)
r.globalTick = time.NewTicker(time.Millisecond * 100)
r.globalTickCount = 0
r.userTickMap = make(map[uint32]*UserTick)
logger.Info("game server tick start at: %v", time.Now().UnixMilli())
return r
}
// 每个玩家自己的tick
// CreateUserGlobalTick 创建玩家tick对象
func (t *TickManager) CreateUserGlobalTick(userId uint32) {
t.userTickMap[userId] = &UserTick{
globalTick: time.NewTicker(time.Second * 1),
globalTickCount: 0,
timerIdCounter: 0,
timerMap: make(map[uint64]*UserTimer),
}
}
// DestroyUserGlobalTick 销毁玩家tick对象
func (t *TickManager) DestroyUserGlobalTick(userId uint32) {
delete(t.userTickMap, userId)
}
// CreateUserTimer 创建玩家定时任务
func (t *TickManager) CreateUserTimer(userId uint32, action int, delay uint32) {
userTick, exist := t.userTickMap[userId]
if !exist {
logger.Error("user not exist, uid: %v", userId)
return
}
userTick.timerIdCounter++
userTick.timerMap[userTick.timerIdCounter] = &UserTimer{
timer: time.NewTimer(time.Second * time.Duration(delay)),
action: action,
}
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"))
}
func (t *TickManager) onUserTickSecond(userId uint32, now int64) {
// logger.Info("on user tick second, uid: %v, time: %v", userId, now)
}
func (t *TickManager) onUserTickMinute(userId uint32, now int64) {
logger.Info("on user tick minute, uid: %v, time: %v", userId, now)
// 每分钟保存玩家数据
saveUserIdList := []uint32{userId}
LOCAL_EVENT_MANAGER.localEventChan <- &LocalEvent{
EventId: RunUserCopyAndSave,
Msg: saveUserIdList,
}
}
// 玩家定时任务常量
const (
UserTimerActionTest = iota
)
func (t *TickManager) userTimerHandle(userId uint32, action int) {
switch action {
case UserTimerActionTest:
logger.Debug("UserTimerActionTest, uid: %v", userId)
}
}
// 服务器全局tick
func (t *TickManager) OnGameServerTick() {
t.tickCount++
t.globalTickCount++
now := time.Now().UnixMilli()
t.onTick100MilliSecond(now)
if t.tickCount%2 == 0 {
if t.globalTickCount%2 == 0 {
t.onTick200MilliSecond(now)
}
if t.tickCount%(10*1) == 0 {
if t.globalTickCount%(10*1) == 0 {
t.onTickSecond(now)
}
if t.tickCount%(10*5) == 0 {
if t.globalTickCount%(10*5) == 0 {
t.onTick5Second(now)
}
if t.tickCount%(10*10) == 0 {
if t.globalTickCount%(10*10) == 0 {
t.onTick10Second(now)
}
if t.tickCount%(10*60) == 0 {
if t.globalTickCount%(10*60) == 0 {
t.onTickMinute(now)
}
if t.tickCount%(10*60*10) == 0 {
if t.globalTickCount%(10*60*10) == 0 {
t.onTick10Minute(now)
}
if t.tickCount%(10*3600) == 0 {
if t.globalTickCount%(10*3600) == 0 {
t.onTickHour(now)
}
if t.tickCount%(10*3600*24) == 0 {
if t.globalTickCount%(10*3600*24) == 0 {
t.onTickDay(now)
}
if t.tickCount%(10*3600*24*7) == 0 {
if t.globalTickCount%(10*3600*24*7) == 0 {
t.onTickWeek(now)
}
for userId, userTick := range t.userTickMap {
if len(userTick.globalTick.C) == 0 {
// 跳过还没到时间的定时器
continue
}
userTick.globalTickCount++
if userTick.globalTickCount%(10*1) == 0 {
t.onUserTickSecond(userId, now)
}
if userTick.globalTickCount%(10*60) == 0 {
t.onUserTickMinute(userId, now)
}
for timerId, timer := range userTick.timerMap {
if len(timer.timer.C) == 0 {
// 跳过还没到时间的定时器
continue
}
timer.timer.Stop()
delete(userTick.timerMap, timerId)
t.userTimerHandle(userId, timer.action)
}
}
}
func (t *TickManager) onTickWeek(now int64) {
@@ -259,7 +358,7 @@ func (t *TickManager) onTickSecond(now int64) {
monsterEntityCount++
}
}
if monsterEntityCount < 30 {
if monsterEntityCount < 3 {
monsterEntityId := t.createMonster(scene)
GAME_MANAGER.AddSceneEntityNotify(world.owner, proto.VisionType_VISION_TYPE_BORN, []uint32{monsterEntityId}, true, false)
}

View File

@@ -152,6 +152,7 @@ func (g *GameManager) ServerAppidBindNotify(userId uint32, fightAppId string, jo
world.AddPlayer(player, player.SceneId)
player.WorldId = world.id
// 进入场景
player.SceneJump = true
player.SceneLoadState = model.SceneNone
g.SendMsg(cmd.PlayerEnterSceneNotify, userId, player.ClientSeq, g.PacketPlayerEnterSceneNotifyLogin(player, proto.EnterType_ENTER_TYPE_SELF))
}

View File

@@ -222,7 +222,7 @@ func (g *GameManager) ClientAbilityInitFinishNotify(player *model.Player, payloa
}
invokeHandler := model.NewInvokeHandler[proto.AbilityInvokeEntry]()
for _, entry := range req.Invokes {
logger.Debug("ClientAbilityInitFinishNotify: %v", entry, player.PlayerID)
// logger.Debug("ClientAbilityInitFinishNotify: %v", entry, player.PlayerID)
invokeHandler.AddEntry(entry.ForwardType, entry)
}
DoForward[proto.AbilityInvokeEntry](player, &proto.ClientAbilityInitFinishNotify{}, []string{"EntityId"}, "Invokes", invokeHandler)
@@ -236,7 +236,7 @@ func (g *GameManager) ClientAbilityChangeNotify(player *model.Player, payloadMsg
}
invokeHandler := model.NewInvokeHandler[proto.AbilityInvokeEntry]()
for _, entry := range req.Invokes {
logger.Debug("ClientAbilityChangeNotify: %v", entry, player.PlayerID)
// logger.Debug("ClientAbilityChangeNotify: %v", entry, player.PlayerID)
invokeHandler.AddEntry(entry.ForwardType, entry)
}

View File

@@ -1,18 +1,19 @@
package game
import (
pb "google.golang.org/protobuf/proto"
"hk4e/common/constant"
"hk4e/gs/model"
"hk4e/protocol/cmd"
"hk4e/protocol/proto"
pb "google.golang.org/protobuf/proto"
)
func (g *GameManager) GCGLogin(player *model.Player) {
player.SceneId = 1076
player.Pos.X = 8.974
player.Pos.Y = 0
player.Pos.Z = 9.373
// player.SceneId = 1076
// player.Pos.X = 8.974
// player.Pos.Y = 0
// player.Pos.Z = 9.373
// GCG基础信息
g.SendMsg(cmd.GCGBasicDataNotify, player.PlayerID, player.ClientSeq, g.PacketGCGBasicDataNotify(player))
// GCG等级挑战解锁
@@ -27,28 +28,25 @@ func (g *GameManager) GCGLogin(player *model.Player) {
// GCGTavernInit GCG酒馆初始化
func (g *GameManager) GCGTavernInit(player *model.Player) {
//// GCG酒馆信息通知
//g.SendMsg(cmd.GCGTCTavernInfoNotify, player.PlayerID, player.ClientSeq, g.PacketGCGTCTavernInfoNotify(player))
//// GCG酒馆NPC信息通知
//g.SendMsg(cmd.GCGTavernNpcInfoNotify, player.PlayerID, player.ClientSeq, g.PacketGCGTavernNpcInfoNotify(player))
// // GCG酒馆信息通知
// g.SendMsg(cmd.GCGTCTavernInfoNotify, player.PlayerID, player.ClientSeq, g.PacketGCGTCTavernInfoNotify(player))
// // GCG酒馆NPC信息通知
// g.SendMsg(cmd.GCGTavernNpcInfoNotify, player.PlayerID, player.ClientSeq, g.PacketGCGTavernNpcInfoNotify(player))
// 可能是包没发全导致卡进度条?
g.SendMsg(cmd.DungeonWayPointNotify, player.PlayerID, player.ClientSeq, &proto.DungeonWayPointNotify{})
g.SendMsg(cmd.DungeonDataNotify, player.PlayerID, player.ClientSeq, &proto.DungeonDataNotify{})
g.SendMsg(cmd.Unk3300_DGBNCDEIIFC, player.PlayerID, player.ClientSeq, &proto.Unk3300_DGBNCDEIIFC{})
}
// GCGStartChallenge GCG开始挑战
func (g *GameManager) GCGStartChallenge(player *model.Player) {
// GCG开始游戏通知
//gcgStartChallengeByCheckRewardRsp := &proto.GCGStartChallengeByCheckRewardRsp{
// gcgStartChallengeByCheckRewardRsp := &proto.GCGStartChallengeByCheckRewardRsp{
// ExceededItemTypeList: make([]uint32, 0, 0),
// LevelId: 0,
// ExceededItemList: make([]uint32, 0, 0),
// LevelType: proto.GCGLevelType_GCG_LEVEL_TYPE_GUIDE_GROUP,
// ConfigId: 7066505,
// Retcode: 0,
//}
//g.SendMsg(cmd.GCGStartChallengeByCheckRewardRsp, player.PlayerID, player.ClientSeq, gcgStartChallengeByCheckRewardRsp)
// }
// g.SendMsg(cmd.GCGStartChallengeByCheckRewardRsp, player.PlayerID, player.ClientSeq, gcgStartChallengeByCheckRewardRsp)
// GCG游戏简要信息通知
GAME_MANAGER.SendMsg(cmd.GCGGameBriefDataNotify, player.PlayerID, player.ClientSeq, g.PacketGCGGameBriefDataNotify(player, proto.GCGGameBusinessType_GCG_GAME_BUSINESS_TYPE_GUIDE_GROUP, 30102))
@@ -74,7 +72,7 @@ func (g *GameManager) GCGAskDuelReq(player *model.Player, payloadMsg pb.Message)
return
}
// PacketGCGAskDuelRsp
//gcgAskDuelRsp := &proto.GCGAskDuelRsp{
// gcgAskDuelRsp := &proto.GCGAskDuelRsp{
// Duel: &proto.GCGDuel{
// ServerSeq: game.serverSeqCounter,
// ShowInfoList: make([]*proto.GCGControllerShowInfo, 0, len(game.controllerMap)),
@@ -97,9 +95,9 @@ func (g *GameManager) GCGAskDuelReq(player *model.Player, payloadMsg pb.Message)
// Unk3300_JBBMBKGOONO: 0,
// Phase: nil,
// },
//}
//// 玩家信息列表
//for _, controller := range game.controllerMap {
// }
// // 玩家信息列表
// for _, controller := range game.controllerMap {
// gcgControllerShowInfo := &proto.GCGControllerShowInfo{
// ControllerId: controller.controllerId,
// ProfilePicture: &proto.ProfilePicture{},
@@ -110,8 +108,8 @@ func (g *GameManager) GCGAskDuelReq(player *model.Player, payloadMsg pb.Message)
// gcgControllerShowInfo.ProfilePicture.AvatarId = player.AvatarMap[player.HeadImage].Costume
// }
// gcgAskDuelRsp.Duel.ShowInfoList = append(gcgAskDuelRsp.Duel.ShowInfoList)
//}
//GAME_MANAGER.SendMsg(cmd.GCGAskDuelRsp, player.PlayerID, player.ClientSeq, gcgAskDuelRsp)
// }
// GAME_MANAGER.SendMsg(cmd.GCGAskDuelRsp, player.PlayerID, player.ClientSeq, gcgAskDuelRsp)
// PacketGCGAskDuelRsp
gcgAskDuelRsp := new(proto.GCGAskDuelRsp)
gcgAskDuelRsp.Duel = &proto.GCGDuel{

View File

@@ -39,7 +39,7 @@ func (g *GameManager) OnLogin(userId uint32, clientSeq uint32, gateAppId string)
func (g *GameManager) OnLoginOk(userId uint32, player *model.Player, clientSeq uint32, gateAppId string) {
if player == nil {
g.SendMsgEx(cmd.DoSetPlayerBornDataNotify, userId, clientSeq, gateAppId, new(proto.DoSetPlayerBornDataNotify))
g.SendMsgToGate(cmd.DoSetPlayerBornDataNotify, userId, clientSeq, gateAppId, new(proto.DoSetPlayerBornDataNotify))
return
}
player.OnlineTime = uint32(time.Now().UnixMilli())
@@ -56,6 +56,12 @@ func (g *GameManager) OnLoginOk(userId uint32, player *model.Player, clientSeq u
player.Pos.Y = player.SafePos.Y
player.Pos.Z = player.SafePos.Z
if player.SceneId > 100 {
player.SceneId = 3
player.Pos = &model.Vector{X: 2747, Y: 194, Z: -1719}
player.Rot = &model.Vector{X: 0, Y: 307, Z: 0}
}
player.CombatInvokeHandler = model.NewInvokeHandler[proto.CombatInvokeEntry]()
player.AbilityInvokeHandler = model.NewInvokeHandler[proto.AbilityInvokeEntry]()
@@ -71,6 +77,8 @@ func (g *GameManager) OnLoginOk(userId uint32, player *model.Player, clientSeq u
},
})
}
TICK_MANAGER.CreateUserGlobalTick(userId)
TICK_MANAGER.CreateUserTimer(userId, UserTimerActionTest, 100)
}
func (g *GameManager) OnReg(userId uint32, clientSeq uint32, gateAppId string, payloadMsg pb.Message) {
@@ -104,7 +112,7 @@ func (g *GameManager) OnRegOk(exist bool, req *proto.SetPlayerBornDataReq, userI
}
USER_MANAGER.AddUser(player)
g.SendMsgEx(cmd.SetPlayerBornDataRsp, userId, clientSeq, gateAppId, new(proto.SetPlayerBornDataRsp))
g.SendMsgToGate(cmd.SetPlayerBornDataRsp, userId, clientSeq, gateAppId, new(proto.SetPlayerBornDataRsp))
g.OnLogin(userId, clientSeq, gateAppId)
}
@@ -115,6 +123,7 @@ func (g *GameManager) OnUserOffline(userId uint32, changeGsInfo *ChangeGsInfo) {
logger.Error("player is nil, userId: %v", userId)
return
}
TICK_MANAGER.DestroyUserGlobalTick(userId)
world := WORLD_MANAGER.GetWorldByID(player.WorldId)
if world != nil {
g.UserWorldRemovePlayer(world, player)

View File

@@ -1,8 +1,6 @@
package game
import (
"time"
"hk4e/gs/dao"
"hk4e/gs/model"
"hk4e/pkg/logger"
@@ -30,6 +28,7 @@ func NewUserManager(dao *dao.Dao) (r *UserManager) {
r.playerMap = make(map[uint32]*model.Player)
r.saveUserChan = make(chan *SaveUserData) // 无缓冲区chan 避免主协程在写入时被迫加锁
r.remotePlayerMap = make(map[uint32]string)
go r.saveUserHandle()
return r
}
@@ -356,24 +355,12 @@ type SaveUserData struct {
updatePlayerList []*model.Player
}
// StartAutoSaveUser 玩家定时保存
func (u *UserManager) StartAutoSaveUser() {
go func() {
ticker := time.NewTicker(time.Minute * 5)
for {
LOCAL_EVENT_MANAGER.localEventChan <- &LocalEvent{
EventId: RunUserCopyAndSave,
}
<-ticker.C
}
}()
go func() {
for {
saveUserData := <-u.saveUserChan
u.SaveUserListToDbSync(saveUserData)
u.SaveUserListToRedisSync(saveUserData)
}
}()
func (u *UserManager) saveUserHandle() {
for {
saveUserData := <-u.saveUserChan
u.SaveUserListToDbSync(saveUserData)
u.SaveUserListToRedisSync(saveUserData)
}
}
func (u *UserManager) LoadUserFromDbSync(userId uint32) *model.Player {

View File

@@ -78,6 +78,7 @@ func (g *GameManager) TeleportPlayer(player *model.Player, enterReason uint16, s
if newSceneId != oldSceneId {
jumpScene = true
}
player.SceneJump = jumpScene
world := WORLD_MANAGER.GetWorldByID(player.WorldId)
oldScene := world.GetSceneById(oldSceneId)
activeAvatarId := world.GetPlayerActiveAvatarId(player)
@@ -87,14 +88,14 @@ func (g *GameManager) TeleportPlayer(player *model.Player, enterReason uint16, s
g.SendMsg(cmd.DelTeamEntityNotify, player.PlayerID, player.ClientSeq, delTeamEntityNotify)
oldScene.RemovePlayer(player)
player.SceneId = newSceneId
newScene := world.GetSceneById(newSceneId)
newScene.AddPlayer(player)
}
player.SceneLoadState = model.SceneNone
player.Pos.X = pos.X
player.Pos.Y = pos.Y
player.Pos.Z = pos.Z
player.SceneId = newSceneId
player.SceneLoadState = model.SceneNone
var enterType proto.EnterType
switch enterReason {

View File

@@ -79,15 +79,16 @@ func (g *GameManager) JoinPlayerSceneReq(player *model.Player, payloadMsg pb.Mes
func (g *GameManager) JoinOtherWorld(player *model.Player, hostPlayer *model.Player) {
hostWorld := WORLD_MANAGER.GetWorldByID(hostPlayer.WorldId)
if hostPlayer.SceneLoadState == model.SceneEnterDone {
player.SceneJump = true
player.SceneId = hostPlayer.SceneId
player.SceneLoadState = model.SceneNone
player.Pos.X = hostPlayer.Pos.X
player.Pos.Y = hostPlayer.Pos.Y
player.Pos.Z = hostPlayer.Pos.Z
player.Rot.X = hostPlayer.Rot.X
player.Rot.Y = hostPlayer.Rot.Y
player.Rot.Z = hostPlayer.Rot.Z
player.SceneId = hostPlayer.SceneId
g.UserWorldAddPlayer(hostWorld, player)
player.SceneLoadState = model.SceneNone
playerEnterSceneNotify := g.PacketPlayerEnterSceneNotifyLogin(player, proto.EnterType_ENTER_TYPE_OTHER)
g.SendMsg(cmd.PlayerEnterSceneNotify, player.PlayerID, player.ClientSeq, playerEnterSceneNotify)
@@ -318,6 +319,7 @@ func (g *GameManager) HostEnterMpWorld(hostPlayer *model.Player, otherUid uint32
}
g.SendMsg(cmd.WorldDataNotify, hostPlayer.PlayerID, hostPlayer.ClientSeq, worldDataNotify)
hostPlayer.SceneJump = true
hostPlayer.SceneLoadState = model.SceneNone
hostPlayerEnterSceneNotify := g.PacketPlayerEnterSceneNotifyMp(

View File

@@ -45,7 +45,7 @@ func (g *GameManager) SceneInitFinishReq(player *model.Player, payloadMsg pb.Mes
}
g.SendMsg(cmd.ServerTimeNotify, player.PlayerID, player.ClientSeq, serverTimeNotify)
if world.IsPlayerFirstEnter(player) {
if player.SceneJump {
worldPlayerInfoNotify := &proto.WorldPlayerInfoNotify{
PlayerInfoList: make([]*proto.OnlinePlayerInfo, 0),
PlayerUidList: make([]uint32, 0),
@@ -214,6 +214,9 @@ func (g *GameManager) SceneInitFinishReq(player *model.Player, payloadMsg pb.Mes
g.GCGTavernInit(player) // GCG酒馆信息通知
g.SendMsg(cmd.DungeonWayPointNotify, player.PlayerID, player.ClientSeq, &proto.DungeonWayPointNotify{})
g.SendMsg(cmd.DungeonDataNotify, player.PlayerID, player.ClientSeq, &proto.DungeonDataNotify{})
SceneInitFinishRsp := &proto.SceneInitFinishRsp{
EnterSceneToken: player.EnterSceneToken,
}
@@ -234,20 +237,25 @@ func (g *GameManager) EnterSceneDoneReq(player *model.Player, payloadMsg pb.Mess
g.SendMsg(cmd.GuestPostEnterSceneNotify, world.owner.PlayerID, world.owner.ClientSeq, guestPostEnterSceneNotify)
}
var visionType = proto.VisionType_VISION_TYPE_TRANSPORT
var visionType = proto.VisionType_VISION_TYPE_NONE
activeAvatarId := world.GetPlayerActiveAvatarId(player)
if world.IsPlayerFirstEnter(player) {
if player.SceneJump {
visionType = proto.VisionType_VISION_TYPE_BORN
} else {
visionType = proto.VisionType_VISION_TYPE_TRANSPORT
}
g.AddSceneEntityNotify(player, visionType, []uint32{world.GetPlayerWorldAvatarEntityId(player, activeAvatarId)}, true, false)
activeAvatarEntityId := world.GetPlayerWorldAvatarEntityId(player, activeAvatarId)
g.AddSceneEntityNotify(player, visionType, []uint32{activeAvatarEntityId}, true, false)
// 通过aoi获取场景中在自己周围格子里的全部实体id
// entityIdList := world.aoiManager.GetEntityIdListByPos(float32(player.Pos.X), float32(player.Pos.Y), float32(player.Pos.Z))
entityIdList := world.GetSceneById(player.SceneId).GetEntityIdList()
if world.IsPlayerFirstEnter(player) {
if player.SceneJump {
visionType = proto.VisionType_VISION_TYPE_MEET
} else {
visionType = proto.VisionType_VISION_TYPE_TRANSPORT
}
entityIdList := world.GetSceneById(player.SceneId).GetEntityIdList()
g.AddSceneEntityNotify(player, visionType, entityIdList, false, false)
sceneAreaWeatherNotify := &proto.SceneAreaWeatherNotify{
@@ -453,7 +461,7 @@ func (g *GameManager) AddSceneEntityNotify(player *model.Player, visionType prot
for _, entityId := range entityIdList[begin:end] {
entity, ok := scene.entityMap[entityId]
if !ok {
// logger.Error("get entity is nil, entityId: %v", entityId)
logger.Error("get entity is nil, entityId: %v", entityId)
continue
}
switch entity.entityType {

View File

@@ -21,28 +21,11 @@ func (g *GameManager) GetPlayerSocialDetailReq(player *model.Player, payloadMsg
req := payloadMsg.(*proto.GetPlayerSocialDetailReq)
targetUid := req.Uid
targetPlayer, _, remote := USER_MANAGER.LoadGlobalPlayer(targetUid)
targetPlayer, _, _ := USER_MANAGER.LoadGlobalPlayer(targetUid)
if targetPlayer == nil {
g.CommonRetError(cmd.GetPlayerSocialDetailRsp, player, &proto.GetPlayerSocialDetailRsp{}, proto.Retcode_RET_PLAYER_NOT_EXIST)
return
}
if remote {
gsAppId := USER_MANAGER.GetRemoteUserGsAppId(targetUid)
MESSAGE_QUEUE.SendToGs(gsAppId, &mq.NetMsg{
MsgType: mq.MsgTypeServer,
EventId: mq.ServerUserBaseInfoReq,
ServerMsg: &mq.ServerMsg{
UserBaseInfo: &mq.UserBaseInfo{
OriginInfo: &mq.OriginInfo{
CmdName: "GetPlayerSocialDetailReq",
UserId: player.PlayerID,
},
UserId: targetUid,
},
},
})
return
}
_, exist := player.FriendList[targetPlayer.PlayerID]
socialDetail := &proto.SocialDetail{
Uid: targetPlayer.PlayerID,
@@ -441,31 +424,16 @@ func (g *GameManager) GetOnlinePlayerInfoReq(player *model.Player, payloadMsg pb
return
}
if USER_MANAGER.GetUserOnlineState(targetUid.TargetUid) {
g.SendMsg(cmd.GetOnlinePlayerInfoRsp, player.PlayerID, player.ClientSeq, &proto.GetOnlinePlayerInfoRsp{
TargetUid: targetUid.TargetUid,
TargetPlayerInfo: g.PacketOnlinePlayerInfo(player),
})
targetPlayer, online, _ := USER_MANAGER.LoadGlobalPlayer(targetUid.TargetUid)
if targetPlayer == nil || !online {
g.CommonRetError(cmd.GetOnlinePlayerInfoRsp, player, &proto.GetOnlinePlayerInfoRsp{}, proto.Retcode_RET_PLAYER_NOT_ONLINE)
return
}
if USER_MANAGER.GetRemoteUserOnlineState(targetUid.TargetUid) {
gsAppId := USER_MANAGER.GetRemoteUserGsAppId(targetUid.TargetUid)
MESSAGE_QUEUE.SendToGs(gsAppId, &mq.NetMsg{
MsgType: mq.MsgTypeServer,
EventId: mq.ServerUserBaseInfoReq,
ServerMsg: &mq.ServerMsg{
UserBaseInfo: &mq.UserBaseInfo{
OriginInfo: &mq.OriginInfo{
CmdName: "GetOnlinePlayerInfoReq",
UserId: player.PlayerID,
},
UserId: targetUid.TargetUid,
},
},
})
return
}
g.CommonRetError(cmd.GetOnlinePlayerInfoRsp, player, &proto.GetOnlinePlayerInfoRsp{}, proto.Retcode_RET_PLAYER_NOT_ONLINE)
g.SendMsg(cmd.GetOnlinePlayerInfoRsp, player.PlayerID, player.ClientSeq, &proto.GetOnlinePlayerInfoRsp{
TargetUid: targetUid.TargetUid,
TargetPlayerInfo: g.PacketOnlinePlayerInfo(targetPlayer),
})
}
func (g *GameManager) PacketOnlinePlayerInfo(player *model.Player) *proto.OnlinePlayerInfo {
@@ -488,89 +456,6 @@ func (g *GameManager) PacketOnlinePlayerInfo(player *model.Player) *proto.Online
return onlinePlayerInfo
}
// 跨服玩家基础数据请求
func (g *GameManager) ServerUserBaseInfoReq(userBaseInfo *mq.UserBaseInfo, gsAppId string) {
switch userBaseInfo.OriginInfo.CmdName {
case "GetOnlinePlayerInfoReq":
fallthrough
case "GetPlayerSocialDetailReq":
player := USER_MANAGER.GetOnlineUser(userBaseInfo.UserId)
if player == nil {
logger.Error("player is nil, uid: %v", userBaseInfo.UserId)
return
}
world := WORLD_MANAGER.GetWorldByID(player.WorldId)
MESSAGE_QUEUE.SendToGs(gsAppId, &mq.NetMsg{
MsgType: mq.MsgTypeServer,
EventId: mq.ServerUserBaseInfoRsp,
ServerMsg: &mq.ServerMsg{
UserBaseInfo: &mq.UserBaseInfo{
OriginInfo: userBaseInfo.OriginInfo,
UserId: player.PlayerID,
Nickname: player.NickName,
PlayerLevel: player.PropertiesMap[constant.PlayerPropertyConst.PROP_PLAYER_LEVEL],
MpSettingType: uint8(player.PropertiesMap[constant.PlayerPropertyConst.PROP_PLAYER_MP_SETTING_TYPE]),
NameCardId: player.NameCard,
Signature: player.Signature,
HeadImageId: player.HeadImage,
WorldPlayerNum: uint32(world.GetWorldPlayerNum()),
WorldLevel: player.PropertiesMap[constant.PlayerPropertyConst.PROP_PLAYER_WORLD_LEVEL],
Birthday: player.Birthday,
},
},
})
}
}
func (g *GameManager) ServerUserBaseInfoRsp(userBaseInfo *mq.UserBaseInfo) {
switch userBaseInfo.OriginInfo.CmdName {
case "GetOnlinePlayerInfoReq":
player := USER_MANAGER.GetOnlineUser(userBaseInfo.OriginInfo.UserId)
if player == nil {
logger.Error("player is nil, uid: %v", userBaseInfo.OriginInfo.UserId)
return
}
g.SendMsg(cmd.GetOnlinePlayerInfoRsp, player.PlayerID, player.ClientSeq, &proto.GetOnlinePlayerInfoRsp{
TargetUid: userBaseInfo.UserId,
TargetPlayerInfo: &proto.OnlinePlayerInfo{
Uid: userBaseInfo.UserId,
Nickname: userBaseInfo.Nickname,
PlayerLevel: userBaseInfo.PlayerLevel,
MpSettingType: proto.MpSettingType(userBaseInfo.MpSettingType),
NameCardId: userBaseInfo.NameCardId,
Signature: userBaseInfo.Signature,
ProfilePicture: &proto.ProfilePicture{AvatarId: userBaseInfo.HeadImageId},
CurPlayerNumInWorld: userBaseInfo.WorldPlayerNum,
},
})
case "GetPlayerSocialDetailReq":
player := USER_MANAGER.GetOnlineUser(userBaseInfo.OriginInfo.UserId)
if player == nil {
logger.Error("player is nil, uid: %v", userBaseInfo.OriginInfo.UserId)
return
}
_, exist := player.FriendList[userBaseInfo.UserId]
socialDetail := &proto.SocialDetail{
Uid: userBaseInfo.UserId,
ProfilePicture: &proto.ProfilePicture{AvatarId: userBaseInfo.HeadImageId},
Nickname: userBaseInfo.Nickname,
Signature: userBaseInfo.Signature,
Level: userBaseInfo.PlayerLevel,
Birthday: &proto.Birthday{Month: uint32(userBaseInfo.Birthday[0]), Day: uint32(userBaseInfo.Birthday[1])},
WorldLevel: userBaseInfo.WorldLevel,
NameCardId: userBaseInfo.NameCardId,
IsShowAvatar: false,
FinishAchievementNum: 0,
IsFriend: exist,
}
getPlayerSocialDetailRsp := &proto.GetPlayerSocialDetailRsp{
DetailData: socialDetail,
}
g.SendMsg(cmd.GetPlayerSocialDetailRsp, player.PlayerID, player.ClientSeq, getPlayerSocialDetailRsp)
}
}
// 跨服添加好友通知
func (g *GameManager) ServerAddFriendNotify(addFriendInfo *mq.AddFriendInfo) {

View File

@@ -5,13 +5,11 @@ import (
"time"
"hk4e/common/constant"
"hk4e/protocol/cmd"
"hk4e/common/mq"
"hk4e/gs/game/aoi"
"hk4e/gs/model"
"hk4e/pkg/alg"
"hk4e/pkg/logger"
"hk4e/protocol/cmd"
"hk4e/protocol/proto"
)
@@ -50,24 +48,24 @@ func (w *WorldManager) CreateWorld(owner *model.Player) *World {
multiplayer: false,
mpLevelEntityId: 0,
chatMsgList: make([]*proto.ChatInfo, 0),
// aoi划分
// TODO 为减少内存占用暂时去掉Y轴AOI格子划分 原来的Y轴格子数量为80
aoiManager: aoi.NewAoiManager(
-8000, 4000, 120,
-2000, 2000, 1,
-5500, 6500, 120,
),
// // aoi划分
// // TODO 为减少内存占用暂时去掉Y轴AOI格子划分 原来的Y轴格子数量为80
// aoiManager: aoi.NewAoiManager(
// -8000, 4000, 120,
// -2000, 2000, 1,
// -5500, 6500, 120,
// ),
playerFirstEnterMap: make(map[uint32]int64),
waitEnterPlayerMap: make(map[uint32]int64),
multiplayerTeam: CreateMultiplayerTeam(),
peerList: make([]*model.Player, 0),
}
if world.IsBigWorld() {
world.aoiManager = aoi.NewAoiManager(
-8000, 4000, 800,
-2000, 2000, 1,
-5500, 6500, 800,
)
// world.aoiManager = aoi.NewAoiManager(
// -8000, 4000, 800,
// -2000, 2000, 1,
// -5500, 6500, 800,
// )
}
world.mpLevelEntityId = world.GetNextWorldEntityId(constant.EntityIdTypeConst.MPLEVEL)
w.worldMap[worldId] = world
@@ -101,18 +99,18 @@ func (w *World) IsBigWorld() bool {
// 世界数据结构
type World struct {
id uint32
owner *model.Player
playerMap map[uint32]*model.Player
sceneMap map[uint32]*Scene
entityIdCounter uint32 // 世界的实体id生成计数器
worldLevel uint8 // 世界等级
multiplayer bool // 是否多人世界
mpLevelEntityId uint32
chatMsgList []*proto.ChatInfo // 世界聊天消息列表
aoiManager *aoi.AoiManager // 当前世界地图的aoi管理器
playerFirstEnterMap map[uint32]int64 // 玩家第一次进入世界的时间 key:uid value:进入时间
waitEnterPlayerMap map[uint32]int64 // 进入世界的玩家等待列表 key:uid value:开始时间
id uint32
owner *model.Player
playerMap map[uint32]*model.Player
sceneMap map[uint32]*Scene
entityIdCounter uint32 // 世界的实体id生成计数器
worldLevel uint8 // 世界等级
multiplayer bool // 是否多人世界
mpLevelEntityId uint32
chatMsgList []*proto.ChatInfo // 世界聊天消息列表
// aoiManager *aoi.AoiManager // 当前世界地图的aoi管理器
playerFirstEnterMap map[uint32]int64 // 玩家第一次进入世界的时间 key:uid value:进入时间
waitEnterPlayerMap map[uint32]int64 // 进入世界的玩家等待列表 key:uid value:开始时间
multiplayerTeam *MultiplayerTeam
peerList []*model.Player // 玩家编号列表
}
@@ -263,7 +261,7 @@ func (w *World) InitPlayerWorldAvatar(player *model.Player) {
if worldAvatar.uid != player.PlayerID {
continue
}
if worldAvatar.avatarEntityId != 0 || worldAvatar.weaponEntityId != 0 {
if !player.SceneJump && (worldAvatar.avatarEntityId != 0 || worldAvatar.weaponEntityId != 0) {
continue
}
worldAvatar.avatarEntityId = scene.CreateEntityAvatar(player, worldAvatar.avatarId)
@@ -706,9 +704,9 @@ func (s *Scene) CreateEntityAvatar(player *model.Player, avatarId uint32) uint32
},
}
s.entityMap[entity.id] = entity
if avatarId == s.world.GetPlayerActiveAvatarId(player) {
s.world.aoiManager.AddEntityIdToGridByPos(entity.id, float32(entity.pos.X), float32(entity.pos.Y), float32(entity.pos.Z))
}
// if avatarId == s.world.GetPlayerActiveAvatarId(player) {
// s.world.aoiManager.AddEntityIdToGridByPos(entity.id, float32(entity.pos.X), float32(entity.pos.Y), float32(entity.pos.Z))
// }
MESSAGE_QUEUE.SendToFight(s.world.owner.FightAppId, &mq.NetMsg{
MsgType: mq.MsgTypeFight,
EventId: mq.FightRoutineAddEntity,
@@ -759,7 +757,7 @@ func (s *Scene) CreateEntityMonster(pos *model.Vector, level uint8, fightProp ma
monsterEntity: &MonsterEntity{},
}
s.entityMap[entity.id] = entity
s.world.aoiManager.AddEntityIdToGridByPos(entity.id, float32(entity.pos.X), float32(entity.pos.Y), float32(entity.pos.Z))
// s.world.aoiManager.AddEntityIdToGridByPos(entity.id, float32(entity.pos.X), float32(entity.pos.Y), float32(entity.pos.Z))
MESSAGE_QUEUE.SendToFight(s.world.owner.FightAppId, &mq.NetMsg{
MsgType: mq.MsgTypeFight,
EventId: mq.FightRoutineAddEntity,
@@ -798,7 +796,7 @@ func (s *Scene) CreateEntityNpc(pos, rot *model.Vector, npcId, roomId, parentQue
},
}
s.entityMap[entity.id] = entity
s.world.aoiManager.AddEntityIdToGridByPos(entity.id, float32(entity.pos.X), float32(entity.pos.Y), float32(entity.pos.Z))
// s.world.aoiManager.AddEntityIdToGridByPos(entity.id, float32(entity.pos.X), float32(entity.pos.Y), float32(entity.pos.Z))
return entity.id
}
@@ -826,7 +824,7 @@ func (s *Scene) CreateEntityGadgetNormal(pos *model.Vector, gadgetId uint32) uin
},
}
s.entityMap[entity.id] = entity
s.world.aoiManager.AddEntityIdToGridByPos(entity.id, float32(entity.pos.X), float32(entity.pos.Y), float32(entity.pos.Z))
// s.world.aoiManager.AddEntityIdToGridByPos(entity.id, float32(entity.pos.X), float32(entity.pos.Y), float32(entity.pos.Z))
return entity.id
}
@@ -856,7 +854,7 @@ func (s *Scene) CreateEntityGadgetGather(pos *model.Vector, gatherId uint32) uin
},
}
s.entityMap[entity.id] = entity
s.world.aoiManager.AddEntityIdToGridByPos(entity.id, float32(entity.pos.X), float32(entity.pos.Y), float32(entity.pos.Z))
// s.world.aoiManager.AddEntityIdToGridByPos(entity.id, float32(entity.pos.X), float32(entity.pos.Y), float32(entity.pos.Z))
return entity.id
}
@@ -890,7 +888,7 @@ func (s *Scene) CreateEntityGadgetClient(pos, rot *model.Vector, entityId uint32
},
}
s.entityMap[entity.id] = entity
s.world.aoiManager.AddEntityIdToGridByPos(entity.id, float32(entity.pos.X), float32(entity.pos.Y), float32(entity.pos.Z))
// s.world.aoiManager.AddEntityIdToGridByPos(entity.id, float32(entity.pos.X), float32(entity.pos.Y), float32(entity.pos.Z))
}
func (s *Scene) CreateEntityGadgetVehicle(uid uint32, pos, rot *model.Vector, vehicleId uint32) uint32 {
@@ -929,7 +927,7 @@ func (s *Scene) CreateEntityGadgetVehicle(uid uint32, pos, rot *model.Vector, ve
},
}
s.entityMap[entity.id] = entity
s.world.aoiManager.AddEntityIdToGridByPos(entity.id, float32(entity.pos.X), float32(entity.pos.Y), float32(entity.pos.Z))
// s.world.aoiManager.AddEntityIdToGridByPos(entity.id, float32(entity.pos.X), float32(entity.pos.Y), float32(entity.pos.Z))
return entity.id
}
@@ -938,7 +936,7 @@ func (s *Scene) DestroyEntity(entityId uint32) {
if entity == nil {
return
}
s.world.aoiManager.RemoveEntityIdFromGridByPos(entity.id, float32(entity.pos.X), float32(entity.pos.Y), float32(entity.pos.Z))
// s.world.aoiManager.RemoveEntityIdFromGridByPos(entity.id, float32(entity.pos.X), float32(entity.pos.Y), float32(entity.pos.Z))
delete(s.entityMap, entityId)
MESSAGE_QUEUE.SendToFight(s.world.owner.FightAppId, &mq.NetMsg{
MsgType: mq.MsgTypeFight,

View File

@@ -65,6 +65,7 @@ type Player struct {
GameObjectGuidMap map[uint64]GameObject `bson:"-" msgpack:"-"` // 游戏对象guid映射表
Online bool `bson:"-" msgpack:"-"` // 在线状态
Pause bool `bson:"-" msgpack:"-"` // 暂停状态
SceneJump bool `bson:"-" msgpack:"-"` // 是否场景切换
SceneLoadState int `bson:"-" msgpack:"-"` // 场景加载状态
CoopApplyMap map[uint32]int64 `bson:"-" msgpack:"-"` // 敲门申请的玩家uid及时间
StaminaInfo *StaminaInfo `bson:"-" msgpack:"-"` // 耐力临时数据

View File

@@ -1,12 +1,10 @@
package aoi
package alg
import (
"fmt"
"hk4e/pkg/logger"
)
// aoi管理模块
// AoiManager aoi管理模块
type AoiManager struct {
// 区域边界坐标
minX int16
@@ -21,7 +19,7 @@ type AoiManager struct {
gridMap map[uint32]*Grid // 当前区域中都有哪些格子 key:gid value:格子对象
}
// 初始化aoi区域
// NewAoiManager 初始化aoi区域
func NewAoiManager(minX, maxX, numX, minY, maxY, numY, minZ, maxZ, numZ int16) (r *AoiManager) {
r = new(AoiManager)
r.minX = minX
@@ -56,25 +54,31 @@ func NewAoiManager(minX, maxX, numX, minY, maxY, numY, minZ, maxZ, numZ int16) (
}
}
logger.Info("init aoi area grid finish")
logger.Debug("AoiMgr: minX: %d, maxX: %d, numX: %d, minY: %d, maxY: %d, numY: %d, minZ: %d, maxZ: %d, numZ: %d\n",
r.minX, r.maxX, r.numX, r.minY, r.maxY, r.numY, r.minZ, r.maxZ, r.numZ)
for _, grid := range r.gridMap {
logger.Debug("Grid: gid: %d, minX: %d, maxX: %d, minY: %d, maxY: %d, minZ: %d, maxZ: %d, entityIdMap: %v",
grid.gid, grid.minX, grid.maxX, grid.minY, grid.maxY, grid.minZ, grid.maxZ, grid.entityIdMap)
}
return r
}
// 每个格子在x轴方向的长度
// GridXLen 每个格子在x轴方向的长度
func (a *AoiManager) GridXLen() int16 {
return (a.maxX - a.minX) / a.numX
}
// 每个格子在y轴方向的长度
// GridYLen 每个格子在y轴方向的长度
func (a *AoiManager) GridYLen() int16 {
return (a.maxY - a.minY) / a.numY
}
// 每个格子在z轴方向的长度
// GridZLen 每个格子在z轴方向的长度
func (a *AoiManager) GridZLen() int16 {
return (a.maxZ - a.minZ) / a.numZ
}
// 通过坐标获取对应的格子id
// GetGidByPos 通过坐标获取对应的格子id
func (a *AoiManager) GetGidByPos(x, y, z float32) uint32 {
gx := (int16(x) - a.minX) / a.GridXLen()
gy := (int16(y) - a.minY) / a.GridYLen()
@@ -82,7 +86,7 @@ func (a *AoiManager) GetGidByPos(x, y, z float32) uint32 {
return uint32(gy)*(uint32(a.numX)*uint32(a.numZ)) + uint32(gz)*uint32(a.numX) + uint32(gx)
}
// 判断坐标是否存在于aoi区域内
// IsValidAoiPos 判断坐标是否存在于aoi区域内
func (a *AoiManager) IsValidAoiPos(x, y, z float32) bool {
if (int16(x) > a.minX && int16(x) < a.maxX) &&
(int16(y) > a.minY && int16(y) < a.maxY) &&
@@ -93,18 +97,7 @@ func (a *AoiManager) IsValidAoiPos(x, y, z float32) bool {
}
}
// 打印信息方法
func (a *AoiManager) DebugString() string {
s := fmt.Sprintf("AoiMgr: minX: %d, maxX: %d, numX: %d, minY: %d, maxY: %d, numY: %d, minZ: %d, maxZ: %d, numZ: %d\n",
a.minX, a.maxX, a.numX, a.minY, a.maxY, a.numY, a.minZ, a.maxZ, a.numZ)
s += "gridList in AoiMgr:\n"
for _, grid := range a.gridMap {
s += fmt.Sprintln(grid.DebugString())
}
return s
}
// 根据格子的gid得到当前周边的格子信息
// GetSurrGridListByGid 根据格子的gid得到当前周边的格子信息
func (a *AoiManager) GetSurrGridListByGid(gid uint32) (gridList []*Grid) {
gridList = make([]*Grid, 0)
// 判断grid是否存在
@@ -165,7 +158,7 @@ func (a *AoiManager) GetSurrGridListByGid(gid uint32) (gridList []*Grid) {
return gridList
}
// 通过坐标得到周边格子内的全部entityId
// GetEntityIdListByPos 通过坐标得到周边格子内的全部entityId
func (a *AoiManager) GetEntityIdListByPos(x, y, z float32) (entityIdList []uint32) {
// 根据坐标得到当前坐标属于哪个格子id
gid := a.GetGidByPos(x, y, z)
@@ -175,37 +168,37 @@ func (a *AoiManager) GetEntityIdListByPos(x, y, z float32) (entityIdList []uint3
for _, v := range gridList {
tmp := v.GetEntityIdList()
entityIdList = append(entityIdList, tmp...)
// logger.Debug("Grid: gid: %d, tmp len: %v", v.gid, len(tmp))
logger.Debug("Grid: gid: %d, tmp len: %v", v.gid, len(tmp))
}
return entityIdList
}
// 通过gid获取当前格子的全部entityId
// GetEntityIdListByGid 通过gid获取当前格子的全部entityId
func (a *AoiManager) GetEntityIdListByGid(gid uint32) (entityIdList []uint32) {
grid := a.gridMap[gid]
entityIdList = grid.GetEntityIdList()
return entityIdList
}
// 添加一个entityId到一个格子中
// AddEntityIdToGrid 添加一个entityId到一个格子中
func (a *AoiManager) AddEntityIdToGrid(entityId uint32, gid uint32) {
grid := a.gridMap[gid]
grid.AddEntityId(entityId)
}
// 移除一个格子中的entityId
// RemoveEntityIdFromGrid 移除一个格子中的entityId
func (a *AoiManager) RemoveEntityIdFromGrid(entityId uint32, gid uint32) {
grid := a.gridMap[gid]
grid.RemoveEntityId(entityId)
}
// 通过坐标添加一个entityId到一个格子中
// AddEntityIdToGridByPos 通过坐标添加一个entityId到一个格子中
func (a *AoiManager) AddEntityIdToGridByPos(entityId uint32, x, y, z float32) {
gid := a.GetGidByPos(x, y, z)
a.AddEntityIdToGrid(entityId, gid)
}
// 通过坐标把一个entityId从对应的格子中删除
// RemoveEntityIdFromGridByPos 通过坐标把一个entityId从对应的格子中删除
func (a *AoiManager) RemoveEntityIdFromGridByPos(entityId uint32, x, y, z float32) {
gid := a.GetGidByPos(x, y, z)
a.RemoveEntityIdFromGrid(entityId, gid)

View File

@@ -1,12 +1,10 @@
package aoi
package alg
import (
"fmt"
"hk4e/pkg/logger"
)
// 地图格子
// Grid 地图格子
type Grid struct {
gid uint32 // 格子id
// 格子边界坐标
@@ -19,7 +17,7 @@ type Grid struct {
entityIdMap map[uint32]bool // k:entityId v:是否存在
}
// 初始化格子
// NewGrid 初始化格子
func NewGrid(gid uint32, minX, maxX, minY, maxY, minZ, maxZ int16) (r *Grid) {
r = new(Grid)
r.gid = gid
@@ -33,12 +31,12 @@ func NewGrid(gid uint32, minX, maxX, minY, maxY, minZ, maxZ int16) (r *Grid) {
return r
}
// 向格子中添加一个实体id
// AddEntityId 向格子中添加一个实体id
func (g *Grid) AddEntityId(entityId uint32) {
g.entityIdMap[entityId] = true
}
// 从格子中删除一个实体id
// RemoveEntityId 从格子中删除一个实体id
func (g *Grid) RemoveEntityId(entityId uint32) {
_, exist := g.entityIdMap[entityId]
if exist {
@@ -48,7 +46,7 @@ func (g *Grid) RemoveEntityId(entityId uint32) {
}
}
// 获取格子中所有实体id
// GetEntityIdList 获取格子中所有实体id
func (g *Grid) GetEntityIdList() (entityIdList []uint32) {
entityIdList = make([]uint32, 0)
for k := range g.entityIdMap {
@@ -56,9 +54,3 @@ func (g *Grid) GetEntityIdList() (entityIdList []uint32) {
}
return entityIdList
}
// 打印信息方法
func (g *Grid) DebugString() string {
return fmt.Sprintf("Grid: gid: %d, minX: %d, maxX: %d, minY: %d, maxY: %d, minZ: %d, maxZ: %d, entityIdMap: %v",
g.gid, g.minX, g.maxX, g.minY, g.maxY, g.minZ, g.maxZ, g.entityIdMap)
}

View File

@@ -1,4 +1,4 @@
package aoi
package alg
import (
"testing"
@@ -16,7 +16,6 @@ func TestAoiManagerGetSurrGridListByGid(t *testing.T) {
-150, 150, 3,
-150, 150, 3,
)
logger.Debug("aoiManager: %s", aoiManager.DebugString())
for k := range aoiManager.gridMap {
// 得到当前格子周边的九宫格
gridList := aoiManager.GetSurrGridListByGid(k)

View File

@@ -6,7 +6,7 @@ type LinkList struct {
nextNode *LinkList
}
// LinkListQueue 无界队列 每个元素可存储不同数据结构
// LLQueue LinkListQueue 无界队列 每个元素可存储不同数据结构
type LLQueue struct {
headPtr *LinkList
tailPtr *LinkList
@@ -48,7 +48,7 @@ func (q *LLQueue) DeQueue() any {
return ret
}
// ArrayListQueue 无界队列 泛型
// ALQueue ArrayListQueue 无界队列 泛型
type ALQueue[T any] struct {
array []T
}
@@ -77,7 +77,7 @@ func (q *ALQueue[T]) DeQueue() T {
return ret
}
// RingArrayQueue 有界队列 性能最好
// RAQueue RingArrayQueue 有界队列 性能最好
type RAQueue[T any] struct {
ringArray []T
ringArrayLen uint64

View File

@@ -26,7 +26,7 @@ func NewSource64() rand.Source64 { return &source{index: N + 1} }
func (s *source) Seed(seed int64) {
s.array[0] = uint64(seed)
for s.index = 1; s.index < N; s.index++ {
s.array[s.index] = (0x5851F42D4C957F2D*(s.array[s.index-1]^(s.array[s.index-1]>>62)) + s.index)
s.array[s.index] = 0x5851F42D4C957F2D*(s.array[s.index-1]^(s.array[s.index-1]>>62)) + s.index
}
}
@@ -59,7 +59,7 @@ func (s *source) Uint64() uint64 {
x ^= (x >> 29) & 0x5555555555555555
x ^= (x << 17) & 0x71D67FFFEDA60000
x ^= (x << 37) & 0xFFF7EEE000000000
x ^= (x >> 43)
x ^= x >> 43
return x
}
@@ -68,12 +68,15 @@ type KeyBlock struct {
data [4096]byte
}
func NewKeyBlock(seed uint64) *KeyBlock {
func NewKeyBlock(seed uint64, useMagicSeed bool) *KeyBlock {
b := &KeyBlock{seed: seed}
r := NewRand()
r.Seed(int64(b.seed))
r.Seed(int64(r.Uint64()))
r.Uint64()
if useMagicSeed {
// 2.8.0版本后加入的黑魔法 刘慈欣:6
r.Seed(int64(r.Uint64()))
r.Uint64()
}
for i := 0; i < 4096>>3; i++ {
binary.BigEndian.PutUint64(b.data[i<<3:], r.Uint64())
}

View File

@@ -1,6 +1,7 @@
package random
import (
"encoding/hex"
"fmt"
"testing"
)
@@ -18,8 +19,11 @@ func TestKey(t *testing.T) {
gateDispatchXorKey := gateDispatchEc2b.XorKey()
keyBlock := NewKeyBlock(uint64(11468049314633205968))
fmt.Printf("dispatchXorKey: %v\n", hex.EncodeToString(dispatchXorKey))
fmt.Printf("gateDispatchXorKey: %v\n", hex.EncodeToString(gateDispatchXorKey))
keyBlock := NewKeyBlock(uint64(11468049314633205968), false)
gateXorKey := keyBlock.XorKey()
fmt.Println(dispatchXorKey, gateDispatchXorKey, gateXorKey)
fmt.Printf("gateXorKey: %v\n", hex.EncodeToString(gateXorKey[:]))
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,5 @@
package cmd
const (
GCGDSBanCardNotify uint16 = 65501
)

View File

@@ -105,6 +105,8 @@ func (c *CmdProtoMap) registerAllMessage() {
c.registerMessage(SceneEntityDrownReq, &proto.SceneEntityDrownReq{}) // 场景实体溺水请求
c.registerMessage(SceneEntityDrownRsp, &proto.SceneEntityDrownRsp{}) // 场景实体溺水响应
c.registerMessage(ObstacleModifyNotify, &proto.ObstacleModifyNotify{}) // 寻路阻挡变动通知
c.registerMessage(DungeonWayPointNotify, &proto.DungeonWayPointNotify{}) // 地牢副本相关
c.registerMessage(DungeonDataNotify, &proto.DungeonDataNotify{}) // 地牢副本相关
// 战斗与同步
c.registerMessage(AvatarFightPropNotify, &proto.AvatarFightPropNotify{}) // 角色战斗属性通知
@@ -261,15 +263,12 @@ func (c *CmdProtoMap) registerAllMessage() {
c.registerMessage(GCGAskDuelRsp, &proto.GCGAskDuelRsp{}) // GCG决斗响应
c.registerMessage(GCGInitFinishReq, &proto.GCGInitFinishReq{}) // GCG初始化完成请求
c.registerMessage(GCGInitFinishRsp, &proto.GCGInitFinishRsp{}) // GCG初始化完成响应
c.registerMessage(Unk3300_DGBNCDEIIFC, &proto.Unk3300_DGBNCDEIIFC{}) // GCG
c.registerMessage(DungeonWayPointNotify, &proto.DungeonWayPointNotify{}) // GCG
c.registerMessage(DungeonDataNotify, &proto.DungeonDataNotify{}) // GCG
//// TODO 客户端开始GCG游戏
//c.registerMessage(GCGStartChallengeByCheckRewardReq, &proto.GCGStartChallengeByCheckRewardReq{}) // GCG开始挑战来自检测奖励请求
//c.registerMessage(GCGStartChallengeByCheckRewardRsp, &proto.GCGStartChallengeByCheckRewardRsp{}) // GCG开始挑战来自检测奖励响应
//c.registerMessage(GCGStartChallengeReq, &proto.GCGStartChallengeReq{}) // GCG开始挑战请求
//c.registerMessage(GCGStartChallengeRsp, &proto.GCGStartChallengeRsp{}) // GCG开始挑战响应
// // TODO 客户端开始GCG游戏
// c.registerMessage(GCGStartChallengeByCheckRewardReq, &proto.GCGStartChallengeByCheckRewardReq{}) // GCG开始挑战来自检测奖励请求
// c.registerMessage(GCGStartChallengeByCheckRewardRsp, &proto.GCGStartChallengeByCheckRewardRsp{}) // GCG开始挑战来自检测奖励响应
// c.registerMessage(GCGStartChallengeReq, &proto.GCGStartChallengeReq{}) // GCG开始挑战请求
// c.registerMessage(GCGStartChallengeRsp, &proto.GCGStartChallengeRsp{}) // GCG开始挑战响应
// 乱七八糟
c.registerMessage(MarkMapReq, &proto.MarkMapReq{}) // 标记地图请求

View File

@@ -16,6 +16,7 @@
syntax = "proto3";
package proto;
option go_package = "./;proto";
enum GCGActionType {

View File

@@ -16,6 +16,7 @@
syntax = "proto3";
package proto;
option go_package = "./;proto";
message GCGApplyInviteBattleNotify {

View File

@@ -16,6 +16,7 @@
syntax = "proto3";
package proto;
option go_package = "./;proto";
message GCGApplyInviteBattleReq {

View File

@@ -16,6 +16,7 @@
syntax = "proto3";
package proto;
option go_package = "./;proto";
message GCGApplyInviteBattleRsp {

View File

@@ -16,6 +16,7 @@
syntax = "proto3";
package proto;
option go_package = "./;proto";
message GCGAskDuelReq {

View File

@@ -18,6 +18,7 @@ syntax = "proto3";
import "GCGDuel.proto";
package proto;
option go_package = "./;proto";
message GCGAskDuelRsp {

View File

@@ -18,6 +18,7 @@ syntax = "proto3";
import "Uint32Pair.proto";
package proto;
option go_package = "./;proto";
message GCGAttackCostInfo {

View File

@@ -16,6 +16,7 @@
syntax = "proto3";
package proto;
option go_package = "./;proto";
message GCGBackToDuelReq {

View File

@@ -16,6 +16,7 @@
syntax = "proto3";
package proto;
option go_package = "./;proto";
message GCGBackToDuelRsp {

View File

@@ -16,6 +16,7 @@
syntax = "proto3";
package proto;
option go_package = "./;proto";
message GCGBasicDataNotify {

View File

@@ -16,6 +16,7 @@
syntax = "proto3";
package proto;
option go_package = "./;proto";
message GCGBossChallengeData {

View File

@@ -18,6 +18,7 @@ syntax = "proto3";
import "GCGBossChallengeData.proto";
package proto;
option go_package = "./;proto";
message GCGBossChallengeUpdateNotify {

View File

@@ -19,6 +19,7 @@ syntax = "proto3";
import "GCGSkillLimitsInfo.proto";
import "GCGToken.proto";
package proto;
option go_package = "./;proto";
message GCGCard {

View File

@@ -18,6 +18,7 @@ syntax = "proto3";
import "GCGSkillLimitsInfo.proto";
package proto;
option go_package = "./;proto";
message GCGCardSkillLimitsInfo {

View File

@@ -16,6 +16,7 @@
syntax = "proto3";
package proto;
option go_package = "./;proto";
message GCGChallengeData {

View File

@@ -18,6 +18,7 @@ syntax = "proto3";
import "GCGDuelChallenge.proto";
package proto;
option go_package = "./;proto";
message GCGChallengeUpdateNotify {

View File

@@ -18,6 +18,7 @@ syntax = "proto3";
import "GCGSkillPreviewInfo.proto";
package proto;
option go_package = "./;proto";
message GCGChangeOnstageInfo {

View File

@@ -16,6 +16,7 @@
syntax = "proto3";
package proto;
option go_package = "./;proto";
enum GCGClientPerformType {

View File

@@ -16,6 +16,7 @@
syntax = "proto3";
package proto;
option go_package = "./;proto";
message GCGClientSettleReq {

View File

@@ -16,6 +16,7 @@
syntax = "proto3";
package proto;
option go_package = "./;proto";
message GCGClientSettleRsp {

View File

@@ -18,6 +18,7 @@ syntax = "proto3";
import "ProfilePicture.proto";
package proto;
option go_package = "./;proto";
message GCGControllerShowInfo {

View File

@@ -20,6 +20,7 @@ import "GCGAttackCostInfo.proto";
import "GCGPlayCardCostInfo.proto";
import "GCGSelectOnStageCostInfo.proto";
package proto;
option go_package = "./;proto";
message GCGCostReviseInfo {

View File

@@ -16,6 +16,7 @@
syntax = "proto3";
package proto;
option go_package = "./;proto";
message GCGDSBanCardNotify {

View File

@@ -16,6 +16,7 @@
syntax = "proto3";
package proto;
option go_package = "./;proto";
message GCGDSCardBackUnlockNotify {

View File

@@ -16,6 +16,7 @@
syntax = "proto3";
package proto;
option go_package = "./;proto";
message GCGDSCardData {

View File

@@ -16,6 +16,7 @@
syntax = "proto3";
package proto;
option go_package = "./;proto";
message GCGDSCardFaceUnlockNotify {

View File

@@ -16,6 +16,7 @@
syntax = "proto3";
package proto;
option go_package = "./;proto";
message GCGDSCardFaceUpdateNotify {

View File

@@ -16,6 +16,7 @@
syntax = "proto3";
package proto;
option go_package = "./;proto";
message GCGDSCardNumChangeNotify {

View File

@@ -16,6 +16,7 @@
syntax = "proto3";
package proto;
option go_package = "./;proto";
message GCGDSCardProficiencyNotify {

View File

@@ -16,6 +16,7 @@
syntax = "proto3";
package proto;
option go_package = "./;proto";
message GCGDSChangeCardBackReq {

View File

@@ -16,6 +16,7 @@
syntax = "proto3";
package proto;
option go_package = "./;proto";
message GCGDSChangeCardBackRsp {

View File

@@ -16,6 +16,7 @@
syntax = "proto3";
package proto;
option go_package = "./;proto";
message GCGDSChangeCardFaceReq {

View File

@@ -16,6 +16,7 @@
syntax = "proto3";
package proto;
option go_package = "./;proto";
message GCGDSChangeCardFaceRsp {

View File

@@ -16,6 +16,7 @@
syntax = "proto3";
package proto;
option go_package = "./;proto";
message GCGDSChangeCurDeckReq {

View File

@@ -16,6 +16,7 @@
syntax = "proto3";
package proto;
option go_package = "./;proto";
message GCGDSChangeCurDeckRsp {

View File

@@ -16,6 +16,7 @@
syntax = "proto3";
package proto;
option go_package = "./;proto";
message GCGDSChangeDeckNameReq {

View File

@@ -16,6 +16,7 @@
syntax = "proto3";
package proto;
option go_package = "./;proto";
message GCGDSChangeDeckNameRsp {

View File

@@ -16,6 +16,7 @@
syntax = "proto3";
package proto;
option go_package = "./;proto";
message GCGDSChangeFieldReq {

View File

@@ -16,6 +16,7 @@
syntax = "proto3";
package proto;
option go_package = "./;proto";
message GCGDSChangeFieldRsp {

View File

@@ -16,6 +16,7 @@
syntax = "proto3";
package proto;
option go_package = "./;proto";
message GCGDSCurDeckChangeNotify {

View File

@@ -19,6 +19,7 @@ syntax = "proto3";
import "GCGDSCardData.proto";
import "GCGDSDeckData.proto";
package proto;
option go_package = "./;proto";
message GCGDSDataNotify {

View File

@@ -16,6 +16,7 @@
syntax = "proto3";
package proto;
option go_package = "./;proto";
message GCGDSDeckData {

View File

@@ -16,6 +16,7 @@
syntax = "proto3";
package proto;
option go_package = "./;proto";
message GCGDSDeckSaveReq {

View File

@@ -16,6 +16,7 @@
syntax = "proto3";
package proto;
option go_package = "./;proto";
message GCGDSDeckSaveRsp {

View File

@@ -16,6 +16,7 @@
syntax = "proto3";
package proto;
option go_package = "./;proto";
message GCGDSDeckUnlockNotify {

View File

@@ -16,6 +16,7 @@
syntax = "proto3";
package proto;
option go_package = "./;proto";
message GCGDSDeckUpdateNotify {

View File

@@ -16,6 +16,7 @@
syntax = "proto3";
package proto;
option go_package = "./;proto";
message GCGDSDeleteDeckReq {

View File

@@ -16,6 +16,7 @@
syntax = "proto3";
package proto;
option go_package = "./;proto";
message GCGDSDeleteDeckRsp {

View File

@@ -16,6 +16,7 @@
syntax = "proto3";
package proto;
option go_package = "./;proto";
message GCGDSFieldUnlockNotify {

View File

@@ -16,6 +16,7 @@
syntax = "proto3";
package proto;
option go_package = "./;proto";
message GCGDSTakeCardProficiencyRewardReq {

View File

@@ -16,6 +16,7 @@
syntax = "proto3";
package proto;
option go_package = "./;proto";
message GCGDSTakeCardProficiencyRewardRsp {

View File

@@ -16,6 +16,7 @@
syntax = "proto3";
package proto;
option go_package = "./;proto";
message GCGDamageDetail {

View File

@@ -16,6 +16,7 @@
syntax = "proto3";
package proto;
option go_package = "./;proto";
message GCGDebugReplayNotify {

View File

@@ -16,6 +16,7 @@
syntax = "proto3";
package proto;
option go_package = "./;proto";
enum GCGDiceSideType {

View File

@@ -27,6 +27,7 @@ import "GCGPhase.proto";
import "GCGPlayerField.proto";
import "Unk3300_ADHENCIFKNI.proto";
package proto;
option go_package = "./;proto";
message GCGDuel {

View File

@@ -16,6 +16,7 @@
syntax = "proto3";
package proto;
option go_package = "./;proto";
message GCGDuelChallenge {

View File

@@ -19,6 +19,7 @@ syntax = "proto3";
import "GCGChallengeData.proto";
import "PlatformType.proto";
package proto;
option go_package = "./;proto";
message GCGDuelExtra {

View File

@@ -16,6 +16,7 @@
syntax = "proto3";
package proto;
option go_package = "./;proto";
enum GCGEndReason {

View File

@@ -19,6 +19,7 @@ syntax = "proto3";
import "GCGGameBusinessType.proto";
import "GCGPlayerBriefData.proto";
package proto;
option go_package = "./;proto";
message GCGGameBriefData {

View File

@@ -18,6 +18,7 @@ syntax = "proto3";
import "GCGGameBriefData.proto";
package proto;
option go_package = "./;proto";
message GCGGameBriefDataNotify {

View File

@@ -16,6 +16,7 @@
syntax = "proto3";
package proto;
option go_package = "./;proto";
enum GCGGameBusinessType {

View File

@@ -16,6 +16,7 @@
syntax = "proto3";
package proto;
option go_package = "./;proto";
message GCGGameCreateFailReasonNotify {

View File

@@ -16,6 +16,7 @@
syntax = "proto3";
package proto;
option go_package = "./;proto";
message GCGGameMaxNotify {

Some files were not shown because too many files have changed in this diff Show More