修改聊天和登录信息的数据库结构

This commit is contained in:
flswld
2023-02-12 16:08:56 +08:00
parent 15199d31e8
commit 36a150c9bb
17 changed files with 171 additions and 118 deletions

View File

@@ -47,9 +47,7 @@ func NewController(dao *dao.Dao, discovery *rpc.DiscoveryClient) (r *Controller)
func (c *Controller) authorize() gin.HandlerFunc { func (c *Controller) authorize() gin.HandlerFunc {
return func(context *gin.Context) { return func(context *gin.Context) {
// TODO auth token或其他验证方式 if context.Query("key") == "flswld" {
ok := true
if ok {
context.Next() context.Next()
return return
} }
@@ -80,10 +78,10 @@ func (c *Controller) registerRouter() {
{ {
// 调度 // 调度
// dispatchosglobal.yuanshen.com // dispatchosglobal.yuanshen.com
engine.GET("/query_security_file", c.query_security_file) engine.GET("/query_security_file", c.querySecurityFile)
engine.GET("/query_region_list", c.query_region_list) engine.GET("/query_region_list", c.queryRegionList)
// osusadispatch.yuanshen.com // osusadispatch.yuanshen.com
engine.GET("/query_cur_region", c.query_cur_region) engine.GET("/query_cur_region", c.queryCurRegion)
} }
{ {
// 登录 // 登录

View File

@@ -18,7 +18,7 @@ import (
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
) )
func (c *Controller) query_security_file(context *gin.Context) { func (c *Controller) querySecurityFile(context *gin.Context) {
// 很早以前2.6.0版本的时候抓包为了完美还原写的 不清楚有没有副作用暂时不要了 // 很早以前2.6.0版本的时候抓包为了完美还原写的 不清楚有没有副作用暂时不要了
return return
file, err := os.ReadFile("static/security_file") file, err := os.ReadFile("static/security_file")
@@ -30,7 +30,7 @@ func (c *Controller) query_security_file(context *gin.Context) {
_, _ = context.Writer.WriteString(string(file)) _, _ = context.Writer.WriteString(string(file))
} }
func (c *Controller) query_region_list(context *gin.Context) { func (c *Controller) queryRegionList(context *gin.Context) {
context.Header("Content-type", "text/html; charset=UTF-8") context.Header("Content-type", "text/html; charset=UTF-8")
regionListBase64 := region.GetRegionListBase64(c.ec2b) regionListBase64 := region.GetRegionListBase64(c.ec2b)
_, _ = context.Writer.WriteString(regionListBase64) _, _ = context.Writer.WriteString(regionListBase64)
@@ -66,7 +66,7 @@ func (c *Controller) getClientVersionByName(versionName string) (int, string) {
return version, strconv.Itoa(version) return version, strconv.Itoa(version)
} }
func (c *Controller) query_cur_region(context *gin.Context) { func (c *Controller) queryCurRegion(context *gin.Context) {
rspError := func() { rspError := func() {
rspContentError := "CAESGE5vdCBGb3VuZCB2ZXJzaW9uIGNvbmZpZw==" rspContentError := "CAESGE5vdCBGb3VuZCB2ZXJzaW9uIGNvbmZpZw=="
rspSignError := "TW9yZSBsb3ZlIGZvciBVQSBQYXRjaCBwbGF5ZXJz" rspSignError := "TW9yZSBsb3ZlIGZvciBVQSBQYXRjaCBwbGF5ZXJz"

View File

@@ -42,29 +42,29 @@ func (c *Controller) gateTokenVerify(context *gin.Context) {
verifyFail(0) verifyFail(0)
return return
} }
account, err := c.dao.QueryAccountByField("accountID", accountId) account, err := c.dao.QueryAccountByField("AccountID", accountId)
if err != nil || account == nil { if err != nil || account == nil {
verifyFail(0) verifyFail(0)
return return
} }
if tokenVerifyReq.AccountToken != account.ComboToken { if tokenVerifyReq.AccountToken != account.ComboToken {
verifyFail(uint32(account.PlayerID)) verifyFail(account.PlayerID)
return return
} }
if account.ComboTokenUsed { if account.ComboTokenUsed {
verifyFail(uint32(account.PlayerID)) verifyFail(account.PlayerID)
return return
} }
_, err = c.dao.UpdateAccountFieldByFieldName("accountID", account.AccountID, "comboTokenUsed", true) _, err = c.dao.UpdateAccountFieldByFieldName("AccountID", account.AccountID, "ComboTokenUsed", true)
if err != nil { if err != nil {
verifyFail(uint32(account.PlayerID)) verifyFail(account.PlayerID)
return return
} }
context.JSON(http.StatusOK, &TokenVerifyRsp{ context.JSON(http.StatusOK, &TokenVerifyRsp{
Valid: true, Valid: true,
Forbid: account.Forbid, Forbid: account.Forbid,
ForbidEndTime: uint32(account.ForbidEndTime), ForbidEndTime: account.ForbidEndTime,
PlayerID: uint32(account.PlayerID), PlayerID: account.PlayerID,
}) })
} }
@@ -85,7 +85,7 @@ func (c *Controller) gateTokenReset(context *gin.Context) {
}) })
return return
} }
_, err = c.dao.UpdateAccountFieldByFieldName("playerID", req.PlayerId, "comboTokenUsed", false) _, err = c.dao.UpdateAccountFieldByFieldName("PlayerID", req.PlayerId, "ComboTokenUsed", false)
if err != nil { if err != nil {
context.JSON(http.StatusOK, &TokenResetRsp{ context.JSON(http.StatusOK, &TokenResetRsp{
Result: false, Result: false,

View File

@@ -92,8 +92,7 @@ func (c *Controller) apiLogin(context *gin.Context) {
context.JSON(http.StatusOK, responseData) context.JSON(http.StatusOK, responseData)
return return
} }
// TODO SDK账号登陆 account, err := c.dao.QueryAccountByField("Username", username)
account, err := c.dao.QueryAccountByField("username", username)
if err != nil { if err != nil {
logger.Error("query account from db error: %v", err) logger.Error("query account from db error: %v", err)
return return
@@ -141,14 +140,14 @@ func (c *Controller) apiLogin(context *gin.Context) {
} }
// 生成新的token // 生成新的token
account.Token = base64.StdEncoding.EncodeToString(random.GetRandomByte(24)) account.Token = base64.StdEncoding.EncodeToString(random.GetRandomByte(24))
_, err = c.dao.UpdateAccountFieldByFieldName("accountID", account.AccountID, "token", account.Token) _, err = c.dao.UpdateAccountFieldByFieldName("AccountID", account.AccountID, "Token", account.Token)
if err != nil { if err != nil {
responseData.Retcode = -201 responseData.Retcode = -201
responseData.Message = "服务器内部错误:-4" responseData.Message = "服务器内部错误:-4"
context.JSON(http.StatusOK, responseData) context.JSON(http.StatusOK, responseData)
return return
} }
_, err = c.dao.UpdateAccountFieldByFieldName("accountID", account.AccountID, "tokenCreateTime", time.Now().UnixMilli()) _, err = c.dao.UpdateAccountFieldByFieldName("AccountID", account.AccountID, "TokenCreateTime", time.Now().UnixMilli())
if err != nil { if err != nil {
responseData.Retcode = -201 responseData.Retcode = -201
responseData.Message = "服务器内部错误:-5" responseData.Message = "服务器内部错误:-5"
@@ -174,7 +173,7 @@ func (c *Controller) apiVerify(context *gin.Context) {
logger.Error("parse uid error: %v", err) logger.Error("parse uid error: %v", err)
return return
} }
account, err := c.dao.QueryAccountByField("accountID", uid) account, err := c.dao.QueryAccountByField("AccountID", uid)
if err != nil { if err != nil {
logger.Error("query account from db error: %v", err) logger.Error("query account from db error: %v", err)
return return
@@ -223,7 +222,7 @@ func (c *Controller) v2Login(context *gin.Context) {
return return
} }
responseData := api.NewComboTokenRsp() responseData := api.NewComboTokenRsp()
account, err := c.dao.QueryAccountByField("accountID", uid) account, err := c.dao.QueryAccountByField("AccountID", uid)
if account == nil || account.Token != loginData.Token { if account == nil || account.Token != loginData.Token {
responseData.Retcode = -201 responseData.Retcode = -201
responseData.Message = "token错误" responseData.Message = "token错误"
@@ -232,14 +231,14 @@ func (c *Controller) v2Login(context *gin.Context) {
} }
// 生成新的comboToken // 生成新的comboToken
account.ComboToken = random.GetRandomByteHexStr(20) account.ComboToken = random.GetRandomByteHexStr(20)
_, err = c.dao.UpdateAccountFieldByFieldName("accountID", account.AccountID, "comboToken", account.ComboToken) _, err = c.dao.UpdateAccountFieldByFieldName("AccountID", account.AccountID, "ComboToken", account.ComboToken)
if err != nil { if err != nil {
responseData.Retcode = -201 responseData.Retcode = -201
responseData.Message = "服务器内部错误:-1" responseData.Message = "服务器内部错误:-1"
context.JSON(http.StatusOK, responseData) context.JSON(http.StatusOK, responseData)
return return
} }
_, err = c.dao.UpdateAccountFieldByFieldName("accountID", account.AccountID, "comboTokenUsed", false) _, err = c.dao.UpdateAccountFieldByFieldName("AccountID", account.AccountID, "ComboTokenUsed", false)
if err != nil { if err != nil {
responseData.Retcode = -201 responseData.Retcode = -201
responseData.Message = "服务器内部错误:-2" responseData.Message = "服务器内部错误:-2"

View File

@@ -8,26 +8,26 @@ const RedisPlayerKeyPrefix = "HK4E"
const ( const (
AccountIdRedisKey = "AccountId" AccountIdRedisKey = "AccountId"
AccountIdBegin uint64 = 10000 AccountIdBegin uint32 = 10000
YuanShenUidRedisKey = "YuanShenUid" YuanShenUidRedisKey = "YuanShenUid"
YuanShenUidBegin uint64 = 100000000 YuanShenUidBegin uint32 = 100000000
) )
func (d *Dao) GetNextAccountId() (uint64, error) { func (d *Dao) GetNextAccountId() (uint32, error) {
return d.redisInc(RedisPlayerKeyPrefix + ":" + AccountIdRedisKey) return d.redisInc(RedisPlayerKeyPrefix + ":" + AccountIdRedisKey)
} }
func (d *Dao) GetNextYuanShenUid() (uint64, error) { func (d *Dao) GetNextYuanShenUid() (uint32, error) {
return d.redisInc(RedisPlayerKeyPrefix + ":" + YuanShenUidRedisKey) return d.redisInc(RedisPlayerKeyPrefix + ":" + YuanShenUidRedisKey)
} }
func (d *Dao) redisInc(keyName string) (uint64, error) { func (d *Dao) redisInc(keyName string) (uint32, error) {
exist, err := d.redis.Exists(context.TODO(), keyName).Result() exist, err := d.redis.Exists(context.TODO(), keyName).Result()
if err != nil { if err != nil {
return 0, err return 0, err
} }
if exist == 0 { if exist == 0 {
var value uint64 = 0 var value uint32 = 0
if keyName == RedisPlayerKeyPrefix+":"+AccountIdRedisKey { if keyName == RedisPlayerKeyPrefix+":"+AccountIdRedisKey {
value = AccountIdBegin value = AccountIdBegin
} else if keyName == RedisPlayerKeyPrefix+":"+YuanShenUidRedisKey { } else if keyName == RedisPlayerKeyPrefix+":"+YuanShenUidRedisKey {
@@ -42,5 +42,5 @@ func (d *Dao) redisInc(keyName string) (uint64, error) {
if err != nil { if err != nil {
return 0, err return 0, err
} }
return uint64(id), nil return uint32(id), nil
} }

View File

@@ -4,14 +4,14 @@ import "go.mongodb.org/mongo-driver/bson/primitive"
type Account struct { type Account struct {
ID primitive.ObjectID `bson:"_id,omitempty"` ID primitive.ObjectID `bson:"_id,omitempty"`
AccountID uint64 `bson:"accountID"` AccountID uint32 `bson:"AccountID"`
Username string `bson:"username"` PlayerID uint32 `bson:"PlayerID"`
Password string `bson:"password"` Username string `bson:"Username"`
PlayerID uint64 `bson:"playerID"` Password string `bson:"Password"`
Token string `bson:"token"` Token string `bson:"Token"`
TokenCreateTime uint64 `bson:"tokenCreateTime"` // 毫秒时间戳 TokenCreateTime uint64 `bson:"TokenCreateTime"` // 毫秒时间戳
ComboToken string `bson:"comboToken"` ComboToken string `bson:"ComboToken"`
ComboTokenUsed bool `bson:"comboTokenUsed"` ComboTokenUsed bool `bson:"ComboTokenUsed"`
Forbid bool `bson:"forbid"` Forbid bool `bson:"Forbid"`
ForbidEndTime uint64 `bson:"forbidEndTime"` // 秒时间戳 ForbidEndTime uint32 `bson:"ForbidEndTime"` // 秒时间戳
} }

View File

@@ -6,19 +6,19 @@ import (
type ClientLog struct { type ClientLog struct {
ID primitive.ObjectID `json:"-" bson:"_id,omitempty"` ID primitive.ObjectID `json:"-" bson:"_id,omitempty"`
Auid string `json:"auid" bson:"auid"` Auid string `json:"auid" bson:"Auid"`
ClientIp string `json:"clientIp" bson:"clientIp"` ClientIp string `json:"clientIp" bson:"ClientIp"`
CpuInfo string `json:"cpuInfo" bson:"cpuInfo"` CpuInfo string `json:"cpuInfo" bson:"CpuInfo"`
DeviceModel string `json:"deviceModel" bson:"deviceModel"` DeviceModel string `json:"deviceModel" bson:"DeviceModel"`
DeviceName string `json:"deviceName" bson:"deviceName"` DeviceName string `json:"deviceName" bson:"DeviceName"`
GpuInfo string `json:"gpuInfo" bson:"gpuInfo"` GpuInfo string `json:"gpuInfo" bson:"GpuInfo"`
Guid string `json:"guid" bson:"guid"` Guid string `json:"guid" bson:"Guid"`
LogStr string `json:"logStr" bson:"logStr"` LogStr string `json:"logStr" bson:"LogStr"`
LogType string `json:"logType" bson:"logType"` LogType string `json:"logType" bson:"LogType"`
OperatingSystem string `json:"operatingSystem" bson:"operatingSystem"` OperatingSystem string `json:"operatingSystem" bson:"OperatingSystem"`
StackTrace string `json:"stackTrace" bson:"stackTrace"` StackTrace string `json:"stackTrace" bson:"StackTrace"`
Time string `json:"time" bson:"time"` Time string `json:"time" bson:"Time"`
Uid uint64 `json:"uid" bson:"uid"` Uid uint64 `json:"uid" bson:"Uid"`
UserName string `json:"userName" bson:"userName"` UserName string `json:"userName" bson:"UserName"`
Version string `json:"version" bson:"version"` Version string `json:"version" bson:"Version"`
} }

View File

@@ -11,7 +11,7 @@ type Service struct {
// UserPasswordChange 用户密码改变 // UserPasswordChange 用户密码改变
func (s *Service) UserPasswordChange(uid uint32) bool { func (s *Service) UserPasswordChange(uid uint32) bool {
// http登录态失效 // http登录态失效
_, err := s.dao.UpdateAccountFieldByFieldName("playerID", uid, "tokenCreateTime", 0) _, err := s.dao.UpdateAccountFieldByFieldName("PlayerID", uid, "TokenCreateTime", 0)
if err != nil { if err != nil {
return false return false
} }
@@ -22,11 +22,11 @@ func (s *Service) UserPasswordChange(uid uint32) bool {
// ForbidUser 封号 // ForbidUser 封号
func (s *Service) ForbidUser(uid uint32, forbidEndTime uint64) bool { func (s *Service) ForbidUser(uid uint32, forbidEndTime uint64) bool {
// 写入账号封禁信息 // 写入账号封禁信息
_, err := s.dao.UpdateAccountFieldByFieldName("playerID", uid, "forbid", true) _, err := s.dao.UpdateAccountFieldByFieldName("PlayerID", uid, "Forbid", true)
if err != nil { if err != nil {
return false return false
} }
_, err = s.dao.UpdateAccountFieldByFieldName("playerID", uid, "forbidEndTime", forbidEndTime) _, err = s.dao.UpdateAccountFieldByFieldName("PlayerID", uid, "ForbidEndTime", forbidEndTime)
if err != nil { if err != nil {
return false return false
} }
@@ -37,7 +37,7 @@ func (s *Service) ForbidUser(uid uint32, forbidEndTime uint64) bool {
// UnForbidUser 解封 // UnForbidUser 解封
func (s *Service) UnForbidUser(uid uint32) bool { func (s *Service) UnForbidUser(uid uint32) bool {
// 解除账号封禁 // 解除账号封禁
_, err := s.dao.UpdateAccountFieldByFieldName("playerID", uid, "forbid", false) _, err := s.dao.UpdateAccountFieldByFieldName("PlayerID", uid, "Forbid", false)
if err != nil { if err != nil {
return false return false
} }

View File

@@ -190,9 +190,12 @@ func (k *KcpConnectManager) sendMsgHandle() {
ServerMsg: serverMsg, ServerMsg: serverMsg,
}) })
} else if protoMsg.CmdId == cmd.ClientReconnectNotify { } else if protoMsg.CmdId == cmd.ClientReconnectNotify {
tokenResetRsp, err := httpclient.Post[controller.TokenResetRsp](config.CONF.Hk4e.LoginSdkUrl+"/gate/token/reset", &controller.TokenResetReq{ tokenResetRsp, err := httpclient.Post[controller.TokenResetRsp](
PlayerId: session.userId, config.CONF.Hk4e.LoginSdkUrl+"/gate/token/reset?key=flswld",
}, "") &controller.TokenResetReq{
PlayerId: session.userId,
},
"")
if err != nil { if err != nil {
logger.Error("reset token error: %v", err) logger.Error("reset token error: %v", err)
k.kcpEventInput <- &KcpEvent{ k.kcpEventInput <- &KcpEvent{
@@ -335,10 +338,13 @@ func (k *KcpConnectManager) getPlayerToken(req *proto.GetPlayerTokenReq, session
EventMessage: uint32(kcp.EnetLoginUnfinished), EventMessage: uint32(kcp.EnetLoginUnfinished),
} }
} }
tokenVerifyRsp, err := httpclient.Post[controller.TokenVerifyRsp](config.CONF.Hk4e.LoginSdkUrl+"/gate/token/verify", &controller.TokenVerifyReq{ tokenVerifyRsp, err := httpclient.Post[controller.TokenVerifyRsp](
AccountId: req.AccountUid, config.CONF.Hk4e.LoginSdkUrl+"/gate/token/verify?key=flswld",
AccountToken: req.AccountToken, &controller.TokenVerifyReq{
}, "") AccountId: req.AccountUid,
AccountToken: req.AccountToken,
},
"")
if err != nil { if err != nil {
logger.Error("verify token error: %v, account uid: %v", err, req.AccountUid) logger.Error("verify token error: %v, account uid: %v", err, req.AccountUid)
loginFailClose() loginFailClose()

View File

@@ -279,3 +279,24 @@ func (d *Dao) QueryChatMsgListByUid(uid uint32) ([]*model.ChatMsg, error) {
} }
return result, nil return result, nil
} }
func (d *Dao) ReadAndUpdateChatMsgByUid(uid uint32, targetUid uint32) error {
db := d.db.Collection("chat_msg")
_, err := db.UpdateOne(
context.TODO(),
bson.D{{"ToUid", uid}, {"Uid", targetUid}},
bson.D{{"$set", bson.D{{"IsRead", true}}}},
)
if err != nil {
return err
}
_, err = db.UpdateOne(
context.TODO(),
bson.D{{"Uid", uid}, {"ToUid", targetUid}},
bson.D{{"$set", bson.D{{"IsRead", true}}}},
)
if err != nil {
return err
}
return nil
}

View File

@@ -24,12 +24,14 @@ import (
) )
const ( const (
AiBaseUid = 10000 PlayerBaseUid = 100000000
AiName = "GM" MaxPlayerBaseUid = 200000000
AiSign = "快捷指令" AiBaseUid = 10000
BigWorldAiUid = 100 AiName = "GM"
BigWorldAiName = "小可爱" AiSign = "快捷指令"
BigWorldAiSign = "UnKownOwO" BigWorldAiUid = 100
BigWorldAiName = "小可爱"
BigWorldAiSign = "UnKownOwO"
) )
var GAME_MANAGER *GameManager = nil var GAME_MANAGER *GameManager = nil
@@ -271,7 +273,7 @@ func (g *GameManager) Close() {
// SendMsgToGate 发送消息给客户端 指定网关 // SendMsgToGate 发送消息给客户端 指定网关
func (g *GameManager) SendMsgToGate(cmdId uint16, userId uint32, clientSeq uint32, gateAppId string, payloadMsg pb.Message) { func (g *GameManager) SendMsgToGate(cmdId uint16, userId uint32, clientSeq uint32, gateAppId string, payloadMsg pb.Message) {
if userId < 100000000 { if userId < PlayerBaseUid {
return return
} }
if payloadMsg == nil { if payloadMsg == nil {
@@ -293,7 +295,7 @@ func (g *GameManager) SendMsgToGate(cmdId uint16, userId uint32, clientSeq uint3
// SendMsg 发送消息给客户端 // SendMsg 发送消息给客户端
func (g *GameManager) SendMsg(cmdId uint16, userId uint32, clientSeq uint32, payloadMsg pb.Message) { func (g *GameManager) SendMsg(cmdId uint16, userId uint32, clientSeq uint32, payloadMsg pb.Message) {
if userId < 100000000 { if userId < PlayerBaseUid {
return return
} }
if payloadMsg == nil { if payloadMsg == nil {

View File

@@ -74,7 +74,7 @@ func (l *LocalEventManager) LocalEventHandle(localEvent *LocalEvent) {
startTime := time.Now().UnixNano() startTime := time.Now().UnixNano()
playerList := make(PlayerLastSaveTimeSortList, 0) playerList := make(PlayerLastSaveTimeSortList, 0)
for _, player := range USER_MANAGER.playerMap { for _, player := range USER_MANAGER.playerMap {
if player.PlayerID < 100000000 { if player.PlayerID < PlayerBaseUid {
continue continue
} }
playerList = append(playerList, player) playerList = append(playerList, player)

View File

@@ -13,7 +13,7 @@ import (
) )
const ( const (
MaxMsgListLen = 1000 // 与某人的最大聊天记录条数 MaxMsgListLen = 100 // 与某人的最大聊天记录条数
) )
func (g *GameManager) PullRecentChatReq(player *model.Player, payloadMsg pb.Message) { func (g *GameManager) PullRecentChatReq(player *model.Player, payloadMsg pb.Message) {
@@ -84,9 +84,9 @@ func (g *GameManager) PullPrivateChatReq(player *model.Player, payloadMsg pb.Mes
// SendPrivateChat 发送私聊文本消息给玩家 // SendPrivateChat 发送私聊文本消息给玩家
func (g *GameManager) SendPrivateChat(player *model.Player, targetUid uint32, content any) { func (g *GameManager) SendPrivateChat(player *model.Player, targetUid uint32, content any) {
chatInfo := &proto.ChatInfo{ chatMsg := &model.ChatMsg{
Sequence: 0,
Time: uint32(time.Now().Unix()), Time: uint32(time.Now().Unix()),
Sequence: 101,
ToUid: targetUid, ToUid: targetUid,
Uid: player.PlayerID, Uid: player.PlayerID,
IsRead: false, IsRead: false,
@@ -95,24 +95,25 @@ func (g *GameManager) SendPrivateChat(player *model.Player, targetUid uint32, co
switch content.(type) { switch content.(type) {
case string: case string:
// 文本消息 // 文本消息
chatInfo.Content = &proto.ChatInfo_Text{ chatMsg.MsgType = model.ChatMsgTypeText
Text: content.(string), chatMsg.Text = content.(string)
}
case uint32: case uint32:
// 图标消息 // 图标消息
chatInfo.Content = &proto.ChatInfo_Icon{ chatMsg.MsgType = model.ChatMsgTypeIcon
Icon: content.(uint32), chatMsg.Icon = content.(uint32)
}
} }
chatMsg := g.ConvChatInfoToChatMsg(chatInfo)
// 写入db // 写入db
go USER_MANAGER.SaveUserChatMsgToDbSync(chatMsg) go USER_MANAGER.SaveUserChatMsgToDbSync(chatMsg)
// 消息加入自己的队列 // 消息加入自己的队列
msgList, exist := player.ChatMsgMap[targetUid] msgList, exist := player.ChatMsgMap[targetUid]
// 处理序号
if !exist { if !exist {
msgList = make([]*model.ChatMsg, 0) msgList = make([]*model.ChatMsg, 0)
chatMsg.Sequence = 101
} else {
chatMsg.Sequence = uint32(len(msgList)) + 101
} }
if len(msgList) > MaxMsgListLen { if len(msgList) > MaxMsgListLen {
msgList = msgList[1:] msgList = msgList[1:]
@@ -120,6 +121,8 @@ func (g *GameManager) SendPrivateChat(player *model.Player, targetUid uint32, co
msgList = append(msgList, chatMsg) msgList = append(msgList, chatMsg)
player.ChatMsgMap[targetUid] = msgList player.ChatMsgMap[targetUid] = msgList
chatInfo := g.ConvChatMsgToChatInfo(chatMsg)
privateChatNotify := &proto.PrivateChatNotify{ privateChatNotify := &proto.PrivateChatNotify{
ChatInfo: chatInfo, ChatInfo: chatInfo,
} }
@@ -213,6 +216,9 @@ func (g *GameManager) ReadPrivateChatReq(player *model.Player, payloadMsg pb.Mes
} }
player.ChatMsgMap[targetUid] = msgList player.ChatMsgMap[targetUid] = msgList
// 更新db
go USER_MANAGER.ReadAndUpdateUserChatMsgToDbSync(player.PlayerID, targetUid)
g.SendMsg(cmd.ReadPrivateChatRsp, player.PlayerID, player.ClientSeq, new(proto.ReadPrivateChatRsp)) g.SendMsg(cmd.ReadPrivateChatRsp, player.PlayerID, player.ClientSeq, new(proto.ReadPrivateChatRsp))
} }
@@ -261,13 +267,14 @@ func (g *GameManager) PlayerChatReq(player *model.Player, payloadMsg pb.Message)
func (g *GameManager) ConvChatInfoToChatMsg(chatInfo *proto.ChatInfo) (chatMsg *model.ChatMsg) { func (g *GameManager) ConvChatInfoToChatMsg(chatInfo *proto.ChatInfo) (chatMsg *model.ChatMsg) {
chatMsg = &model.ChatMsg{ chatMsg = &model.ChatMsg{
Time: chatInfo.Time, Sequence: chatInfo.Sequence,
ToUid: chatInfo.ToUid, Time: chatInfo.Time,
Uid: chatInfo.Uid, ToUid: chatInfo.ToUid,
IsRead: chatInfo.IsRead, Uid: chatInfo.Uid,
MsgType: 0, IsRead: chatInfo.IsRead,
Text: "", MsgType: 0,
Icon: 0, Text: "",
Icon: 0,
} }
switch chatInfo.Content.(type) { switch chatInfo.Content.(type) {
case *proto.ChatInfo_Text: case *proto.ChatInfo_Text:
@@ -284,7 +291,7 @@ func (g *GameManager) ConvChatInfoToChatMsg(chatInfo *proto.ChatInfo) (chatMsg *
func (g *GameManager) ConvChatMsgToChatInfo(chatMsg *model.ChatMsg) (chatInfo *proto.ChatInfo) { func (g *GameManager) ConvChatMsgToChatInfo(chatMsg *model.ChatMsg) (chatInfo *proto.ChatInfo) {
chatInfo = &proto.ChatInfo{ chatInfo = &proto.ChatInfo{
Time: chatMsg.Time, Time: chatMsg.Time,
Sequence: 0, Sequence: chatMsg.Sequence,
ToUid: chatMsg.ToUid, ToUid: chatMsg.ToUid,
Uid: chatMsg.Uid, Uid: chatMsg.Uid,
IsRead: chatMsg.IsRead, IsRead: chatMsg.IsRead,

View File

@@ -26,13 +26,17 @@ func (g *GameManager) SetPlayerBornDataReq(userId uint32, clientSeq uint32, gate
logger.Info("user reg req, uid: %v, gateAppId: %v", userId, gateAppId) logger.Info("user reg req, uid: %v, gateAppId: %v", userId, gateAppId)
req := payloadMsg.(*proto.SetPlayerBornDataReq) req := payloadMsg.(*proto.SetPlayerBornDataReq)
logger.Debug("reg data: %v", req) logger.Debug("reg data: %v", req)
if userId < PlayerBaseUid {
logger.Error("uid can not less than player base uid, reg req uid: %v", userId)
return
}
g.OnReg(userId, clientSeq, gateAppId, req) g.OnReg(userId, clientSeq, gateAppId, req)
} }
func (g *GameManager) OnLogin(userId uint32, clientSeq uint32, gateAppId string) { func (g *GameManager) OnLogin(userId uint32, clientSeq uint32, gateAppId string) {
logger.Info("user login, uid: %v", userId) logger.Info("user login, uid: %v", userId)
player, asyncWait := USER_MANAGER.OnlineUser(userId, clientSeq, gateAppId) player, isRobot := USER_MANAGER.OnlineUser(userId, clientSeq, gateAppId)
if !asyncWait { if isRobot {
g.OnLoginOk(userId, player, clientSeq, gateAppId) g.OnLoginOk(userId, player, clientSeq, gateAppId)
} }
} }
@@ -64,7 +68,7 @@ func (g *GameManager) OnLoginOk(userId uint32, player *model.Player, clientSeq u
player.CombatInvokeHandler = model.NewInvokeHandler[proto.CombatInvokeEntry]() player.CombatInvokeHandler = model.NewInvokeHandler[proto.CombatInvokeEntry]()
player.AbilityInvokeHandler = model.NewInvokeHandler[proto.AbilityInvokeEntry]() player.AbilityInvokeHandler = model.NewInvokeHandler[proto.AbilityInvokeEntry]()
if userId < 100000000 { if userId < PlayerBaseUid {
return return
} }
@@ -98,7 +102,7 @@ func (g *GameManager) OnReg(userId uint32, clientSeq uint32, gateAppId string, p
func (g *GameManager) OnRegOk(exist bool, req *proto.SetPlayerBornDataReq, userId uint32, clientSeq uint32, gateAppId string) { func (g *GameManager) OnRegOk(exist bool, req *proto.SetPlayerBornDataReq, userId uint32, clientSeq uint32, gateAppId string) {
if exist { if exist {
logger.Error("recv reg req, but user is already exist, userId: %v", userId) logger.Error("recv reg req, but user is already exist, uid: %v", userId)
return return
} }
@@ -124,7 +128,7 @@ 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 {
logger.Error("player is nil, userId: %v", userId) logger.Error("player is nil, uid: %v", userId)
return return
} }
TICK_MANAGER.DestroyUserGlobalTick(userId) TICK_MANAGER.DestroyUserGlobalTick(userId)

View File

@@ -132,12 +132,13 @@ type PlayerLoginInfo struct {
// OnlineUser 玩家上线 // 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 userId > PlayerBaseUid {
u.ChangeUserDbState(player, model.DbNormal) // 每次玩家上线必须从数据库加载最新的档 如果之前存在于内存则删掉
return player, false if exist {
} else { u.DeleteUser(userId)
}
go func() { go func() {
player = u.LoadUserFromDbSync(userId) player := u.LoadUserFromDbSync(userId)
if player != nil { if player != nil {
u.SaveUserToRedisSync(player) u.SaveUserToRedisSync(player)
u.ChangeUserDbState(player, model.DbNormal) u.ChangeUserDbState(player, model.DbNormal)
@@ -155,7 +156,9 @@ func (u *UserManager) OnlineUser(userId uint32, clientSeq uint32, gateAppId stri
}, },
} }
}() }()
return nil, true return nil, false
} else {
return player, true
} }
} }
@@ -325,8 +328,8 @@ func (u *UserManager) LoadTempOfflineUser(userId uint32) *model.Player {
if player == nil { if player == nil {
// 玩家可能不存在于redis 尝试从db查询出来然后写入redis // 玩家可能不存在于redis 尝试从db查询出来然后写入redis
// 大多数情况下活跃玩家都在redis 所以不会走到下面 // 大多数情况下活跃玩家都在redis 所以不会走到下面
// TODO 布隆过滤器防止恶意攻击造成redis缓存穿透 // TODO 防止恶意攻击造成redis缓存穿透
if userId < 100000000 || userId > 200000000 { if userId < PlayerBaseUid || userId > MaxPlayerBaseUid {
logger.Error("try to load a not exist uid, uid: %v", userId) logger.Error("try to load a not exist uid, uid: %v", userId)
return nil return nil
} }
@@ -487,8 +490,12 @@ func (u *UserManager) LoadUserChatMsgFromDbSync(userId uint32) map[uint32][]*mod
} }
for otherUid, msgList := range chatMsgMap { for otherUid, msgList := range chatMsgMap {
if len(msgList) > MaxMsgListLen { if len(msgList) > MaxMsgListLen {
chatMsgMap[otherUid] = msgList[len(msgList)-MaxMsgListLen:] msgList = msgList[len(msgList)-MaxMsgListLen:]
} }
for index, chatMsg := range msgList {
chatMsg.Sequence = uint32(index) + 101
}
chatMsgMap[otherUid] = msgList
} }
return chatMsgMap return chatMsgMap
} }
@@ -501,6 +508,14 @@ func (u *UserManager) SaveUserChatMsgToDbSync(chatMsg *model.ChatMsg) {
} }
} }
func (u *UserManager) ReadAndUpdateUserChatMsgToDbSync(uid uint32, targetUid uint32) {
err := u.dao.ReadAndUpdateChatMsgByUid(uid, targetUid)
if err != nil {
logger.Error("read chat msg error: %v", err)
return
}
}
func (u *UserManager) LoadUserFromRedisSync(userId uint32) *model.Player { func (u *UserManager) LoadUserFromRedisSync(userId uint32) *model.Player {
player := u.dao.GetRedisPlayer(userId) player := u.dao.GetRedisPlayer(userId)
return player return player

View File

@@ -203,7 +203,7 @@ func (w *WorldManager) IsAiWorld(world *World) bool {
} }
func (w *WorldManager) IsRobotWorld(world *World) bool { func (w *WorldManager) IsRobotWorld(world *World) bool {
return world.owner.PlayerID < 100000000 return world.owner.PlayerID < PlayerBaseUid
} }
func (w *WorldManager) IsBigWorld(world *World) bool { func (w *WorldManager) IsBigWorld(world *World) bool {

View File

@@ -10,12 +10,13 @@ const (
) )
type ChatMsg struct { type ChatMsg struct {
ID primitive.ObjectID `bson:"_id,omitempty"` ID primitive.ObjectID `bson:"_id,omitempty"`
Time uint32 `bson:"Time"` Sequence uint32 `bson:"-"`
ToUid uint32 `bson:"ToUid"` Time uint32 `bson:"Time"`
Uid uint32 `bson:"Uid"` ToUid uint32 `bson:"ToUid"`
IsRead bool `bson:"IsRead"` Uid uint32 `bson:"Uid"`
MsgType uint8 `bson:"MsgType"` IsRead bool `bson:"IsRead"`
Text string `bson:"Text"` MsgType uint8 `bson:"MsgType"`
Icon uint32 `bson:"Icon"` Text string `bson:"Text"`
Icon uint32 `bson:"Icon"`
} }