ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/CrossBillboard.py
@@ -17,19 +17,21 @@
import CommFunc
import ShareDefine
import IpyGameDataPY
import CrossRealmMsg
import PlayerViewCache
import PyGameDataStruct
import ChPyNetSendPack
import DataRecordPack
import NetPackCommon
import PyDataManager
import CrossRealmPK
import GameWorld
import operator
import time
import json
Def_CrossBillboard_MaxDataCount = 100 # 跨服榜单数据最大条数暂固定最大为100条,如有需要调整需针对实际情况进行评估(如数据同步、同步封包等)
class CrossBillboardManager(object):
    ## 跨服排行榜管理,注意该类只处理数据逻辑,功能相关逻辑不要写在该类,不然重读脚本不会生效
    
@@ -66,6 +68,27 @@
        for key in self.__billboardDict.keys():
            if key[0] == billboardType:
                self.__billboardDict.pop(key)
        return
    def ClearBillboard(self, billboardType, groupValue1=None, groupValue2=None):
        '''清除某个类型的榜单所有数据,可指定过滤groupValue,有流向记录
        @param groupValue1: 不为None时验证 groupValue1 是否相同
        @param groupValue2: 不为None时验证 groupValue2 是否相同
        如果groupValue1 groupValue2 都传入None,相当于清空 billboardType 类型的所有榜单数据
        '''
        clearList = []
        for bType, gValue1, gValue2 in self.__billboardDict.keys():
            if bType != billboardType:
                continue
            if groupValue1 != None and groupValue1 != gValue1:
                continue
            if groupValue2 != None and groupValue2 != gValue2:
                continue
            key = (bType, gValue1, gValue2)
            clearList.append(key)
        for bType, gValue1, gValue2 in clearList:
            self.GetCrossBillboard(bType, gValue1, gValue2).ClearData()
        return
    
    # 保存数据 存数据库和realtimebackup
@@ -115,7 +138,10 @@
        self.__crossServerDataVer = 0 # 主服榜单数据版本
        self.__clientServerDataVer = 0 # 子服榜单数据版本
        self.__billboardList = [] # [tagDBCrossBillboard, ...] 
        self.__idIndexDict = {} # {id:index, ...}
        self.__idOrderDict = {} # {id:名次, ...}
        self.__orderRuleList = None
        self.__sortDelay = False # 是否需要延迟排序
        return
    
    def GetBillboardType(self): return self.__billboardType
@@ -123,20 +149,40 @@
    def GetGroupValue2(self): return self.__groupValue2
    
    def ClearData(self):
        GameWorld.Log("CrossBillboard ClearData billboardType=%s,groupValue1=%s,groupValue2=%s"
                      % (self.__billboardType, self.__groupValue1, self.__groupValue2))
        GameWorld.Log("CrossBillboard ClearData billboardType=%s,groupValue1=%s,groupValue2=%s,dataCount=%s"
                      % (self.__billboardType, self.__groupValue1, self.__groupValue2, len(self.__billboardList)))
        if GameWorld.IsCrossServer():
            self.SaveDRData()
            self.SaveDRData("Clear")
        self.__billboardList = [] # [tagDBCrossBillboard, ...] 
        self.__idOrderDict = {} # {id:名次, ...}
        self.__idIndexDict = {}
        
        self.UpdCrossServerDataVer(0)
        return
    
    def SortData(self):
        GameWorld.DebugLog("跨服榜单排序: billboardType=%s,groupValue1=%s,groupValue2=%s,dataCount=%s"
                      % (self.__billboardType, self.__groupValue1, self.__groupValue2, len(self.__billboardList)))
        self.__billboardList.sort(key=operator.attrgetter("CmpValue", "CmpValue2", "CmpValue3"), reverse=True)
        self.__idOrderDict = {} # 排序后重置,下次查询时更新并缓存
        self.__idIndexDict = {}
        self.__sortDelay = False
        self.UpdCrossServerDataVer()
        return
    def SetDelaySort(self):
        ## 设置延迟排序
        GameWorld.DebugLog("跨服榜单设置延迟排序: billboardType=%s,groupValue1=%s,groupValue2=%s,dataCount=%s"
                      % (self.__billboardType, self.__groupValue1, self.__groupValue2, len(self.__billboardList)))
        self.__sortDelay = True
        self.UpdCrossServerDataVer()
        return
    def DoDelaySort(self):
        ## 延迟排序
        if not self.__sortDelay:
            return
        self.SortData()
        return
    
    def AddBillboardData(self, billboardData):
