| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326 |
- package db
- import (
- "context"
- "errors"
- capp "f1-game/internal/cherry_app"
- "f1-game/internal/component/db"
- dbFacade "f1-game/internal/component/db/facade"
- "f1-game/internal/component/redis"
- "f1-game/internal/data"
- "f1-game/internal/enum"
- nameDB "f1-game/internal/name/db"
- nameRedis "f1-game/internal/name/redis"
- "f1-game/internal/pb"
- "f1-game/internal/sessions"
- dbPlayer "f1-game/nodes/game/internal/db/data/player"
- "fmt"
- "slices"
- ctime "github.com/cherry-game/cherry/extend/time"
- cproto "github.com/cherry-game/cherry/net/proto"
- "go.mongodb.org/mongo-driver/v2/bson"
- "go.mongodb.org/mongo-driver/v2/mongo"
- clog "github.com/cherry-game/cherry/logger"
- )
- // PlayerTable 玩家表
- type (
- PlayerTable struct {
- PlayerID int64 `bson:"PlayerID,omitempty"`
- PID int32 `bson:"PID,omitempty"`
- OpenID string `bson:"OpenID,omitempty"`
- UID int64 `bson:"UID,omitempty"`
- NodeID string `bson:"NodeID,omitempty"`
- OriginNodeID string `bson:"OriginNodeID,omitempty"`
- CreateTime int64 `bson:"CreateTime,omitempty"`
- CreateIP string `bson:"CreateIP,omitempty"`
- dbPlayer.Data `bson:"Data,omitempty"`
- dbFacade.TableBase `bson:",inline"`
- }
- )
- func (*PlayerTable) TableName() string {
- return nameDB.Table_Player
- }
- func (p *PlayerTable) PrimaryValue() any {
- return p.PlayerID
- }
- func (p *PlayerTable) CheckField() {
- p.Data.CheckField()
- }
- func (p *PlayerTable) Save2Queue() {
- save2Queue(p)
- }
- func (p *PlayerTable) ToPlayerProto() pb.Player {
- return pb.Player{
- PlayerID: p.PlayerID,
- CreateTime: p.CreateTime,
- GameNodeID: p.NodeID, // TODO 这个为何要下发?
- HasMap: p.Map.MapNodeID != "",
- ChangeNameCount: p.Lord.ChangeNameCount,
- LastChangeNameTime: p.Lord.LastChangeNameTime,
- ClientSettings: p.Settings.List,
- }
- }
- func (p *PlayerTable) ToAOIWatcher() *pb.AOIObject {
- return &pb.AOIObject{
- ObjectID: p.Map.ObjectID,
- ObjectType: int32(enum.ObjectType_Player),
- X: p.Map.Point.X,
- Y: p.Map.Point.Y,
- IsWatcher: true,
- IsMarker: false,
- OnwerID: p.PlayerID,
- }
- }
- // NewPlayer 创建新玩家
- func NewPlayer(playerID int64, session *cproto.Session, name string) (*PlayerTable, bool) {
- var (
- pid = sessions.GetPID(session)
- openID = sessions.GetOpenID(session)
- language = session.GetString(sessions.Language)
- uid = session.Uid
- ip = session.Ip
- )
- if playerID < 1 {
- clog.Warnf("playerID error. [pid = %d, openID = %s, name = %s]", pid, openID, name)
- return nil, false
- }
- if uid < 1 || pid < 1 || openID == "" {
- clog.Warnf("params error. [pid = %d, openID = %s, name = %s]", pid, openID, name)
- return nil, false
- }
- if name == "" {
- name = fmt.Sprintf("%d", playerID)
- }
- player := newPlayerTable(playerID)
- player.PID = pid
- player.OpenID = openID
- player.UID = uid
- player.Lord.Name = name
- player.Lord.IconID = data.Const.PlayerInitIcon
- player.Lord.BgID = data.Const.PlayerInitBg
- player.CreateTime = ctime.Now().ToMillisecond()
- player.CreateIP = ip
- if language != "" {
- player.Settings.Language = language
- }
- player.Save2Queue() // 提交到db队列
- uidCache.Put(uid, player.PlayerID) // 缓存 uid->playerID
- uidCount.Add(1) // 用户总数+1
- playerNameCache.Put(name, player.PlayerID) // 缓存 playerName->playerID
- playerTableCache.Put(playerID, player) // 缓存 playerID->playerTable
- // 初始玩家相关表
- initTables(playerID)
- return player, true
- }
- func GetPlayerTable(playerID int64) (*PlayerTable, bool) {
- if val, ok := playerTableCache.GetIfPresent(playerID); ok {
- return val.(*PlayerTable), true
- }
- if playerTable, found := GetPlayerTableFromDB(playerID); found {
- playerTableCache.Put(playerID, playerTable)
- return playerTable, true
- }
- return nil, false
- }
- func GetPlayerTableFromDB(playerID int64) (*PlayerTable, bool) {
- playerTable := newPlayerTable(playerID)
- filter := bson.M{
- nameDB.Field_NodeID: playerTable.NodeID,
- nameDB.Field_PlayerID: playerTable.PlayerID,
- }
- err := dbComponent.FindOne(playerTable, filter)
- if err != nil {
- if !errors.Is(err, mongo.ErrNoDocuments) {
- clog.Errorf("[playerID = %d] db error = %v", playerID, err)
- }
- return nil, false
- }
- playerTable.CheckField()
- return playerTable, true
- }
- func newPlayerTable(playerID int64) *PlayerTable {
- return &PlayerTable{
- PlayerID: playerID,
- NodeID: capp.NodeID(),
- OriginNodeID: capp.NodeID(),
- Data: dbPlayer.NewData(),
- }
- }
- func GetPlayerIDWithUID(uid int64) (int64, bool) {
- if val, ok := uidCache.GetIfPresent(uid); ok {
- return val.(int64), true
- }
- return 0, false
- }
- // PlayerNameIsExist 玩家名全局唯一
- func PlayerNameIsExist(playerName string) (int64, bool) {
- if val, ok := playerNameCache.GetIfPresent(playerName); ok {
- return val.(int64), true
- }
- return 0, false
- }
- // GetPlayerIDList 批量查询玩家id(过滤不存在的)
- func GetPlayerIDList(ids []int64) []int64 {
- var list []int64
- for _, playerID := range ids {
- if _, found := GetPlayerTable(playerID); found {
- list = append(list, playerID)
- }
- }
- return list
- }
- // preloadPlayerTable 预加载所有玩家部份信息
- func preloadPlayerTable() {
- var (
- collection = dbComponent.Collection(nameDB.Table_Player)
- ctx = context.TODO()
- pageNum int32 = 1
- pageSize int32 = 100000 // 10W
- filter = bson.M{nameDB.Field_NodeID: capp.NodeID()}
- projection = bson.M{
- nameDB.Field_PlayerID: 1,
- nameDB.Field_LordName: 1,
- nameDB.Field_UID: 1,
- }
- count int64 = 0
- )
- for {
- list, _, err := db.Pagination[*PlayerTable](collection, ctx, filter, projection, nil, pageNum, pageSize, false)
- if err != nil {
- clog.Errorf("[preloadPlayerTable] err = %v", err)
- break
- }
- // clog.Debugf("[preloadPlayerTable] pageNum = %d, count = %d, total = %d", pageNum, len(list), total)
- if len(list) < 1 {
- break
- }
- for _, playerTable := range list {
- // 加载UID uid-> playerID
- uidCache.Put(playerTable.UID, playerTable.PlayerID)
- // 加载玩家名 playerName -> playerID
- playerNameCache.Put(playerTable.Lord.Name, playerTable.PlayerID)
- }
- pageNum++
- count += int64(len(list))
- }
- clog.Infof("preload player info count = %d", count)
- }
- func (p *PlayerTable) ToPlayerInfo() *pb.PlayerInfo {
- return &pb.PlayerInfo{
- GameNodeID: p.NodeID,
- PlayerID: p.PlayerID,
- PlayerName: p.Lord.Name,
- Level: p.Lord.Level,
- Power: p.Lord.Power,
- RegisterIP: p.CreateIP,
- RegisterTime: p.CreateTime,
- }
- }
- func (p *PlayerTable) UpdatePlayerName(newName string, curTime int64) {
- p.Lord.Name = newName
- // 删除原来名字
- playerNameCache.Invalidate(p.Lord.Name)
- playerNameCache.Put(newName, p.PlayerID)
- p.Lord.ChangeNameCount += 1
- p.Lord.LastChangeNameTime = curTime
- }
- // 检测外显过期
- func (p *PlayerTable) CheckShowExpire(nowSecond int64) ([]int32, []*pb.I32I32) {
- if p.Shows.ShowMap.Empty() {
- return nil, nil
- }
- expireShowIDs := p.Shows.CheckExpire(nowSecond)
- if len(expireShowIDs) <= 0 {
- return nil, nil
- }
- var (
- changeShows = []*pb.I32I32{}
- fields = map[string]any{}
- )
- // 检测头像是否过期 // TODO 过期后默认的头像、头像框和背景是否使用默认的外显ID
- if slices.Contains(expireShowIDs, p.Lord.IconID) {
- p.Lord.IconID = 0
- changeShows = append(changeShows, &pb.I32I32{
- Key: enum.ShowType_Icon,
- Value: 0,
- })
- fields[nameRedis.Player_IconID] = p.Lord.IconID
- }
- // 检测头像框是否过期
- if slices.Contains(expireShowIDs, p.Lord.FrameID) {
- p.Lord.FrameID = 0
- changeShows = append(changeShows, &pb.I32I32{
- Key: enum.ShowType_Frame,
- Value: 0,
- })
- fields[nameRedis.Player_FrameID] = p.Lord.FrameID
- }
- // 检测背景是否过期
- if slices.Contains(expireShowIDs, p.Lord.BgID) {
- p.Lord.BgID = 0
- changeShows = append(changeShows, &pb.I32I32{
- Key: enum.ShowType_Bg,
- Value: 0,
- })
- fields[nameRedis.Player_BgID] = p.Lord.BgID
- }
- // 更新redis数据
- if len(fields) > 0 {
- redis.Game.SavePlayerDataFields(p.PlayerID, fields)
- }
- return expireShowIDs, changeShows
- }
|