From 5878f2872607b9b9186ad5ce3623aff88bbcef6b Mon Sep 17 00:00:00 2001
From: hxp <ale99527@vip.qq.com>
Date: 星期二, 04 三月 2025 16:34:07 +0800
Subject: [PATCH] 5563 【英文】【BT】跨服服务器维护优化(打包数据改为db自己管理存取)

---
 ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerPackData.py |  295 +++++++++-------------------------------------------------
 1 files changed, 47 insertions(+), 248 deletions(-)

diff --git a/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerPackData.py b/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerPackData.py
index 49e8ab3..8775a48 100644
--- a/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerPackData.py
+++ b/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerPackData.py
@@ -24,25 +24,25 @@
 #            如切磋一下,玩家可以在任意场景对任意本服或跨服玩家发起切磋,与其镜像进行一场友谊PK,纯娱乐
 #            这种为被动式,即目标玩家可能不存在打包数据表中,需要取拉取
 #
+# 由于打包数据较大,影响开关服及备档的速度,还会导致内存不足,故改为db直接管理打包数据获取及入库
+# GameServer仅保留单次启动后有同步/获取的玩家数据,一般比db少,只保留打包数据信息,玩家基本信息改为从ViewCahce中获取
 #-------------------------------------------------------------------------------
 #"""Version = 2024-10-17 15:00"""
 #-------------------------------------------------------------------------------
 
-import CommFunc
 import GameWorld
 import PyDataManager
 import PlayerViewCache
 import PyGameDataStruct
-import CrossChampionship
 import CrossRealmMsg
 import PlayerControl
 import ShareDefine
 import PyGameData
 import ChConfig
 
-import time
 import base64
 
+Def_CahceCountMax = 100 # 最大缓存个数,注:GameServer缓不缓存这个数据都无所谓(改为在db缓存),保留原取数据逻辑不变,暂时缓存个x条,方便本服的直接取
 TempDBPlayer = PyGameDataStruct.tagDBPlayer()
 
 def GetDBPlayerByPackData(packData):
@@ -51,249 +51,48 @@
     if packData:
         TempDBPlayer.readData(base64.b64decode(packData))
     return TempDBPlayer
-
-class PlayerPackDataObj():
-    
-    def __init__(self):
-        self.dbPlayerPackData = None
-        self.playerID = 0
-        self.playerName = ""
-        self.accID = ""
-        self.lv = 0
-        self.job = 0
-        self.realmLV = 0
-        self.face = 0
-        self.facePic = 0
-        self.fightPower = 0
-        self.serverID = 0
-        return
-    
-    def GetBaseDict(self):
-        return {"playerID":self.playerID, "playerName":self.playerName, "lv":self.lv, "job":self.job, 
-                "realmLV":self.realmLV, "face":self.face, "facePic":self.facePic, "fightPower":self.fightPower}
-        
-    def UpdPackData(self, packData):
-        if not packData:
-            return
-        if not self.dbPlayerPackData:
-            self.dbPlayerPackData = PyGameDataStruct.tagDBPlayerPackData()
-        self.dbPlayerPackData.PlayerID = self.playerID
-        self.dbPlayerPackData.PackData = packData
-        self.dbPlayerPackData.PackDataSize = len(self.dbPlayerPackData.PackData)
-        self.dbPlayerPackData.UpdTime = int(time.time())
-        self.Unpack()
-        return
-    
-    def Unpack(self):
-        if not self.dbPlayerPackData:
-            return
-        dbPlayer = GetDBPlayerByPackData(self.dbPlayerPackData.PackData)
-        self.playerID = dbPlayer.PlayerID
-        self.accID = dbPlayer.AccID
-        self.playerName = dbPlayer.PlayerName
-        self.lv = dbPlayer.LV
-        self.job = dbPlayer.Job
-        self.realmLV = dbPlayer.OfficialRank
-        self.face = dbPlayer.Face
-        self.facePic = dbPlayer.FacePic
-        self.fightPower = dbPlayer.FightPowerEx * ChConfig.Def_PerPointValue + dbPlayer.FightPower
-        self.serverID = GameWorld.GetAccIDServerID(self.accID)
-        return
-    
-    def GetPackData(self): return self.dbPlayerPackData.PackData if self.dbPlayerPackData else ""
-    def GetUpdTime(self): return self.dbPlayerPackData.UpdTime if self.dbPlayerPackData else 0
     
 class DBPlayerPackDataManager():