@@ -153,43 +199,110 @@
        @param findID: 查找的ID
        @return: None or PyGameDataStruct.tagDBCrossBillboard()
        '''
        idOrderDict = self.GetIDOrderDict()
        if findID not in idOrderDict:
        self.GetIDOrderDict()
        if findID not in self.__idIndexDict:
            return None
        order = idOrderDict[findID]
        return self.__billboardList[order - 1]
        idIndex = self.__idIndexDict[findID]
        if idIndex >= len(self.__billboardList):
            return None
        return self.__billboardList[idIndex]
    
    def SaveDRData(self):
    def IndexOfByID(self, findID):
        ''' 根据ID查询所在榜单索引
        @param findID: 查找的ID
        @return: -1 or >=0
        '''
        self.GetIDOrderDict()
        if findID not in self.__idIndexDict:
            return -1
        idIndex = self.__idIndexDict[findID]
        return idIndex
    def SaveDRData(self, eventName="", addDataDict={}):
        ## 记录流向数据
        eventTypeName = "CrossBillboard_%s" % (self.__billboardType)
        drDict = {"BillboardType":self.__billboardType, "GroupValue1":self.__groupValue1, "GroupValue2":self.__groupValue2,
                  "DataCount":len(self.__billboardList)}
        DataRecordPack.SendEventPack(eventTypeName, drDict)
        for billboardData in self.__billboardList:
            dataDict = {"BillboardType":billboardData.BillboardType, "GroupValue1":billboardData.GroupValue1,
                        "GroupValue2":billboardData.GroupValue2, "Type2":billboardData.Type2,
                        "ID":billboardData.ID, "ID2":billboardData.ID2,
        self.DoDelaySort()
        dataCount = len(self.__billboardList)
        if not dataCount:
            return
        idOrderDict = self.GetIDOrderDict()
        serverTime = GameWorld.GetServerTime()
        timeStr = "%02d%02d%02d%s" % (serverTime.hour, serverTime.minute, serverTime.second, str(serverTime.microsecond)[:3])
        eventTypeStr = "Billboard_%s_%s_%s_%s_%s" % (self.__billboardType, self.__groupValue1, self.__groupValue2, eventName, timeStr)
        dataDict = {"BillboardType":self.__billboardType, "DataCount":dataCount, "addDataDict":addDataDict,
                    "GroupValue1":self.__groupValue1, "GroupValue2":self.__groupValue2}
        DataRecordPack.SendEventPack(eventTypeStr, dataDict)
        for index, billboardData in enumerate(self.__billboardList):
            rank = idOrderDict.get(billboardData.ID, index + 1)
            dataDict = {"Type2":billboardData.Type2, "Rank":rank, "Index":index,
                        "ID":billboardData.ID, "ID2":billboardData.ID2,
                        "Name1":billboardData.Name1, "Name2":billboardData.Name2,
                        "Value1":billboardData.Value1, "Value2":billboardData.Value2,
                        "Value3":billboardData.Value3, "Value4":billboardData.Value4,
                        "Value5":billboardData.Value5, "Value6":billboardData.Value6,
                        "Value7":billboardData.Value7, "Value8":billboardData.Value8,
                        "CmpValue":billboardData.CmpValue, "CmpValue2":billboardData.CmpValue2, 
                        "CmpValue3":billboardData.CmpValue3}
            DataRecordPack.SendEventPack(eventTypeName, dataDict)
                        "CmpValue3":billboardData.CmpValue3, "UserData":billboardData.UserData}
            DataRecordPack.SendEventPack(eventTypeStr, dataDict)
        return
    
    def GetBillboardDataList(self): return self.__billboardList
    def GetIDOrderDict(self):
        ## 获取ID对应名次字典
        # @return: {ID:名次, ...}  名次从1开始
        if not self.__idOrderDict:
            for order, billboardData in enumerate(self.__billboardList, 1):
                self.__idOrderDict[billboardData.ID] = order
        if not self.__idOrderDict or not self.__idIndexDict:
            self.__idOrderDict = {}
            self.__idIndexDict = {}
            if self.__orderRuleList:
                billboardDataCount = self.GetCount()
                rankPre = 0
                billboardIndex = 0
                for rank, needCmpValue in self.__orderRuleList:
                    orderCountTotal = rank - rankPre # 奖励名次数量
                    rankPre = rank
                    for index in xrange(billboardIndex, billboardDataCount):
                        if orderCountTotal <= 0:
                            break
                        billboardData = self.At(index)
                        if billboardData.CmpValue < needCmpValue:
                            break
                        orderReal = rank - orderCountTotal + 1
                        self.__idOrderDict[billboardData.ID] = orderReal
                        orderCountTotal -= 1
                        billboardIndex += 1
                for order, billboardData in enumerate(self.__billboardList, 1):
                    self.__idIndexDict[billboardData.ID] = order - 1
            else:
                for order, billboardData in enumerate(self.__billboardList, 1):
                    self.__idOrderDict[billboardData.ID] = order
                    self.__idIndexDict[billboardData.ID] = order - 1
        return self.__idOrderDict
    
    def GetCount(self): return len(self.__billboardList)
    def GetMaxCount(self): return Def_CrossBillboard_MaxDataCount
    def SetOrderRuleList(self, orderRuleList):
        ## 排名所需值规则列表
        # @param orderRuleList: 排名所需值规则列表 [[order, needCmpValue], ...]
        self.__orderRuleList = orderRuleList
        self.__idOrderDict = {} # 设置后需重置,可能配置规则变化了导致实际排名可能变化
        self.__idIndexDict = {}
        GameWorld.Log("设置排名所需值规则列表: billboardType=%s,groupValue1=%s,groupValue2=%s, %s"
                      % (self.__billboardType, self.__groupValue1, self.__groupValue2, orderRuleList))
        return
    
    def At(self, i): return self.__billboardList[i]
    def IsFull(self): return len(self.__billboardList) >= Def_CrossBillboard_MaxDataCount
    def GetCount(self): return len(self.__billboardList)
    def GetMaxCount(self):
        maxCountDict = IpyGameDataPY.GetFuncEvalCfg("CrossBillboardSet", 1, {})
        return maxCountDict.get(self.__billboardType, 100)
    def At(self, i):
        billData = self.__billboardList[i]
        if not billData and False:
            billData = PyGameDataStruct.tagDBCrossBillboard() # 不会执行到,只为了.出代码提示
        return billData
    def IsFull(self): return len(self.__billboardList) >= self.GetMaxCount()
    
    def UpdCrossServerDataVer(self, version=None):
        ## 更新跨服榜单数据版本号,用于跨服主服、子服验证数据版本,同步榜单数据用
@@ -198,7 +311,7 @@
        if version == None:
            version = int(time.time())
        self.__crossServerDataVer = version
        SyncCrossBillboardToClientServer(self.__billboardType, self.__groupValue1, self.__groupValue2)
        #SyncCrossBillboardToClientServer(self.__billboardType, self.__groupValue1, self.__groupValue2)
        return
    def GetCrossServerDataVer(self): return self.__crossServerDataVer
    
@@ -220,8 +333,9 @@
        if syncBillboardList != None:
            self.__billboardList = self.__billboardList[:len(syncBillboardList)] # 直接用本服以后的排行数据实例clear后覆盖更新,不足的创建新实例
            self.__idOrderDict = {}
            self.__idIndexDict = {}
            for i, syncData in enumerate(syncBillboardList):
                ID, ID2, Name1, Name2, Type2, Value1, Value2, CmpValue, CmpValue2, CmpValue3 = syncData
                ID, ID2, Name1, Name2, Type2, Value1, Value2, CmpValue, CmpValue2, CmpValue3, Value3, Value4, Value5, Value6, Value7, Value8, UserData = syncData
                if i < len(self.__billboardList):
                    billboardData = self.__billboardList[i]
                    billboardData.clear()
@@ -239,11 +353,20 @@
                billboardData.Type2 = Type2
                billboardData.Value1 = Value1
                billboardData.Value2 = Value2
                billboardData.Value3 = Value3
                billboardData.Value4 = Value4
                billboardData.Value5 = Value5
                billboardData.Value6 = Value6
                billboardData.Value7 = Value7
                billboardData.Value8 = Value8
                billboardData.UserData = UserData
                billboardData.DataLen = len(billboardData.UserData)
                billboardData.CmpValue = CmpValue
                billboardData.CmpValue2 = CmpValue2
                billboardData.CmpValue3 = CmpValue3
                
                self.__idOrderDict[ID] = i + 1
                self.__idIndexDict[ID] = i
                
            self.__clientServerDataVer = crossServerDataVer
            
@@ -252,10 +375,21 @@
def CopyBillboardOnDay():
    billboardMgr = PyDataManager.GetCrossBillboardManager()
    for billboardType in ShareDefine.CrossBillboardTypeList:
        if billboardType in [ShareDefine.Def_CBT_BossTrialSubmitBak, ShareDefine.Def_CBT_BossTrialSubmitFamilyBak, ShareDefine.Def_CBT_CrossRealmPK]:
            continue
        groupList = billboardMgr.GetBillboardGroupList(billboardType)
        for billboardType, groupValue1, groupValue2 in groupList:
            billboardObj = billboardMgr.GetCrossBillboard(billboardType, groupValue1, groupValue2)
            billboardObj.SaveDRData()
            billboardObj.SaveDRData("OnDay")
    return
def OnMinuteProcess():
    billboardMgr = PyDataManager.GetCrossBillboardManager()
    for billboardType in ShareDefine.CrossBillboardTypeList:
        groupList = billboardMgr.GetBillboardGroupList(billboardType)
        for billboardType, groupValue1, groupValue2 in groupList:
            billboardObj = billboardMgr.GetCrossBillboard(billboardType, groupValue1, groupValue2)
            billboardObj.DoDelaySort()
    return
def CopyBillboard(fromBillboardType, toBillboardType):
@@ -282,11 +416,55 @@
            tobillboardData.Type2 = frbillboardData.Type2
            tobillboardData.Value1 = frbillboardData.Value1
            tobillboardData.Value2 = frbillboardData.Value2
            tobillboardData.Value3 = frbillboardData.Value3
            tobillboardData.Value4 = frbillboardData.Value4
            tobillboardData.Value5 = frbillboardData.Value5
            tobillboardData.Value6 = frbillboardData.Value6
            tobillboardData.Value7 = frbillboardData.Value7
            tobillboardData.Value8 = frbillboardData.Value8
            tobillboardData.UserData = frbillboardData.UserData
            tobillboardData.DataLen = len(tobillboardData.UserData)
            tobillboardData.CmpValue = frbillboardData.CmpValue
            tobillboardData.CmpValue2 = frbillboardData.CmpValue2
            tobillboardData.CmpValue3 = frbillboardData.CmpValue3
            toBillboardObj.AddBillboardData(tobillboardData)
            
    return
def CopyBillboardEx(fromBillboardType, toBillboardType, groupValue1, groupValue2=0):
    ## 将某个类型的榜单完全拷贝到其他榜单 - 一般用于备份、转移数据
    billboardMgr = PyDataManager.GetCrossBillboardManager()
    frbillboardObj = billboardMgr.GetCrossBillboard(fromBillboardType, groupValue1, groupValue2)
    toBillboardObj = billboardMgr.GetCrossBillboard(toBillboardType, groupValue1, groupValue2)
    toBillboardObj.ClearData()
    GameWorld.Log("CopyBillboardEx: fromBillboardType=%s,toBillboardType=%s,groupValue1=%s,groupValue2=%s"
                  % (fromBillboardType, toBillboardType, groupValue1, groupValue2))
    for frbillboardData in frbillboardObj.GetBillboardDataList():
        tobillboardData = PyGameDataStruct.tagDBCrossBillboard()
        tobillboardData.GroupValue1 = groupValue1
        tobillboardData.GroupValue2 = groupValue2
        tobillboardData.BillboardType = toBillboardType
        tobillboardData.ID = frbillboardData.ID
        tobillboardData.ID2 = frbillboardData.ID2
        tobillboardData.Name1 = frbillboardData.Name1
        tobillboardData.Name2 = frbillboardData.Name2
        tobillboardData.Type2 = frbillboardData.Type2
        tobillboardData.Value1 = frbillboardData.Value1
        tobillboardData.Value2 = frbillboardData.Value2
        tobillboardData.Value3 = frbillboardData.Value3
        tobillboardData.Value4 = frbillboardData.Value4
        tobillboardData.Value5 = frbillboardData.Value5
        tobillboardData.Value6 = frbillboardData.Value6
        tobillboardData.Value7 = frbillboardData.Value7
        tobillboardData.Value8 = frbillboardData.Value8
        tobillboardData.UserData = frbillboardData.UserData
        tobillboardData.DataLen = len(tobillboardData.UserData)
        tobillboardData.CmpValue = frbillboardData.CmpValue
        tobillboardData.CmpValue2 = frbillboardData.CmpValue2
        tobillboardData.CmpValue3 = frbillboardData.CmpValue3
        toBillboardObj.AddBillboardData(tobillboardData)
    return
#// C0 04 查看跨服排行榜 #tagCGViewCrossBillboard
@@ -295,8 +473,11 @@
#{
#    tagHead        Head;
#    BYTE        Type;        //榜单类型
#    BYTE        GroupValue1;    // 分组值1
#    BYTE        GroupValue2;    // 分组值2,与分组值1组合归为同组榜单数据
#    DWORD        GroupValue1;    // 分组值1
#    DWORD        GroupValue2;    // 分组值2,与分组值1组合归为同组榜单数据
#    DWORD        StartIndex;    //查看的起始名次索引, 默认0
#    BYTE        WatchCnt;    //查看条数,默认20,最大不超过100
#    DWORD        WatchID;        //查看指定ID名次前后,如玩家ID、家族ID等
#};
def OnViewCrossBillboard(index, clientData, tick):
    curPlayer = GameWorld.GetPlayerManager().GetPlayerByIndex(index)
@@ -304,21 +485,33 @@
        return
    playerID = curPlayer.GetPlayerID()
    billboardType, groupValue1, groupValue2 = clientData.Type, clientData.GroupValue1, clientData.GroupValue2
    startIndex = clientData.StartIndex
    watchCnt = clientData.WatchCnt
    watchID = clientData.WatchID
    
    if billboardType not in ShareDefine.CrossBillboardTypeList:
        return
    
    billboardMgr = PyDataManager.GetCrossBillboardManager()
    billboardObj = billboardMgr.GetCrossBillboard(billboardType, groupValue1, groupValue2)
    # 支持分页查询,改为直接查跨服服务器
    
    GameWorld.DebugLog("玩家请求查看跨服排行榜: billboardType=%s,groupValue1=%s,groupValue2=%s" % (billboardType, groupValue1, groupValue2))
    if not billboardObj.CheckClientServerDataVer():
        SyncCrossBillboardToPlayer(curPlayer, billboardType, groupValue1, groupValue2, billboardObj.GetBillboardDataList())
        return
    
    # 请求查询跨服服务器
    dataMsg = {"BillboardType":billboardType, "GroupValue1":groupValue1, "GroupValue2":groupValue2,
               "QueryData":{"EventName":"View", "PlayerID":playerID}}
    dataMsg = {"BillboardType":billboardType, "GroupValue1":groupValue1, "GroupValue2":groupValue2, "PlayerID":playerID,
               "QueryType":"View", "QueryData":{"StartIndex":startIndex, "WatchCnt":watchCnt, "WatchID":watchID}}
    CrossRealmMsg.SendMsgToCrossServer(ShareDefine.ClientServerMsg_QueryBillboard, dataMsg)
    return
def OnQueryPlayerBillboardRank(playerID, funcName, funcData, billboardType, groupValue1, groupValue2=0, tagPlayerID=0):
    ## 查询玩家ID排名
    if GameWorld.IsCrossServer():
        return
    if billboardType not in ShareDefine.CrossBillboardTypeList:
        return
    if not tagPlayerID:
        tagPlayerID = playerID # 默认查自己
    dataMsg = {"BillboardType":billboardType, "GroupValue1":groupValue1, "GroupValue2":groupValue2, "PlayerID":playerID,
               "QueryType":"Ranking", "QueryData":{"PlayerID":tagPlayerID, "funcName":funcName, "funcData":funcData}}
    CrossRealmMsg.SendMsgToCrossServer(ShareDefine.ClientServerMsg_QueryBillboard, dataMsg)
    return
@@ -327,11 +520,13 @@
    billboardType = msgData["BillboardType"]
    groupValue1 = msgData["GroupValue1"]
    groupValue2 = msgData["GroupValue2"]
    playerID = msgData.get("PlayerID", 0) # 发起的玩家ID
    queryType = msgData.get("QueryType", "") # 原数据返回子服
    queryData = msgData.get("QueryData", {}) # 原数据返回子服
    SyncCrossBillboardToClientServer(billboardType, groupValue1, groupValue2, [serverGroupID], queryData)
    SyncCrossBillboardToClientServer(billboardType, groupValue1, groupValue2, [serverGroupID], playerID, queryType, queryData)
    return
def SyncCrossBillboardToClientServer(billboardType, groupValue1, groupValue2, serverGroupIDList=None, queryData=None):
def SyncCrossBillboardToClientServer(billboardType, groupValue1, groupValue2, serverGroupIDList=None, playerID=0, queryType="", queryData=None):
    ## 同步跨服榜单到子服
    if not GameWorld.IsCrossServer():
        return
@@ -341,15 +536,55 @@
        queryData = {}
    billboardMgr = PyDataManager.GetCrossBillboardManager()
    billboardObj = billboardMgr.GetCrossBillboard(billboardType, groupValue1, groupValue2)
    crossServerDataVer = billboardObj.GetCrossServerDataVer()
    msgData = {"BillboardType":billboardType, "GroupValue1":groupValue1, "GroupValue2":groupValue2,
               "QueryData":queryData, "CrossServerDataVer":crossServerDataVer}
    billboardObj.DoDelaySort()
    idOrderDict = billboardObj.GetIDOrderDict()
    msgData = {"BillboardType":billboardType, "GroupValue1":groupValue1, "GroupValue2":groupValue2, "PlayerID":playerID,
               "QueryType":queryType, "QueryData":queryData}
    # 查询名次
    if queryType == "Ranking":
        tagPlayerID = queryData.get("PlayerID", 0)
        if not tagPlayerID:
            return
        queryData["OrderIndex"] = idOrderDict.get(tagPlayerID, 0) - 1 # -1-未上榜,0-第一名
        CrossRealmMsg.SendMsgToClientServer(ShareDefine.CrossServerMsg_SyncBillboard, msgData, serverGroupIDList)
        return
    
    # 有查询数据时才同步榜单数据列表,否则只同步数据版本号
    if queryData:
        #playerID = queryData.get("PlayerID", 0)
        startIndex = queryData.get("StartIndex", 0)
        watchCnt = queryData.get("WatchCnt", 0)
        watchID = queryData.get("WatchID", 0)
        count = billboardObj.GetCount()
        endIndex = 0
        # 查看自己前后名次
        if watchID:
            playerIndex = billboardObj.IndexOfByID(watchID)
            if playerIndex != -1:
                # 前5后4,首尾补足10条记录
                endIndex = min(playerIndex + 5, count)
                startIndex = max(0, endIndex - 10)
                endIndex = min(endIndex + (10 - (endIndex - startIndex)), count)
            else:
                startIndex = 0
        # 指定索引分页查看
        else:
            startIndex = max(startIndex, 0)
            startIndex = min(startIndex, count)
            watchCnt = 20 if not watchCnt else min(watchCnt, 100) # 默认20,最多100
            endIndex = min(startIndex + watchCnt, count)
        syncBillboardList = []
        billboardList = billboardObj.GetBillboardDataList()
        for billboardData in billboardList:
        for index in xrange(startIndex, endIndex):
            if startIndex < 0 or index >= count:
                break
            billboardData = billboardObj.At(index)
            ID = billboardData.ID
            ID2 = billboardData.ID2
            Name1 = billboardData.Name1
@@ -357,10 +592,18 @@
            Type2 = billboardData.Type2
            Value1 = billboardData.Value1
            Value2 = billboardData.Value2
            Value3 = billboardData.Value3
            Value4 = billboardData.Value4
            Value5 = billboardData.Value5
            Value6 = billboardData.Value6
            Value7 = billboardData.Value7
            Value8 = billboardData.Value8
            UserData = billboardData.UserData
            CmpValue = billboardData.CmpValue
            CmpValue2 = billboardData.CmpValue2
            CmpValue3 = billboardData.CmpValue3
            syncBillboardList.append([ID, ID2, Name1, Name2, Type2, Value1, Value2, CmpValue, CmpValue2, CmpValue3])
            orderIndex = idOrderDict.get(ID, index + 1) - 1
            syncBillboardList.append([orderIndex, ID, ID2, Name1, Name2, Type2, Value1, Value2, CmpValue, CmpValue2, CmpValue3, Value3, Value4, Value5, Value6, Value7, Value8, UserData])
        msgData["BillboardDataList"] = syncBillboardList
        
    CrossRealmMsg.SendMsgToClientServer(ShareDefine.CrossServerMsg_SyncBillboard, msgData, serverGroupIDList)
@@ -371,57 +614,62 @@
    billboardType = msgData["BillboardType"]
    groupValue1 = msgData["GroupValue1"]
    groupValue2 = msgData["GroupValue2"]
    crossServerDataVer = msgData["CrossServerDataVer"]
    syncBillboardList = msgData.get("BillboardDataList")
    GameWorld.DebugLog("收到跨服服务器同步的排行榜信息: billboardType=%s,groupValue1=%s,groupValue2=%s,crossServerDataVer=%s"
                       % (billboardType, groupValue1, groupValue2, crossServerDataVer))
    billboardMgr = PyDataManager.GetCrossBillboardManager()
    billboardObj = billboardMgr.GetCrossBillboard(billboardType, groupValue1, groupValue2)
    billboardObj.UpdClientServerBillboard(crossServerDataVer, syncBillboardList)
    queryData = msgData.get("QueryData")
    if not queryData:
    playerID = msgData.get("PlayerID", 0) # 发起的玩家ID
    queryType = msgData.get("QueryType", "")
    queryData = msgData.get("QueryData", {})
    GameWorld.DebugLog("收到跨服服务器同步的排行榜信息: billboardType=%s,groupValue1=%s,groupValue2=%s,queryType=%s"
                       % (billboardType, groupValue1, groupValue2, queryType), playerID)
    if not queryType or not queryData:
        return
    
    eventName = queryData.get("EventName")
    eventData = queryData.get("EventData")
    queryPlayerID = queryData.get("PlayerID", 0)
    if not eventName or not queryPlayerID:
        return
    queryPlayer = GameWorld.GetPlayerManager().FindPlayerByID(queryPlayerID)
    if not queryPlayer:
        return
    if eventName == "View":
        SyncCrossBillboardToPlayer(queryPlayer, billboardType, groupValue1, groupValue2, billboardObj.GetBillboardDataList())
    else:
        idOrderDict = billboardObj.GetIDOrderDict()
        order = idOrderDict.get(queryPlayerID, 0)
        sysMsg = str([billboardType, groupValue1, groupValue2, eventName, eventData, order])
        queryPlayer.MapServer_QueryPlayerResult(0, 0, "CrossBillboardOrder", sysMsg, len(sysMsg))
    if queryType == "View":
        queryPlayer = GameWorld.GetPlayerManager().FindPlayerByID(playerID)
        if not queryPlayer:
            return
        watchID = queryData.get("WatchID", 0)
        syncBillboardList = msgData.get("BillboardDataList")
        SyncCrossBillboardToPlayer(queryPlayer, billboardType, groupValue1, groupValue2, syncBillboardList, watchID)
        
    elif queryType == "Ranking":
        funcName = queryData.get("funcName", "")
        funcData = queryData.get("funcData", {})
        #tagPlayerID = queryData.get("PlayerID", 0)
        orderIndex = queryData.get("OrderIndex", 0)
        if funcName == "QueryCrossPKSeasonOrder":
            CrossRealmPK.OnQueryCrossPKSeasonOrderRet(playerID, funcData, orderIndex)
    return
def SyncCrossBillboardToPlayer(curPlayer, billboardType, groupValue1, groupValue2, billboardList):
def SyncCrossBillboardToPlayer(curPlayer, billboardType, groupValue1, groupValue2, billboardList, watchID):
    ## 同步给玩家跨服榜单
    billboardInfo = ChPyNetSendPack.tagGCCrossBillboardInfo()
    billboardInfo.Type = billboardType
    billboardInfo.GroupValue1 = groupValue1
    billboardInfo.GroupValue2 = groupValue2
    billboardInfo.WatchID = watchID
    billboardInfo.CrossBillboardDataList = []
    for billboardData in billboardList:
    for dataInfo in billboardList:
        orderIndex, ID, ID2, Name1, Name2, Type2, Value1, Value2, CmpValue, CmpValue2, CmpValue3, Value3, Value4, Value5, Value6, Value7, Value8, UserData = dataInfo
        billboardInfoData = ChPyNetSendPack.tagGCCrossBillboardData()
        billboardInfoData.ID = billboardData.ID
        billboardInfoData.Name1 = billboardData.Name1
        billboardInfoData.Name2 = billboardData.Name2
        billboardInfoData.Type2 = billboardData.Type2
        billboardInfoData.Value1 = billboardData.Value1
        billboardInfoData.Value2 = billboardData.Value2
        billboardInfoData.CmpValue = billboardData.CmpValue
        billboardInfoData.CmpValue2 = billboardData.CmpValue2
        billboardInfoData.CmpValue3 = billboardData.CmpValue3
        billboardInfoData.OrderIndex = orderIndex
        billboardInfoData.ID = ID
        billboardInfoData.ID2 = ID2
        billboardInfoData.Name1 = Name1
        billboardInfoData.Name2 = Name2
        billboardInfoData.Type2 = Type2
        billboardInfoData.Value1 = Value1
        billboardInfoData.Value2 = Value2
        billboardInfoData.Value3 = Value3
        billboardInfoData.Value4 = Value4
        billboardInfoData.Value5 = Value5
        billboardInfoData.Value6 = Value6
        billboardInfoData.Value7 = Value7
        billboardInfoData.Value8 = Value8
        billboardInfoData.CmpValue = CmpValue
        billboardInfoData.CmpValue2 = CmpValue2
        billboardInfoData.CmpValue3 = CmpValue3
        billboardInfoData.UserData = UserData
        billboardInfoData.DataLen = len(billboardInfoData.UserData)
        billboardInfo.CrossBillboardDataList.append(billboardInfoData)
    billboardInfo.BillboardCount = len(billboardInfo.CrossBillboardDataList)
    NetPackCommon.SendFakePack(curPlayer, billboardInfo)
@@ -454,9 +702,16 @@
    name2 = billInfoDict["Name2"]
    value1 = billInfoDict["Value1"]
    value2 = billInfoDict["Value2"]
    value3 = billInfoDict.get("Value3", 0)
    value4 = billInfoDict.get("Value4", 0)
    value5 = billInfoDict.get("Value5", 0)
    value6 = billInfoDict.get("Value6", 0)
    value7 = billInfoDict.get("Value7", 0)
    value8 = billInfoDict.get("Value8", 0)
    cmpValue = billInfoDict["CmpValue"]
    cmpValue2 = billInfoDict["CmpValue2"]
    cmpValue3 = billInfoDict["CmpValue3"]
    userData = billInfoDict.get("UserData", "")
    
    billboardMgr = PyDataManager.GetCrossBillboardManager()
    billboardObj = billboardMgr.GetCrossBillboard(billboardType, groupValue1, groupValue2)
@@ -465,8 +720,11 @@
        if cmpValue == billboardData.CmpValue and cmpValue2 == billboardData.CmpValue2 \
            and (not cmpValue3 or cmpValue3 == billboardData.CmpValue3) \
            and value1 == billboardData.Value1 and value2 == billboardData.Value2 \
            and value3 == billboardData.Value3 and value4 == billboardData.Value4 \
            and value5 == billboardData.Value5 and value6 == billboardData.Value6 \
            and value7 == billboardData.Value7 and value8 == billboardData.Value8 \
            and name1 == billboardData.Name1 and name2 == billboardData.Name2 \
            and type2 == billboardData.Type2 and id2 == billboardData.ID2:
            and type2 == billboardData.Type2 and id2 == billboardData.ID2 and userData == billboardData.UserData:
            GameWorld.DebugLog("    榜单值相同,不同步跨服服务器! ")
            return
        
@@ -499,16 +757,61 @@
    name2 = billInfoDict["Name2"]
    value1 = billInfoDict["Value1"]
    value2 = billInfoDict["Value2"]
    value3 = billInfoDict.get("Value3", 0)
    value4 = billInfoDict.get("Value4", 0)
    value5 = billInfoDict.get("Value5", 0)
    value6 = billInfoDict.get("Value6", 0)
    value7 = billInfoDict.get("Value7", 0)
    value8 = billInfoDict.get("Value8", 0)
    cmpValue = billInfoDict["CmpValue"]
    cmpValue2 = billInfoDict["CmpValue2"]
    cmpValue3 = billInfoDict["CmpValue3"]
    userData = billInfoDict.get("UserData", "")
    kwargs = {"value3":value3, "value4":value4, "value5":value5, "value6":value6, "value7":value7, "value8":value8, "userData":userData}
    
    UpdCrossBillboard(billboardType, groupValue1, dataID, name1, name2, type2, value1, value2,
                      cmpValue, cmpValue2, cmpValue3, groupValue2, id2)
                      cmpValue, cmpValue2, cmpValue3, groupValue2, id2, **kwargs)
    return
def UpdCrossBillboardFamily(bType, groupValue1, familyBillInfo, cmpValue, cmpValue2=0, autoSort=True):
    ## 更新跨服仙盟榜单
    if not familyBillInfo:
        return
    if "id" not in familyBillInfo:
        return
    familyID = familyBillInfo["id"]
    familyName = familyBillInfo["name"]
    id2 = familyBillInfo["id2"]
    name2 = familyBillInfo["name2"]
    value1 = familyBillInfo["value1"]
    value2 = familyBillInfo["value2"]
    value3 = familyBillInfo["value3"]
    value4 = familyBillInfo["value4"]
    value5 = familyBillInfo["value5"]
    type2 = 0
    UpdCrossBillboard(bType, groupValue1, familyID, familyName, name2, type2, value1, value2, cmpValue, cmpValue2,
                      id2=id2, autoSort=autoSort, value3=value3, value4=value4, value5=value5)
    return
def UpdCrossBillboardPlayer(bType, playerID, groupValue1, cmpValue, cmpValue2=0, value1=0, value2=0, groupValue2=0, autoSort=True, **kwargs):
    ## 通用的更新跨服玩家榜,GameServer直接调用
    playerInfo = PlayerViewCache.GetShotCacheDict(playerID, "AccID", "ServerID", "Face", "FacePic")
    name1 = playerInfo.get("Name", "")
    name2 = playerInfo.get("AccID", "")
    type2 = playerInfo.get("Job", 1)
    if not value1:
        value1 = playerInfo.get("RealmLV", 1)
    value3 = playerInfo.get("Face", 0)
    value4 = playerInfo.get("FacePic", 0)
    value5 = playerInfo.get("ServerID", 0)
    UpdCrossBillboard(bType, groupValue1, playerID, name1, name2, type2, value1, value2, cmpValue, cmpValue2,
                      autoSort=autoSort, value3=value3, value4=value4, value5=value5)
    return
def UpdCrossBillboard(billboardType, groupValue1, dataID, name1, name2, type2, value1, value2, cmpValue,
                      cmpValue2=0, cmpValue3=0, groupValue2=0, id2=0, autoSort=True, noSortAndSync=False):
                      cmpValue2=0, cmpValue3=0, groupValue2=0, id2=0, autoSort=True, noSortAndSync=False,
                      **kwargs):
    ''' 更新跨服排行榜
    @param billboardType: 排行榜索引类型,同个榜单类型可以有多个分组榜单数据,独立排序
    @param groupValue1: 榜单分组1
