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