-    ## 玩家打包数据管理
+    ## 玩家打包数据管理 - 这里仅管理本次启动后的热数据缓存,不入库
     
     def __init__(self):
         self.Clear()
         return
     
     def Clear(self):
-        self.__packDataList = [] # [PlayerPackDataObj, ...]
-        self.__idIndexDict = {} # {playerID:index, ...}
-        self.__needSort = False
-        self.__serverIDRangePlayerIDDict = {} # {serverIDRangeTuple:[playerID, ...], ....}
+        self.__packDataDcit = {} # {playerID:packData, ...}
+        self.__packDataPlayerIDList = [] # [playerID, ...] # 限制缓存数,先进先出
         return
-    
-    def GetPlayerPackObj(self, playerID, isAddNew=False):
-        packDataObj = None
-        self.__refreshIDIndex()
-        if playerID in self.__idIndexDict:
-            index = self.__idIndexDict[playerID]
-            if index < len(self.__packDataList):
-                packDataObj = self.__packDataList[index]
-                
-        if not packDataObj and isAddNew:
-            packDataObj = PlayerPackDataObj()
-            packDataObj.playerID = playerID
-            self.__packDataList.append(packDataObj)
-            self.__idIndexDict[playerID] = len(self.__packDataList) - 1
-            self.__needSort = True
-            
-        return packDataObj
-    
-    def GetPlayerIDListByServerIDInfo(self, serverIDList):
-        ## 根据服务器ID列表信息获取对应服务器ID范围的玩家ID战力排序列表
-        self.Sort()
-        key = tuple(serverIDList)
-        if key not in self.__serverIDRangePlayerIDDict:
-            playerIDList = []
-            for dataObj in self.__packDataList:
-                playerID = dataObj.playerID
-                serverID = dataObj.serverID
-                for idInfo in serverIDList:
-                    if (isinstance(idInfo, int) and serverID == idInfo) \
-                        or ((isinstance(idInfo, tuple) or isinstance(idInfo, list)) \
-                            and len(idInfo) == 2 and idInfo[0] <= serverID <= idInfo[1]):
-                        playerIDList.append(playerID)
-            GameWorld.DebugLog("重新加载区服打包玩家ID列表: %s, %s, %s" % (key, len(playerIDList), playerIDList))
-            self.__serverIDRangePlayerIDDict[key] = playerIDList
-        return self.__serverIDRangePlayerIDDict[key]
-    
+        
     def IsPlayerIn(self, playerID):
-        self.__refreshIDIndex()
-        return playerID in self.__idIndexDict
+        return playerID in self.__packDataDcit
     
-    def __refreshIDIndex(self):
-        if not self.__idIndexDict:
-            self.__idIndexDict = {}
-            for index, dataObj in enumerate(self.__packDataList):
-                self.__idIndexDict[dataObj.playerID] = index
-        return self.__idIndexDict
+    def GetCount(self): return len(self.__packDataDcit)
+    
+    def GetPlayerPackdata(self, playerID):
+        if playerID not in self.__packDataDcit:
+            return ""
+        # 恢复数据热度
+        if playerID in self.__packDataPlayerIDList:
+            self.__packDataPlayerIDList.remove(playerID)
+        self.__packDataPlayerIDList.append(playerID)
+        GameWorld.DebugLog("获取打包数据缓存数更新: %s,%s" % (len(self.__packDataPlayerIDList), self.__packDataPlayerIDList))
+        return self.__packDataDcit[playerID]
     
     def UpdPlayerPackData(self, playerID, packData):
         if not packData:
             return