@@ -551,40 +854,58 @@
            if not billboardObj.AddBillboardData(billboardData):
                return
            
    cmpValueChange = isNewData or billboardData.CmpValue != cmpValue or billboardData.CmpValue2 != cmpValue2 or (cmpValue3 and billboardData.CmpValue3 != cmpValue3)
    # 没设置值默认为时间time,先上榜的排前面
    if cmpValue3 == 0:
        # 时间权值仅在比较值变更的情况下才更新, 防止其他附属值更新时导致比较值相同的玩家名次间会变动的问题
        if isNewData or billboardData.CmpValue != cmpValue or billboardData.CmpValue2 != cmpValue2:
        if cmpValueChange:
            calcTime = GameWorld.ChangeTimeStrToNum("2090-01-01 00:00:00")
            cmpValue3 = max(0, calcTime - int(time.time())) # 比较值3如果没指定值则默认存当前更新的time
        else:
            cmpValue3 = billboardData.CmpValue3
            
    cmpValueChange = billboardData.CmpValue != cmpValue or billboardData.CmpValue2 != cmpValue2 or billboardData.CmpValue3 != cmpValue3
    # 更新所有值
    billboardData.GroupValue1 = groupValue1
    billboardData.GroupValue2 = groupValue2
    billboardData.BillboardType = billboardType
    billboardData.ID = dataID
    billboardData.ID2 = id2
    billboardData.Name1 = "" if len(name1) > 33 else name1
    billboardData.Name2 = "" if len(name2) > 33 else name2
    billboardData.SetName1(name1)
    billboardData.SetName2(name2)
    billboardData.Type2 = type2
    billboardData.Value1 = value1
    billboardData.Value2 = value2
    billboardData.Value3 = kwargs.get("value3", 0)
    billboardData.Value4 = kwargs.get("value4", 0)
    billboardData.Value5 = kwargs.get("value5", 0)
    billboardData.Value6 = kwargs.get("value6", 0)
    billboardData.Value7 = kwargs.get("value7", 0)
    billboardData.Value8 = kwargs.get("value8", 0)
    userData = kwargs.get("userData", "")
    if userData and not isinstance(userData, str):
        if isinstance(userData, dict) or isinstance(userData, list):
            userData = json.dumps(userData, ensure_ascii=False)
        userData = userData.replace(" ", "")
    billboardData.UserData = userData
    billboardData.DataLen = len(billboardData.UserData)
    billboardData.CmpValue = cmpValue
    billboardData.CmpValue2 = cmpValue2
    billboardData.CmpValue3 = cmpValue3
    
    GameWorld.DebugLog("更新跨服排行榜值: billboardType=%s,groupValue1=%s,groupValue2=%s,dataID=%s,isNewData=%s,cmpValueChange=%s,type2=%s,value1=%s,value2=%s,cmpValue=%s,cmpValue2=%s,cmpValue3=%s"
    GameWorld.DebugLog("更新跨服排行榜值: billboardType=%s,groupValue1=%s,groupValue2=%s,dataID=%s,isNewData=%s,cmpValueChange=%s,type2=%s,value1=%s,value2=%s,cmpValue=%s,cmpValue2=%s,cmpValue3=%s,%s"
                       % (billboardType, groupValue1, groupValue2, dataID, isNewData, cmpValueChange,
                          type2, value1, value2, cmpValue, cmpValue2, cmpValue3), dataID)
                          type2, value1, value2, cmpValue, cmpValue2, cmpValue3, kwargs), dataID)
    if noSortAndSync:
        return True
    if autoSort and cmpValueChange:
    # 新数据可能导致榜单ID增减,强制排序一次
    if isNewData:
        billboardObj.SortData()
    elif cmpValueChange:
        if autoSort:
            billboardObj.SortData()
        else:
            billboardObj.SetDelaySort()
    else:
        billboardObj.UpdCrossServerDataVer()
    return True