ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerPackData.py
@@ -33,6 +33,7 @@
import PyDataManager
import PlayerViewCache
import PyGameDataStruct
import CrossChampionship
import CrossRealmMsg
import PlayerControl
import ShareDefine
@@ -40,7 +41,68 @@
import ChConfig
import time
import base64
TempDBPlayer = PyGameDataStruct.tagDBPlayer()
def GetDBPlayerByPackData(packData):
    ## 根据 curPlayer.GetPackData() 打包返回的数据获取DBPlayer数据
    TempDBPlayer.clear()
    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():
    ## 玩家打包数据管理
    
@@ -49,26 +111,92 @@
        return
    
    def Clear(self):
        self.playerPackDataDict = {} # {playerID:tagDBPlayerPackData, ...}
        self.__packDataList = [] # [PlayerPackDataObj, ...]
        self.__idIndexDict = {} # {playerID:index, ...}
        self.__needSort = False
        self.__serverIDRangePlayerIDDict = {} # {serverIDRangeTuple:[playerID, ...], ....}
        return
    
    def GetPlayerPackObj(self, playerID, isAddNew=False):
        packDataObj = None
        if playerID in self.playerPackDataDict:
            packDataObj = self.playerPackDataDict[playerID]
        elif isAddNew:
            packDataObj = PyGameDataStruct.tagDBPlayerPackData()
            packDataObj.PlayerID = playerID
            self.playerPackDataDict[playerID] = packDataObj
        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
    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 UpdPlayerPackData(self, playerID, packData):
        if not packData:
            return
        packObj = self.GetPlayerPackObj(playerID, True)
        packObj.UpdTime = int(time.time())
        packObj.PackData = packData
        packObj.PackDataSize = len(packObj.PackData)
        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)
        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
@@ -77,9 +205,14 @@
        cntData = ""
        cnt = 0
        
        for dbData in self.playerPackDataDict.values():
        for index in xrange(self.GetCount()):
            dataObj = self.At(index)
            if not dataObj.dbPlayerPackData:
                continue
            cnt += 1
            savaData += dbData.getBuffer()
            savaData += dataObj.dbPlayerPackData.getBuffer()
            if cnt >= 200:
                break
            
        GameWorld.Log("Save DBPlayerPackData count :%s len=%s" % (cnt, len(savaData)))
        return CommFunc.WriteDWORD(cntData, cnt) + savaData
@@ -94,9 +227,13 @@
        for _ in xrange(cnt):
            dbData = PyGameDataStruct.tagDBPlayerPackData()
            pos += dbData.readData(datas, pos, dataslen)
            playerID = dbData.PlayerID
            
            self.playerPackDataDict[dbData.PlayerID] = dbData
            packObj = self.GetPlayerPackObj(playerID, True)
            packObj.dbPlayerPackData = dbData
            packObj.Unpack()
            
        self.Sort()
        return pos
def IsSaveDB(packDataObj):
@@ -104,13 +241,39 @@
    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.UpdTime
    passTime = curTime - packDataObj.GetUpdTime()
    if passTime < MaxTime:
        return True
    
@@ -120,32 +283,23 @@
    ## 删除过期
    
    packDataMgr = PyDataManager.GetDBPlayerPackDataManager()
    playerPackDataDict = packDataMgr.playerPackDataDict
    for playerID, packDataObj in playerPackDataDict.items():
    for index in range(packDataMgr.GetCount())[::-1]: # 可能删数据,倒序遍历
        packDataObj = packDataMgr.At(index)
        if IsSaveDB(packDataObj):
            continue
        playerPackDataDict.pop(playerID)
        packDataMgr.DelPlayerPackData(packDataObj.playerID)
        
    return
def IsPackDataPlayer(playerID):
    return playerID in PyDataManager.GetDBPlayerPackDataManager().playerPackDataDict
    return PyDataManager.GetDBPlayerPackDataManager().IsPlayerIn(playerID)
def OnPlayerLogin(curPlayer):
    ## 本服登录逻辑
    playerID = curPlayer.GetPlayerID()
    packDataMgr = PyDataManager.GetDBPlayerPackDataManager()
    if playerID in packDataMgr.playerPackDataDict:
        isCross, isNeed = 0, 1
        QueryPlayerResult_PlayerMirror(curPlayer, "PackDataSyncState", [isCross, isNeed])
    return
def OnPlayerLogin_CrossLogic(serverGroupID, serverID, playerID):
    ## 跨服登录逻辑
    packDataMgr = PyDataManager.GetDBPlayerPackDataManager()
    if playerID in packDataMgr.playerPackDataDict:
        dataMsg = {"playerID":playerID}
        CrossRealmMsg.SendMsgToClientServer(ShareDefine.CrossServerMsg_PlayerPackDataState, dataMsg, [serverGroupID])
    if packDataMgr.IsPlayerIn(playerID):
        QueryPlayerResult_PlayerMirror(curPlayer, "PackDataSyncState", {"PackData":1})
    return
def SetNeedPackData(playerIDList):
@@ -157,7 +311,7 @@
    pullPlayerIDList = []
    packDataMgr = PyDataManager.GetDBPlayerPackDataManager()
    for playerID in playerIDList:
        if playerID in packDataMgr.playerPackDataDict:
        if packDataMgr.IsPlayerIn(playerID):
            continue
        pullPlayerIDList.append(playerID)
        