-        packObj = self.GetPlayerPackObj(playerID, True)
-        packObj.UpdPackData(packData)
-        self.__needSort = True
-        return packObj
-    
-    def DelPlayerPackData(self, playerID):
-        self.__refreshIDIndex()
-        index = self.__idIndexDict.pop(playerID, -1)
-        if index >= 0 and index < len(self.__packDataList):
-            self.__packDataList.pop(index)
-        for playerIDList in self.__serverIDRangePlayerIDDict.values():
-            if playerID in playerIDList:
-                playerIDList.remove(playerID)
-                
-        #只要有删除,需重置index映射
-        self.__idIndexDict = {}
-        self.__serverIDRangePlayerIDDict = {}
+        self.__packDataDcit[playerID] = packData
+        if playerID in self.__packDataPlayerIDList:
+            # 添加热度,重复更新的不影响热度
+            self.__packDataPlayerIDList.append(playerID)
+            if len(self.__packDataPlayerIDList) > Def_CahceCountMax:
+                delPlayerID = self.__packDataPlayerIDList.pop(0)
+                if delPlayerID in self.__packDataDcit:
+                    del self.__packDataDcit[delPlayerID]
+                GameWorld.DebugLog("删除打包数据缓存: delPlayerID=%s" % delPlayerID)
+            GameWorld.DebugLog("添加打包数据缓存数更新: %s,%s" % (len(self.__packDataPlayerIDList), self.__packDataPlayerIDList))
         return
-    
-    def GetCount(self): return len(self.__packDataList)    
-    def At(self, index):
-        dataObj = self.__packDataList[index]
-        if not dataObj and False:
-            dataObj = PlayerPackDataObj() # 不会执行到,只为了.出代码提示
-        return dataObj
-    
-    def Sort(self):
-        ## 默认按战力倒序排
-        if not self.__needSort:
-            return
-        self.__needSort = False
-        self.__packDataList.sort(key=lambda d: (d.fightPower), reverse=True)
-        self.__idIndexDict = {}
-        self.__serverIDRangePlayerIDDict = {}
-        self.__refreshIDIndex()
-        return
-    
-    # 保存数据 存数据库和realtimebackup
-    def GetSaveData(self):
-        savaData = ""
-        cntData = ""
-        cnt = 0
-        
-        for index in xrange(self.GetCount()):
-            dataObj = self.At(index)
-            if not dataObj.dbPlayerPackData:
-                continue
-            cnt += 1
-            savaData += dataObj.dbPlayerPackData.getBuffer()
-            if cnt >= 10:
-                break
-            
-        GameWorld.Log("Save DBPlayerPackData count :%s len=%s" % (cnt, len(savaData)))
-        return CommFunc.WriteDWORD(cntData, cnt) + savaData
-    
-    # 从数据库载入数据
-    def LoadPyGameData(self, datas, pos, dataslen):
-        cnt, pos = CommFunc.ReadDWORD(datas, pos)
-        GameWorld.Log("Load DBPlayerPackData count :%s" % cnt)
-        
-        self.Clear()
-        
-        for _ in xrange(cnt):
-            dbData = PyGameDataStruct.tagDBPlayerPackData()
-            pos += dbData.readData(datas, pos, dataslen)
-            playerID = dbData.PlayerID
-            
-            packObj = self.GetPlayerPackObj(playerID, True)
-            packObj.dbPlayerPackData = dbData
-            packObj.Unpack()
-            
-        self.Sort()
-        return pos
-
-def IsSaveDB(packDataObj):
-    ## 是否入库
-    if not packDataObj:
-        return False
-    
-    playerID = packDataObj.playerID
-    
-    if CrossChampionship.IsChampionshipPlayer(playerID):
-        return True
-    
-    #跨服榜单上的默认保留
-    if GameWorld.IsCrossServer():
-        billboardMgr = PyDataManager.GetCrossBillboardManager()
-        for billboardType in ShareDefine.CrossBillboardTypeList:
-            groupList = billboardMgr.GetBillboardGroupList(billboardType)
-            for billboardType, groupValue1, groupValue2 in groupList:
-                billboardObj = billboardMgr.GetCrossBillboard(billboardType, groupValue1, groupValue2)
-                if billboardObj.FindByID(playerID):
-                    return True
-                
-    else:
-        pass
-#        NeedCheckBillBoardType = IpyGameDataPY.GetFuncEvalCfg("PlayerViewCache", 2)
-#        #校验玩家是否上排行榜
-#        billboardMgr = GameWorld.GetBillboard()
-#        for BillBoardType in NeedCheckBillBoardType:
-#            curBillboard = billboardMgr.FindBillboard(BillBoardType)
-#            if not curBillboard:
-#                continue
-#            if curBillboard.FindByID(playerID):
-#                return True
-            
-    # 以上是相关功能需要用到的数据,必定不能删除的
-    
-    maxDays = 7 # 默认7天
-    MaxTime = maxDays * 3600 * 24
-    curTime = int(time.time())
-    passTime = curTime - packDataObj.GetUpdTime()
-    if passTime < MaxTime:
-        return True
-    
-    return False
-
-def DelOutofTimePackData():
-    ## 删除过期
-    
-    packDataMgr = PyDataManager.GetDBPlayerPackDataManager()
-    for index in range(packDataMgr.GetCount())[::-1]: # 可能删数据,倒序遍历
-        packDataObj = packDataMgr.At(index)
-        if IsSaveDB(packDataObj):
-            continue
-        packDataMgr.DelPlayerPackData(packDataObj.playerID)
-        
-    return
 
 def IsPackDataPlayer(playerID):
     return PyDataManager.GetDBPlayerPackDataManager().IsPlayerIn(playerID)
