From d35291cb5e39f07009fde5080dfd234962e9878b Mon Sep 17 00:00:00 2001 From: flswld Date: Sun, 12 Feb 2023 02:00:52 +0800 Subject: [PATCH] =?UTF-8?q?=E6=8B=86=E5=88=86=E4=BA=86=E8=81=8A=E5=A4=A9?= =?UTF-8?q?=E6=95=B0=E6=8D=AE=EF=BC=8C=E5=87=8F=E5=B0=8F=E7=8E=A9=E5=AE=B6?= =?UTF-8?q?=E6=95=B0=E6=8D=AE=E7=BB=93=E6=9E=84=E5=A4=A7=E5=B0=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- common/mq/net_msg.go | 126 ++++++++++++++++---------------- gs/dao/player_mongo.go | 154 ++++++++++++++++++++++++++++++++++++---- gs/game/player_chat.go | 20 +++++- gs/game/player_login.go | 10 +-- gs/game/user_manager.go | 67 +++++++++++++++++ gs/game/world_scene.go | 15 ++-- gs/model/avatar.go | 36 +++++----- gs/model/chat.go | 14 ++-- gs/model/drop.go | 12 ++-- gs/model/gcg.go | 62 ++++++++-------- gs/model/item.go | 4 +- gs/model/player.go | 60 ++++++++-------- gs/model/reliquary.go | 18 ++--- gs/model/team.go | 10 +-- gs/model/vector.go | 6 +- gs/model/weapon.go | 18 ++--- pkg/object/object.go | 17 +++++ 17 files changed, 433 insertions(+), 216 deletions(-) diff --git a/common/mq/net_msg.go b/common/mq/net_msg.go index 61c75bf8..6633d6c9 100644 --- a/common/mq/net_msg.go +++ b/common/mq/net_msg.go @@ -10,17 +10,17 @@ const ( ) type NetMsg struct { - MsgType uint8 `msgpack:"MsgType"` - EventId uint16 `msgpack:"EventId"` - ServerType string `msgpack:"-"` - AppId string `msgpack:"-"` - Topic string `msgpack:"-"` - GameMsg *GameMsg `msgpack:"GameMsg"` - FightMsg *FightMsg `msgpack:"FightMsg"` - ConnCtrlMsg *ConnCtrlMsg `msgpack:"ConnCtrlMsg"` - ServerMsg *ServerMsg `msgpack:"ServerMsg"` - OriginServerType string `msgpack:"OriginServerType"` - OriginServerAppId string `msgpack:"OriginServerAppId"` + MsgType uint8 + EventId uint16 + ServerType string `msgpack:"-"` + AppId string `msgpack:"-"` + Topic string `msgpack:"-"` + GameMsg *GameMsg + FightMsg *FightMsg + ConnCtrlMsg *ConnCtrlMsg + ServerMsg *ServerMsg + OriginServerType string + OriginServerAppId string } const ( @@ -28,11 +28,11 @@ const ( ) type GameMsg struct { - UserId uint32 `msgpack:"UserId"` - CmdId uint16 `msgpack:"CmdId"` - ClientSeq uint32 `msgpack:"ClientSeq"` + UserId uint32 + CmdId uint16 + ClientSeq uint32 PayloadMessage pb.Message `msgpack:"-"` - PayloadMessageData []byte `msgpack:"PayloadMessageData"` + PayloadMessageData []byte } const ( @@ -43,11 +43,11 @@ const ( ) type ConnCtrlMsg struct { - UserId uint32 `msgpack:"UserId"` - ClientRtt uint32 `msgpack:"ClientRtt"` - ClientTime uint32 `msgpack:"ClientTime"` - KickUserId uint32 `msgpack:"KickUserId"` - KickReason uint32 `msgpack:"KickReason"` + UserId uint32 + ClientRtt uint32 + ClientTime uint32 + KickUserId uint32 + KickReason uint32 } const ( @@ -58,12 +58,12 @@ const ( ) type FightMsg struct { - FightRoutineId uint32 `msgpack:"FightRoutineId"` - EntityId uint32 `msgpack:"EntityId"` - FightPropMap map[uint32]float32 `msgpack:"FightPropMap"` - Uid uint32 `msgpack:"Uid"` - AvatarGuid uint64 `msgpack:"AvatarGuid"` - GateServerAppId string `msgpack:"GateServerAppId"` + FightRoutineId uint32 + EntityId uint32 + FightPropMap map[uint32]float32 + Uid uint32 + AvatarGuid uint64 + GateServerAppId string } const ( @@ -77,56 +77,56 @@ const ( ) type ServerMsg struct { - FightServerAppId string `msgpack:"FightServerAppId"` - UserId uint32 `msgpack:"UserId"` - IsOnline bool `msgpack:"IsOnline"` - GameServerAppId string `msgpack:"GameServerAppId"` - JoinHostUserId uint32 `msgpack:"JoinHostUserId"` - UserMpInfo *UserMpInfo `msgpack:"UserMpInfo"` - ChatMsgInfo *ChatMsgInfo `msgpack:"ChatMsgInfo"` - AddFriendInfo *AddFriendInfo `msgpack:"AddFriendInfo"` + FightServerAppId string + UserId uint32 + IsOnline bool + GameServerAppId string + JoinHostUserId uint32 + UserMpInfo *UserMpInfo + ChatMsgInfo *ChatMsgInfo + AddFriendInfo *AddFriendInfo } type OriginInfo struct { - CmdName string `msgpack:"CmdName"` - UserId uint32 `msgpack:"UserId"` + CmdName string + UserId uint32 } type UserBaseInfo struct { - UserId uint32 `msgpack:"UserId"` - Nickname string `msgpack:"Nickname"` - PlayerLevel uint32 `msgpack:"PlayerLevel"` - MpSettingType uint8 `msgpack:"MpSettingType"` - NameCardId uint32 `msgpack:"NameCardId"` - Signature string `msgpack:"Signature"` - HeadImageId uint32 `msgpack:"HeadImageId"` - WorldPlayerNum uint32 `msgpack:"WorldPlayerNum"` - WorldLevel uint32 `msgpack:"WorldLevel"` + UserId uint32 + Nickname string + PlayerLevel uint32 + MpSettingType uint8 + NameCardId uint32 + Signature string + HeadImageId uint32 + WorldPlayerNum uint32 + WorldLevel uint32 } 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"` - Reason int32 `msgpack:"Reason"` - HostNickname string `msgpack:"HostNickname"` + OriginInfo *OriginInfo + HostUserId uint32 + ApplyUserId uint32 + ApplyPlayerOnlineInfo *UserBaseInfo + ApplyOk bool + Agreed bool + Reason int32 + HostNickname string } 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"` + Time uint32 + ToUid uint32 + Uid uint32 + IsRead bool + MsgType uint8 + Text string + Icon uint32 } type AddFriendInfo struct { - OriginInfo *OriginInfo `msgpack:"OriginInfo"` - TargetUserId uint32 `msgpack:"TargetUserId"` - ApplyPlayerOnlineInfo *UserBaseInfo `msgpack:"ApplyPlayerOnlineInfo"` + OriginInfo *OriginInfo + TargetUserId uint32 + ApplyPlayerOnlineInfo *UserBaseInfo } diff --git a/gs/dao/player_mongo.go b/gs/dao/player_mongo.go index 31e29f09..d6e509f4 100644 --- a/gs/dao/player_mongo.go +++ b/gs/dao/player_mongo.go @@ -6,13 +6,33 @@ import ( "hk4e/gs/model" "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/bson/primitive" "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) - return err + if err != nil { + return err + } + return nil +} + +func (d *Dao) InsertPlayerDb(playerDb *PlayerDb) error { + db := d.db.Collection("player_db") + _, err := db.InsertOne(context.TODO(), playerDb) + if err != nil { + return err + } + return nil } func (d *Dao) InsertPlayerList(playerList []*model.Player) error { @@ -26,13 +46,45 @@ func (d *Dao) InsertPlayerList(playerList []*model.Player) error { modelOperateList = append(modelOperateList, modelOperate) } _, err := db.BulkWrite(context.TODO(), modelOperateList) - return err + if err != nil { + return err + } + return nil +} + +func (d *Dao) InsertPlayerDbList(playerDbList []*PlayerDb) error { + if len(playerDbList) == 0 { + return nil + } + db := d.db.Collection("player_db") + modelOperateList := make([]mongo.WriteModel, 0) + for _, playerDb := range playerDbList { + modelOperate := mongo.NewInsertOneModel().SetDocument(playerDb) + modelOperateList = append(modelOperateList, modelOperate) + } + _, err := db.BulkWrite(context.TODO(), modelOperateList) + if err != nil { + return err + } + return nil } func (d *Dao) DeletePlayer(playerID uint32) error { db := d.db.Collection("player") - _, err := db.DeleteOne(context.TODO(), bson.D{{"playerID", playerID}}) - return err + _, err := db.DeleteOne(context.TODO(), bson.D{{"PlayerID", playerID}}) + if err != nil { + return err + } + return nil +} + +func (d *Dao) DeletePlayerDb(playerID uint32) error { + db := d.db.Collection("player_db") + _, err := db.DeleteOne(context.TODO(), bson.D{{"PlayerID", playerID}}) + if err != nil { + return err + } + return nil } func (d *Dao) DeletePlayerList(playerIDList []uint32) error { @@ -42,21 +94,57 @@ func (d *Dao) DeletePlayerList(playerIDList []uint32) error { db := d.db.Collection("player") modelOperateList := make([]mongo.WriteModel, 0) for _, playerID := range playerIDList { - modelOperate := mongo.NewDeleteOneModel().SetFilter(bson.D{{"playerID", playerID}}) + modelOperate := mongo.NewDeleteOneModel().SetFilter(bson.D{{"PlayerID", playerID}}) modelOperateList = append(modelOperateList, modelOperate) } _, err := db.BulkWrite(context.TODO(), modelOperateList) - return err + if err != nil { + return err + } + return nil +} + +func (d *Dao) DeletePlayerDbList(playerIDList []uint32) error { + if len(playerIDList) == 0 { + return nil + } + db := d.db.Collection("player_db") + modelOperateList := make([]mongo.WriteModel, 0) + for _, playerID := range playerIDList { + modelOperate := mongo.NewDeleteOneModel().SetFilter(bson.D{{"PlayerID", playerID}}) + modelOperateList = append(modelOperateList, modelOperate) + } + _, err := db.BulkWrite(context.TODO(), modelOperateList) + if err != nil { + return err + } + return nil } func (d *Dao) UpdatePlayer(player *model.Player) error { db := d.db.Collection("player") _, err := db.UpdateOne( context.TODO(), - bson.D{{"playerID", player.PlayerID}}, + bson.D{{"PlayerID", player.PlayerID}}, bson.D{{"$set", player}}, ) - return err + if err != nil { + return err + } + return nil +} + +func (d *Dao) UpdatePlayerDb(playerDb *PlayerDb) error { + db := d.db.Collection("player_db") + _, err := db.UpdateOne( + context.TODO(), + bson.D{{"PlayerID", playerDb.PlayerID}}, + bson.D{{"$set", playerDb}}, + ) + if err != nil { + return err + } + return nil } func (d *Dao) UpdatePlayerList(playerList []*model.Player) error { @@ -66,27 +154,65 @@ func (d *Dao) UpdatePlayerList(playerList []*model.Player) error { db := d.db.Collection("player") modelOperateList := make([]mongo.WriteModel, 0) for _, player := range playerList { - modelOperate := mongo.NewUpdateOneModel().SetFilter(bson.D{{"playerID", player.PlayerID}}).SetUpdate(bson.D{{"$set", player}}) + modelOperate := mongo.NewUpdateOneModel().SetFilter(bson.D{{"PlayerID", player.PlayerID}}).SetUpdate(bson.D{{"$set", player}}) modelOperateList = append(modelOperateList, modelOperate) } _, err := db.BulkWrite(context.TODO(), modelOperateList) - return err + if err != nil { + return err + } + return nil +} + +func (d *Dao) UpdatePlayerDbList(playerDbList []*PlayerDb) error { + if len(playerDbList) == 0 { + return nil + } + db := d.db.Collection("player_db") + modelOperateList := make([]mongo.WriteModel, 0) + for _, playerDb := range playerDbList { + modelOperate := mongo.NewUpdateOneModel().SetFilter(bson.D{{"PlayerID", playerDb.PlayerID}}).SetUpdate(bson.D{{"$set", playerDb}}) + modelOperateList = append(modelOperateList, modelOperate) + } + _, err := db.BulkWrite(context.TODO(), modelOperateList) + if err != nil { + return err + } + return nil } func (d *Dao) QueryPlayerByID(playerID uint32) (*model.Player, error) { db := d.db.Collection("player") result := db.FindOne( context.TODO(), - bson.D{{"playerID", playerID}}, + bson.D{{"PlayerID", playerID}}, ) - item := new(model.Player) - err := result.Decode(item) + player := new(model.Player) + err := result.Decode(player) if err != nil { return nil, err } - return item, nil + return player, nil } +func (d *Dao) QueryPlayerDbByID(playerID uint32) (*PlayerDb, error) { + db := d.db.Collection("player_db") + result := db.FindOne( + context.TODO(), + bson.D{{"PlayerID", playerID}}, + ) + playerDb := new(PlayerDb) + err := result.Decode(playerDb) + if err != nil { + return nil, err + } + if playerDb.ChatMsgMap == nil { + playerDb.ChatMsgMap = make(map[uint32][]*model.ChatMsg) + } + return playerDb, nil +} + +// QueryPlayerList 危险接口 非测试禁止使用 func (d *Dao) QueryPlayerList() ([]*model.Player, error) { db := d.db.Collection("player") find, err := db.Find( diff --git a/gs/game/player_chat.go b/gs/game/player_chat.go index 8f0c1eeb..bb0f2ee3 100644 --- a/gs/game/player_chat.go +++ b/gs/game/player_chat.go @@ -12,6 +12,10 @@ import ( pb "google.golang.org/protobuf/proto" ) +const ( + MaxMsgListLen = 1000 // 与某人的最大聊天记录条数 +) + func (g *GameManager) PullRecentChatReq(player *model.Player, payloadMsg pb.Message) { logger.Debug("user pull recent chat, uid: %v", player.PlayerID) req := payloadMsg.(*proto.PullRecentChatReq) @@ -94,7 +98,7 @@ func (g *GameManager) SendPrivateChat(player *model.Player, targetUid uint32, co chatInfo.Content = &proto.ChatInfo_Text{ Text: content.(string), } - case int, int32, uint32: + case uint32: // 图标消息 chatInfo.Content = &proto.ChatInfo_Icon{ Icon: content.(uint32), @@ -106,6 +110,9 @@ func (g *GameManager) SendPrivateChat(player *model.Player, targetUid uint32, co if !exist { msgList = make([]*model.ChatMsg, 0) } + if len(msgList) > MaxMsgListLen { + msgList = msgList[1:] + } msgList = append(msgList, chatMsg) player.ChatMsgMap[targetUid] = msgList @@ -136,7 +143,10 @@ func (g *GameManager) SendPrivateChat(player *model.Player, targetUid uint32, co }) } else { // 目标玩家全服离线 - // TODO 接入redis直接同步写入数据 + chatMsgMap := map[uint32][]*model.ChatMsg{ + player.PlayerID: {chatMsg}, + } + go USER_MANAGER.AppendOfflineUserChatMsgToDbSync(targetUid, chatMsgMap) } return } @@ -145,6 +155,9 @@ func (g *GameManager) SendPrivateChat(player *model.Player, targetUid uint32, co if !exist { msgList = make([]*model.ChatMsg, 0) } + if len(msgList) > MaxMsgListLen { + msgList = msgList[1:] + } msgList = append(msgList, chatMsg) targetPlayer.ChatMsgMap[player.PlayerID] = msgList @@ -167,7 +180,8 @@ func (g *GameManager) PrivateChatReq(player *model.Player, payloadMsg pb.Message switch content.(type) { case *proto.PrivateChatReq_Text: text := content.(*proto.PrivateChatReq_Text).Text - if len(text) == 0 { + if len(text) == 0 || len(text) > 80 { + g.SendError(cmd.PrivateChatRsp, player, &proto.PrivateChatRsp{}, proto.Retcode_RET_PRIVATE_CHAT_CONTENT_TOO_LONG) return } // 发送私聊文本消息 diff --git a/gs/game/player_login.go b/gs/game/player_login.go index 0bfb1f3e..9f0724e5 100644 --- a/gs/game/player_login.go +++ b/gs/game/player_login.go @@ -149,13 +149,13 @@ func (g *GameManager) LoginNotify(userId uint32, player *model.Player, clientSeq g.GCGLogin(player) // 发送GCG登录相关的通知包 playerLoginRsp := &proto.PlayerLoginRsp{ IsUseAbilityHash: true, - AbilityHashCode: -228935105, + AbilityHashCode: 0, GameBiz: "hk4e_cn", IsScOpen: false, RegisterCps: "taptap", CountryCode: "CN", Birthday: "2000-01-01", - TotalTickTime: 1185941.871788, + TotalTickTime: 0.0, } g.SendMsg(cmd.PlayerLoginRsp, userId, clientSeq, playerLoginRsp) } @@ -165,7 +165,7 @@ func (g *GameManager) PacketPlayerDataNotify(player *model.Player) *proto.Player NickName: player.NickName, ServerTime: uint64(time.Now().UnixMilli()), IsFirstLoginToday: true, - RegionId: player.RegionId, + RegionId: 1, PropMap: make(map[uint32]*proto.PropValue), } for k, v := range player.PropertiesMap { @@ -344,7 +344,6 @@ func (g *GameManager) CreatePlayer(userId uint32, nickName string, mainCharAvata player.FriendList = make(map[uint32]bool) player.FriendApplyList = make(map[uint32]bool) - player.RegionId = 1 player.SceneId = 3 player.PropertiesMap = make(map[uint16]uint32) @@ -397,7 +396,6 @@ func (g *GameManager) CreatePlayer(userId uint32, nickName string, mainCharAvata player.AvatarMap = make(map[uint32]*model.Avatar) player.GameObjectGuidMap = make(map[uint64]model.GameObject) player.DropInfo = model.NewDropInfo() - player.ChatMsgMap = make(map[uint32][]*model.ChatMsg) player.GCGInfo = model.NewGCGInfo() // 添加选定的主角 @@ -418,5 +416,7 @@ func (g *GameManager) CreatePlayer(userId uint32, nickName string, mainCharAvata player.TeamConfig = model.NewTeamInfo() player.TeamConfig.GetActiveTeam().SetAvatarIdList([]uint32{mainCharAvatarId}) + player.ChatMsgMap = make(map[uint32][]*model.ChatMsg) + return player } diff --git a/gs/game/user_manager.go b/gs/game/user_manager.go index ede882e7..72fff596 100644 --- a/gs/game/user_manager.go +++ b/gs/game/user_manager.go @@ -6,6 +6,7 @@ import ( "hk4e/gs/dao" "hk4e/gs/model" "hk4e/pkg/logger" + "hk4e/pkg/object" "hk4e/protocol/proto" "github.com/vmihailenco/msgpack/v5" @@ -141,6 +142,8 @@ 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 } else { logger.Error("can not find user from db, uid: %v", userId) } @@ -170,11 +173,20 @@ type PlayerOfflineInfo struct { // OfflineUser 玩家离线 func (u *UserManager) OfflineUser(player *model.Player, changeGsInfo *ChangeGsInfo) { + startTime := time.Now().UnixNano() playerData, err := msgpack.Marshal(player) if err != nil { 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) go func() { playerCopy := new(model.Player) err := msgpack.Unmarshal(playerData, playerCopy) @@ -185,6 +197,16 @@ 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{ @@ -457,6 +479,51 @@ 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) + if err != nil { + logger.Error("query player db error: %v", err) + return nil + } + return playerDb +} + +func (u *UserManager) SaveUserChatMsgToDbSync(playerDb *dao.PlayerDb) { + _, err := u.dao.QueryPlayerDbByID(playerDb.PlayerID) + 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 { + 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 { player := u.dao.GetRedisPlayer(userId) return player diff --git a/gs/game/world_scene.go b/gs/game/world_scene.go index 0b799f80..44135568 100644 --- a/gs/game/world_scene.go +++ b/gs/game/world_scene.go @@ -101,7 +101,6 @@ func (s *Scene) SetEntityLifeState(entity *Entity, lifeState uint16, dieType pro GAME_MANAGER.EntityFightPropUpdateNotifyBroadcast(s, entity, uint32(constant.FIGHT_PROP_CUR_HP)) } - // PacketAvatarLifeStateChangeNotify avatarLifeStateChangeNotify := &proto.AvatarLifeStateChangeNotify{ LifeState: uint32(lifeState), AttackTag: "", @@ -111,9 +110,7 @@ func (s *Scene) SetEntityLifeState(entity *Entity, lifeState uint16, dieType pro SourceEntityId: 0, AvatarGuid: avatar.Guid, } - for _, p := range s.playerMap { - GAME_MANAGER.SendMsg(cmd.AvatarLifeStateChangeNotify, p.PlayerID, p.ClientSeq, avatarLifeStateChangeNotify) - } + GAME_MANAGER.SendToWorldA(s.world, cmd.AvatarLifeStateChangeNotify, 0, avatarLifeStateChangeNotify) } else { // 设置存活状态 entity.lifeState = lifeState @@ -124,7 +121,6 @@ func (s *Scene) SetEntityLifeState(entity *Entity, lifeState uint16, dieType pro GAME_MANAGER.EntityFightPropUpdateNotifyBroadcast(s, entity, uint32(constant.FIGHT_PROP_CUR_HP)) } - // PacketLifeStateChangeNotify lifeStateChangeNotify := &proto.LifeStateChangeNotify{ EntityId: entity.id, AttackTag: "", @@ -133,9 +129,7 @@ func (s *Scene) SetEntityLifeState(entity *Entity, lifeState uint16, dieType pro LifeState: uint32(lifeState), SourceEntityId: 0, } - for _, p := range s.playerMap { - GAME_MANAGER.SendMsg(cmd.LifeStateChangeNotify, p.PlayerID, p.ClientSeq, lifeStateChangeNotify) - } + GAME_MANAGER.SendToWorldA(s.world, cmd.LifeStateChangeNotify, 0, lifeStateChangeNotify) // 删除实体 s.DestroyEntity(entity.id) @@ -159,9 +153,8 @@ func (s *Scene) CreateEntityAvatar(player *model.Player, avatarId uint32) uint32 moveState: uint16(proto.MotionState_MOTION_NONE), lastMoveSceneTimeMs: 0, lastMoveReliableSeq: 0, - // fightProp: player.AvatarMap[avatarId].FightPropMap, // 使用角色结构的数据 - entityType: uint32(proto.ProtEntityType_PROT_ENTITY_AVATAR), - // level: 0, // 使用角色结构的数据 + fightProp: player.AvatarMap[avatarId].FightPropMap, // 使用角色结构的数据 + entityType: uint32(proto.ProtEntityType_PROT_ENTITY_AVATAR), avatarEntity: &AvatarEntity{ uid: player.PlayerID, avatarId: avatarId, diff --git a/gs/model/avatar.go b/gs/model/avatar.go index ad579f71..882e5bed 100644 --- a/gs/model/avatar.go +++ b/gs/model/avatar.go @@ -9,24 +9,24 @@ import ( ) type Avatar struct { - AvatarId uint32 `bson:"avatarId"` // 角色id - LifeState uint16 `bson:"lifeState"` // 存活状态 - Level uint8 `bson:"level"` // 等级 - Exp uint32 `bson:"exp"` // 经验值 - Promote uint8 `bson:"promote"` // 突破等阶 - Satiation uint32 `bson:"satiation"` // 饱食度 - SatiationPenalty uint32 `bson:"satiationPenalty"` // 饱食度溢出 - CurrHP float64 `bson:"currHP"` // 当前生命值 - CurrEnergy float64 `bson:"currEnergy"` // 当前元素能量值 - FetterList []uint32 `bson:"fetterList"` // 资料解锁条目 - SkillLevelMap map[uint32]uint32 `bson:"skillLevelMap"` // 技能等级数据 - SkillDepotId uint32 `bson:"skillDepotId"` // 技能库id - FlyCloak uint32 `bson:"flyCloak"` // 当前风之翼 - Costume uint32 `bson:"costume"` // 当前衣装 - BornTime int64 `bson:"bornTime"` // 获得时间 - FetterLevel uint8 `bson:"fetterLevel"` // 好感度等级 - FetterExp uint32 `bson:"fetterExp"` // 好感度经验 - PromoteRewardMap map[uint32]bool `bson:"promoteRewardMap"` // 突破奖励 map[突破等级]是否已被领取 + AvatarId uint32 // 角色id + LifeState uint16 // 存活状态 + Level uint8 // 等级 + Exp uint32 // 经验值 + Promote uint8 // 突破等阶 + Satiation uint32 // 饱食度 + SatiationPenalty uint32 // 饱食度溢出 + CurrHP float64 // 当前生命值 + CurrEnergy float64 // 当前元素能量值 + FetterList []uint32 // 资料解锁条目 + SkillLevelMap map[uint32]uint32 // 技能等级数据 + SkillDepotId uint32 // 技能库id + FlyCloak uint32 // 当前风之翼 + Costume uint32 // 当前衣装 + BornTime int64 // 获得时间 + FetterLevel uint8 // 好感度等级 + FetterExp uint32 // 好感度经验 + PromoteRewardMap map[uint32]bool // 突破奖励 map[突破等级]是否已被领取 Guid uint64 `bson:"-" msgpack:"-"` EquipGuidMap map[uint64]uint64 `bson:"-" msgpack:"-"` EquipWeapon *Weapon `bson:"-" msgpack:"-"` diff --git a/gs/model/chat.go b/gs/model/chat.go index f0f3c97e..84afacc4 100644 --- a/gs/model/chat.go +++ b/gs/model/chat.go @@ -6,11 +6,11 @@ const ( ) type ChatMsg struct { - 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"` + Time uint32 + ToUid uint32 + Uid uint32 + IsRead bool + MsgType uint8 + Text string + Icon uint32 } diff --git a/gs/model/drop.go b/gs/model/drop.go index b1f532c1..acdbd9f2 100644 --- a/gs/model/drop.go +++ b/gs/model/drop.go @@ -1,15 +1,15 @@ package model type GachaPoolInfo struct { - GachaType uint32 `bson:"gachaType"` // 卡池类型 - OrangeTimes uint32 `bson:"orangeTimes"` // 5星保底计数 - PurpleTimes uint32 `bson:"purpleTimes"` // 4星保底计数 - MustGetUpOrange bool `bson:"mustGetUpOrange"` // 是否5星大保底 - MustGetUpPurple bool `bson:"mustGetUpPurple"` // 是否4星大保底 + GachaType uint32 // 卡池类型 + OrangeTimes uint32 // 5星保底计数 + PurpleTimes uint32 // 4星保底计数 + MustGetUpOrange bool // 是否5星大保底 + MustGetUpPurple bool // 是否4星大保底 } type DropInfo struct { - GachaPoolInfo map[uint32]*GachaPoolInfo `bson:"gachaPoolInfo"` + GachaPoolInfo map[uint32]*GachaPoolInfo } func NewDropInfo() (r *DropInfo) { diff --git a/gs/model/gcg.go b/gs/model/gcg.go index 14083cad..c12d504b 100644 --- a/gs/model/gcg.go +++ b/gs/model/gcg.go @@ -2,61 +2,61 @@ package model // GCGCard 卡牌 type GCGCard struct { - CardId uint32 `bson:"cardId"` // 卡牌Id - Num uint32 `bson:"num"` // 数量 - FaceType uint32 `bson:"faceType"` // 卡面类型 - UnlockFaceTypeList []uint32 `bson:"unlockFaceTypeList"` // 解锁的卡面类型 - Proficiency uint32 `bson:"proficiency"` // 熟练程度等级 - ProficiencyRewardTakenIdxList []uint32 `bson:"faceType"` // 熟练程度奖励列表 + CardId uint32 // 卡牌Id + Num uint32 // 数量 + FaceType uint32 // 卡面类型 + UnlockFaceTypeList []uint32 // 解锁的卡面类型 + Proficiency uint32 // 熟练程度等级 + ProficiencyRewardTakenIdxList []uint32 // 熟练程度奖励列表 } // GCGDeck 卡组 type GCGDeck struct { - Name string `bson:"name"` // 卡组名 - CharacterCardList []uint32 `bson:"characterCardList"` // 角色牌列表 - CardList []uint32 `bson:"cardList"` // 卡牌列表 - FieldId uint32 `bson:"fieldId"` // 牌盒样式Id - CardBackId uint32 `bson:"cardBackId"` // 牌背样式Id - CreateTime int64 `bson:"createTime"` // 卡组创建时间 + Name string // 卡组名 + CharacterCardList []uint32 // 角色牌列表 + CardList []uint32 // 卡牌列表 + FieldId uint32 // 牌盒样式Id + CardBackId uint32 // 牌背样式Id + CreateTime int64 // 卡组创建时间 } // GCGTavernChallenge 酒馆挑战信息 type GCGTavernChallenge struct { - CharacterId uint32 `bson:"characterId"` // 角色Id - UnlockLevelIdList []uint32 `bson:"unlockLevelIdList"` // 解锁的等级Id + CharacterId uint32 // 角色Id + UnlockLevelIdList []uint32 // 解锁的等级Id } // GCGBossChallenge Boss挑战信息 type GCGBossChallenge struct { - Id uint32 `bson:"Id"` // BossId - UnlockLevelIdList []uint32 `bson:"unlockLevelIdList"` // 解锁的等级Id + Id uint32 // BossId + UnlockLevelIdList []uint32 // 解锁的等级Id } // GCGLevelChallenge 等级挑战信息 type GCGLevelChallenge struct { - LevelId uint32 `bson:"levelId"` // 等级Id - FinishedChallengeIdList []uint32 `bson:"finishedChallengeIdList"` // 完成的挑战Id列表 + LevelId uint32 // 等级Id + FinishedChallengeIdList []uint32 // 完成的挑战Id列表 } // GCGInfo 七圣召唤信息 type GCGInfo struct { // 基础信息 - Level uint32 `bson:"level"` // 等级 - Exp uint32 `bson:"exp"` // 经验 + Level uint32 // 等级 + Exp uint32 // 经验 // 卡牌 - CardList map[uint32]*GCGCard `bson:"cardList"` // 拥有的卡牌 uint32 -> CardId(卡牌Id) - CurDeckId uint32 `bson:"CurDeckId"` // 现行的卡组Id - DeckList []*GCGDeck `bson:"deckList"` // 卡组列表 - UnlockDeckIdList []uint32 `bson:"unlockDeckIdList"` // 解锁的卡组 - UnlockCardBackIdList []uint32 `bson:"unlockCardBackIdList"` // 解锁的卡背 - UnlockFieldIdList []uint32 `bson:"unlockFieldIdList"` // 解锁的牌盒 + CardList map[uint32]*GCGCard // 拥有的卡牌 uint32 -> CardId(卡牌Id) + CurDeckId uint32 // 现行的卡组Id + DeckList []*GCGDeck // 卡组列表 + UnlockDeckIdList []uint32 // 解锁的卡组 + UnlockCardBackIdList []uint32 // 解锁的卡背 + UnlockFieldIdList []uint32 // 解锁的牌盒 // 挑战 - TavernChallengeMap map[uint32]*GCGTavernChallenge `bson:"tavernChallengeMap"` // 酒馆挑战 uint32 -> CharacterId(角色Id) - LevelChallengeMap map[uint32]*GCGLevelChallenge `bson:"levelChallengeMap"` // 等级挑战 uint32 -> LevelId(等级Id) - UnlockBossChallengeMap map[uint32]*GCGBossChallenge `bson:"unlockBossChallengeMap"` // 解锁的Boss挑战 uint32 -> Id - UnlockWorldChallengeList []uint32 `bson:"unlockWorldChallengeList"` // 解锁的世界挑战 + TavernChallengeMap map[uint32]*GCGTavernChallenge // 酒馆挑战 uint32 -> CharacterId(角色Id) + LevelChallengeMap map[uint32]*GCGLevelChallenge // 等级挑战 uint32 -> LevelId(等级Id) + UnlockBossChallengeMap map[uint32]*GCGBossChallenge // 解锁的Boss挑战 uint32 -> Id + UnlockWorldChallengeList []uint32 // 解锁的世界挑战 // 其他 - BanCardList []uint32 `bson:"banCardList"` // 被禁止的卡牌列表 + BanCardList []uint32 // 被禁止的卡牌列表 } func NewGCGInfo() *GCGInfo { diff --git a/gs/model/item.go b/gs/model/item.go index 1f4ef2a4..f5a2693d 100644 --- a/gs/model/item.go +++ b/gs/model/item.go @@ -3,8 +3,8 @@ package model import "hk4e/common/constant" type Item struct { - ItemId uint32 `bson:"itemId"` // 道具id - Count uint32 `bson:"count"` // 道具数量 + ItemId uint32 // 道具id + Count uint32 // 道具数量 Guid uint64 `bson:"-" msgpack:"-"` } diff --git a/gs/model/player.go b/gs/model/player.go index 7e30b99d..f93e40ec 100644 --- a/gs/model/player.go +++ b/gs/model/player.go @@ -26,36 +26,34 @@ type GameObject interface { type Player struct { // 离线数据 请尽量不要定义接口等复杂数据结构 ID primitive.ObjectID `bson:"_id,omitempty"` - PlayerID uint32 `bson:"playerID"` // 玩家uid - NickName string `bson:"nickname"` // 玩家昵称 - Signature string `bson:"signature"` // 玩家签名 - HeadImage uint32 `bson:"headImage"` // 玩家头像 - Birthday []uint8 `bson:"birthday"` // 生日 - NameCard uint32 `bson:"nameCard"` // 当前名片 - NameCardList []uint32 `bson:"nameCardList"` // 已解锁名片列表 - FriendList map[uint32]bool `bson:"friendList"` // 好友uid列表 - FriendApplyList map[uint32]bool `bson:"friendApplyList"` // 好友申请uid列表 - OfflineTime uint32 `bson:"offlineTime"` // 离线时间点 - OnlineTime uint32 `bson:"onlineTime"` // 上线时间点 - TotalOnlineTime uint32 `bson:"totalOnlineTime"` // 玩家累计在线时长 - PropertiesMap map[uint16]uint32 `bson:"propertiesMap"` // 玩家自身相关的一些属性 - RegionId uint32 `bson:"regionId"` // regionId - FlyCloakList []uint32 `bson:"flyCloakList"` // 风之翼列表 - CostumeList []uint32 `bson:"costumeList"` // 角色衣装列表 - SceneId uint32 `bson:"sceneId"` // 场景 - SafePos *Vector `bson:"safePos"` // 玩家在陆地时的坐标 - Pos *Vector `bson:"pos"` // 玩家坐标 - Rot *Vector `bson:"rot"` // 玩家朝向 - ItemMap map[uint32]*Item `bson:"itemMap"` // 玩家统一大背包仓库 - WeaponMap map[uint64]*Weapon `bson:"weaponMap"` // 玩家武器背包 - ReliquaryMap map[uint64]*Reliquary `bson:"reliquaryMap"` // 玩家圣遗物背包 - TeamConfig *TeamInfo `bson:"teamConfig"` // 队伍配置 - AvatarMap map[uint32]*Avatar `bson:"avatarMap"` // 角色信息 - DropInfo *DropInfo `bson:"dropInfo"` // 掉落信息 - MainCharAvatarId uint32 `bson:"mainCharAvatarId"` // 主角id - ChatMsgMap map[uint32][]*ChatMsg `bson:"chatMsgMap"` // 聊天信息 - GCGInfo *GCGInfo `bson:"gcgInfo"` // 七圣召唤信息 - IsGM uint8 `bson:"isGM"` // 管理员权限等级 + PlayerID uint32 `bson:"PlayerID"` // 玩家uid + NickName string // 玩家昵称 + Signature string // 玩家签名 + HeadImage uint32 // 玩家头像 + Birthday []uint8 // 生日 + NameCard uint32 // 当前名片 + NameCardList []uint32 // 已解锁名片列表 + FriendList map[uint32]bool // 好友uid列表 + FriendApplyList map[uint32]bool // 好友申请uid列表 + OfflineTime uint32 // 离线时间点 + OnlineTime uint32 // 上线时间点 + TotalOnlineTime uint32 // 玩家累计在线时长 + PropertiesMap map[uint16]uint32 // 玩家自身相关的一些属性 + FlyCloakList []uint32 // 风之翼列表 + CostumeList []uint32 // 角色衣装列表 + SceneId uint32 // 场景 + SafePos *Vector // 玩家在陆地时的坐标 + Pos *Vector // 玩家坐标 + Rot *Vector // 玩家朝向 + ItemMap map[uint32]*Item // 玩家统一大背包仓库 + WeaponMap map[uint64]*Weapon // 玩家武器背包 + ReliquaryMap map[uint64]*Reliquary // 玩家圣遗物背包 + TeamConfig *TeamInfo // 队伍配置 + AvatarMap map[uint32]*Avatar // 角色信息 + DropInfo *DropInfo // 掉落信息 + MainCharAvatarId uint32 // 主角id + GCGInfo *GCGInfo // 七圣召唤信息 + IsGM uint8 // 管理员权限等级 // 在线数据 请随意 记得加忽略字段的tag LastSaveTime uint32 `bson:"-" msgpack:"-"` // 上一次保存时间 EnterSceneToken uint32 `bson:"-" msgpack:"-"` // 玩家的世界进入令牌 @@ -79,6 +77,8 @@ type Player struct { GateAppId string `bson:"-" msgpack:"-"` // 网关服务器的appid FightAppId string `bson:"-" msgpack:"-"` // 战斗服务器的appid GCGCurGameGuid uint32 `bson:"-" msgpack:"-"` // GCG玩家所在的游戏guid + // 特殊数据 + ChatMsgMap map[uint32][]*ChatMsg `bson:"-" msgpack:"-"` // 聊天信息 数据量偏大 只从db读写 不保存到redis } func (p *Player) GetNextGameObjectGuid() uint64 { diff --git a/gs/model/reliquary.go b/gs/model/reliquary.go index 1a5aba7a..3d587218 100644 --- a/gs/model/reliquary.go +++ b/gs/model/reliquary.go @@ -6,15 +6,15 @@ import ( ) type Reliquary struct { - ReliquaryId uint64 `bson:"reliquaryId"` // 圣遗物的唯一id - ItemId uint32 `bson:"itemId"` // 圣遗物的道具id - Level uint8 `bson:"level"` // 等级 - Exp uint32 `bson:"exp"` // 当前经验值 - Promote uint8 `bson:"promote"` // 突破等阶 - Lock bool `bson:"lock"` // 锁定状态 - AffixIdList []uint32 `bson:"affixIdList"` // 词缀 - MainPropId uint32 `bson:"mainPropId"` // 主词条id - AvatarId uint32 `bson:"avatarId"` // 装备角色id + ReliquaryId uint64 // 圣遗物的唯一id + ItemId uint32 // 圣遗物的道具id + Level uint8 // 等级 + Exp uint32 // 当前经验值 + Promote uint8 // 突破等阶 + Lock bool // 锁定状态 + AffixIdList []uint32 // 词缀 + MainPropId uint32 // 主词条id + AvatarId uint32 // 装备角色id Guid uint64 `bson:"-" msgpack:"-"` } diff --git a/gs/model/team.go b/gs/model/team.go index 9736f557..6ada0eb0 100644 --- a/gs/model/team.go +++ b/gs/model/team.go @@ -7,8 +7,8 @@ import ( ) type Team struct { - Name string `bson:"name"` - AvatarIdList []uint32 `bson:"avatarIdList"` + Name string + AvatarIdList []uint32 } func (t *Team) GetAvatarIdList() []uint32 { @@ -33,9 +33,9 @@ func (t *Team) SetAvatarIdList(avatarIdList []uint32) { } type TeamInfo struct { - TeamList []*Team `bson:"teamList"` - CurrTeamIndex uint8 `bson:"currTeamIndex"` - CurrAvatarIndex uint8 `bson:"currAvatarIndex"` + TeamList []*Team + CurrTeamIndex uint8 + CurrAvatarIndex uint8 TeamResonances map[uint16]bool `bson:"-" msgpack:"-"` TeamResonancesConfig map[int32]bool `bson:"-" msgpack:"-"` } diff --git a/gs/model/vector.go b/gs/model/vector.go index eb5054ad..f6bc2ed1 100644 --- a/gs/model/vector.go +++ b/gs/model/vector.go @@ -3,9 +3,9 @@ package model import "math" type Vector struct { - X float64 `bson:"x"` - Y float64 `bson:"y"` - Z float64 `bson:"z"` + X float64 + Y float64 + Z float64 } // Distance 两坐标之间的距离 diff --git a/gs/model/weapon.go b/gs/model/weapon.go index 9c02df0b..a3ef88a1 100644 --- a/gs/model/weapon.go +++ b/gs/model/weapon.go @@ -6,15 +6,15 @@ import ( ) type Weapon struct { - WeaponId uint64 `bson:"weaponId"` // 武器的唯一id - ItemId uint32 `bson:"itemId"` // 武器的道具id - Level uint8 `bson:"level"` // 等级 - Exp uint32 `bson:"exp"` // 当前经验值 - Promote uint8 `bson:"promote"` // 突破等阶 - Lock bool `bson:"lock"` // 锁定状态 - AffixIdList []uint32 `bson:"affixIdList"` // 词缀 - Refinement uint8 `bson:"refinement"` // 精炼等阶 - AvatarId uint32 `bson:"avatarId"` // 装备角色id + WeaponId uint64 // 武器的唯一id + ItemId uint32 // 武器的道具id + Level uint8 // 等级 + Exp uint32 // 当前经验值 + Promote uint8 // 突破等阶 + Lock bool // 锁定状态 + AffixIdList []uint32 // 词缀 + Refinement uint8 // 精炼等阶 + AvatarId uint32 // 装备角色id Guid uint64 `bson:"-" msgpack:"-"` } diff --git a/pkg/object/object.go b/pkg/object/object.go index b1faaac2..e736c341 100644 --- a/pkg/object/object.go +++ b/pkg/object/object.go @@ -25,6 +25,23 @@ func DeepCopy(dst, src any) error { return nil } +func DeepMarshal(src any) ([]byte, error) { + var buf bytes.Buffer + err := gob.NewEncoder(&buf).Encode(src) + if err != nil { + return nil, err + } + return buf.Bytes(), nil +} + +func DeepUnmarshal(dst any, data []byte) error { + err := gob.NewDecoder(bytes.NewBuffer(data)).Decode(dst) + if err != nil { + return err + } + return nil +} + func CopyProtoBufSameField(dst, src pb.Message) ([]string, error) { data, err := protojson.Marshal(src) if err != nil {