diff --git a/gs/dao/player_mongo.go b/gs/dao/player_mongo.go index d6e509f4..cd19af6e 100644 --- a/gs/dao/player_mongo.go +++ b/gs/dao/player_mongo.go @@ -10,13 +10,6 @@ import ( "go.mongodb.org/mongo-driver/mongo" ) -// PlayerDb 只从数据库读写的结构 -type PlayerDb struct { - ID primitive.ObjectID `bson:"_id,omitempty"` - PlayerID uint32 `bson:"PlayerID"` // 玩家uid - ChatMsgMap map[uint32][]*model.ChatMsg // 聊天信息 -} - func (d *Dao) InsertPlayer(player *model.Player) error { db := d.db.Collection("player") _, err := db.InsertOne(context.TODO(), player) @@ -26,9 +19,9 @@ func (d *Dao) InsertPlayer(player *model.Player) error { return nil } -func (d *Dao) InsertPlayerDb(playerDb *PlayerDb) error { - db := d.db.Collection("player_db") - _, err := db.InsertOne(context.TODO(), playerDb) +func (d *Dao) InsertChatMsg(chatMsg *model.ChatMsg) error { + db := d.db.Collection("chat_msg") + _, err := db.InsertOne(context.TODO(), chatMsg) if err != nil { return err } @@ -52,14 +45,14 @@ func (d *Dao) InsertPlayerList(playerList []*model.Player) error { return nil } -func (d *Dao) InsertPlayerDbList(playerDbList []*PlayerDb) error { - if len(playerDbList) == 0 { +func (d *Dao) InsertChatMsgList(chatMsgList []*model.ChatMsg) error { + if len(chatMsgList) == 0 { return nil } - db := d.db.Collection("player_db") + db := d.db.Collection("chat_msg") modelOperateList := make([]mongo.WriteModel, 0) - for _, playerDb := range playerDbList { - modelOperate := mongo.NewInsertOneModel().SetDocument(playerDb) + for _, chatMsg := range chatMsgList { + modelOperate := mongo.NewInsertOneModel().SetDocument(chatMsg) modelOperateList = append(modelOperateList, modelOperate) } _, err := db.BulkWrite(context.TODO(), modelOperateList) @@ -78,9 +71,9 @@ func (d *Dao) DeletePlayer(playerID uint32) error { return nil } -func (d *Dao) DeletePlayerDb(playerID uint32) error { - db := d.db.Collection("player_db") - _, err := db.DeleteOne(context.TODO(), bson.D{{"PlayerID", playerID}}) +func (d *Dao) DeleteChatMsg(id primitive.ObjectID) error { + db := d.db.Collection("chat_msg") + _, err := db.DeleteOne(context.TODO(), bson.D{{"_id", id}}) if err != nil { return err } @@ -104,14 +97,14 @@ func (d *Dao) DeletePlayerList(playerIDList []uint32) error { return nil } -func (d *Dao) DeletePlayerDbList(playerIDList []uint32) error { - if len(playerIDList) == 0 { +func (d *Dao) DeleteChatMsgList(idList []primitive.ObjectID) error { + if len(idList) == 0 { return nil } - db := d.db.Collection("player_db") + db := d.db.Collection("chat_msg") modelOperateList := make([]mongo.WriteModel, 0) - for _, playerID := range playerIDList { - modelOperate := mongo.NewDeleteOneModel().SetFilter(bson.D{{"PlayerID", playerID}}) + for _, id := range idList { + modelOperate := mongo.NewDeleteOneModel().SetFilter(bson.D{{"_id", id}}) modelOperateList = append(modelOperateList, modelOperate) } _, err := db.BulkWrite(context.TODO(), modelOperateList) @@ -134,12 +127,12 @@ func (d *Dao) UpdatePlayer(player *model.Player) error { return nil } -func (d *Dao) UpdatePlayerDb(playerDb *PlayerDb) error { - db := d.db.Collection("player_db") +func (d *Dao) UpdateChatMsg(chatMsg *model.ChatMsg) error { + db := d.db.Collection("chat_msg") _, err := db.UpdateOne( context.TODO(), - bson.D{{"PlayerID", playerDb.PlayerID}}, - bson.D{{"$set", playerDb}}, + bson.D{{"_id", chatMsg.ID}}, + bson.D{{"$set", chatMsg}}, ) if err != nil { return err @@ -164,14 +157,14 @@ func (d *Dao) UpdatePlayerList(playerList []*model.Player) error { return nil } -func (d *Dao) UpdatePlayerDbList(playerDbList []*PlayerDb) error { - if len(playerDbList) == 0 { +func (d *Dao) UpdateChatMsgList(chatMsgList []*model.ChatMsg) error { + if len(chatMsgList) == 0 { return nil } - db := d.db.Collection("player_db") + db := d.db.Collection("chat_msg") modelOperateList := make([]mongo.WriteModel, 0) - for _, playerDb := range playerDbList { - modelOperate := mongo.NewUpdateOneModel().SetFilter(bson.D{{"PlayerID", playerDb.PlayerID}}).SetUpdate(bson.D{{"$set", playerDb}}) + for _, chatMsg := range chatMsgList { + modelOperate := mongo.NewUpdateOneModel().SetFilter(bson.D{{"_id", chatMsg.ID}}).SetUpdate(bson.D{{"$set", chatMsg}}) modelOperateList = append(modelOperateList, modelOperate) } _, err := db.BulkWrite(context.TODO(), modelOperateList) @@ -195,24 +188,20 @@ func (d *Dao) QueryPlayerByID(playerID uint32) (*model.Player, error) { return player, nil } -func (d *Dao) QueryPlayerDbByID(playerID uint32) (*PlayerDb, error) { - db := d.db.Collection("player_db") +func (d *Dao) QueryChatMsgByID(id primitive.ObjectID) (*model.ChatMsg, error) { + db := d.db.Collection("chat_msg") result := db.FindOne( context.TODO(), - bson.D{{"PlayerID", playerID}}, + bson.D{{"_id", id}}, ) - playerDb := new(PlayerDb) - err := result.Decode(playerDb) + chatMsg := new(model.ChatMsg) + err := result.Decode(chatMsg) if err != nil { return nil, err } - if playerDb.ChatMsgMap == nil { - playerDb.ChatMsgMap = make(map[uint32][]*model.ChatMsg) - } - return playerDb, nil + return chatMsg, nil } -// QueryPlayerList 危险接口 非测试禁止使用 func (d *Dao) QueryPlayerList() ([]*model.Player, error) { db := d.db.Collection("player") find, err := db.Find( @@ -233,3 +222,45 @@ func (d *Dao) QueryPlayerList() ([]*model.Player, error) { } return result, nil } + +func (d *Dao) QueryChatMsgList() ([]*model.ChatMsg, error) { + db := d.db.Collection("chat_msg") + find, err := db.Find( + context.TODO(), + bson.D{}, + ) + if err != nil { + return nil, err + } + result := make([]*model.ChatMsg, 0) + for find.Next(context.TODO()) { + item := new(model.ChatMsg) + err = find.Decode(item) + if err != nil { + return nil, err + } + result = append(result, item) + } + return result, nil +} + +func (d *Dao) QueryChatMsgListByUid(uid uint32) ([]*model.ChatMsg, error) { + db := d.db.Collection("chat_msg") + find, err := db.Find( + context.TODO(), + bson.D{{"ToUid", uid}, {"Uid", uid}}, + ) + if err != nil { + return nil, err + } + result := make([]*model.ChatMsg, 0) + for find.Next(context.TODO()) { + item := new(model.ChatMsg) + err = find.Decode(item) + if err != nil { + return nil, err + } + result = append(result, item) + } + return result, nil +} diff --git a/gs/game/player_chat.go b/gs/game/player_chat.go index bb0f2ee3..79985072 100644 --- a/gs/game/player_chat.go +++ b/gs/game/player_chat.go @@ -105,6 +105,10 @@ func (g *GameManager) SendPrivateChat(player *model.Player, targetUid uint32, co } } chatMsg := g.ConvChatInfoToChatMsg(chatInfo) + + // 写入db + go USER_MANAGER.SaveUserChatMsgToDbSync(chatMsg) + // 消息加入自己的队列 msgList, exist := player.ChatMsgMap[targetUid] if !exist { @@ -141,15 +145,10 @@ func (g *GameManager) SendPrivateChat(player *model.Player, targetUid uint32, co }, }, }) - } else { - // 目标玩家全服离线 - chatMsgMap := map[uint32][]*model.ChatMsg{ - player.PlayerID: {chatMsg}, - } - go USER_MANAGER.AppendOfflineUserChatMsgToDbSync(targetUid, chatMsgMap) } return } + // 消息加入目标玩家的队列 msgList, exist = targetPlayer.ChatMsgMap[player.PlayerID] if !exist { @@ -327,6 +326,9 @@ func (g *GameManager) ServerChatMsgNotify(chatMsgInfo *mq.ChatMsgInfo) { if !exist { msgList = make([]*model.ChatMsg, 0) } + if len(msgList) > MaxMsgListLen { + msgList = msgList[1:] + } msgList = append(msgList, chatMsg) targetPlayer.ChatMsgMap[chatMsgInfo.Uid] = msgList diff --git a/gs/game/user_manager.go b/gs/game/user_manager.go index 72fff596..808e336d 100644 --- a/gs/game/user_manager.go +++ b/gs/game/user_manager.go @@ -6,7 +6,6 @@ import ( "hk4e/gs/dao" "hk4e/gs/model" "hk4e/pkg/logger" - "hk4e/pkg/object" "hk4e/protocol/proto" "github.com/vmihailenco/msgpack/v5" @@ -142,8 +141,7 @@ func (u *UserManager) OnlineUser(userId uint32, clientSeq uint32, gateAppId stri if player != nil { u.SaveUserToRedisSync(player) u.ChangeUserDbState(player, model.DbNormal) - playerDb := u.LoadUserChatMsgFromDbSync(userId) - player.ChatMsgMap = playerDb.ChatMsgMap + player.ChatMsgMap = u.LoadUserChatMsgFromDbSync(userId) } else { logger.Error("can not find user from db, uid: %v", userId) } @@ -179,14 +177,9 @@ func (u *UserManager) OfflineUser(player *model.Player, changeGsInfo *ChangeGsIn logger.Error("marshal player data error: %v", err) return } - chatMsgMapData, err := object.DeepMarshal(&player.ChatMsgMap) - if err != nil { - logger.Error("marshal chat msg map error: %v", err) - return - } endTime := time.Now().UnixNano() costTime := endTime - startTime - logger.Info("offline copy player data and chat msg cost time: %v ns", costTime) + logger.Info("offline copy player data cost time: %v ns", costTime) go func() { playerCopy := new(model.Player) err := msgpack.Unmarshal(playerData, playerCopy) @@ -197,16 +190,6 @@ func (u *UserManager) OfflineUser(player *model.Player, changeGsInfo *ChangeGsIn playerCopy.DbState = player.DbState u.SaveUserToDbSync(playerCopy) u.SaveUserToRedisSync(playerCopy) - chatMsgMap := make(map[uint32][]*model.ChatMsg) - err = object.DeepUnmarshal(&chatMsgMap, chatMsgMapData) - if err != nil { - logger.Error("unmarshal chat msg map error: %v", err) - return - } - playerDb := new(dao.PlayerDb) - playerDb.PlayerID = playerCopy.PlayerID - playerDb.ChatMsgMap = chatMsgMap - u.SaveUserChatMsgToDbSync(playerDb) LOCAL_EVENT_MANAGER.localEventChan <- &LocalEvent{ EventId: UserOfflineSaveToDbFinish, Msg: &PlayerOfflineInfo{ @@ -479,49 +462,33 @@ func (u *UserManager) SaveUserListToDbSync(insertPlayerList []*model.Player, upd logger.Info("save user finish, insert user count: %v, update user count: %v", len(insertPlayerList), len(updatePlayerList)) } -func (u *UserManager) LoadUserChatMsgFromDbSync(userId uint32) *dao.PlayerDb { - playerDb, err := u.dao.QueryPlayerDbByID(userId) +func (u *UserManager) LoadUserChatMsgFromDbSync(userId uint32) map[uint32][]*model.ChatMsg { + chatMsgMap := make(map[uint32][]*model.ChatMsg) + chatMsgList, err := u.dao.QueryChatMsgListByUid(userId) if err != nil { - logger.Error("query player db error: %v", err) - return nil + logger.Error("query chat msg list error: %v", err) + return chatMsgMap } - return playerDb + for _, chatMsg := range chatMsgList { + msgList, exist := chatMsgMap[chatMsg.ToUid] + if !exist { + msgList = make([]*model.ChatMsg, 0) + } + if len(msgList) > MaxMsgListLen { + continue + } + msgList = append(msgList, chatMsg) + chatMsgMap[chatMsg.ToUid] = msgList + } + return chatMsgMap } -func (u *UserManager) SaveUserChatMsgToDbSync(playerDb *dao.PlayerDb) { - _, err := u.dao.QueryPlayerDbByID(playerDb.PlayerID) +func (u *UserManager) SaveUserChatMsgToDbSync(chatMsg *model.ChatMsg) { + err := u.dao.InsertChatMsg(chatMsg) if err != nil { - err := u.dao.InsertPlayerDb(playerDb) - if err != nil { - logger.Error("insert player db error: %v", err) - return - } - } else { - err := u.dao.UpdatePlayerDb(playerDb) - if err != nil { - logger.Error("update player db error: %v", err) - return - } - } -} - -func (u *UserManager) AppendOfflineUserChatMsgToDbSync(userId uint32, chatMsgMap map[uint32][]*model.ChatMsg) { - playerDb := u.LoadUserChatMsgFromDbSync(userId) - if playerDb == nil { + logger.Error("insert chat msg error: %v", err) return } - for uid, msgList := range chatMsgMap { - allMsgList, exist := playerDb.ChatMsgMap[uid] - if !exist { - allMsgList = make([]*model.ChatMsg, 0) - } - allMsgList = append(allMsgList, msgList...) - if len(allMsgList) > MaxMsgListLen { - allMsgList = allMsgList[len(allMsgList)-MaxMsgListLen:] - } - playerDb.ChatMsgMap[uid] = allMsgList - } - u.SaveUserChatMsgToDbSync(playerDb) } func (u *UserManager) LoadUserFromRedisSync(userId uint32) *model.Player { diff --git a/gs/model/chat.go b/gs/model/chat.go index 84afacc4..87477a01 100644 --- a/gs/model/chat.go +++ b/gs/model/chat.go @@ -1,16 +1,21 @@ package model +import ( + "go.mongodb.org/mongo-driver/bson/primitive" +) + const ( ChatMsgTypeText = iota ChatMsgTypeIcon ) type ChatMsg struct { - Time uint32 - ToUid uint32 - Uid uint32 - IsRead bool - MsgType uint8 - Text string - Icon uint32 + ID primitive.ObjectID `bson:"_id,omitempty"` + Time uint32 `bson:"Time"` + ToUid uint32 `bson:"ToUid"` + Uid uint32 `bson:"Uid"` + IsRead bool `bson:"IsRead"` + MsgType uint8 `bson:"MsgType"` + Text string `bson:"Text"` + Icon uint32 `bson:"Icon"` }