@@ -341,6 +140,7 @@
     
     # pullFrom 0-跨服拉子服; >0-子服通过跨服拉子服
     if GameWorld.IsCrossServer():
+        PlayerViewCache.SetNeedViewCache(pullPlayerIDList) # 拉打包数据的时候默认需要缓存数据
         # 广播给子服拉数据
         msgInfo["pullFrom"] = 0
         dataMsg = {"pullPlayerIDList":pullPlayerIDList, "msgInfo":msgInfo}
@@ -371,7 +171,7 @@
     if not curPlayer:
         GameWorld.DebugLog("玩家不在线的调用打包db数据! playerID=%s" % (playerID), playerID)
         data = str(msgInfo)
-        GameWorld.GetGameWorld().SendDBLogic(ChConfig.gstDBLogic_PlayerPackData, playerID, data, len(data))
+        GameWorld.GetGameWorld().SendDBLogic(ChConfig.gstDBLogic_PlayerPackDataReq, playerID, data, len(data))
         return
     GameWorld.DebugLog("玩家在线的发给地图打包数据! playerID=%s" % (playerID), playerID)
     # 在线的转发给地图
@@ -442,9 +242,6 @@
     ## 收到子服同步的玩家打包数据
     playerID = msgData["playerID"]
     packData = msgData["packData"]
-    cacheBase = msgData.get("cacheBase", {})
-    if cacheBase:
-        PlayerViewCache.UpdCrossCacheBase(playerID, cacheBase)
     PyDataManager.GetDBPlayerPackDataManager().UpdPlayerPackData(playerID, packData)
     
     msgInfo = msgData.get("msgInfo", {})
@@ -469,21 +266,23 @@
     
     msgInfo = msgData["msgInfo"]
     pullPlayerIDList = msgData["pullPlayerIDList"]
+    dbPackDataIDList = msgData.get("dbPackDataIDList", []) # db标记的有打包数据的玩家ID
     
     otherServerPlayerIDList = []
     packDataMgr = PyDataManager.GetDBPlayerPackDataManager()
     for playerID in pullPlayerIDList:
-        packObj = packDataMgr.GetPlayerPackObj(playerID)
+        packData = packDataMgr.GetPlayerPackdata(playerID)
         # 已经有的数据先推送回去
