玩家管理模块接入redis,已完整实现好友、多人世界的跨服交互功能

This commit is contained in:
flswld
2022-12-29 22:42:57 +08:00
parent 0a2e13fad3
commit 6fd3d6a349
25 changed files with 1094 additions and 407 deletions

View File

@@ -13,5 +13,9 @@ max_size = 10485760
[database] [database]
url = "mongodb://mongo:27017" url = "mongodb://mongo:27017"
[redis]
addr = "redis:6379"
password = ""
[mq] [mq]
nats_url = "nats://nats:4222" nats_url = "nats://nats:4222"

View File

@@ -13,6 +13,7 @@ type Config struct {
HttpPort int32 `toml:"http_port"` HttpPort int32 `toml:"http_port"`
Logger Logger `toml:"logger"` Logger Logger `toml:"logger"`
Database Database `toml:"database"` Database Database `toml:"database"`
Redis Redis `toml:"redis"`
Hk4e Hk4e `toml:"hk4e"` Hk4e Hk4e `toml:"hk4e"`
MQ MQ `toml:"mq"` MQ MQ `toml:"mq"`
} }
@@ -30,6 +31,11 @@ type Database struct {
Url string `toml:"url"` Url string `toml:"url"`
} }
type Redis struct {
Addr string `toml:"addr"`
Password string `toml:"password"`
}
// Hk4e 原神相关 // Hk4e 原神相关
type Hk4e struct { type Hk4e struct {
KcpPort int32 `toml:"kcp_port"` KcpPort int32 `toml:"kcp_port"`

View File

@@ -3,10 +3,10 @@ package mq
import pb "google.golang.org/protobuf/proto" import pb "google.golang.org/protobuf/proto"
const ( const (
MsgTypeGame = iota MsgTypeGame = iota // 来自客户端的游戏消息
MsgTypeFight MsgTypeFight // 战斗服务器消息
MsgTypeConnCtrl MsgTypeConnCtrl // GATE客户端连接信息消息
MsgTypeServer MsgTypeServer // 服务器之间转发的消息
) )
type NetMsg struct { type NetMsg struct {
@@ -22,8 +22,7 @@ type NetMsg struct {
} }
const ( const (
NormalMsg = iota NormalMsg = iota // 正常的游戏消息
UserOfflineNotify
) )
type GameMsg struct { type GameMsg struct {
@@ -35,9 +34,10 @@ type GameMsg struct {
} }
const ( const (
ClientRttNotify = iota ClientRttNotify = iota // 客户端网络时延上报
ClientTimeNotify ClientTimeNotify // 客户端本地时间上报
KickPlayerNotify KickPlayerNotify // 通知GATE剔除玩家
UserOfflineNotify // 玩家离线通知GS
) )
type ConnCtrlMsg struct { type ConnCtrlMsg struct {
@@ -49,10 +49,10 @@ type ConnCtrlMsg struct {
} }
const ( const (
AddFightRoutine = iota AddFightRoutine = iota // 添加战斗实例
DelFightRoutine DelFightRoutine // 删除战斗实例
FightRoutineAddEntity FightRoutineAddEntity // 战斗实例添加实体
FightRoutineDelEntity FightRoutineDelEntity // 战斗实例删除实体
) )
type FightMsg struct { type FightMsg struct {
@@ -65,20 +65,27 @@ type FightMsg struct {
} }
const ( const (
ServerAppidBindNotify = iota ServerAppidBindNotify = iota // 玩家连接绑定的各个服务器appid通知
ServerUserOnlineStateChangeNotify ServerUserOnlineStateChangeNotify // 广播玩家上线和离线状态以及所在GS的appid
ServerGetUserBaseInfoReq ServerUserBaseInfoReq // 跨服玩家基础数据请求
ServerGetUserBaseInfoRsp ServerUserBaseInfoRsp // 跨服玩家基础数据响应
ServerUserGsChangeNotify ServerUserGsChangeNotify // 跨服玩家迁移通知
ServerUserMpReq // 跨服多人世界相关请求
ServerUserMpRsp // 跨服多人世界相关响应
ServerChatMsgNotify // 跨服玩家聊天消息通知
ServerAddFriendNotify // 跨服添加好友通知
) )
type ServerMsg struct { type ServerMsg struct {
FightServerAppId string `msgpack:"FightServerAppId"` FightServerAppId string `msgpack:"FightServerAppId"`
UserId uint32 `msgpack:"UserId"` UserId uint32 `msgpack:"UserId"`
IsOnline bool `msgpack:"IsOnline"` IsOnline bool `msgpack:"IsOnline"`
UserBaseInfo *UserBaseInfo `msgpack:"UserBaseInfo"` UserBaseInfo *UserBaseInfo `msgpack:"UserBaseInfo"`
GameServerAppId string `msgpack:"GameServerAppId"` GameServerAppId string `msgpack:"GameServerAppId"`
JoinHostUserId uint32 `msgpack:"JoinHostUserId"` JoinHostUserId uint32 `msgpack:"JoinHostUserId"`
UserMpInfo *UserMpInfo `msgpack:"UserMpInfo"`
ChatMsgInfo *ChatMsgInfo `msgpack:"ChatMsgInfo"`
AddFriendInfo *AddFriendInfo `msgpack:"AddFriendInfo"`
} }
type OriginInfo struct { type OriginInfo struct {
@@ -96,4 +103,32 @@ type UserBaseInfo struct {
Signature string `msgpack:"Signature"` Signature string `msgpack:"Signature"`
HeadImageId uint32 `msgpack:"HeadImageId"` HeadImageId uint32 `msgpack:"HeadImageId"`
WorldPlayerNum uint32 `msgpack:"WorldPlayerNum"` WorldPlayerNum uint32 `msgpack:"WorldPlayerNum"`
WorldLevel uint32 `msgpack:"WorldLevel"`
Birthday []uint8 `msgpack:"Birthday"`
}
type UserMpInfo struct {
OriginInfo *OriginInfo `msgpack:"OriginInfo"`
HostUserId uint32 `msgpack:"HostUserId"`
ApplyUserId uint32 `msgpack:"ApplyUserId"`
ApplyPlayerOnlineInfo *UserBaseInfo `msgpack:"ApplyPlayerOnlineInfo"`
ApplyOk bool `msgpack:"ApplyOk"`
Agreed bool `msgpack:"Agreed"`
HostNickname string `msgpack:"HostNickname"`
}
type ChatMsgInfo struct {
Time uint32 `msgpack:"Time"`
ToUid uint32 `msgpack:"ToUid"`
Uid uint32 `msgpack:"Uid"`
IsRead bool `msgpack:"IsRead"`
MsgType uint8 `msgpack:"MsgType"`
Text string `msgpack:"Text"`
Icon uint32 `msgpack:"Icon"`
}
type AddFriendInfo struct {
OriginInfo *OriginInfo `msgpack:"OriginInfo"`
TargetUserId uint32 `msgpack:"TargetUserId"`
ApplyPlayerOnlineInfo *UserBaseInfo `msgpack:"ApplyPlayerOnlineInfo"`
} }

View File

@@ -8,28 +8,34 @@ import (
"go.mongodb.org/mongo-driver/mongo" "go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options" "go.mongodb.org/mongo-driver/mongo/options"
"go.mongodb.org/mongo-driver/mongo/readpref"
) )
type Dao struct { type Dao struct {
client *mongo.Client mongo *mongo.Client
db *mongo.Database db *mongo.Database
} }
func NewDao() (r *Dao) { func NewDao() (r *Dao) {
r = new(Dao) r = new(Dao)
clientOptions := options.Client().ApplyURI(config.CONF.Database.Url) clientOptions := options.Client().ApplyURI(config.CONF.Database.Url).SetMinPoolSize(10).SetMaxPoolSize(100)
client, err := mongo.Connect(context.TODO(), clientOptions) client, err := mongo.Connect(context.TODO(), clientOptions)
if err != nil { if err != nil {
logger.Error("mongo connect error: %v", err) logger.Error("mongo connect error: %v", err)
return nil return nil
} }
r.client = client err = client.Ping(context.TODO(), readpref.Primary())
if err != nil {
logger.Error("mongo ping error: %v", err)
return nil
}
r.mongo = client
r.db = client.Database("dispatch_hk4e") r.db = client.Database("dispatch_hk4e")
return r return r
} }
func (d *Dao) CloseDao() { func (d *Dao) CloseDao() {
err := d.client.Disconnect(context.TODO()) err := d.mongo.Disconnect(context.TODO())
if err != nil { if err != nil {
logger.Error("mongo close error: %v", err) logger.Error("mongo close error: %v", err)
} }

View File

@@ -361,14 +361,14 @@ func (k *KcpConnectManager) closeKcpConn(session *Session, enetType uint32) {
EventId: KcpConnCloseNotify, EventId: KcpConnCloseNotify,
} }
// 通知GS玩家下线 // 通知GS玩家下线
gameMsg := new(mq.GameMsg) connCtrlMsg := new(mq.ConnCtrlMsg)
gameMsg.UserId = session.userId connCtrlMsg.UserId = session.userId
k.messageQueue.SendToGs(session.gsServerAppId, &mq.NetMsg{ k.messageQueue.SendToGs(session.gsServerAppId, &mq.NetMsg{
MsgType: mq.MsgTypeGame, MsgType: mq.MsgTypeConnCtrl,
EventId: mq.UserOfflineNotify, EventId: mq.UserOfflineNotify,
GameMsg: gameMsg, ConnCtrlMsg: connCtrlMsg,
}) })
logger.Info("send to gs user offline, ConvId: %v, UserId: %v", convId, gameMsg.UserId) logger.Info("send to gs user offline, ConvId: %v, UserId: %v", convId, connCtrlMsg.UserId)
k.destroySessionChan <- session k.destroySessionChan <- session
} }

7
go.mod
View File

@@ -50,8 +50,13 @@ require github.com/byebyebruce/natsrpc v0.5.5-0.20221125150611-56cd29a4e335
// cobra // cobra
require github.com/spf13/cobra v1.6.1 require github.com/spf13/cobra v1.6.1
// redis
require github.com/go-redis/redis/v8 v8.11.5
require ( require (
github.com/cespare/xxhash/v2 v2.1.2 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect github.com/davecgh/go-spew v1.1.1 // indirect
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
github.com/gin-contrib/sse v0.1.0 // indirect github.com/gin-contrib/sse v0.1.0 // indirect
github.com/go-playground/locales v0.13.0 // indirect github.com/go-playground/locales v0.13.0 // indirect
github.com/go-playground/universal-translator v0.17.0 // indirect github.com/go-playground/universal-translator v0.17.0 // indirect
@@ -83,6 +88,6 @@ require (
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e // indirect golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e // indirect
golang.org/x/sys v0.0.0-20220928140112-f11e5e49a4ec // indirect golang.org/x/sys v0.0.0-20220928140112-f11e5e49a4ec // indirect
golang.org/x/text v0.3.6 // indirect golang.org/x/text v0.3.6 // indirect
gopkg.in/yaml.v2 v2.2.8 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect
) )

14
go.sum
View File

@@ -6,15 +6,20 @@ github.com/arl/statsviz v0.5.1/go.mod h1:zDnjgRblGm1Dyd7J5YlbH7gM1/+HRC+SfkhZhQb
github.com/byebyebruce/natsrpc v0.5.5-0.20221125150611-56cd29a4e335 h1:V5qahA5kDL/TBnlwvYjemR5du/uQ7q75qkBBlTc4rXI= github.com/byebyebruce/natsrpc v0.5.5-0.20221125150611-56cd29a4e335 h1:V5qahA5kDL/TBnlwvYjemR5du/uQ7q75qkBBlTc4rXI=
github.com/byebyebruce/natsrpc v0.5.5-0.20221125150611-56cd29a4e335/go.mod h1:w61gLVOQWr/Tq/1wxSOMLxDPbH66rEo8jEHMh7j3qjo= github.com/byebyebruce/natsrpc v0.5.5-0.20221125150611-56cd29a4e335/go.mod h1:w61gLVOQWr/Tq/1wxSOMLxDPbH66rEo8jEHMh7j3qjo=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE=
github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
github.com/gin-gonic/gin v1.6.3 h1:ahKqKTFpO5KTPHxWZjEdPScmYaGtLo8Y4DMHoEsnp14= github.com/gin-gonic/gin v1.6.3 h1:ahKqKTFpO5KTPHxWZjEdPScmYaGtLo8Y4DMHoEsnp14=
@@ -27,6 +32,8 @@ github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD87
github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA=
github.com/go-playground/validator/v10 v10.2.0 h1:KgJ0snyC2R9VXYN2rneOtQcw5aHQB1Vv0sFl1UcHBOY= github.com/go-playground/validator/v10 v10.2.0 h1:KgJ0snyC2R9VXYN2rneOtQcw5aHQB1Vv0sFl1UcHBOY=
github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI= github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI=
github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC0oI=
github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo=
github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk= github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/golang-jwt/jwt/v4 v4.4.0 h1:EmVIxB5jzbllGIjiCV5JG4VylbK3KE400tLGLI1cdfU= github.com/golang-jwt/jwt/v4 v4.4.0 h1:EmVIxB5jzbllGIjiCV5JG4VylbK3KE400tLGLI1cdfU=
@@ -96,6 +103,9 @@ github.com/nats-io/nkeys v0.3.0 h1:cgM5tL53EvYRU+2YLXIK0G2mJtK12Ft9oeooSZMA2G8=
github.com/nats-io/nkeys v0.3.0/go.mod h1:gvUNGjVcM2IPr5rCsRsC6Wb3Hr2CQAm08dsxtV6A5y4= github.com/nats-io/nkeys v0.3.0/go.mod h1:gvUNGjVcM2IPr5rCsRsC6Wb3Hr2CQAm08dsxtV6A5y4=
github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw= github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw=
github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c=
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
github.com/onsi/gomega v1.18.1 h1:M1GfJqGRrBrrGGsbxzV5dqM2U2ApXefZCQpkukxYRLE=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
@@ -212,9 +222,11 @@ google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqw
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

View File

@@ -6,31 +6,55 @@ import (
"hk4e/common/config" "hk4e/common/config"
"hk4e/pkg/logger" "hk4e/pkg/logger"
"github.com/go-redis/redis/v8"
"go.mongodb.org/mongo-driver/mongo" "go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options" "go.mongodb.org/mongo-driver/mongo/options"
"go.mongodb.org/mongo-driver/mongo/readpref"
) )
type Dao struct { type Dao struct {
client *mongo.Client mongo *mongo.Client
db *mongo.Database db *mongo.Database
redis *redis.Client
} }
func NewDao() (r *Dao, err error) { func NewDao() (r *Dao, err error) {
r = new(Dao) r = new(Dao)
clientOptions := options.Client().ApplyURI(config.CONF.Database.Url) clientOptions := options.Client().ApplyURI(config.CONF.Database.Url).SetMinPoolSize(1).SetMaxPoolSize(10)
client, err := mongo.Connect(context.TODO(), clientOptions) client, err := mongo.Connect(context.TODO(), clientOptions)
if err != nil { if err != nil {
logger.Error("mongo connect error: %v", err) logger.Error("mongo connect error: %v", err)
return nil, err return nil, err
} }
r.client = client err = client.Ping(context.TODO(), readpref.Primary())
if err != nil {
logger.Error("mongo ping error: %v", err)
return nil, err
}
r.mongo = client
r.db = client.Database("gs_hk4e") r.db = client.Database("gs_hk4e")
r.redis = redis.NewClient(&redis.Options{
Addr: config.CONF.Redis.Addr,
Password: config.CONF.Redis.Password,
DB: 0,
PoolSize: 10,
MinIdleConns: 1,
})
err = r.redis.Ping(context.TODO()).Err()
if err != nil {
logger.Error("redis ping error: %v", err)
return nil, err
}
return r, nil return r, nil
} }
func (d *Dao) CloseDao() { func (d *Dao) CloseDao() {
err := d.client.Disconnect(context.TODO()) err := d.mongo.Disconnect(context.TODO())
if err != nil { if err != nil {
logger.Error("mongo close error: %v", err) logger.Error("mongo close error: %v", err)
} }
err = d.redis.Close()
if err != nil {
logger.Error("redis close error: %v", err)
}
} }

53
gs/dao/player_redis.go Normal file
View File

@@ -0,0 +1,53 @@
package dao
import (
"context"
"strconv"
"time"
"hk4e/gs/model"
"hk4e/pkg/logger"
"github.com/vmihailenco/msgpack/v5"
)
const RedisPlayerKeyPrefix = "HK4E"
func (d *Dao) GetRedisPlayerKey(userId uint32) string {
return RedisPlayerKeyPrefix + ":USER:" + strconv.Itoa(int(userId))
}
func (d *Dao) GetRedisPlayer(userId uint32) *model.Player {
playerData, err := d.redis.Get(context.TODO(), d.GetRedisPlayerKey(userId)).Result()
if err != nil {
logger.Error("get player from redis error: %v", err)
return nil
}
player := new(model.Player)
err = msgpack.Unmarshal([]byte(playerData), player)
if err != nil {
logger.Error("unmarshal player error: %v", err)
return nil
}
return player
}
func (d *Dao) SetRedisPlayer(player *model.Player) {
playerData, err := msgpack.Marshal(player)
if err != nil {
logger.Error("marshal player error: %v", err)
return
}
err = d.redis.Set(context.TODO(), d.GetRedisPlayerKey(player.PlayerID), playerData, time.Hour*24*30).Err()
if err != nil {
logger.Error("set player from redis error: %v", err)
return
}
}
func (d *Dao) SetRedisPlayerList(playerList []*model.Player) {
// TODO 换成redis批量命令执行
for _, player := range playerList {
d.SetRedisPlayer(player)
}
}

View File

@@ -225,7 +225,7 @@ func (c *CommandManager) SendMessage(executor any, msg string, param ...any) {
case *model.Player: case *model.Player:
// 玩家类型 // 玩家类型
player := executor.(*model.Player) player := executor.(*model.Player)
GAME_MANAGER.SendPrivateChat(c.system, player, fmt.Sprintf(msg, param...)) GAME_MANAGER.SendPrivateChat(c.system, player.PlayerID, fmt.Sprintf(msg, param...))
case string: case string:
// GM接口等 // GM接口等
// str := executor.(string) // str := executor.(string)

View File

@@ -26,12 +26,12 @@ var USER_MANAGER *UserManager = nil
var WORLD_MANAGER *WorldManager = nil var WORLD_MANAGER *WorldManager = nil
var TICK_MANAGER *TickManager = nil var TICK_MANAGER *TickManager = nil
var COMMAND_MANAGER *CommandManager = nil var COMMAND_MANAGER *CommandManager = nil
var MESSAGE_QUEUE *mq.MessageQueue
var SELF *model.Player var SELF *model.Player
type GameManager struct { type GameManager struct {
dao *dao.Dao dao *dao.Dao
messageQueue *mq.MessageQueue
snowflake *alg.SnowflakeWorker snowflake *alg.SnowflakeWorker
clientCmdProtoMap *client_proto.ClientCmdProtoMap clientCmdProtoMap *client_proto.ClientCmdProtoMap
clientCmdProtoMapRefValue reflect.Value clientCmdProtoMapRefValue reflect.Value
@@ -40,7 +40,7 @@ type GameManager struct {
func NewGameManager(dao *dao.Dao, messageQueue *mq.MessageQueue, gsId uint32) (r *GameManager) { func NewGameManager(dao *dao.Dao, messageQueue *mq.MessageQueue, gsId uint32) (r *GameManager) {
r = new(GameManager) r = new(GameManager)
r.dao = dao r.dao = dao
r.messageQueue = messageQueue MESSAGE_QUEUE = messageQueue
r.snowflake = alg.NewSnowflakeWorker(int64(gsId)) r.snowflake = alg.NewSnowflakeWorker(int64(gsId))
if appConfig.CONF.Hk4e.ClientProtoProxyEnable { if appConfig.CONF.Hk4e.ClientProtoProxyEnable {
r.clientCmdProtoMap = client_proto.NewClientCmdProtoMap() r.clientCmdProtoMap = client_proto.NewClientCmdProtoMap()
@@ -115,7 +115,7 @@ func (g *GameManager) gameMainLoop() {
commandCost = 0 commandCost = 0
} }
select { select {
case netMsg := <-g.messageQueue.GetNetMsg(): case netMsg := <-MESSAGE_QUEUE.GetNetMsg():
// 接收客户端消息 // 接收客户端消息
start := time.Now().UnixNano() start := time.Now().UnixNano()
ROUTE_MANAGER.RouteHandle(netMsg) ROUTE_MANAGER.RouteHandle(netMsg)
@@ -171,7 +171,7 @@ func (g *GameManager) SendMsgEx(cmdId uint16, userId uint32, clientSeq uint32, g
ClientSeq: clientSeq, ClientSeq: clientSeq,
PayloadMessage: payloadMsg, PayloadMessage: payloadMsg,
} }
g.messageQueue.SendToGate(gateAppId, &mq.NetMsg{ MESSAGE_QUEUE.SendToGate(gateAppId, &mq.NetMsg{
MsgType: mq.MsgTypeGame, MsgType: mq.MsgTypeGame,
EventId: mq.NormalMsg, EventId: mq.NormalMsg,
GameMsg: gameMsg, GameMsg: gameMsg,
@@ -203,7 +203,7 @@ func (g *GameManager) SendMsg(cmdId uint16, userId uint32, clientSeq uint32, pay
return return
} }
gameMsg.PayloadMessageData = payloadMessageData gameMsg.PayloadMessageData = payloadMessageData
g.messageQueue.SendToGate(player.GateAppId, &mq.NetMsg{ MESSAGE_QUEUE.SendToGate(player.GateAppId, &mq.NetMsg{
MsgType: mq.MsgTypeGame, MsgType: mq.MsgTypeGame,
EventId: mq.NormalMsg, EventId: mq.NormalMsg,
GameMsg: gameMsg, GameMsg: gameMsg,
@@ -271,7 +271,7 @@ func (g *GameManager) DisconnectPlayer(userId uint32, reason uint32) {
if player == nil { if player == nil {
return return
} }
g.messageQueue.SendToGate(player.GateAppId, &mq.NetMsg{ MESSAGE_QUEUE.SendToGate(player.GateAppId, &mq.NetMsg{
MsgType: mq.MsgTypeConnCtrl, MsgType: mq.MsgTypeConnCtrl,
EventId: mq.KickPlayerNotify, EventId: mq.KickPlayerNotify,
ConnCtrlMsg: &mq.ConnCtrlMsg{ ConnCtrlMsg: &mq.ConnCtrlMsg{

View File

@@ -3,6 +3,7 @@ package game
import ( import (
"time" "time"
"hk4e/common/mq"
"hk4e/gs/model" "hk4e/gs/model"
"hk4e/pkg/logger" "hk4e/pkg/logger"
"hk4e/pkg/object" "hk4e/pkg/object"
@@ -11,9 +12,10 @@ import (
// 本地事件队列管理器 // 本地事件队列管理器
const ( const (
LoadLoginUserFromDbFinish = iota LoadLoginUserFromDbFinish = iota // 玩家登录从数据库加载完成回调
CheckUserExistOnRegFromDbFinish CheckUserExistOnRegFromDbFinish // 玩家注册从数据库查询是否已存在完成回调
RunUserCopyAndSave RunUserCopyAndSave // 执行一次在线玩家内存数据复制到数据库写入协程
UserOfflineSaveToDbFinish
) )
type LocalEvent struct { type LocalEvent struct {
@@ -89,5 +91,30 @@ func (l *LocalEventManager) LocalEventHandle(localEvent *LocalEvent) {
endTime := time.Now().UnixNano() endTime := time.Now().UnixNano()
costTime := endTime - startTime costTime := endTime - startTime
logger.Info("run save user copy cost time: %v ns", costTime) logger.Info("run save user copy cost time: %v ns", costTime)
case UserOfflineSaveToDbFinish:
playerOfflineInfo := localEvent.Msg.(*PlayerOfflineInfo)
USER_MANAGER.DeleteUser(playerOfflineInfo.Player.PlayerID)
MESSAGE_QUEUE.SendToAll(&mq.NetMsg{
MsgType: mq.MsgTypeServer,
EventId: mq.ServerUserOnlineStateChangeNotify,
ServerMsg: &mq.ServerMsg{
UserId: playerOfflineInfo.Player.PlayerID,
IsOnline: false,
},
})
if playerOfflineInfo.ChangeGsInfo.IsChangeGs {
gsAppId := USER_MANAGER.GetRemoteUserGsAppId(playerOfflineInfo.ChangeGsInfo.JoinHostUserId)
MESSAGE_QUEUE.SendToGate(playerOfflineInfo.Player.GateAppId, &mq.NetMsg{
MsgType: mq.MsgTypeServer,
EventId: mq.ServerUserGsChangeNotify,
ServerMsg: &mq.ServerMsg{
UserId: playerOfflineInfo.Player.PlayerID,
GameServerAppId: gsAppId,
JoinHostUserId: playerOfflineInfo.ChangeGsInfo.JoinHostUserId,
},
})
logger.Info("user change gs notify to gate, uid: %v, gate appid: %v, gs appid: %v, host uid: %v",
playerOfflineInfo.Player.PlayerID, playerOfflineInfo.Player.GateAppId, gsAppId, playerOfflineInfo.ChangeGsInfo.JoinHostUserId)
}
} }
} }

View File

@@ -42,6 +42,10 @@ func (r *RouteManager) doRoute(cmdId uint16, userId uint32, clientSeq uint32, pa
GAME_MANAGER.DisconnectPlayer(userId, kcp.EnetNotFoundSession) GAME_MANAGER.DisconnectPlayer(userId, kcp.EnetNotFoundSession)
return return
} }
if !player.Online {
logger.Error("player not online, uid: %v", userId)
return
}
player.ClientSeq = clientSeq player.ClientSeq = clientSeq
SELF = player SELF = player
handlerFunc(player, payloadMsg) handlerFunc(player, payloadMsg)
@@ -139,8 +143,6 @@ func (r *RouteManager) RouteHandle(netMsg *mq.NetMsg) {
return return
} }
r.doRoute(gameMsg.CmdId, gameMsg.UserId, gameMsg.ClientSeq, gameMsg.PayloadMessage) r.doRoute(gameMsg.CmdId, gameMsg.UserId, gameMsg.ClientSeq, gameMsg.PayloadMessage)
case mq.UserOfflineNotify:
GAME_MANAGER.OnUserOffline(gameMsg.UserId)
} }
case mq.MsgTypeConnCtrl: case mq.MsgTypeConnCtrl:
if netMsg.OriginServerType != api.GATE { if netMsg.OriginServerType != api.GATE {
@@ -152,6 +154,10 @@ func (r *RouteManager) RouteHandle(netMsg *mq.NetMsg) {
GAME_MANAGER.ClientRttNotify(connCtrlMsg.UserId, connCtrlMsg.ClientRtt) GAME_MANAGER.ClientRttNotify(connCtrlMsg.UserId, connCtrlMsg.ClientRtt)
case mq.ClientTimeNotify: case mq.ClientTimeNotify:
GAME_MANAGER.ClientTimeNotify(connCtrlMsg.UserId, connCtrlMsg.ClientTime) GAME_MANAGER.ClientTimeNotify(connCtrlMsg.UserId, connCtrlMsg.ClientTime)
case mq.UserOfflineNotify:
GAME_MANAGER.OnUserOffline(connCtrlMsg.UserId, &ChangeGsInfo{
IsChangeGs: false,
})
} }
case mq.MsgTypeServer: case mq.MsgTypeServer:
serverMsg := netMsg.ServerMsg serverMsg := netMsg.ServerMsg
@@ -161,10 +167,18 @@ func (r *RouteManager) RouteHandle(netMsg *mq.NetMsg) {
USER_MANAGER.SetRemoteUserOnlineState(serverMsg.UserId, serverMsg.IsOnline, netMsg.OriginServerAppId) USER_MANAGER.SetRemoteUserOnlineState(serverMsg.UserId, serverMsg.IsOnline, netMsg.OriginServerAppId)
case mq.ServerAppidBindNotify: case mq.ServerAppidBindNotify:
GAME_MANAGER.ServerAppidBindNotify(serverMsg.UserId, serverMsg.FightServerAppId, serverMsg.JoinHostUserId) GAME_MANAGER.ServerAppidBindNotify(serverMsg.UserId, serverMsg.FightServerAppId, serverMsg.JoinHostUserId)
case mq.ServerGetUserBaseInfoReq: case mq.ServerUserBaseInfoReq:
GAME_MANAGER.ServerGetUserBaseInfoReq(serverMsg.UserBaseInfo, netMsg.OriginServerAppId) GAME_MANAGER.ServerUserBaseInfoReq(serverMsg.UserBaseInfo, netMsg.OriginServerAppId)
case mq.ServerGetUserBaseInfoRsp: case mq.ServerUserBaseInfoRsp:
GAME_MANAGER.ServerGetUserBaseInfoRsp(serverMsg.UserBaseInfo) GAME_MANAGER.ServerUserBaseInfoRsp(serverMsg.UserBaseInfo)
case mq.ServerUserMpReq:
GAME_MANAGER.ServerUserMpReq(serverMsg.UserMpInfo, netMsg.OriginServerAppId)
case mq.ServerUserMpRsp:
GAME_MANAGER.ServerUserMpRsp(serverMsg.UserMpInfo)
case mq.ServerChatMsgNotify:
GAME_MANAGER.ServerChatMsgNotify(serverMsg.ChatMsgInfo)
case mq.ServerAddFriendNotify:
GAME_MANAGER.ServerAddFriendNotify(serverMsg.AddFriendInfo)
} }
} }
} }

View File

@@ -3,6 +3,7 @@ package game
import ( import (
"time" "time"
"hk4e/common/mq"
"hk4e/gs/model" "hk4e/gs/model"
"hk4e/pkg/logger" "hk4e/pkg/logger"
"hk4e/protocol/cmd" "hk4e/protocol/cmd"
@@ -78,15 +79,14 @@ func (g *GameManager) PullPrivateChatReq(player *model.Player, payloadMsg pb.Mes
} }
// SendPrivateChat 发送私聊文本消息给玩家 // SendPrivateChat 发送私聊文本消息给玩家
func (g *GameManager) SendPrivateChat(player, targetPlayer *model.Player, content any) { func (g *GameManager) SendPrivateChat(player *model.Player, targetUid uint32, content any) {
chatInfo := &proto.ChatInfo{ chatInfo := &proto.ChatInfo{
Time: uint32(time.Now().Unix()), Time: uint32(time.Now().Unix()),
Sequence: 101, Sequence: 101,
ToUid: targetPlayer.PlayerID, ToUid: targetUid,
Uid: player.PlayerID, Uid: player.PlayerID,
IsRead: false, IsRead: false,
} }
// 根据传入的值判断消息类型 // 根据传入的值判断消息类型
switch content.(type) { switch content.(type) {
case string: case string:
@@ -100,21 +100,52 @@ func (g *GameManager) SendPrivateChat(player, targetPlayer *model.Player, conten
Icon: content.(uint32), Icon: content.(uint32),
} }
} }
chatMsg := g.ConvChatInfoToChatMsg(chatInfo)
// 消息加入自己的队列 // 消息加入自己的队列
msgList, exist := player.ChatMsgMap[targetPlayer.PlayerID] msgList, exist := player.ChatMsgMap[targetUid]
if !exist { if !exist {
msgList = make([]*model.ChatMsg, 0) msgList = make([]*model.ChatMsg, 0)
} }
msgList = append(msgList, g.ConvChatInfoToChatMsg(chatInfo)) msgList = append(msgList, chatMsg)
player.ChatMsgMap[targetPlayer.PlayerID] = msgList player.ChatMsgMap[targetUid] = msgList
privateChatNotify := &proto.PrivateChatNotify{
ChatInfo: chatInfo,
}
g.SendMsg(cmd.PrivateChatNotify, player.PlayerID, player.ClientSeq, privateChatNotify)
targetPlayer := USER_MANAGER.GetOnlineUser(targetUid)
if targetPlayer == nil {
if USER_MANAGER.GetRemoteUserOnlineState(targetUid) {
// 目标玩家在别的服在线
gsAppId := USER_MANAGER.GetRemoteUserGsAppId(targetUid)
MESSAGE_QUEUE.SendToGs(gsAppId, &mq.NetMsg{
MsgType: mq.MsgTypeServer,
EventId: mq.ServerChatMsgNotify,
ServerMsg: &mq.ServerMsg{
ChatMsgInfo: &mq.ChatMsgInfo{
Time: chatMsg.Time,
ToUid: chatMsg.ToUid,
Uid: chatMsg.Uid,
IsRead: chatMsg.IsRead,
MsgType: chatMsg.MsgType,
Text: chatMsg.Text,
Icon: chatMsg.Icon,
},
},
})
} else {
// 目标玩家全服离线
// TODO 接入redis直接同步写入数据
}
return
}
// 消息加入目标玩家的队列 // 消息加入目标玩家的队列
msgList, exist = targetPlayer.ChatMsgMap[player.PlayerID] msgList, exist = targetPlayer.ChatMsgMap[player.PlayerID]
if !exist { if !exist {
msgList = make([]*model.ChatMsg, 0) msgList = make([]*model.ChatMsg, 0)
} }
msgList = append(msgList, g.ConvChatInfoToChatMsg(chatInfo)) msgList = append(msgList, chatMsg)
targetPlayer.ChatMsgMap[player.PlayerID] = msgList targetPlayer.ChatMsgMap[player.PlayerID] = msgList
// 如果目标玩家在线发送消息 // 如果目标玩家在线发送消息
@@ -124,11 +155,6 @@ func (g *GameManager) SendPrivateChat(player, targetPlayer *model.Player, conten
} }
g.SendMsg(cmd.PrivateChatNotify, targetPlayer.PlayerID, player.ClientSeq, privateChatNotify) g.SendMsg(cmd.PrivateChatNotify, targetPlayer.PlayerID, player.ClientSeq, privateChatNotify)
} }
privateChatNotify := &proto.PrivateChatNotify{
ChatInfo: chatInfo,
}
g.SendMsg(cmd.PrivateChatNotify, player.PlayerID, player.ClientSeq, privateChatNotify)
} }
func (g *GameManager) PrivateChatReq(player *model.Player, payloadMsg pb.Message) { func (g *GameManager) PrivateChatReq(player *model.Player, payloadMsg pb.Message) {
@@ -137,12 +163,6 @@ func (g *GameManager) PrivateChatReq(player *model.Player, payloadMsg pb.Message
targetUid := req.TargetUid targetUid := req.TargetUid
content := req.Content content := req.Content
// TODO 同步阻塞待优化
targetPlayer := USER_MANAGER.LoadTempOfflineUserSync(targetUid)
if targetPlayer == nil {
return
}
// 根据发送的类型发送消息 // 根据发送的类型发送消息
switch content.(type) { switch content.(type) {
case *proto.PrivateChatReq_Text: case *proto.PrivateChatReq_Text:
@@ -150,25 +170,14 @@ func (g *GameManager) PrivateChatReq(player *model.Player, payloadMsg pb.Message
if len(text) == 0 { if len(text) == 0 {
return return
} }
// 发送私聊文本消息 // 发送私聊文本消息
g.SendPrivateChat(player, targetPlayer, text) g.SendPrivateChat(player, targetUid, text)
// 输入命令 会检测是否为命令的 // 输入命令 会检测是否为命令的
COMMAND_MANAGER.InputCommand(player, text) COMMAND_MANAGER.InputCommand(player, text)
if text == "VPU" {
g.VideoPlayerUpdate(false)
} else if text == "VPUR" {
g.VideoPlayerUpdate(true)
}
case *proto.PrivateChatReq_Icon: case *proto.PrivateChatReq_Icon:
icon := content.(*proto.PrivateChatReq_Icon).Icon icon := content.(*proto.PrivateChatReq_Icon).Icon
// 发送私聊图标消息 // 发送私聊图标消息
g.SendPrivateChat(player, targetPlayer, icon) g.SendPrivateChat(player, targetUid, icon)
default: default:
return return
} }
@@ -281,3 +290,37 @@ func (g *GameManager) ConvChatMsgToChatInfo(chatMsg *model.ChatMsg) (chatInfo *p
} }
return chatInfo return chatInfo
} }
// 跨服玩家聊天通知
func (g *GameManager) ServerChatMsgNotify(chatMsgInfo *mq.ChatMsgInfo) {
targetPlayer := USER_MANAGER.GetOnlineUser(chatMsgInfo.ToUid)
if targetPlayer == nil {
logger.Error("player is nil, uid: %v", chatMsgInfo.ToUid)
return
}
chatMsg := &model.ChatMsg{
Time: chatMsgInfo.Time,
ToUid: chatMsgInfo.ToUid,
Uid: chatMsgInfo.Uid,
IsRead: chatMsgInfo.IsRead,
MsgType: chatMsgInfo.MsgType,
Text: chatMsgInfo.Text,
Icon: chatMsgInfo.Icon,
}
// 消息加入目标玩家的队列
msgList, exist := targetPlayer.ChatMsgMap[chatMsgInfo.Uid]
if !exist {
msgList = make([]*model.ChatMsg, 0)
}
msgList = append(msgList, chatMsg)
targetPlayer.ChatMsgMap[chatMsgInfo.Uid] = msgList
// 如果目标玩家在线发送消息
if targetPlayer.Online {
privateChatNotify := &proto.PrivateChatNotify{
ChatInfo: g.ConvChatMsgToChatInfo(chatMsg),
}
g.SendMsg(cmd.PrivateChatNotify, targetPlayer.PlayerID, targetPlayer.ClientSeq, privateChatNotify)
}
}

View File

@@ -3,7 +3,6 @@ package game
import ( import (
"time" "time"
"hk4e/common/constant"
"hk4e/common/mq" "hk4e/common/mq"
"hk4e/gs/model" "hk4e/gs/model"
"hk4e/pkg/logger" "hk4e/pkg/logger"
@@ -131,7 +130,10 @@ func (g *GameManager) ServerAppidBindNotify(userId uint32, fightAppId string, jo
} }
if joinHostUserId != 0 { if joinHostUserId != 0 {
hostPlayer := USER_MANAGER.GetOnlineUser(joinHostUserId) hostPlayer := USER_MANAGER.GetOnlineUser(joinHostUserId)
g.HostEnterMpWorld(hostPlayer, player.PlayerID) if hostPlayer == nil {
logger.Error("player is nil, uid: %v", joinHostUserId)
return
}
g.JoinOtherWorld(player, hostPlayer) g.JoinOtherWorld(player, hostPlayer)
return return
} }
@@ -139,7 +141,7 @@ func (g *GameManager) ServerAppidBindNotify(userId uint32, fightAppId string, jo
player.FightAppId = fightAppId player.FightAppId = fightAppId
// 创建世界 // 创建世界
world := WORLD_MANAGER.CreateWorld(player) world := WORLD_MANAGER.CreateWorld(player)
GAME_MANAGER.messageQueue.SendToFight(fightAppId, &mq.NetMsg{ MESSAGE_QUEUE.SendToFight(fightAppId, &mq.NetMsg{
MsgType: mq.MsgTypeFight, MsgType: mq.MsgTypeFight,
EventId: mq.AddFightRoutine, EventId: mq.AddFightRoutine,
FightMsg: &mq.FightMsg{ FightMsg: &mq.FightMsg{
@@ -153,53 +155,3 @@ func (g *GameManager) ServerAppidBindNotify(userId uint32, fightAppId string, jo
player.SceneLoadState = model.SceneNone player.SceneLoadState = model.SceneNone
g.SendMsg(cmd.PlayerEnterSceneNotify, userId, player.ClientSeq, g.PacketPlayerEnterSceneNotifyLogin(player, proto.EnterType_ENTER_TYPE_SELF)) g.SendMsg(cmd.PlayerEnterSceneNotify, userId, player.ClientSeq, g.PacketPlayerEnterSceneNotifyLogin(player, proto.EnterType_ENTER_TYPE_SELF))
} }
func (g *GameManager) ServerGetUserBaseInfoReq(userBaseInfo *mq.UserBaseInfo, gsAppId string) {
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)
g.messageQueue.SendToGs(gsAppId, &mq.NetMsg{
MsgType: mq.MsgTypeServer,
EventId: mq.ServerGetUserBaseInfoRsp,
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()),
},
},
})
}
func (g *GameManager) ServerGetUserBaseInfoRsp(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,
},
})
}
}

View File

@@ -61,14 +61,16 @@ func (g *GameManager) OnLoginOk(userId uint32, player *model.Player, clientSeq u
g.LoginNotify(userId, player, clientSeq) g.LoginNotify(userId, player, clientSeq)
g.messageQueue.SendToAll(&mq.NetMsg{ if userId >= 100000000 {
MsgType: mq.MsgTypeServer, MESSAGE_QUEUE.SendToAll(&mq.NetMsg{
EventId: mq.ServerUserOnlineStateChangeNotify, MsgType: mq.MsgTypeServer,
ServerMsg: &mq.ServerMsg{ EventId: mq.ServerUserOnlineStateChangeNotify,
UserId: userId, ServerMsg: &mq.ServerMsg{
IsOnline: true, UserId: userId,
}, IsOnline: true,
}) },
})
}
} }
func (g *GameManager) OnReg(userId uint32, clientSeq uint32, gateAppId string, payloadMsg pb.Message) { func (g *GameManager) OnReg(userId uint32, clientSeq uint32, gateAppId string, payloadMsg pb.Message) {
@@ -106,7 +108,7 @@ func (g *GameManager) OnRegOk(exist bool, req *proto.SetPlayerBornDataReq, userI
g.OnLogin(userId, clientSeq, gateAppId) g.OnLogin(userId, clientSeq, gateAppId)
} }
func (g *GameManager) OnUserOffline(userId uint32) { func (g *GameManager) OnUserOffline(userId uint32, changeGsInfo *ChangeGsInfo) {
logger.Info("user offline, uid: %v", userId) logger.Info("user offline, uid: %v", userId)
player := USER_MANAGER.GetOnlineUser(userId) player := USER_MANAGER.GetOnlineUser(userId)
if player == nil { if player == nil {
@@ -120,16 +122,7 @@ func (g *GameManager) OnUserOffline(userId uint32) {
player.OfflineTime = uint32(time.Now().Unix()) player.OfflineTime = uint32(time.Now().Unix())
player.Online = false player.Online = false
player.TotalOnlineTime += uint32(time.Now().UnixMilli()) - player.OnlineTime player.TotalOnlineTime += uint32(time.Now().UnixMilli()) - player.OnlineTime
USER_MANAGER.DeleteUser(player) USER_MANAGER.OfflineUser(player, changeGsInfo)
g.messageQueue.SendToAll(&mq.NetMsg{
MsgType: mq.MsgTypeServer,
EventId: mq.ServerUserOnlineStateChangeNotify,
ServerMsg: &mq.ServerMsg{
UserId: userId,
IsOnline: false,
},
})
} }
func (g *GameManager) LoginNotify(userId uint32, player *model.Player, clientSeq uint32) { func (g *GameManager) LoginNotify(userId uint32, player *model.Player, clientSeq uint32) {

View File

@@ -6,56 +6,36 @@ import (
"hk4e/gs/dao" "hk4e/gs/dao"
"hk4e/gs/model" "hk4e/gs/model"
"hk4e/pkg/logger" "hk4e/pkg/logger"
"hk4e/pkg/object"
"hk4e/protocol/proto" "hk4e/protocol/proto"
) )
type SaveUserData struct { // 玩家管理器
insertPlayerList []*model.Player
updatePlayerList []*model.Player // 玩家注册 从db查询对应uid是否存在并异步回调返回结果
} // 玩家登录 从db查询出来然后写入redis并异步回调返回玩家对象
// 玩家离线 写入db和redis
// 玩家定时保存 写入db和redis
type UserManager struct { type UserManager struct {
dao *dao.Dao dao *dao.Dao // db对象
playerMap map[uint32]*model.Player playerMap map[uint32]*model.Player // 内存玩家数据
saveUserChan chan *SaveUserData saveUserChan chan *SaveUserData // 用于主协程发送玩家数据给定时保存协程
remotePlayerMap map[uint32]string // 远程玩家 key:userId value:玩家所在gs的appid remotePlayerMap map[uint32]string // 远程玩家 key:userId value:玩家所在gs的appid
} }
func NewUserManager(dao *dao.Dao) (r *UserManager) { func NewUserManager(dao *dao.Dao) (r *UserManager) {
r = new(UserManager) r = new(UserManager)
r.dao = dao r.dao = dao
r.playerMap = make(map[uint32]*model.Player) r.playerMap = make(map[uint32]*model.Player)
r.saveUserChan = make(chan *SaveUserData) r.saveUserChan = make(chan *SaveUserData) // 无缓冲区chan 避免主协程在写入时被迫加锁
r.remotePlayerMap = make(map[uint32]string) r.remotePlayerMap = make(map[uint32]string)
return r return r
} }
func (u *UserManager) GetRemoteUserOnlineState(userId uint32) bool { // 在线玩家相关操作
_, exist := u.remotePlayerMap[userId]
if !exist {
return false
} else {
return true
}
}
func (u *UserManager) GetRemoteUserGsAppId(userId uint32) string {
appId, exist := u.remotePlayerMap[userId]
if !exist {
return ""
} else {
return appId
}
}
func (u *UserManager) SetRemoteUserOnlineState(userId uint32, isOnline bool, appId string) {
if isOnline {
u.remotePlayerMap[userId] = appId
} else {
delete(u.remotePlayerMap, userId)
}
}
// GetUserOnlineState 获取玩家在线状态
func (u *UserManager) GetUserOnlineState(userId uint32) bool { func (u *UserManager) GetUserOnlineState(userId uint32) bool {
player, exist := u.playerMap[userId] player, exist := u.playerMap[userId]
if !exist { if !exist {
@@ -65,6 +45,7 @@ func (u *UserManager) GetUserOnlineState(userId uint32) bool {
} }
} }
// GetOnlineUser 获取在线玩家对象
func (u *UserManager) GetOnlineUser(userId uint32) *model.Player { func (u *UserManager) GetOnlineUser(userId uint32) *model.Player {
player, exist := u.playerMap[userId] player, exist := u.playerMap[userId]
if !exist { if !exist {
@@ -78,6 +59,7 @@ func (u *UserManager) GetOnlineUser(userId uint32) *model.Player {
} }
} }
// GetAllOnlineUserList 获取全部在线玩家
func (u *UserManager) GetAllOnlineUserList() map[uint32]*model.Player { func (u *UserManager) GetAllOnlineUserList() map[uint32]*model.Player {
onlinePlayerMap := make(map[uint32]*model.Player) onlinePlayerMap := make(map[uint32]*model.Player)
for userId, player := range u.playerMap { for userId, player := range u.playerMap {
@@ -97,13 +79,14 @@ type PlayerRegInfo struct {
GateAppId string GateAppId string
} }
// CheckUserExistOnReg 玩家注册检查是否已存在
func (u *UserManager) CheckUserExistOnReg(userId uint32, req *proto.SetPlayerBornDataReq, clientSeq uint32, gateAppId string) (exist bool, asyncWait bool) { func (u *UserManager) CheckUserExistOnReg(userId uint32, req *proto.SetPlayerBornDataReq, clientSeq uint32, gateAppId string) (exist bool, asyncWait bool) {
_, exist = u.playerMap[userId] _, exist = u.playerMap[userId]
if exist { if exist {
return true, false return true, false
} else { } else {
go func() { go func() {
player := u.loadUserFromDb(userId) player := u.LoadUserFromDbSync(userId)
exist = false exist = false
if player != nil { if player != nil {
exist = true exist = true
@@ -123,38 +106,7 @@ func (u *UserManager) CheckUserExistOnReg(userId uint32, req *proto.SetPlayerBor
} }
} }
func (u *UserManager) LoadTempOfflineUserSync(userId uint32) *model.Player { // AddUser 向内存玩家数据里添加一个玩家
player, exist := u.playerMap[userId]
if exist {
return player
} else {
player = u.loadUserFromDb(userId)
if player == nil {
return nil
}
u.ChangeUserDbState(player, model.DbDelete)
u.playerMap[player.PlayerID] = player
return player
}
}
func (u *UserManager) loadUserFromDb(userId uint32) *model.Player {
player, err := u.dao.QueryPlayerByID(userId)
if err != nil {
logger.Error("query player error: %v", err)
return nil
}
return player
}
func (u *UserManager) saveUserToDb(player *model.Player) {
err := u.dao.UpdatePlayer(player)
if err != nil {
logger.Error("update player error: %v", err)
return
}
}
func (u *UserManager) AddUser(player *model.Player) { func (u *UserManager) AddUser(player *model.Player) {
if player == nil { if player == nil {
return return
@@ -163,12 +115,9 @@ func (u *UserManager) AddUser(player *model.Player) {
u.playerMap[player.PlayerID] = player u.playerMap[player.PlayerID] = player
} }
func (u *UserManager) DeleteUser(player *model.Player) { // DeleteUser 从内存玩家数据里删除一个玩家
if player == nil { func (u *UserManager) DeleteUser(userId uint32) {
return delete(u.playerMap, userId)
}
u.ChangeUserDbState(player, model.DbDelete)
u.playerMap[player.PlayerID] = player
} }
type PlayerLoginInfo struct { type PlayerLoginInfo struct {
@@ -178,6 +127,7 @@ type PlayerLoginInfo struct {
GateAppId string GateAppId string
} }
// OnlineUser 玩家上线
func (u *UserManager) OnlineUser(userId uint32, clientSeq uint32, gateAppId string) (*model.Player, bool) { func (u *UserManager) OnlineUser(userId uint32, clientSeq uint32, gateAppId string) (*model.Player, bool) {
player, exist := u.playerMap[userId] player, exist := u.playerMap[userId]
if exist { if exist {
@@ -185,8 +135,9 @@ func (u *UserManager) OnlineUser(userId uint32, clientSeq uint32, gateAppId stri
return player, false return player, false
} else { } else {
go func() { go func() {
player = u.loadUserFromDb(userId) player = u.LoadUserFromDbSync(userId)
if player != nil { if player != nil {
u.SaveUserToRedisSync(player)
u.ChangeUserDbState(player, model.DbNormal) u.ChangeUserDbState(player, model.DbNormal)
} else { } else {
logger.Error("can not find user from db, uid: %v", userId) logger.Error("can not find user from db, uid: %v", userId)
@@ -205,6 +156,38 @@ func (u *UserManager) OnlineUser(userId uint32, clientSeq uint32, gateAppId stri
} }
} }
type ChangeGsInfo struct {
IsChangeGs bool
JoinHostUserId uint32
}
type PlayerOfflineInfo struct {
Player *model.Player
ChangeGsInfo *ChangeGsInfo
}
// OfflineUser 玩家离线
func (u *UserManager) OfflineUser(player *model.Player, changeGsInfo *ChangeGsInfo) {
playerCopy := new(model.Player)
err := object.FastDeepCopy(playerCopy, player)
if err != nil {
logger.Error("deep copy player error: %v", err)
return
}
go func() {
u.SaveUserToDbSync(playerCopy)
u.SaveUserToRedisSync(playerCopy)
LOCAL_EVENT_MANAGER.localEventChan <- &LocalEvent{
EventId: UserOfflineSaveToDbFinish,
Msg: &PlayerOfflineInfo{
Player: player,
ChangeGsInfo: changeGsInfo,
},
}
}()
}
// ChangeUserDbState 玩家存档状态机 主要用于玩家定时保存时进行分类处理
func (u *UserManager) ChangeUserDbState(player *model.Player, state int) { func (u *UserManager) ChangeUserDbState(player *model.Player, state int) {
if player == nil { if player == nil {
return return
@@ -238,8 +221,140 @@ func (u *UserManager) ChangeUserDbState(player *model.Player, state int) {
} }
} }
// 用户数据库定时同步 // 远程玩家相关操作
func (u *UserManager) GetRemoteUserOnlineState(userId uint32) bool {
_, exist := u.remotePlayerMap[userId]
if !exist {
return false
} else {
return true
}
}
func (u *UserManager) GetRemoteUserGsAppId(userId uint32) string {
appId, exist := u.remotePlayerMap[userId]
if !exist {
return ""
} else {
return appId
}
}
func (u *UserManager) SetRemoteUserOnlineState(userId uint32, isOnline bool, appId string) {
if isOnline {
u.remotePlayerMap[userId] = appId
} else {
delete(u.remotePlayerMap, userId)
u.DeleteUser(userId)
}
}
// GetRemoteOnlineUserList 获取指定数量的远程在线玩家
func (u *UserManager) GetRemoteOnlineUserList(total int) map[uint32]*model.Player {
if total > 50 {
return nil
}
onlinePlayerMap := make(map[uint32]*model.Player)
count := 0
for userId := range u.remotePlayerMap {
player := u.LoadTempOfflineUser(userId)
if player == nil {
continue
}
onlinePlayerMap[player.PlayerID] = player
count++
if count >= total {
break
}
}
return onlinePlayerMap
}
// LoadGlobalPlayer 加载并返回一个全服玩家及其在线状态
// 参见LoadTempOfflineUser说明
func (u *UserManager) LoadGlobalPlayer(userId uint32) (player *model.Player, online bool, remote bool) {
online = u.GetUserOnlineState(userId)
remote = false
if !online {
// 本地不在线就看看远程在不在线
online = u.GetRemoteUserOnlineState(userId)
if online {
remote = true
}
}
if online {
if remote {
// 远程在线玩家 为了简化实现流程 直接加载数据库临时档
player = u.LoadTempOfflineUser(userId)
} else {
// 本地在线玩家
player = u.GetOnlineUser(userId)
}
} else {
// 全服离线玩家
player = u.LoadTempOfflineUser(userId)
}
return player, online, remote
}
// 离线玩家相关操作
// LoadTempOfflineUser 加载临时离线玩家
// 正常情况速度较快可以同步阻塞调用
func (u *UserManager) LoadTempOfflineUser(userId uint32) *model.Player {
player := u.GetOnlineUser(userId)
if player != nil && player.Online {
logger.Error("not allow get a online player as offline player, uid: %v", userId)
return nil
}
player = u.LoadUserFromRedisSync(userId)
if player == nil {
// 玩家可能不存在于redis 尝试从db查询出来然后写入redis
// 大多数情况下活跃玩家都在redis 所以不会走到下面
// TODO 布隆过滤器防止恶意攻击造成redis缓存穿透
if userId < 100000000 || userId > 200000000 {
logger.Error("try to load a not exist uid, uid: %v", userId)
return nil
}
player = u.LoadUserFromDbSync(userId)
if player == nil {
// 玩家根本就不存在
logger.Error("try to load a not exist player from db, uid: %v", userId)
return nil
}
u.SaveUserToRedisSync(player)
}
u.ChangeUserDbState(player, model.DbDelete)
u.playerMap[player.PlayerID] = player
return player
}
// SaveTempOfflineUser 保存临时离线玩家
// 如果在调用LoadTempOfflineUser后修改了离线玩家数据 则必须立即调用此函数回写
func (u *UserManager) SaveTempOfflineUser(player *model.Player) {
// 主协程同步写入redis
u.SaveUserToRedisSync(player)
// 另一个协程异步的写回db
playerCopy := new(model.Player)
err := object.FastDeepCopy(playerCopy, player)
if err != nil {
logger.Error("deep copy player error: %v", err)
return
}
go func() {
u.SaveUserToDbSync(playerCopy)
}()
}
// db和redis相关操作
type SaveUserData struct {
insertPlayerList []*model.Player
updatePlayerList []*model.Player
}
// StartAutoSaveUser 玩家定时保存
func (u *UserManager) StartAutoSaveUser() { func (u *UserManager) StartAutoSaveUser() {
go func() { go func() {
ticker := time.NewTicker(time.Minute * 5) ticker := time.NewTicker(time.Minute * 5)
@@ -253,12 +368,30 @@ func (u *UserManager) StartAutoSaveUser() {
go func() { go func() {
for { for {
saveUserData := <-u.saveUserChan saveUserData := <-u.saveUserChan
u.SaveUser(saveUserData) u.SaveUserListToDbSync(saveUserData)
u.SaveUserListToRedisSync(saveUserData)
} }
}() }()
} }
func (u *UserManager) SaveUser(saveUserData *SaveUserData) { func (u *UserManager) LoadUserFromDbSync(userId uint32) *model.Player {
player, err := u.dao.QueryPlayerByID(userId)
if err != nil {
logger.Error("query player error: %v", err)
return nil
}
return player
}
func (u *UserManager) SaveUserToDbSync(player *model.Player) {
err := u.dao.UpdatePlayer(player)
if err != nil {
logger.Error("update player error: %v", err)
return
}
}
func (u *UserManager) SaveUserListToDbSync(saveUserData *SaveUserData) {
err := u.dao.InsertPlayerList(saveUserData.insertPlayerList) err := u.dao.InsertPlayerList(saveUserData.insertPlayerList)
if err != nil { if err != nil {
logger.Error("insert player list error: %v", err) logger.Error("insert player list error: %v", err)
@@ -271,3 +404,23 @@ func (u *UserManager) SaveUser(saveUserData *SaveUserData) {
} }
logger.Info("save user finish, insert user count: %v, update user count: %v", len(saveUserData.insertPlayerList), len(saveUserData.updatePlayerList)) logger.Info("save user finish, insert user count: %v, update user count: %v", len(saveUserData.insertPlayerList), len(saveUserData.updatePlayerList))
} }
func (u *UserManager) LoadUserFromRedisSync(userId uint32) *model.Player {
player := u.dao.GetRedisPlayer(userId)
return player
}
func (u *UserManager) SaveUserToRedisSync(player *model.Player) {
u.dao.SetRedisPlayer(player)
}
func (u *UserManager) SaveUserListToRedisSync(saveUserData *SaveUserData) {
setPlayerList := make([]*model.Player, 0, len(saveUserData.insertPlayerList)+len(saveUserData.updatePlayerList))
for _, player := range saveUserData.insertPlayerList {
setPlayerList = append(setPlayerList, player)
}
for _, player := range saveUserData.updatePlayerList {
setPlayerList = append(setPlayerList, player)
}
u.dao.SetRedisPlayerList(setPlayerList)
}

View File

@@ -5,7 +5,6 @@ import (
"hk4e/common/constant" "hk4e/common/constant"
"hk4e/common/mq" "hk4e/common/mq"
"hk4e/gate/kcp"
"hk4e/gs/model" "hk4e/gs/model"
"hk4e/pkg/logger" "hk4e/pkg/logger"
"hk4e/pkg/object" "hk4e/pkg/object"
@@ -27,16 +26,7 @@ func (g *GameManager) PlayerApplyEnterMpReq(player *model.Player, payloadMsg pb.
} }
g.SendMsg(cmd.PlayerApplyEnterMpRsp, player.PlayerID, player.ClientSeq, playerApplyEnterMpRsp) g.SendMsg(cmd.PlayerApplyEnterMpRsp, player.PlayerID, player.ClientSeq, playerApplyEnterMpRsp)
ok := g.UserApplyEnterWorld(player, targetUid) g.UserApplyEnterWorld(player, targetUid)
if !ok {
playerApplyEnterMpResultNotify := &proto.PlayerApplyEnterMpResultNotify{
TargetUid: targetUid,
TargetNickname: "",
IsAgreed: false,
Reason: proto.PlayerApplyEnterMpResultNotify_REASON_PLAYER_CANNOT_ENTER_MP,
}
g.SendMsg(cmd.PlayerApplyEnterMpResultNotify, player.PlayerID, player.ClientSeq, playerApplyEnterMpResultNotify)
}
} }
func (g *GameManager) PlayerApplyEnterMpResultReq(player *model.Player, payloadMsg pb.Message) { func (g *GameManager) PlayerApplyEnterMpResultReq(player *model.Player, payloadMsg pb.Message) {
@@ -73,22 +63,12 @@ func (g *GameManager) JoinPlayerSceneReq(player *model.Player, payloadMsg pb.Mes
if !USER_MANAGER.GetRemoteUserOnlineState(req.TargetUid) { if !USER_MANAGER.GetRemoteUserOnlineState(req.TargetUid) {
// 全服不存在该在线玩家 // 全服不存在该在线玩家
logger.Error("target user not online in any game server, uid: %v", req.TargetUid) logger.Error("target user not online in any game server, uid: %v", req.TargetUid)
g.DisconnectPlayer(player.PlayerID, kcp.EnetServerKick)
return return
} }
// 走玩家在线跨服迁移流程 // 走玩家在线跨服迁移流程
g.OnUserOffline(player.PlayerID) g.OnUserOffline(player.PlayerID, &ChangeGsInfo{
// TODO 改成异步写入数据库 IsChangeGs: true,
USER_MANAGER.saveUserToDb(player) JoinHostUserId: req.TargetUid,
gsAppId := USER_MANAGER.GetRemoteUserGsAppId(req.TargetUid)
g.messageQueue.SendToGate(player.GateAppId, &mq.NetMsg{
MsgType: mq.MsgTypeServer,
EventId: mq.ServerUserGsChangeNotify,
ServerMsg: &mq.ServerMsg{
UserId: player.PlayerID,
GameServerAppId: gsAppId,
JoinHostUserId: req.TargetUid,
},
}) })
return return
} }
@@ -98,13 +78,7 @@ func (g *GameManager) JoinPlayerSceneReq(player *model.Player, payloadMsg pb.Mes
func (g *GameManager) JoinOtherWorld(player *model.Player, hostPlayer *model.Player) { func (g *GameManager) JoinOtherWorld(player *model.Player, hostPlayer *model.Player) {
hostWorld := WORLD_MANAGER.GetWorldByID(hostPlayer.WorldId) hostWorld := WORLD_MANAGER.GetWorldByID(hostPlayer.WorldId)
_, exist := hostWorld.waitEnterPlayerMap[player.PlayerID]
if !exist {
return
}
if hostPlayer.SceneLoadState == model.SceneEnterDone { if hostPlayer.SceneLoadState == model.SceneEnterDone {
delete(hostWorld.waitEnterPlayerMap, player.PlayerID)
player.Pos.X = hostPlayer.Pos.X player.Pos.X = hostPlayer.Pos.X
player.Pos.Y = hostPlayer.Pos.Y player.Pos.Y = hostPlayer.Pos.Y
player.Pos.Z = hostPlayer.Pos.Z player.Pos.Z = hostPlayer.Pos.Z
@@ -112,11 +86,13 @@ func (g *GameManager) JoinOtherWorld(player *model.Player, hostPlayer *model.Pla
player.Rot.Y = hostPlayer.Rot.Y player.Rot.Y = hostPlayer.Rot.Y
player.Rot.Z = hostPlayer.Rot.Z player.Rot.Z = hostPlayer.Rot.Z
player.SceneId = hostPlayer.SceneId player.SceneId = hostPlayer.SceneId
g.UserWorldAddPlayer(hostWorld, player) g.UserWorldAddPlayer(hostWorld, player)
player.SceneLoadState = model.SceneNone player.SceneLoadState = model.SceneNone
g.SendMsg(cmd.PlayerEnterSceneNotify, player.PlayerID, player.ClientSeq, g.PacketPlayerEnterSceneNotifyLogin(player, proto.EnterType_ENTER_TYPE_OTHER))
playerEnterSceneNotify := g.PacketPlayerEnterSceneNotifyLogin(player, proto.EnterType_ENTER_TYPE_OTHER)
g.SendMsg(cmd.PlayerEnterSceneNotify, player.PlayerID, player.ClientSeq, playerEnterSceneNotify)
} else {
hostWorld.waitEnterPlayerMap[player.PlayerID] = time.Now().UnixMilli()
} }
} }
@@ -173,6 +149,10 @@ func (g *GameManager) SceneKickPlayerReq(player *model.Player, payloadMsg pb.Mes
} }
targetUid := req.TargetUid targetUid := req.TargetUid
targetPlayer := USER_MANAGER.GetOnlineUser(targetUid) targetPlayer := USER_MANAGER.GetOnlineUser(targetUid)
if targetPlayer == nil {
logger.Error("player is nil, uid: %v", targetUid)
return
}
ok := g.UserLeaveWorld(targetPlayer) ok := g.UserLeaveWorld(targetPlayer)
if !ok { if !ok {
g.CommonRetError(cmd.SceneKickPlayerRsp, player, &proto.SceneKickPlayerRsp{}, proto.Retcode_RET_MP_TARGET_PLAYER_IN_TRANSFER) g.CommonRetError(cmd.SceneKickPlayerRsp, player, &proto.SceneKickPlayerRsp{}, proto.Retcode_RET_MP_TARGET_PLAYER_IN_TRANSFER)
@@ -193,41 +173,112 @@ func (g *GameManager) SceneKickPlayerReq(player *model.Player, payloadMsg pb.Mes
g.SendMsg(cmd.SceneKickPlayerRsp, player.PlayerID, player.ClientSeq, sceneKickPlayerRsp) g.SendMsg(cmd.SceneKickPlayerRsp, player.PlayerID, player.ClientSeq, sceneKickPlayerRsp)
} }
func (g *GameManager) UserApplyEnterWorld(player *model.Player, targetUid uint32) bool { func (g *GameManager) UserApplyEnterWorld(player *model.Player, targetUid uint32) {
targetPlayer := USER_MANAGER.GetOnlineUser(targetUid) applyFailNotify := func() {
if targetPlayer == nil { playerApplyEnterMpResultNotify := &proto.PlayerApplyEnterMpResultNotify{
return false TargetUid: targetUid,
TargetNickname: "",
IsAgreed: false,
Reason: proto.PlayerApplyEnterMpResultNotify_REASON_PLAYER_CANNOT_ENTER_MP,
}
g.SendMsg(cmd.PlayerApplyEnterMpResultNotify, player.PlayerID, player.ClientSeq, playerApplyEnterMpResultNotify)
} }
world := WORLD_MANAGER.GetWorldByID(player.WorldId) world := WORLD_MANAGER.GetWorldByID(player.WorldId)
if world.multiplayer { if world.multiplayer {
return false applyFailNotify()
return
}
targetPlayer := USER_MANAGER.GetOnlineUser(targetUid)
if targetPlayer == nil {
if !USER_MANAGER.GetRemoteUserOnlineState(targetUid) {
// 全服不存在该在线玩家
logger.Error("target user not online in any game server, uid: %v", targetUid)
applyFailNotify()
return
}
gsAppId := USER_MANAGER.GetRemoteUserGsAppId(targetUid)
MESSAGE_QUEUE.SendToGs(gsAppId, &mq.NetMsg{
MsgType: mq.MsgTypeServer,
EventId: mq.ServerUserMpReq,
ServerMsg: &mq.ServerMsg{
UserMpInfo: &mq.UserMpInfo{
OriginInfo: &mq.OriginInfo{
CmdName: "PlayerApplyEnterMpReq",
UserId: player.PlayerID,
},
HostUserId: targetUid,
ApplyUserId: player.PlayerID,
ApplyPlayerOnlineInfo: &mq.UserBaseInfo{
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()),
},
},
},
})
return
} }
applyTime, exist := targetPlayer.CoopApplyMap[player.PlayerID] applyTime, exist := targetPlayer.CoopApplyMap[player.PlayerID]
if exist && time.Now().UnixNano() < applyTime+int64(10*time.Second) { if exist && time.Now().UnixNano() < applyTime+int64(10*time.Second) {
return false applyFailNotify()
return
} }
targetPlayer.CoopApplyMap[player.PlayerID] = time.Now().UnixNano() targetPlayer.CoopApplyMap[player.PlayerID] = time.Now().UnixNano()
targetWorld := WORLD_MANAGER.GetWorldByID(targetPlayer.WorldId) targetWorld := WORLD_MANAGER.GetWorldByID(targetPlayer.WorldId)
if targetWorld.multiplayer && targetWorld.owner.PlayerID != targetPlayer.PlayerID { if targetWorld.multiplayer && targetWorld.owner.PlayerID != targetPlayer.PlayerID {
return false // 向同一世界内的非房主玩家申请时直接拒绝
applyFailNotify()
return
} }
playerApplyEnterMpNotify := new(proto.PlayerApplyEnterMpNotify) playerApplyEnterMpNotify := new(proto.PlayerApplyEnterMpNotify)
playerApplyEnterMpNotify.SrcPlayerInfo = g.PacketOnlinePlayerInfo(player) playerApplyEnterMpNotify.SrcPlayerInfo = g.PacketOnlinePlayerInfo(player)
g.SendMsg(cmd.PlayerApplyEnterMpNotify, targetPlayer.PlayerID, targetPlayer.ClientSeq, playerApplyEnterMpNotify) g.SendMsg(cmd.PlayerApplyEnterMpNotify, targetPlayer.PlayerID, targetPlayer.ClientSeq, playerApplyEnterMpNotify)
return true
} }
func (g *GameManager) UserDealEnterWorld(hostPlayer *model.Player, otherUid uint32, agree bool) { func (g *GameManager) UserDealEnterWorld(hostPlayer *model.Player, otherUid uint32, agree bool) {
otherPlayer := USER_MANAGER.GetOnlineUser(otherUid)
if otherPlayer == nil {
return
}
applyTime, exist := hostPlayer.CoopApplyMap[otherUid] applyTime, exist := hostPlayer.CoopApplyMap[otherUid]
if !exist || time.Now().UnixNano() > applyTime+int64(10*time.Second) { if !exist || time.Now().UnixNano() > applyTime+int64(10*time.Second) {
return return
} }
delete(hostPlayer.CoopApplyMap, otherUid) delete(hostPlayer.CoopApplyMap, otherUid)
if !agree {
return
}
g.HostEnterMpWorld(hostPlayer, otherUid)
otherPlayer := USER_MANAGER.GetOnlineUser(otherUid)
if otherPlayer == nil {
if !USER_MANAGER.GetRemoteUserOnlineState(otherUid) {
// 全服不存在该在线玩家
logger.Error("target user not online in any game server, uid: %v", otherUid)
return
}
gsAppId := USER_MANAGER.GetRemoteUserGsAppId(otherUid)
MESSAGE_QUEUE.SendToGs(gsAppId, &mq.NetMsg{
MsgType: mq.MsgTypeServer,
EventId: mq.ServerUserMpReq,
ServerMsg: &mq.ServerMsg{
UserMpInfo: &mq.UserMpInfo{
OriginInfo: &mq.OriginInfo{
CmdName: "PlayerApplyEnterMpResultReq",
UserId: hostPlayer.PlayerID,
},
HostUserId: hostPlayer.PlayerID,
ApplyUserId: otherUid,
Agreed: agree,
HostNickname: hostPlayer.NickName,
},
},
})
return
}
otherPlayerWorld := WORLD_MANAGER.GetWorldByID(otherPlayer.WorldId) otherPlayerWorld := WORLD_MANAGER.GetWorldByID(otherPlayer.WorldId)
if otherPlayerWorld.multiplayer { if otherPlayerWorld.multiplayer {
playerApplyEnterMpResultNotify := &proto.PlayerApplyEnterMpResultNotify{ playerApplyEnterMpResultNotify := &proto.PlayerApplyEnterMpResultNotify{
@@ -247,15 +298,10 @@ func (g *GameManager) UserDealEnterWorld(hostPlayer *model.Player, otherUid uint
Reason: proto.PlayerApplyEnterMpResultNotify_REASON_PLAYER_JUDGE, Reason: proto.PlayerApplyEnterMpResultNotify_REASON_PLAYER_JUDGE,
} }
g.SendMsg(cmd.PlayerApplyEnterMpResultNotify, otherPlayer.PlayerID, otherPlayer.ClientSeq, playerApplyEnterMpResultNotify) g.SendMsg(cmd.PlayerApplyEnterMpResultNotify, otherPlayer.PlayerID, otherPlayer.ClientSeq, playerApplyEnterMpResultNotify)
if agree {
g.HostEnterMpWorld(hostPlayer, otherPlayer.PlayerID)
}
} }
func (g *GameManager) HostEnterMpWorld(hostPlayer *model.Player, otherPlayerId uint32) { func (g *GameManager) HostEnterMpWorld(hostPlayer *model.Player, otherUid uint32) {
world := WORLD_MANAGER.GetWorldByID(hostPlayer.WorldId) world := WORLD_MANAGER.GetWorldByID(hostPlayer.WorldId)
world.waitEnterPlayerMap[otherPlayerId] = time.Now().UnixMilli()
if world.multiplayer { if world.multiplayer {
return return
} }
@@ -286,7 +332,7 @@ func (g *GameManager) HostEnterMpWorld(hostPlayer *model.Player, otherPlayerId u
guestBeginEnterSceneNotify := &proto.GuestBeginEnterSceneNotify{ guestBeginEnterSceneNotify := &proto.GuestBeginEnterSceneNotify{
SceneId: hostPlayer.SceneId, SceneId: hostPlayer.SceneId,
Uid: otherPlayerId, Uid: otherUid,
} }
g.SendMsg(cmd.GuestBeginEnterSceneNotify, hostPlayer.PlayerID, hostPlayer.ClientSeq, guestBeginEnterSceneNotify) g.SendMsg(cmd.GuestBeginEnterSceneNotify, hostPlayer.PlayerID, hostPlayer.ClientSeq, guestBeginEnterSceneNotify)
@@ -357,7 +403,7 @@ func (g *GameManager) UserWorldRemovePlayer(world *World, player *model.Player)
if world.owner.PlayerID == player.PlayerID { if world.owner.PlayerID == player.PlayerID {
// 房主离开销毁世界 // 房主离开销毁世界
WORLD_MANAGER.DestroyWorld(world.id) WORLD_MANAGER.DestroyWorld(world.id)
GAME_MANAGER.messageQueue.SendToFight(world.owner.FightAppId, &mq.NetMsg{ MESSAGE_QUEUE.SendToFight(world.owner.FightAppId, &mq.NetMsg{
MsgType: mq.MsgTypeFight, MsgType: mq.MsgTypeFight,
EventId: mq.DelFightRoutine, EventId: mq.DelFightRoutine,
FightMsg: &mq.FightMsg{ FightMsg: &mq.FightMsg{
@@ -462,3 +508,112 @@ func (g *GameManager) UpdateWorldPlayerInfo(hostWorld *World, excludePlayer *mod
g.SendMsg(cmd.SyncScenePlayTeamEntityNotify, worldPlayer.PlayerID, worldPlayer.ClientSeq, syncScenePlayTeamEntityNotify) g.SendMsg(cmd.SyncScenePlayTeamEntityNotify, worldPlayer.PlayerID, worldPlayer.ClientSeq, syncScenePlayTeamEntityNotify)
} }
} }
// 跨服玩家多人世界相关请求
func (g *GameManager) ServerUserMpReq(userMpInfo *mq.UserMpInfo, gsAppId string) {
switch userMpInfo.OriginInfo.CmdName {
case "PlayerApplyEnterMpReq":
applyFailNotify := func() {
MESSAGE_QUEUE.SendToGs(gsAppId, &mq.NetMsg{
MsgType: mq.MsgTypeServer,
EventId: mq.ServerUserMpRsp,
ServerMsg: &mq.ServerMsg{
UserMpInfo: &mq.UserMpInfo{
OriginInfo: userMpInfo.OriginInfo,
HostUserId: userMpInfo.HostUserId,
ApplyOk: false,
},
},
})
}
hostPlayer := USER_MANAGER.GetOnlineUser(userMpInfo.HostUserId)
if hostPlayer == nil {
logger.Error("player is nil, uid: %v", userMpInfo.HostUserId)
applyFailNotify()
return
}
applyTime, exist := hostPlayer.CoopApplyMap[userMpInfo.ApplyUserId]
if exist && time.Now().UnixNano() < applyTime+int64(10*time.Second) {
applyFailNotify()
return
}
hostPlayer.CoopApplyMap[userMpInfo.ApplyUserId] = time.Now().UnixNano()
hostWorld := WORLD_MANAGER.GetWorldByID(hostPlayer.WorldId)
if hostWorld.multiplayer && hostWorld.owner.PlayerID != hostPlayer.PlayerID {
// 向同一世界内的非房主玩家申请时直接拒绝
applyFailNotify()
return
}
playerApplyEnterMpNotify := new(proto.PlayerApplyEnterMpNotify)
playerApplyEnterMpNotify.SrcPlayerInfo = &proto.OnlinePlayerInfo{
Uid: userMpInfo.ApplyPlayerOnlineInfo.UserId,
Nickname: userMpInfo.ApplyPlayerOnlineInfo.Nickname,
PlayerLevel: userMpInfo.ApplyPlayerOnlineInfo.PlayerLevel,
MpSettingType: proto.MpSettingType(userMpInfo.ApplyPlayerOnlineInfo.MpSettingType),
NameCardId: userMpInfo.ApplyPlayerOnlineInfo.NameCardId,
Signature: userMpInfo.ApplyPlayerOnlineInfo.Signature,
ProfilePicture: &proto.ProfilePicture{AvatarId: userMpInfo.ApplyPlayerOnlineInfo.HeadImageId},
CurPlayerNumInWorld: userMpInfo.ApplyPlayerOnlineInfo.WorldPlayerNum,
}
g.SendMsg(cmd.PlayerApplyEnterMpNotify, hostPlayer.PlayerID, hostPlayer.ClientSeq, playerApplyEnterMpNotify)
MESSAGE_QUEUE.SendToGs(gsAppId, &mq.NetMsg{
MsgType: mq.MsgTypeServer,
EventId: mq.ServerUserMpRsp,
ServerMsg: &mq.ServerMsg{
UserMpInfo: &mq.UserMpInfo{
OriginInfo: userMpInfo.OriginInfo,
HostUserId: userMpInfo.HostUserId,
ApplyOk: true,
},
},
})
case "PlayerApplyEnterMpResultReq":
applyPlayer := USER_MANAGER.GetOnlineUser(userMpInfo.ApplyUserId)
if applyPlayer == nil {
logger.Error("player is nil, uid: %v", userMpInfo.ApplyUserId)
return
}
applyPlayerWorld := WORLD_MANAGER.GetWorldByID(applyPlayer.WorldId)
if applyPlayerWorld.multiplayer {
playerApplyEnterMpResultNotify := &proto.PlayerApplyEnterMpResultNotify{
TargetUid: userMpInfo.HostUserId,
TargetNickname: userMpInfo.HostNickname,
IsAgreed: false,
Reason: proto.PlayerApplyEnterMpResultNotify_REASON_PLAYER_CANNOT_ENTER_MP,
}
g.SendMsg(cmd.PlayerApplyEnterMpResultNotify, applyPlayer.PlayerID, applyPlayer.ClientSeq, playerApplyEnterMpResultNotify)
return
}
playerApplyEnterMpResultNotify := &proto.PlayerApplyEnterMpResultNotify{
TargetUid: userMpInfo.HostUserId,
TargetNickname: userMpInfo.HostNickname,
IsAgreed: userMpInfo.Agreed,
Reason: proto.PlayerApplyEnterMpResultNotify_REASON_PLAYER_JUDGE,
}
g.SendMsg(cmd.PlayerApplyEnterMpResultNotify, applyPlayer.PlayerID, applyPlayer.ClientSeq, playerApplyEnterMpResultNotify)
}
}
func (g *GameManager) ServerUserMpRsp(userMpInfo *mq.UserMpInfo) {
switch userMpInfo.OriginInfo.CmdName {
case "PlayerApplyEnterMpReq":
player := USER_MANAGER.GetOnlineUser(userMpInfo.OriginInfo.UserId)
if player == nil {
logger.Error("player is nil, uid: %v", userMpInfo.OriginInfo.UserId)
return
}
if !userMpInfo.ApplyOk {
playerApplyEnterMpResultNotify := &proto.PlayerApplyEnterMpResultNotify{
TargetUid: userMpInfo.HostUserId,
TargetNickname: "",
IsAgreed: false,
Reason: proto.PlayerApplyEnterMpResultNotify_REASON_PLAYER_CANNOT_ENTER_MP,
}
g.SendMsg(cmd.PlayerApplyEnterMpResultNotify, player.PlayerID, player.ClientSeq, playerApplyEnterMpResultNotify)
}
}
}

View File

@@ -263,21 +263,14 @@ func (g *GameManager) EnterSceneDoneReq(player *model.Player, payloadMsg pb.Mess
world.PlayerEnter(player) world.PlayerEnter(player)
for otherPlayerId := range world.waitEnterPlayerMap { for otherPlayerId := range world.waitEnterPlayerMap {
// 房主第一次进入多人世界场景完成 开始通知等待列表中的玩家进入场景
delete(world.waitEnterPlayerMap, otherPlayerId) delete(world.waitEnterPlayerMap, otherPlayerId)
otherPlayer := USER_MANAGER.GetOnlineUser(otherPlayerId) otherPlayer := USER_MANAGER.GetOnlineUser(otherPlayerId)
otherPlayer.Pos.X = player.Pos.X if otherPlayer == nil {
otherPlayer.Pos.Y = player.Pos.Y logger.Error("player is nil, uid: %v", otherPlayerId)
otherPlayer.Pos.Z = player.Pos.Z continue
otherPlayer.Rot.X = player.Rot.X }
otherPlayer.Rot.Y = player.Rot.Y g.JoinOtherWorld(otherPlayer, player)
otherPlayer.Rot.Z = player.Rot.Z
otherPlayer.SceneId = player.SceneId
g.UserWorldAddPlayer(world, otherPlayer)
otherPlayer.SceneLoadState = model.SceneNone
playerEnterSceneNotify := g.PacketPlayerEnterSceneNotifyLogin(otherPlayer, proto.EnterType_ENTER_TYPE_OTHER)
g.SendMsg(cmd.PlayerEnterSceneNotify, otherPlayer.PlayerID, otherPlayer.ClientSeq, playerEnterSceneNotify)
} }
} }

View File

@@ -21,12 +21,28 @@ func (g *GameManager) GetPlayerSocialDetailReq(player *model.Player, payloadMsg
req := payloadMsg.(*proto.GetPlayerSocialDetailReq) req := payloadMsg.(*proto.GetPlayerSocialDetailReq)
targetUid := req.Uid targetUid := req.Uid
// TODO 同步阻塞待优化 targetPlayer, _, remote := USER_MANAGER.LoadGlobalPlayer(targetUid)
targetPlayer := USER_MANAGER.LoadTempOfflineUserSync(targetUid)
if targetPlayer == nil { if targetPlayer == nil {
g.CommonRetError(cmd.GetPlayerSocialDetailRsp, player, &proto.GetPlayerSocialDetailRsp{}, proto.Retcode_RET_PLAYER_NOT_EXIST) g.CommonRetError(cmd.GetPlayerSocialDetailRsp, player, &proto.GetPlayerSocialDetailRsp{}, proto.Retcode_RET_PLAYER_NOT_EXIST)
return 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] _, exist := player.FriendList[targetPlayer.PlayerID]
socialDetail := &proto.SocialDetail{ socialDetail := &proto.SocialDetail{
Uid: targetPlayer.PlayerID, Uid: targetPlayer.PlayerID,
@@ -160,19 +176,18 @@ func (g *GameManager) GetPlayerFriendListReq(player *model.Player, payloadMsg pb
// 用于实现好友列表内的系统且不更改原先的内容 // 用于实现好友列表内的系统且不更改原先的内容
tempFriendList := COMMAND_MANAGER.GetFriendList(player.FriendList) tempFriendList := COMMAND_MANAGER.GetFriendList(player.FriendList)
for uid := range tempFriendList { for uid := range tempFriendList {
// TODO 同步阻塞待优化
var onlineState proto.FriendOnlineState friendPlayer, online, _ := USER_MANAGER.LoadGlobalPlayer(uid)
online := USER_MANAGER.GetUserOnlineState(uid) if friendPlayer == nil {
logger.Error("target player is nil, uid: %v", player.PlayerID)
continue
}
var onlineState proto.FriendOnlineState = 0
if online { if online {
onlineState = proto.FriendOnlineState_FRIEND_ONLINE_STATE_ONLINE onlineState = proto.FriendOnlineState_FRIEND_ONLINE_STATE_ONLINE
} else { } else {
onlineState = proto.FriendOnlineState_FRIEND_ONLINE_STATE_DISCONNECT onlineState = proto.FriendOnlineState_FRIEND_ONLINE_STATE_DISCONNECT
} }
friendPlayer := USER_MANAGER.LoadTempOfflineUserSync(uid)
if friendPlayer == nil {
logger.Error("target player is nil, uid: %v", player.PlayerID)
continue
}
friendBrief := &proto.FriendBrief{ friendBrief := &proto.FriendBrief{
Uid: friendPlayer.PlayerID, Uid: friendPlayer.PlayerID,
Nickname: friendPlayer.NickName, Nickname: friendPlayer.NickName,
@@ -200,19 +215,17 @@ func (g *GameManager) GetPlayerAskFriendListReq(player *model.Player, payloadMsg
AskFriendList: make([]*proto.FriendBrief, 0), AskFriendList: make([]*proto.FriendBrief, 0),
} }
for uid := range player.FriendApplyList { for uid := range player.FriendApplyList {
// TODO 同步阻塞待优化 friendPlayer, online, _ := USER_MANAGER.LoadGlobalPlayer(uid)
if friendPlayer == nil {
logger.Error("target player is nil, uid: %v", player.PlayerID)
continue
}
var onlineState proto.FriendOnlineState var onlineState proto.FriendOnlineState
online := USER_MANAGER.GetUserOnlineState(uid)
if online { if online {
onlineState = proto.FriendOnlineState_FRIEND_ONLINE_STATE_ONLINE onlineState = proto.FriendOnlineState_FRIEND_ONLINE_STATE_ONLINE
} else { } else {
onlineState = proto.FriendOnlineState_FRIEND_ONLINE_STATE_DISCONNECT onlineState = proto.FriendOnlineState_FRIEND_ONLINE_STATE_DISCONNECT
} }
friendPlayer := USER_MANAGER.LoadTempOfflineUserSync(uid)
if friendPlayer == nil {
logger.Error("target player is nil, uid: %v", player.PlayerID)
continue
}
friendBrief := &proto.FriendBrief{ friendBrief := &proto.FriendBrief{
Uid: friendPlayer.PlayerID, Uid: friendPlayer.PlayerID,
Nickname: friendPlayer.NickName, Nickname: friendPlayer.NickName,
@@ -238,13 +251,58 @@ func (g *GameManager) AskAddFriendReq(player *model.Player, payloadMsg pb.Messag
req := payloadMsg.(*proto.AskAddFriendReq) req := payloadMsg.(*proto.AskAddFriendReq)
targetUid := req.TargetUid targetUid := req.TargetUid
// TODO 同步阻塞待优化 askAddFriendRsp := &proto.AskAddFriendRsp{
targetPlayerOnline := USER_MANAGER.GetUserOnlineState(targetUid) TargetUid: targetUid,
targetPlayer := USER_MANAGER.LoadTempOfflineUserSync(targetUid) }
g.SendMsg(cmd.AskAddFriendRsp, player.PlayerID, player.ClientSeq, askAddFriendRsp)
targetPlayer := USER_MANAGER.GetOnlineUser(targetUid)
if targetPlayer == nil { if targetPlayer == nil {
logger.Error("apply add friend target player is nil, uid: %v", player.PlayerID) // 非本地玩家
if USER_MANAGER.GetRemoteUserOnlineState(targetUid) {
// 远程在线玩家
gsAppId := USER_MANAGER.GetRemoteUserGsAppId(targetUid)
MESSAGE_QUEUE.SendToGs(gsAppId, &mq.NetMsg{
MsgType: mq.MsgTypeServer,
EventId: mq.ServerAddFriendNotify,
ServerMsg: &mq.ServerMsg{
AddFriendInfo: &mq.AddFriendInfo{
OriginInfo: &mq.OriginInfo{
CmdName: "AskAddFriendReq",
UserId: player.PlayerID,
},
TargetUserId: targetUid,
ApplyPlayerOnlineInfo: &mq.UserBaseInfo{
UserId: player.PlayerID,
Nickname: player.NickName,
PlayerLevel: player.PropertiesMap[constant.PlayerPropertyConst.PROP_PLAYER_LEVEL],
NameCardId: player.NameCard,
Signature: player.Signature,
HeadImageId: player.HeadImage,
WorldLevel: player.PropertiesMap[constant.PlayerPropertyConst.PROP_PLAYER_WORLD_LEVEL],
},
},
},
})
} else {
// 全服离线玩家
targetPlayer, _, _ := USER_MANAGER.LoadGlobalPlayer(targetUid)
if targetPlayer == nil {
logger.Error("apply add friend target player is nil, uid: %v", targetUid)
return
}
_, applyExist := targetPlayer.FriendApplyList[player.PlayerID]
_, friendExist := targetPlayer.FriendList[player.PlayerID]
if applyExist || friendExist {
logger.Error("friend or apply already exist, uid: %v", player.PlayerID)
return
}
targetPlayer.FriendApplyList[player.PlayerID] = true
USER_MANAGER.SaveTempOfflineUser(targetPlayer)
}
return return
} }
_, applyExist := targetPlayer.FriendApplyList[player.PlayerID] _, applyExist := targetPlayer.FriendApplyList[player.PlayerID]
_, friendExist := targetPlayer.FriendList[player.PlayerID] _, friendExist := targetPlayer.FriendList[player.PlayerID]
if applyExist || friendExist { if applyExist || friendExist {
@@ -253,43 +311,26 @@ func (g *GameManager) AskAddFriendReq(player *model.Player, payloadMsg pb.Messag
} }
targetPlayer.FriendApplyList[player.PlayerID] = true targetPlayer.FriendApplyList[player.PlayerID] = true
if targetPlayerOnline { // 目标玩家在线则通知
askAddFriendNotify := &proto.AskAddFriendNotify{ askAddFriendNotify := &proto.AskAddFriendNotify{
TargetUid: player.PlayerID, TargetUid: player.PlayerID,
}
askAddFriendNotify.TargetFriendBrief = &proto.FriendBrief{
Uid: player.PlayerID,
Nickname: player.NickName,
Level: player.PropertiesMap[constant.PlayerPropertyConst.PROP_PLAYER_LEVEL],
ProfilePicture: &proto.ProfilePicture{AvatarId: player.HeadImage},
WorldLevel: player.PropertiesMap[constant.PlayerPropertyConst.PROP_PLAYER_WORLD_LEVEL],
Signature: player.Signature,
OnlineState: proto.FriendOnlineState_FRIEND_ONLINE_STATE_ONLINE,
IsMpModeAvailable: true,
LastActiveTime: player.OfflineTime,
NameCardId: player.NameCard,
Param: (uint32(time.Now().Unix()) - player.OfflineTime) / 3600 / 24,
IsGameSource: true,
PlatformType: proto.PlatformType_PLATFORM_TYPE_PC,
}
g.SendMsg(cmd.AskAddFriendNotify, targetPlayer.PlayerID, targetPlayer.ClientSeq, askAddFriendNotify)
} }
askAddFriendNotify.TargetFriendBrief = &proto.FriendBrief{
askAddFriendRsp := &proto.AskAddFriendRsp{ Uid: player.PlayerID,
TargetUid: targetUid, Nickname: player.NickName,
Level: player.PropertiesMap[constant.PlayerPropertyConst.PROP_PLAYER_LEVEL],
ProfilePicture: &proto.ProfilePicture{AvatarId: player.HeadImage},
WorldLevel: player.PropertiesMap[constant.PlayerPropertyConst.PROP_PLAYER_WORLD_LEVEL],
Signature: player.Signature,
OnlineState: proto.FriendOnlineState_FRIEND_ONLINE_STATE_ONLINE,
IsMpModeAvailable: true,
LastActiveTime: player.OfflineTime,
NameCardId: player.NameCard,
Param: (uint32(time.Now().Unix()) - player.OfflineTime) / 3600 / 24,
IsGameSource: true,
PlatformType: proto.PlatformType_PLATFORM_TYPE_PC,
} }
g.SendMsg(cmd.AskAddFriendRsp, player.PlayerID, player.ClientSeq, askAddFriendRsp) g.SendMsg(cmd.AskAddFriendNotify, targetPlayer.PlayerID, targetPlayer.ClientSeq, askAddFriendNotify)
}
func (g *GameManager) AddFriend(player *model.Player, targetUid uint32) {
player.FriendList[targetUid] = true
// TODO 同步阻塞待优化
targetPlayer := USER_MANAGER.LoadTempOfflineUserSync(targetUid)
if targetPlayer == nil {
logger.Error("agree friend apply target player is nil, uid: %v", player.PlayerID)
return
}
targetPlayer.FriendList[player.PlayerID] = true
} }
func (g *GameManager) DealAddFriendReq(player *model.Player, payloadMsg pb.Message) { func (g *GameManager) DealAddFriendReq(player *model.Player, payloadMsg pb.Message) {
@@ -298,8 +339,12 @@ func (g *GameManager) DealAddFriendReq(player *model.Player, payloadMsg pb.Messa
targetUid := req.TargetUid targetUid := req.TargetUid
result := req.DealAddFriendResult result := req.DealAddFriendResult
agree := false
if result == proto.DealAddFriendResultType_DEAL_ADD_FRIEND_RESULT_TYPE_ACCEPT { if result == proto.DealAddFriendResultType_DEAL_ADD_FRIEND_RESULT_TYPE_ACCEPT {
g.AddFriend(player, targetUid) agree = true
}
if agree {
player.FriendList[targetUid] = true
} }
delete(player.FriendApplyList, targetUid) delete(player.FriendApplyList, targetUid)
@@ -308,6 +353,44 @@ func (g *GameManager) DealAddFriendReq(player *model.Player, payloadMsg pb.Messa
DealAddFriendResult: result, DealAddFriendResult: result,
} }
g.SendMsg(cmd.DealAddFriendRsp, player.PlayerID, player.ClientSeq, dealAddFriendRsp) g.SendMsg(cmd.DealAddFriendRsp, player.PlayerID, player.ClientSeq, dealAddFriendRsp)
if agree {
targetPlayer := USER_MANAGER.GetOnlineUser(targetUid)
if targetPlayer == nil {
// 非本地玩家
if USER_MANAGER.GetRemoteUserOnlineState(targetUid) {
// 远程在线玩家
gsAppId := USER_MANAGER.GetRemoteUserGsAppId(targetUid)
MESSAGE_QUEUE.SendToGs(gsAppId, &mq.NetMsg{
MsgType: mq.MsgTypeServer,
EventId: mq.ServerAddFriendNotify,
ServerMsg: &mq.ServerMsg{
AddFriendInfo: &mq.AddFriendInfo{
OriginInfo: &mq.OriginInfo{
CmdName: "DealAddFriendReq",
UserId: player.PlayerID,
},
TargetUserId: targetUid,
ApplyPlayerOnlineInfo: &mq.UserBaseInfo{
UserId: player.PlayerID,
},
},
},
})
} else {
// 全服离线玩家
targetPlayer, _, _ := USER_MANAGER.LoadGlobalPlayer(targetUid)
if targetPlayer == nil {
logger.Error("apply add friend target player is nil, uid: %v", targetUid)
return
}
targetPlayer.FriendList[player.PlayerID] = true
USER_MANAGER.SaveTempOfflineUser(targetPlayer)
}
return
}
targetPlayer.FriendList[player.PlayerID] = true
}
} }
func (g *GameManager) GetOnlinePlayerListReq(player *model.Player, payloadMsg pb.Message) { func (g *GameManager) GetOnlinePlayerListReq(player *model.Player, payloadMsg pb.Message) {
@@ -315,6 +398,7 @@ func (g *GameManager) GetOnlinePlayerListReq(player *model.Player, payloadMsg pb
count := 0 count := 0
onlinePlayerList := make([]*model.Player, 0) onlinePlayerList := make([]*model.Player, 0)
// 优先获取本地的在线玩家
for _, onlinePlayer := range USER_MANAGER.GetAllOnlineUserList() { for _, onlinePlayer := range USER_MANAGER.GetAllOnlineUserList() {
if onlinePlayer.PlayerID == player.PlayerID { if onlinePlayer.PlayerID == player.PlayerID {
continue continue
@@ -325,6 +409,19 @@ func (g *GameManager) GetOnlinePlayerListReq(player *model.Player, payloadMsg pb
break break
} }
} }
if count < 50 {
// 本地不够时获取远程的在线玩家
for _, onlinePlayer := range USER_MANAGER.GetRemoteOnlineUserList(50 - count) {
if onlinePlayer.PlayerID == player.PlayerID {
continue
}
onlinePlayerList = append(onlinePlayerList, onlinePlayer)
count++
if count >= 50 {
break
}
}
}
getOnlinePlayerListRsp := &proto.GetOnlinePlayerListRsp{ getOnlinePlayerListRsp := &proto.GetOnlinePlayerListRsp{
PlayerInfoList: make([]*proto.OnlinePlayerInfo, 0), PlayerInfoList: make([]*proto.OnlinePlayerInfo, 0),
@@ -344,11 +441,6 @@ func (g *GameManager) GetOnlinePlayerInfoReq(player *model.Player, payloadMsg pb
return return
} }
// TODO 删除我
g.JoinPlayerSceneReq(player, &proto.JoinPlayerSceneReq{
TargetUid: targetUid.TargetUid,
})
if USER_MANAGER.GetUserOnlineState(targetUid.TargetUid) { if USER_MANAGER.GetUserOnlineState(targetUid.TargetUid) {
g.SendMsg(cmd.GetOnlinePlayerInfoRsp, player.PlayerID, player.ClientSeq, &proto.GetOnlinePlayerInfoRsp{ g.SendMsg(cmd.GetOnlinePlayerInfoRsp, player.PlayerID, player.ClientSeq, &proto.GetOnlinePlayerInfoRsp{
TargetUid: targetUid.TargetUid, TargetUid: targetUid.TargetUid,
@@ -358,9 +450,9 @@ func (g *GameManager) GetOnlinePlayerInfoReq(player *model.Player, payloadMsg pb
} }
if USER_MANAGER.GetRemoteUserOnlineState(targetUid.TargetUid) { if USER_MANAGER.GetRemoteUserOnlineState(targetUid.TargetUid) {
gsAppId := USER_MANAGER.GetRemoteUserGsAppId(targetUid.TargetUid) gsAppId := USER_MANAGER.GetRemoteUserGsAppId(targetUid.TargetUid)
g.messageQueue.SendToGs(gsAppId, &mq.NetMsg{ MESSAGE_QUEUE.SendToGs(gsAppId, &mq.NetMsg{
MsgType: mq.MsgTypeServer, MsgType: mq.MsgTypeServer,
EventId: mq.ServerGetUserBaseInfoReq, EventId: mq.ServerUserBaseInfoReq,
ServerMsg: &mq.ServerMsg{ ServerMsg: &mq.ServerMsg{
UserBaseInfo: &mq.UserBaseInfo{ UserBaseInfo: &mq.UserBaseInfo{
OriginInfo: &mq.OriginInfo{ OriginInfo: &mq.OriginInfo{
@@ -378,6 +470,11 @@ func (g *GameManager) GetOnlinePlayerInfoReq(player *model.Player, payloadMsg pb
func (g *GameManager) PacketOnlinePlayerInfo(player *model.Player) *proto.OnlinePlayerInfo { func (g *GameManager) PacketOnlinePlayerInfo(player *model.Player) *proto.OnlinePlayerInfo {
world := WORLD_MANAGER.GetWorldByID(player.WorldId) world := WORLD_MANAGER.GetWorldByID(player.WorldId)
worldPlayerNum := uint32(1)
// TODO 远程玩家的世界内人数
if world != nil {
worldPlayerNum = uint32(world.GetWorldPlayerNum())
}
onlinePlayerInfo := &proto.OnlinePlayerInfo{ onlinePlayerInfo := &proto.OnlinePlayerInfo{
Uid: player.PlayerID, Uid: player.PlayerID,
Nickname: player.NickName, Nickname: player.NickName,
@@ -386,7 +483,138 @@ func (g *GameManager) PacketOnlinePlayerInfo(player *model.Player) *proto.Online
NameCardId: player.NameCard, NameCardId: player.NameCard,
Signature: player.Signature, Signature: player.Signature,
ProfilePicture: &proto.ProfilePicture{AvatarId: player.HeadImage}, ProfilePicture: &proto.ProfilePicture{AvatarId: player.HeadImage},
CurPlayerNumInWorld: uint32(world.GetWorldPlayerNum()), CurPlayerNumInWorld: worldPlayerNum,
} }
return onlinePlayerInfo 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) {
switch addFriendInfo.OriginInfo.CmdName {
case "AskAddFriendReq":
targetPlayer := USER_MANAGER.GetOnlineUser(addFriendInfo.TargetUserId)
if targetPlayer == nil {
logger.Error("player is nil, uid: %v", addFriendInfo.TargetUserId)
return
}
_, applyExist := targetPlayer.FriendApplyList[addFriendInfo.ApplyPlayerOnlineInfo.UserId]
_, friendExist := targetPlayer.FriendList[addFriendInfo.ApplyPlayerOnlineInfo.UserId]
if applyExist || friendExist {
logger.Error("friend or apply already exist, uid: %v", addFriendInfo.ApplyPlayerOnlineInfo.UserId)
return
}
targetPlayer.FriendApplyList[addFriendInfo.ApplyPlayerOnlineInfo.UserId] = true
// 目标玩家在线则通知
askAddFriendNotify := &proto.AskAddFriendNotify{
TargetUid: addFriendInfo.ApplyPlayerOnlineInfo.UserId,
}
askAddFriendNotify.TargetFriendBrief = &proto.FriendBrief{
Uid: addFriendInfo.ApplyPlayerOnlineInfo.UserId,
Nickname: addFriendInfo.ApplyPlayerOnlineInfo.Nickname,
Level: addFriendInfo.ApplyPlayerOnlineInfo.PlayerLevel,
ProfilePicture: &proto.ProfilePicture{AvatarId: addFriendInfo.ApplyPlayerOnlineInfo.HeadImageId},
WorldLevel: addFriendInfo.ApplyPlayerOnlineInfo.WorldLevel,
Signature: addFriendInfo.ApplyPlayerOnlineInfo.Signature,
OnlineState: proto.FriendOnlineState_FRIEND_ONLINE_STATE_ONLINE,
IsMpModeAvailable: true,
LastActiveTime: 0,
NameCardId: addFriendInfo.ApplyPlayerOnlineInfo.NameCardId,
Param: 0,
IsGameSource: true,
PlatformType: proto.PlatformType_PLATFORM_TYPE_PC,
}
g.SendMsg(cmd.AskAddFriendNotify, targetPlayer.PlayerID, targetPlayer.ClientSeq, askAddFriendNotify)
case "DealAddFriendReq":
targetPlayer := USER_MANAGER.GetOnlineUser(addFriendInfo.TargetUserId)
if targetPlayer == nil {
logger.Error("player is nil, uid: %v", addFriendInfo.TargetUserId)
return
}
targetPlayer.FriendList[addFriendInfo.ApplyPlayerOnlineInfo.UserId] = true
}
}

View File

@@ -206,6 +206,10 @@ func (g *GameManager) PacketSceneTeamUpdateNotify(world *World) *proto.SceneTeam
empty := new(proto.AbilitySyncStateInfo) empty := new(proto.AbilitySyncStateInfo)
for _, worldAvatar := range world.GetWorldAvatarList() { for _, worldAvatar := range world.GetWorldAvatarList() {
worldPlayer := USER_MANAGER.GetOnlineUser(worldAvatar.uid) worldPlayer := USER_MANAGER.GetOnlineUser(worldAvatar.uid)
if worldPlayer == nil {
logger.Error("player is nil, uid: %v", worldAvatar.uid)
continue
}
worldPlayerScene := world.GetSceneById(worldPlayer.SceneId) worldPlayerScene := world.GetSceneById(worldPlayer.SceneId)
worldPlayerAvatar := worldPlayer.AvatarMap[worldAvatar.avatarId] worldPlayerAvatar := worldPlayer.AvatarMap[worldAvatar.avatarId]
equipIdList := make([]uint32, 0) equipIdList := make([]uint32, 0)

View File

@@ -112,7 +112,7 @@ type World struct {
chatMsgList []*proto.ChatInfo // 世界聊天消息列表 chatMsgList []*proto.ChatInfo // 世界聊天消息列表
aoiManager *aoi.AoiManager // 当前世界地图的aoi管理器 aoiManager *aoi.AoiManager // 当前世界地图的aoi管理器
playerFirstEnterMap map[uint32]int64 // 玩家第一次进入世界的时间 key:uid value:进入时间 playerFirstEnterMap map[uint32]int64 // 玩家第一次进入世界的时间 key:uid value:进入时间
waitEnterPlayerMap map[uint32]int64 // 等待进入世界的列表 key:uid value:开始时间 waitEnterPlayerMap map[uint32]int64 // 进入世界的玩家等待列表 key:uid value:开始时间
multiplayerTeam *MultiplayerTeam multiplayerTeam *MultiplayerTeam
peerList []*model.Player // 玩家编号列表 peerList []*model.Player // 玩家编号列表
} }
@@ -701,7 +701,7 @@ func (s *Scene) CreateEntityAvatar(player *model.Player, avatarId uint32) uint32
if avatarId == s.world.GetPlayerActiveAvatarId(player) { if avatarId == s.world.GetPlayerActiveAvatarId(player) {
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))
} }
GAME_MANAGER.messageQueue.SendToFight(s.world.owner.FightAppId, &mq.NetMsg{ MESSAGE_QUEUE.SendToFight(s.world.owner.FightAppId, &mq.NetMsg{
MsgType: mq.MsgTypeFight, MsgType: mq.MsgTypeFight,
EventId: mq.FightRoutineAddEntity, EventId: mq.FightRoutineAddEntity,
FightMsg: &mq.FightMsg{ FightMsg: &mq.FightMsg{
@@ -751,7 +751,7 @@ func (s *Scene) CreateEntityMonster(pos *model.Vector, level uint8, fightProp ma
} }
s.entityMap[entity.id] = entity 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))
GAME_MANAGER.messageQueue.SendToFight(s.world.owner.FightAppId, &mq.NetMsg{ MESSAGE_QUEUE.SendToFight(s.world.owner.FightAppId, &mq.NetMsg{
MsgType: mq.MsgTypeFight, MsgType: mq.MsgTypeFight,
EventId: mq.FightRoutineAddEntity, EventId: mq.FightRoutineAddEntity,
FightMsg: &mq.FightMsg{ FightMsg: &mq.FightMsg{
@@ -901,7 +901,7 @@ func (s *Scene) DestroyEntity(entityId uint32) {
} }
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) delete(s.entityMap, entityId)
GAME_MANAGER.messageQueue.SendToFight(s.world.owner.FightAppId, &mq.NetMsg{ MESSAGE_QUEUE.SendToFight(s.world.owner.FightAppId, &mq.NetMsg{
MsgType: mq.MsgTypeFight, MsgType: mq.MsgTypeFight,
EventId: mq.FightRoutineDelEntity, EventId: mq.FightRoutineDelEntity,
FightMsg: &mq.FightMsg{ FightMsg: &mq.FightMsg{

View File

@@ -60,7 +60,6 @@ type LogInfo struct {
FuncName string FuncName string
Line int Line int
GoroutineId string GoroutineId string
Stack string
} }
func InitLogger(appName string) { func InitLogger(appName string) {
@@ -81,32 +80,29 @@ func (l *Logger) doLog() {
logInfo := <-l.LogInfoChan logInfo := <-l.LogInfoChan
timeNow := time.Now() timeNow := time.Now()
timeNowStr := timeNow.Format("2006-01-02 15:04:05.000") timeNowStr := timeNow.Format("2006-01-02 15:04:05.000")
logHeader := CYAN + "[" + timeNowStr + "]" + RESET + " " logStr := CYAN + "[" + timeNowStr + "]" + RESET + " "
if logInfo.Level == DEBUG { if logInfo.Level == DEBUG {
logHeader += BLUE + "[" + l.getLevelStr(logInfo.Level) + "]" + RESET + " " logStr += BLUE + "[" + l.getLevelStr(logInfo.Level) + "]" + RESET
} else if logInfo.Level == INFO { } else if logInfo.Level == INFO {
logHeader += GREEN + "[" + l.getLevelStr(logInfo.Level) + "]" + RESET + " " logStr += GREEN + "[" + l.getLevelStr(logInfo.Level) + "]" + RESET
} else if logInfo.Level == WARN { } else if logInfo.Level == WARN {
logHeader += YELLOW + "[" + l.getLevelStr(logInfo.Level) + "]" + RESET + " " logStr += YELLOW + "[" + l.getLevelStr(logInfo.Level) + "]" + RESET
} else if logInfo.Level == ERROR { } else if logInfo.Level == ERROR {
logHeader += RED + "[" + l.getLevelStr(logInfo.Level) + "]" + RESET + " " logStr += RED + "[" + l.getLevelStr(logInfo.Level) + "]" + RESET
}
if logInfo.Level == ERROR {
logStr += " " + RED + fmt.Sprintf(logInfo.Msg, logInfo.Param...) + RESET + " "
} else {
logStr += " " + fmt.Sprintf(logInfo.Msg, logInfo.Param...) + " "
} }
if l.Track { if l.Track {
logHeader += MAGENTA + "[" + logStr += MAGENTA + "[" +
logInfo.FileName + ":" + strconv.Itoa(logInfo.Line) + " " + logInfo.FileName + ":" + strconv.Itoa(logInfo.Line) + " " +
logInfo.FuncName + "()" + " " + logInfo.FuncName + "()" + " " +
"goroutine:" + logInfo.GoroutineId + "goroutine:" + logInfo.GoroutineId +
"]" + RESET + " " "]" + RESET
}
logStr := logHeader
if logInfo.Level == ERROR {
logStr += RED + fmt.Sprintf(logInfo.Msg, logInfo.Param...) + RESET + "\n"
} else {
logStr += fmt.Sprintf(logInfo.Msg, logInfo.Param...) + "\n"
}
if logInfo.Stack != "" {
logStr += logInfo.Stack
} }
logStr += "\n"
if l.Mode == CONSOLE { if l.Mode == CONSOLE {
log.Print(logStr) log.Print(logStr)
} else if l.Mode == FILE { } else if l.Mode == FILE {
@@ -222,22 +218,6 @@ func Error(msg string, param ...any) {
LOG.LogInfoChan <- logInfo LOG.LogInfoChan <- logInfo
} }
func ErrorStack(msg string, param ...any) {
if LOG.Level > ERROR {
return
}
logInfo := new(LogInfo)
logInfo.Level = ERROR
logInfo.Msg = msg
logInfo.Param = param
if LOG.Track {
logInfo.FileName, logInfo.Line, logInfo.FuncName = LOG.getLineFunc()
logInfo.GoroutineId = LOG.getGoroutineId()
logInfo.Stack = Stack()
}
LOG.LogInfoChan <- logInfo
}
func (l *Logger) getLevelInt(level string) (ret int) { func (l *Logger) getLevelInt(level string) (ret int) {
switch level { switch level {
case "DEBUG": case "DEBUG":