@@ -256,22 +410,23 @@
    msgType = msgInfo.get("msgType")
    # 镜像战斗
    if msgType == "MirrorBattle":
        sceneMapID = msgInfo.get("sceneMapID", 0)
        playerID = msgInfo.get("playerID", 0)
        # 玩家发起的
        if playerID:
            playerID = msgInfo["playerID"]
            curPlayer = GameWorld.GetPlayerManager().FindPlayerByID(playerID)
            if not curPlayer:
                return
            tagMapID = GameWorld.GetQueryPlayerMapID(curPlayer)
            routeIndex = curPlayer.GetRouteServerIndex()
        else:
            tagMapID = msgInfo.get("requestMapID", 0)
            routeIndex = -1
        routeIndex = -1
#        # 玩家发起的
#        if playerID:
#            playerID = msgInfo["playerID"]
#            curPlayer = GameWorld.GetPlayerManager().FindPlayerByID(playerID)
#            if not curPlayer:
#                return
#            sceneMapID = GameWorld.GetQueryPlayerMapID(curPlayer)
#            routeIndex = curPlayer.GetRouteServerIndex()
#        else:
#            routeIndex = -1
            
        sendMsg = str([msgInfo, packDataDict])
        GameWorld.DebugLog("MapServer_QueryPlayer tagMapID=%s,len=%s" % (tagMapID, len(sendMsg)), playerID)
        GameWorld.GetPlayerManager().MapServer_QueryPlayer(0, 0, playerID, tagMapID, "PlayerMirror", sendMsg, len(sendMsg), routeIndex)
        GameWorld.DebugLog("MapServer_QueryPlayer sceneMapID=%s,len=%s" % (sceneMapID, len(sendMsg)), playerID)
        GameWorld.GetPlayerManager().MapServer_QueryPlayer(0, 0, playerID, sceneMapID, "PlayerMirror", sendMsg, len(sendMsg), routeIndex)
        
    # 其他功能可再扩展
    else:
@@ -312,15 +467,13 @@
    pullPlayerIDList = msgData["pullPlayerIDList"]
    
    otherServerPlayerIDList = []
    packDataDict = {}
    packDataMgr = PyDataManager.GetDBPlayerPackDataManager()
    for playerID in pullPlayerIDList:
        packObj = packDataMgr.GetPlayerPackObj(playerID)
        # 已经有的数据先推送回去
        if packObj:
            GameWorld.DebugLog("跨服有缓存玩家打包数据,直接推给子服! playerID=%s" % playerID)
            packDataDict[playerID] = packObj.PackData
            dataMsg = {"playerID":playerID, "packData":packObj.PackData, "msgInfo":msgInfo}
            dataMsg = {"playerID":playerID, "packData":packObj.GetPackData(), "msgInfo":msgInfo}
            CrossRealmMsg.SendMsgToClientServer(ShareDefine.CrossServerMsg_PushPlayerPackData, dataMsg, [serverGroupID])
        else:
            otherServerPlayerIDList.append(playerID)
@@ -340,8 +493,7 @@
    curPlayer = GameWorld.GetPlayerManager().FindPlayerByID(playerID)
    if not curPlayer:
        return
    isCross, isNeed = 1, 1
    QueryPlayerResult_PlayerMirror(curPlayer, "PackDataSyncState", [isCross, isNeed])
    QueryPlayerResult_PlayerMirror(curPlayer, "PackDataSyncState", msgData)
    return
def CrossServerMsg_PullPlayerPackData(msgData):
@@ -355,7 +507,7 @@
        packObj = packDataMgr.GetPlayerPackObj(playerID)
        if packObj:
            GameWorld.DebugLog("本服有缓存玩家打包数据,直接推给跨服! playerID=%s" % playerID)
            dataMsg = {"playerID":playerID, "packData":packObj.PackData, "msgInfo":msgInfo}
            dataMsg = {"playerID":playerID, "packData":packObj.GetPackData(), "msgInfo":msgInfo}
            CrossRealmMsg.SendMsgToCrossServer(ShareDefine.ClientServerMsg_PlayerPackData, dataMsg)
        else:
            DoPullPlayerPackData(playerID, msgInfo)
@@ -375,7 +527,7 @@
    curPlayer.MapServer_QueryPlayerResult(0, 0, "PlayerMirror", sysMsg, len(sysMsg))
    return
def OnMGUpdatePlayerPackData(curPlayer, curPackData):
def OnMGUpdatePlayerPackData(curPlayer, curPackData, msgInfo):
    ## 地图同步更新的玩家打包数据
    if GameWorld.IsCrossServer():
        return
@@ -384,14 +536,13 @@
    packData = curPackData.PackData
    if not packDataSyncState or not packData:
        return
    msgInfo = eval(curPackData.PackMsg) if curPackData.PackMsg else {} # 打包数据附带的信息
    
    # 本服需要,先更新数据
    if packDataSyncState % 10:
    if packDataSyncState&pow(2, 0):
        PyDataManager.GetDBPlayerPackDataManager().UpdPlayerPackData(playerID, packData)
        
    # 跨服需要,同步给跨服,由跨服服务器再进一步处理
    if packDataSyncState / 10:
    if packDataSyncState&pow(2, 1):
        cacheBase = PlayerViewCache.GetSyncCrossCacheBase(curPlayer) if curPlayer else {}
        dataMsg = {"playerID":playerID, "packData":packData, "cacheBase":cacheBase, "msgInfo":msgInfo}
        CrossRealmMsg.SendMsgToCrossServer(ShareDefine.ClientServerMsg_PlayerPackData, dataMsg)
@@ -432,7 +583,7 @@
    for mirrorID in mirrorIDList:
        packObj = packDataMgr.GetPlayerPackObj(mirrorID)
        if packObj:
            packDataDict[mirrorID] = packObj.PackData
            packDataDict[mirrorID] = packObj.GetPackData()
            continue
        pullPlayerIDList.append(mirrorID)