-        if packObj:
-            GameWorld.DebugLog("跨服有缓存玩家打包数据,直接推给子服! playerID=%s" % playerID)
-            dataMsg = {"playerID":playerID, "packData":packObj.GetPackData(), "msgInfo":msgInfo}
+        if packData or playerID in dbPackDataIDList:
+            GameWorld.DebugLog("跨服GameServer或db有缓存玩家打包数据,直接推给子服! playerID=%s" % playerID)
+            dataMsg = {"playerID":playerID, "packData":packData, "msgInfo":msgInfo}
             CrossRealmMsg.SendMsgToClientServer(ShareDefine.CrossServerMsg_PushPlayerPackData, dataMsg, [serverGroupID])
         else:
             otherServerPlayerIDList.append(playerID)
             
     # 还没有数据的,广播给其他子服拉数据
     if otherServerPlayerIDList:
+        PlayerViewCache.SetNeedViewCache(otherServerPlayerIDList) # 拉打包数据的时候默认需要缓存数据
         dataMsg = {"pullPlayerIDList":otherServerPlayerIDList, "msgInfo":msgInfo}
         CrossRealmMsg.SendMsgToClientServer(ShareDefine.CrossServerMsg_PullPlayerPackData, dataMsg)
         
@@ -508,10 +307,10 @@
     
     packDataMgr = PyDataManager.GetDBPlayerPackDataManager()
     for playerID in pullPlayerIDList:
-        packObj = packDataMgr.GetPlayerPackObj(playerID)
-        if packObj:
+        packData = packDataMgr.GetPlayerPackdata(playerID)
+        if packData:
             GameWorld.DebugLog("本服有缓存玩家打包数据,直接推给跨服! playerID=%s" % playerID)
-            dataMsg = {"playerID":playerID, "packData":packObj.GetPackData(), "msgInfo":msgInfo}
+            dataMsg = {"playerID":playerID, "packData":packData, "msgInfo":msgInfo}
             CrossRealmMsg.SendMsgToCrossServer(ShareDefine.ClientServerMsg_PlayerPackData, dataMsg)
         else:
             DoPullPlayerPackData(playerID, msgInfo)
@@ -541,14 +340,14 @@
     if not packDataSyncState or not packData:
         return
     
-    # 本服需要,先更新数据
-    if packDataSyncState&pow(2, 0):
+    # 本服需要,先更新数据;跨服需要则也默认本服需要
+    if packDataSyncState&pow(2, 0) or packDataSyncState&pow(2, 1):
         PyDataManager.GetDBPlayerPackDataManager().UpdPlayerPackData(playerID, packData)
+        GameWorld.GetGameWorld().SendDBLogic(ChConfig.gstDBLogic_PlayerPackDataUpd, playerID, packData, len(packData))
         
     # 跨服需要,同步给跨服,由跨服服务器再进一步处理
     if packDataSyncState&pow(2, 1):
-        cacheBase = PlayerViewCache.GetSyncCrossCacheBase(curPlayer) if curPlayer else {}
-        dataMsg = {"playerID":playerID, "packData":packData, "cacheBase":cacheBase, "msgInfo":msgInfo}
+        dataMsg = {"playerID":playerID, "packData":packData, "msgInfo":msgInfo}
         CrossRealmMsg.SendMsgToCrossServer(ShareDefine.ClientServerMsg_PlayerPackData, dataMsg)
         
     # 本服需要的功能
@@ -585,9 +384,9 @@
     requestID = msgInfo["requestID"]
     mirrorIDList = msgInfo["mirrorIDList"]
     for mirrorID in mirrorIDList:
-        packObj = packDataMgr.GetPlayerPackObj(mirrorID)
-        if packObj:
-            packDataDict[mirrorID] = packObj.GetPackData()
+        packData = packDataMgr.GetPlayerPackdata(mirrorID)
+        if packData:
+            packDataDict[mirrorID] = packData
             continue
         pullPlayerIDList.append(mirrorID)
         

--
Gitblit v1.8.0