ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/CrossRealmPK.py
@@ -18,19 +18,22 @@
import GameWorld
import PlayerControl
import CrossRealmMsg
import CrossRealmPlayer
import ChPyNetSendPack
import CrossRealmPlayer
import PyGameDataStruct
import PlayerDBGSEvent
import PyDataManager
import NetPackCommon
import IpyGameDataPY
import ShareDefine
import PyGameData
import CommFunc
import ChConfig
import datetime
import operator
import random
PKPlayerState_Matching = 0
PKPlayerState_Fighting = 1
import time
class CrossPKPlayer():
    ## 跨服PK玩家类
@@ -43,6 +46,7 @@
        self.playerLV = 0
        self.maxHP = 0
        self.fightPower = 0
        self.realmLV = 0
        self.pkScore = 0
        self.danLV = 0
        self.matchTick = 0
@@ -58,6 +62,7 @@
    
    def __init__(self):
        self.pkZoneID = 0
        self.seasonID = 0
        self.roomID = 0
        self.mapID = 0
        self.openTick = 0 # 开房时间
@@ -68,11 +73,669 @@
        self.isMapOpen = False # 地图是否已经开启该房间,未开启的房间超时后,本次匹配视为无效,有玩家进地图才会开启副本分线
        return
    
#跨服PK排行榜管理,注意该类只处理数据逻辑,功能相关逻辑不要写在该类,不然重读脚本不会生效
class CrossPKBillboardManager(object):
    DBKEY_CrossPKFinalBillboardData = "CrossPKFinalBillboard_%s_%s" # 是否收到赛区赛季最终榜单同步,参数(zoneID, seasonID)
    def __init__(self):
        self.__ZoneSeasonDataList = "ZoneSeasonDataList_%s_%s" # 分区赛季排行数据列表 [tagDBCrossPKBillboard, ...]
        self.__ZoneSeasonPlayerOrderDict = "ZoneSeasonPlayerOrderDict_%s_%s" # 分区赛季排行数据字典 {playerID:rank, ...}
        self.__ZoneSeasonList = [] # 分区赛季列表 [(zoneID, seasonID), ...]
        self.__UnSortZoneSeasonTimeDict = {} # 未排序的分区赛季排行 {(zoneID, seasonID):tick, ...}
        return
    def GetCrossPKBillboardInfo(self, zoneID, seasonID, isSort=False):
        ## 获取跨服PK排行榜信息
        # @return: billboardList, orderDict
        listAttrName = self.__ZoneSeasonDataList % (zoneID, seasonID)
        orderDictAttrName = self.__ZoneSeasonPlayerOrderDict % (zoneID, seasonID)
        if not hasattr(self, listAttrName):
            setattr(self, listAttrName, [])
            setattr(self, orderDictAttrName, {})
            self.__ZoneSeasonList.append((zoneID, seasonID))
        billboardList = getattr(self, listAttrName)
        if isSort:
            self.__PKBillboardSort(zoneID, seasonID, billboardList)
        orderDict = getattr(self, orderDictAttrName)
        return billboardList, orderDict
    def __PKBillboardSort(self, zoneID, seasonID, billboardList):
        ## 排序
        if (zoneID, seasonID) not in self.__UnSortZoneSeasonTimeDict:
            return
        self.__UnSortZoneSeasonTimeDict.pop((zoneID, seasonID))
        billboardList.sort(key=operator.attrgetter("PKScore", "Time"), reverse=True)
        orderDict = {}
        for order, billboardData in enumerate(billboardList, 1):
            orderDict[billboardData.PlayerID] = order # 缓存赛季玩家排名
        orderDictAttrName = self.__ZoneSeasonPlayerOrderDict % (zoneID, seasonID)
        setattr(self, orderDictAttrName, orderDict)
        GameWorld.DebugLog("跨服PK榜单排序: zoneID=%s,seasonID=%s,orderDict=%s" % (zoneID, seasonID, orderDict))
        return
    def PKBillboardSortByTime(self, tick):
        ## 定时排序
        if not self.__UnSortZoneSeasonTimeDict:
            return
        sortCD = 60 * 1000 # 超过1分钟强制排序
        for key, updTick in self.__UnSortZoneSeasonTimeDict.items():
            zoneID, seasonID = key
            if tick - updTick < sortCD:
                continue
            self.GetCrossPKBillboardInfo(zoneID, seasonID, True)
        return
    def SetNeedSort(self, zoneID, seasonID):
        if (zoneID, seasonID) not in self.__UnSortZoneSeasonTimeDict:
            self.__UnSortZoneSeasonTimeDict[(zoneID, seasonID)] = GameWorld.GetGameWorld().GetTick()
        return
    ## ==================================== 子服的榜单数据管理 =====================================
    def UpdClientServerPKBillboard(self, zoneID, seasonID, syncBillboardList, isFinalBillboardData):
        ## 先直接清除本服数据,然后直接覆盖更新
        billboardList = self.GetCrossPKBillboardInfo(zoneID, seasonID)[0]
        billboardList = billboardList[:len(syncBillboardList)] # 直接用本服以后的排行数据实例clear后覆盖更新,不足的创建新实例
        orderDict = {} # 排行信息重新更新
        for i, syncData in enumerate(syncBillboardList):
            playerID, playerName, job, fightPower, realmLV, pkScore, danLV, billTime, order = syncData
            if i < len(billboardList):
                billboardData = billboardList[i]
                billboardData.clear()
            else:
                billboardData = PyGameDataStruct.tagDBCrossPKBillboard()
                billboardList.append(billboardData)
            billboardData.ZoneID = zoneID
            billboardData.SeasonID = seasonID
            billboardData.PlayerID = playerID
            billboardData.PlayerName = playerName
            billboardData.Job = job
            billboardData.FightPower = fightPower
            billboardData.RealmLV = realmLV
            billboardData.PKScore = pkScore
            billboardData.DanLV = danLV
            billboardData.Time = billTime
            orderDict[playerID] = order
        listAttrName = self.__ZoneSeasonDataList % (zoneID, seasonID)
        orderDictAttrName = self.__ZoneSeasonPlayerOrderDict % (zoneID, seasonID)
        setattr(self, listAttrName, billboardList)
        setattr(self, orderDictAttrName, orderDict)
        dbIsFinalData = PlayerDBGSEvent.GetDBGSTrig_ByKey(self.DBKEY_CrossPKFinalBillboardData % (zoneID, seasonID))
        isFinalBillboardData = 1 if isFinalBillboardData else 0
        if dbIsFinalData != isFinalBillboardData:
            PlayerDBGSEvent.SetDBGSTrig_ByKey(self.DBKEY_CrossPKFinalBillboardData % (zoneID, seasonID), isFinalBillboardData)
            GameWorld.Log("更新子服榜单数据是否是最终榜单数据!zoneID=%s,seasonID=%s,isFinalBillboardData=%s"
                          % (zoneID, seasonID, isFinalBillboardData))
        return billboardList, orderDict
    def IsFinalBillboardData(self, zoneID, seasonID):
        ## 子服的赛区赛季榜单数据是否最终榜单数据
        return PlayerDBGSEvent.GetDBGSTrig_ByKey(self.DBKEY_CrossPKFinalBillboardData % (zoneID, seasonID))
    ## ===========================================================================================
    # 保存数据 存数据库和realtimebackup
    def GetSaveData(self):
        savaData = ""
        cntData = ""
        cnt = 0
        for zoneID, seasonID in self.__ZoneSeasonList:
            billboardList = self.GetCrossPKBillboardInfo(zoneID, seasonID)[0]
            for billboardData in billboardList:
                cnt += 1
                savaData += billboardData.getBuffer()
        GameWorld.Log("SaveCrossPKBillboard cnt :%s" % cnt)
        return CommFunc.WriteDWORD(cntData, cnt) + savaData
    # 从数据库载入数据
    def LoadPyGameData(self, datas, pos, dataslen):
        cnt, pos = CommFunc.ReadDWORD(datas, pos)
        GameWorld.Log("LoadCrossPKBillboard cnt :%s" % cnt)
        for _ in xrange(cnt):
            billboardData = PyGameDataStruct.tagDBCrossPKBillboard()
            billboardData.clear()
            pos += billboardData.readData(datas, pos, dataslen)
            zoneID = billboardData.ZoneID
            seasonID = billboardData.SeasonID
            billboardList = self.GetCrossPKBillboardInfo(zoneID, seasonID)[0]
            billboardList.append(billboardData)
        # 排序
        for zoneID, seasonID in self.__ZoneSeasonList:
            self.SetNeedSort(zoneID, seasonID)
            billboardList = self.GetCrossPKBillboardInfo(zoneID, seasonID, True)[0]
            GameWorld.Log("    zoneID=%s, seasonID=%s, count=%s" % (zoneID, seasonID, len(billboardList)))
        return pos
def UpdateCrossPKBillboard(zoneID, seasonID, winner, loser):
    ## 更新跨服PK排行榜,跨服服务器结算调用,子服不调用
    curZoneSeasonID = GameWorld.GetGameWorld().GetDictByKey(ChConfig.Def_WorldKey_CrossPKZoneSeasonID % zoneID)
    if curZoneSeasonID != seasonID:
        GameWorld.ErrLog("不是当前赛季,不更新排行榜! zoneID=%s,seasonID=%s,curZoneSeasonID=%s" % (zoneID, seasonID, curZoneSeasonID))
        return
    billboardCfg = IpyGameDataPY.GetFuncEvalCfg("CrossRealmPKCfg", 1, [])
    if not billboardCfg or len(billboardCfg) != 2:
        GameWorld.ErrLog("跨服竞技场排行榜配置错误!")
        return
    maxCount, danLVLimit = billboardCfg
    if maxCount <= 0:
        return
    maxCount = min(2000, maxCount)
    upBillboardList = []
    if winner.danLV >= danLVLimit:
        upBillboardList.append(winner)
    else:
        GameWorld.DebugLog("    段位不足,无法上榜! winnerDanLV=%s < danLVLimit=%s" % (winner.danLV, danLVLimit), winner.playerID)
    if loser.danLV >= danLVLimit:
        upBillboardList.append(loser)
    else:
        GameWorld.DebugLog("    段位不足,无法上榜! loserDanLV=%s < danLVLimit=%s" % (loser.danLV, danLVLimit), loser.playerID)
    if not upBillboardList:
        return
    crossPKBillboardMgr = PyDataManager.GetCrossPKBillboardManager()
    billboardList, orderDict = crossPKBillboardMgr.GetCrossPKBillboardInfo(zoneID, seasonID)
    isUpd = False
    curTime = int(time.time())
    billboardTime = max(0, GameWorld.ChangeTimeStrToNum("2080-01-01 00:00:00") - curTime) # 因为先上榜排前面,所以时间记录值得反减,倒序排
    for pkPlayer in upBillboardList:
        playerID = pkPlayer.playerID
        if playerID in orderDict:
            order = orderDict[playerID]
            billboardData = billboardList[order - 1]
            GameWorld.DebugLog("    已经在榜单上!playerID=%s,order=%s" % (playerID, order), playerID)
        else:
            if len(billboardList) < maxCount:
                newBillboardData = PyGameDataStruct.tagDBCrossPKBillboard()
                billboardList.append(newBillboardData)
                order = len(billboardList)
                GameWorld.DebugLog("    添加新上榜榜单!playerID=%s,order=%s" % (playerID, order), playerID)
            else:
                lastBillboardData = billboardList[-1]
                # 分数如果超过最后一个,则顶掉最后一个
                if lastBillboardData.PKScore >= pkPlayer.pkScore:
                    GameWorld.DebugLog("    PK积分不超过最后一名玩家,无法上榜! pkScore=%s <= lastPKScore=%s"
                                       % (pkPlayer.pkScore, lastBillboardData.PKScore), playerID)
                    continue
                order = orderDict.pop(lastBillboardData.PlayerID, len(billboardList))
                GameWorld.DebugLog("    顶掉最后一个榜单!playerID=%s,lastPlayer=%s,lastScore=%s,order=%s"
                                   % (playerID, lastBillboardData.PlayerID, lastBillboardData.PKScore, order))
                newBillboardData = PyGameDataStruct.tagDBCrossPKBillboard()
                billboardList[-1] = newBillboardData
            billboardData = newBillboardData
            orderDict[playerID] = order
        isUpd = True
        # 更新值
        billboardData.ZoneID = zoneID
        billboardData.SeasonID = seasonID
        billboardData.PlayerID = playerID
        billboardData.PlayerName = pkPlayer.playerName
        billboardData.Job = pkPlayer.playerJob
        billboardData.FightPower = pkPlayer.fightPower
        billboardData.RealmLV = pkPlayer.realmLV
        billboardData.PKScore = pkPlayer.pkScore
        billboardData.DanLV = pkPlayer.danLV
        billboardData.Time = billboardTime
        GameWorld.Log("    更新PK积分排行榜: playerID=%s,pkScore=%s,order=%s" % (playerID, billboardData.PKScore, order), playerID)
    # 战斗结算更新榜单先不排序,只设置需要排序
    if isUpd:
        crossPKBillboardMgr.SetNeedSort(zoneID, seasonID)
    # 如果匹配已经结束,且没有战斗中的房间了,则处理本阶段匹配总结算
    matchState = GameWorld.GetGameWorld().GetDictByKey(ShareDefine.Def_Notify_WorldKey_CrossDailyActionState % ShareDefine.DailyActionID_CrossReamPK)
    if not matchState and not PyGameData.g_crossPKRoomDict:
        GameWorld.Log("匹配已结束,且当前没有PK中的房间了!主动广播子服最新榜单! ")
        zoneIpyData = IpyGameDataPY.GetIpyGameData("CrossRealmPKZone", zoneID)
        if zoneIpyData:
            serverGroupIDList = zoneIpyData.GetServerGroupIDList()
            SyncPKSyncBillboardToClientServer(zoneID, seasonID, serverGroupIDList)
    return
#// C0 01 查看跨服竞技场赛季排行榜 #tagCGViewCrossPKBillboard
#
#struct    tagCGViewCrossPKBillboard
#{
#    tagHead        Head;
#    BYTE        ZoneID;    // 赛区ID
#    BYTE        SeasonID;    // 赛季ID
#};
def OnViewCrossPKBillboard(index, clientData, tick):
    ''' 赛区赛季榜单同步规则,这里以多台跨服服务器为考虑
            每台跨服服务器单独管理自己关联的子服赛区榜单
                    每日匹配结束结算时间点主动同步所有子服本台跨服服务器的所有赛区当前赛季榜单,这样能确保所有子服的赛区榜单是最新的
                    匹配期间,子服设置同步CD,如果有玩家查询,则每1分钟可向跨服服务器同步当前赛区赛季最新榜单信息,同步后发送玩家
                    非匹配期间,只要子服有数据则可直接发送给玩家,没有的话向跨服服务器同步后再发送玩家
                    历史赛季,因为每日跨服服务器都有主动广播,所以历史赛季只要子服有数据则可直接发送给玩家,没有的话向跨服服务器同步后再发送玩家
                    赛季结束 或 历史赛季 只要不是最终榜单数据的,则需主动向跨服服务器请求同步数据后再发送玩家
                    不同跨服服务器赛区的话由跨服服务器之间自己同步数据,子服只管向自己所属跨服服务器同步数据即可
            跨服服务器与跨服服务器之间的赛区榜单同步,同步规则类似子服与跨服服务器,相互之间做好数据同步即可
            数据同步后再同步各自所有子服,确保子服也是最新的,可考虑匹配结算结束同步一次即可
            这样玩家查看其它跨服服务器赛区数据可能会延迟一次匹配阶段结算的时间,比如两个小时,这个等以后需要多台跨服服务器时再讨论
    '''
    curPlayer = GameWorld.GetPlayerManager().GetPlayerByIndex(index)
    if GameWorld.IsCrossServer():
        return
    playerID = curPlayer.GetPlayerID()
    zoneID, seasonID = clientData.ZoneID, clientData.SeasonID
    tickKey = ChConfig.Def_PlayerKey_ViewCrossPKBillboardTick % (zoneID, seasonID)
    if tick - curPlayer.GetDictByKey(tickKey) < 60000:
        GameWorld.DebugLog("玩家查询跨服PK排行榜CD中: zoneID=%s, seasonID=%s" % (zoneID, seasonID), playerID)
        return
    curPlayer.SetDict(tickKey, tick)
    gameWorld = GameWorld.GetGameWorld()
    serverZoneID = gameWorld.GetDictByKey(ShareDefine.Def_Notify_WorldKey_CrossPKZoneID)
    crossPKBillboardMgr = PyDataManager.GetCrossPKBillboardManager()
    billboardList = crossPKBillboardMgr.GetCrossPKBillboardInfo(zoneID, seasonID)[0]
    isFinalBillboardData = crossPKBillboardMgr.IsFinalBillboardData(zoneID, seasonID)
    GameWorld.DebugLog("玩家请求查看跨服PK排行榜: zoneID=%s,seasonID=%s,serverZoneID=%s,isFinalBillboardData=%s"
                       % (zoneID, seasonID, serverZoneID, isFinalBillboardData))
    # 本服赛区
    if zoneID == serverZoneID:
        curSeasonID = gameWorld.GetDictByKey(ShareDefine.Def_Notify_WorldKey_CrossPKSeasonID)
        seasonState = gameWorld.GetDictByKey(ShareDefine.Def_Notify_WorldKey_CrossPKSeasonState)
    # 其他赛区
    else:
        serverTime = GameWorld.GetServerTime()
        curSeasonID = 0
        seasonState = 0
        seasonList = IpyGameDataPY.GetIpyGameDataList("CrossRealmPKSeason", zoneID)
        seasonList = [] if not seasonList else seasonList
        for seasonIpyData in seasonList:
            startDateStr = seasonIpyData.GetStartDate()
            endDateStr = seasonIpyData.GetEndDate()
            endTimeStr = seasonIpyData.GetEndTime()
            startDateTime = datetime.datetime.strptime("%s 00:00:00" % (startDateStr), ChConfig.TYPE_Time_Format)
            endDateTime = datetime.datetime.strptime("%s %s:00" % (endDateStr, endTimeStr), ChConfig.TYPE_Time_Format)
            if serverTime < startDateTime:
                break
            if serverTime <= endDateTime:
                curSeasonID = seasonIpyData.GetSeasonID()
                seasonState = 1
            else:
                break
    # 查询当前进行中的赛季
    if seasonID == curSeasonID:
        matchState = gameWorld.GetDictByKey(ShareDefine.Def_Notify_WorldKey_CrossDailyActionState % ShareDefine.DailyActionID_CrossReamPK)
        # 非匹配中的
        if not matchState:
            # 最终数据 or 赛季进行中 直接同步
            if isFinalBillboardData or (seasonState == 1 and billboardList):
                SyncCrossPKBillboard(curPlayer, zoneID, seasonID, billboardList)
                return
        # 正在匹配中的,验证本服数据同步CD,暂定1分钟同步一次
        else:
            syncTickKey = ChConfig.Def_WorldKey_CrossPKBillboardSyncTick % (zoneID, seasonID)
            if matchState and billboardList and tick - gameWorld.GetDictByKey(syncTickKey) < 60000:
                SyncCrossPKBillboard(curPlayer, zoneID, seasonID, billboardList)
                return
            gameWorld.SetDict(syncTickKey, tick)
    # 查询历史赛季的
    else:
        # 如果是最终数据则直接同步
        if isFinalBillboardData and billboardList:
            SyncCrossPKBillboard(curPlayer, zoneID, seasonID, billboardList)
            return
    # 请求查询跨服服务器
    dataMsg = {"ZoneID":zoneID, "SeasonID":seasonID, "ExData":{"EventName":"View", "PlayerID":playerID}}
    CrossRealmMsg.SendMsgToCrossServer(ShareDefine.ClientServerMsg_PKBillboard, dataMsg)
    return
def MapServer_QueryCrossPKSeasonOrder(curPlayer, msgList):
    ## 地图服务器查询玩家赛区赛季PK榜排名
    playerID = curPlayer.GetPlayerID()
    zoneID, seasonID, eventName, eventData = msgList
    crossPKBillboardMgr = PyDataManager.GetCrossPKBillboardManager()
    billboardList, orderDict = crossPKBillboardMgr.GetCrossPKBillboardInfo(zoneID, seasonID) # 子服的数据一定是排完序同步过来的,所以这里就不需要再排序了
    if not billboardList:
        # 本服没榜单数据,查询跨服服务器
        # 请求查询跨服服务器
        dataMsg = {"ZoneID":zoneID, "SeasonID":seasonID, "ExData":{"EventName":eventName, "PlayerID":playerID, "EventData":eventData}}
        CrossRealmMsg.SendMsgToCrossServer(ShareDefine.ClientServerMsg_PKBillboard, dataMsg)
        return
    order = orderDict.get(playerID, 0)
    sysMsg = str([zoneID, seasonID, eventName, eventData, order])
    curPlayer.MapServer_QueryPlayerResult(0, 0, "CrossPKSeasonOrder", sysMsg, len(sysMsg))
    return
def ClientServerMsg_PKBillboard(serverGroupID, msgData):
    ## 收到子服请求查询PK排行榜信息
    zoneID = msgData["ZoneID"]
    seasonID = msgData["SeasonID"]
    exData = msgData.get("ExData", {}) # 原数据返回子服
    SyncPKSyncBillboardToClientServer(zoneID, seasonID, [serverGroupID], exData)
    return
def SyncPKSyncBillboardToClientServer(zoneID, seasonID, serverGroupIDList, exData={}):
    ## 同步赛区赛季榜单到子服
    crossPKBillboardMgr = PyDataManager.GetCrossPKBillboardManager()
    billboardList, orderDict  = crossPKBillboardMgr.GetCrossPKBillboardInfo(zoneID, seasonID, True) # 同步子服前需触发排序
    isFinalBillboardData = False # 是否最终的榜单数据
    gameWorld = GameWorld.GetGameWorld()
    curZoneSeasonID = gameWorld.GetDictByKey(ChConfig.Def_WorldKey_CrossPKZoneSeasonID % zoneID)
    if seasonID < curZoneSeasonID:
        isFinalBillboardData = True # 历史赛季在跨服服务器中的一定是最终榜单数据
    elif seasonID == curZoneSeasonID:
        seasonState = gameWorld.GetDictByKey(ChConfig.Def_WorldKey_CrossPKZoneSeasonState % zoneID)
        if seasonState == 2:
            isFinalBillboardData = True # 当前赛季已经是赛季结算状态的了,代表是最终榜单数据
    syncBillboardList = []
    for billboardData in billboardList:
        playerID = billboardData.PlayerID
        playerName = billboardData.PlayerName
        job = billboardData.Job
        fightPower = billboardData.FightPower
        realmLV = billboardData.RealmLV
        pkScore = billboardData.PKScore
        danLV = billboardData.DanLV
        billTime = billboardData.Time
        order = orderDict.get(playerID, 0)
        syncBillboardList.append([playerID, playerName, job, fightPower, realmLV, pkScore, danLV, billTime, order])
    syncInfo = [zoneID, seasonID, syncBillboardList, exData, isFinalBillboardData]
    CrossRealmMsg.SendMsgToClientServer(ShareDefine.CrossServerMsg_PKSyncBillboard, syncInfo, serverGroupIDList)
    return
def CrossServerMsg_PKSyncBillboard(syncInfo):
    ## 收到跨服服务器同步的排行榜信息
    zoneID, seasonID, syncBillboardList, exData, isFinalBillboardData = syncInfo
    GameWorld.Log("收到跨服服务器同步的排行榜信息: zoneID=%s,seasonID=%s,billboardDataCount=%s,exData=%s,isFinalBillboardData=%s"
                  % (zoneID, seasonID, len(syncBillboardList), exData, isFinalBillboardData))
    crossPKBillboardMgr = PyDataManager.GetCrossPKBillboardManager()
    billboardList, orderDict = crossPKBillboardMgr.UpdClientServerPKBillboard(zoneID, seasonID, syncBillboardList, isFinalBillboardData)
    if not exData:
        return
    eventName = exData.get("EventName")
    eventData = exData.get("EventData")
    queryPlayerID = exData.get("PlayerID", 0)
    if not eventName or not queryPlayerID:
        return
    queryPlayer = GameWorld.GetPlayerManager().FindPlayerByID(queryPlayerID)
    if not queryPlayer:
        return
    if eventName == "View":
        SyncCrossPKBillboard(queryPlayer, zoneID, seasonID, billboardList)
    else:
        order = orderDict.get(queryPlayerID, 0)
        sysMsg = str([zoneID, seasonID, eventName, eventData, order])
        queryPlayer.MapServer_QueryPlayerResult(0, 0, "CrossPKSeasonOrder", sysMsg, len(sysMsg))
    return
def SyncCrossPKBillboard(curPlayer, zoneID, seasonID, billboardList):
    ## 同步给玩家跨服PK榜单
    billboardInfo = ChPyNetSendPack.tagGCCrossRealmPKBillboardInfo()
    billboardInfo.ZoneID = zoneID
    billboardInfo.SeasonID = seasonID
    billboardInfo.PKBillboardList = []
    for billboardData in billboardList:
        billboardInfoData = ChPyNetSendPack.tagGCCrossRealmPKBillboardData()
        billboardInfoData.PlayerID = billboardData.PlayerID
        billboardInfoData.PlayerName = billboardData.PlayerName
        billboardInfoData.NameLen = len(billboardInfoData.PlayerName)
        billboardInfoData.Job = billboardData.Job
        billboardInfoData.FightPower = billboardData.FightPower
        billboardInfoData.RealmLV = billboardData.RealmLV
        billboardInfoData.PKScore = billboardData.PKScore
        billboardInfoData.DanLV = billboardData.DanLV
        billboardInfo.PKBillboardList.append(billboardInfoData)
    billboardInfo.Count = len(billboardInfo.PKBillboardList)
    NetPackCommon.SendFakePack(curPlayer, billboardInfo)
    return
################################################################################
def OnPlayerLogin(curPlayer):
def __GetCrossPKZoneSeasonTimeInfo():
    key = "CrossPKZoneSeasonTimeInfo"
    openServerDay = PlayerDBGSEvent.GetDBGSTrig_ByKey(PlayerDBGSEvent.Def_ServerDay) + 1
    ZoneSeasonTimeInfo = IpyGameDataPY.GetConfigEx(key)
    if ZoneSeasonTimeInfo and ZoneSeasonTimeInfo[0] == openServerDay:
        #GameWorld.DebugLog("已经加载过本日跨服PK赛季处理信息!openServerDay=%s" % openServerDay)
        return ZoneSeasonTimeInfo[1]
    GameWorld.Log("加载跨服PK赛季时间信息: openServerDay=%s" % (openServerDay))
    zoneSeasonTimeDict = {}
    serverTime = GameWorld.GetServerTime()
    ipyDataMgr = IpyGameDataPY.IPY_Data()
    for index in xrange(ipyDataMgr.GetCrossRealmPKZoneCount()):
        zoneIpyData = ipyDataMgr.GetCrossRealmPKZoneByIndex(index)
        zoneID = zoneIpyData.GetZoneID()
        # 规定每个赛区的赛季时间需按顺序配置
        seasonIpyDataList = []
        for sIndex in xrange(ipyDataMgr.GetCrossRealmPKSeasonCount()):
            seasonIpyData = ipyDataMgr.GetCrossRealmPKSeasonByIndex(sIndex)
            if zoneID == seasonIpyData.GetZoneID():
                seasonIpyDataList.append(seasonIpyData)
        for i, seasonIpyData in enumerate(seasonIpyDataList):
            seasonID = seasonIpyData.GetSeasonID()
            startDateStr = seasonIpyData.GetStartDate()
            endDateStr = seasonIpyData.GetEndDate()
            endTimeStr = seasonIpyData.GetEndTime()
            startDateTime = datetime.datetime.strptime("%s 00:00:00" % (startDateStr), ChConfig.TYPE_Time_Format)
            endDateTime = datetime.datetime.strptime("%s %s:00" % (endDateStr, endTimeStr), ChConfig.TYPE_Time_Format)
            # 最后一个赛季
            if i == len(seasonIpyDataList) - 1:
                nextSeasonIpyData = None
            else:
                nextSeasonIpyData = seasonIpyDataList[i + 1]
            if serverTime < startDateTime:
                GameWorld.Log("    赛季未开始! zoneID=%s,seasonID=%s,startDateStr=%s,endDateStr=%s" % (zoneID, seasonID, startDateStr, endDateStr))
                break
            elif startDateTime <= serverTime <= endDateTime:
                pass
            elif endDateTime < serverTime:
                if nextSeasonIpyData:
                    nestStartDateStr = nextSeasonIpyData.GetStartDate()
                    nextStartDateTime = datetime.datetime.strptime("%s 00:00:00" % (nestStartDateStr), ChConfig.TYPE_Time_Format)
                    if serverTime >= nextStartDateTime:
                        GameWorld.Log("    赛季已过期! zoneID=%s,seasonID=%s,startDateStr=%s,endDateStr=%s" % (zoneID, seasonID, startDateStr, endDateStr))
                        continue
                else:
                    pass
            else:
                continue
            nextSeasonID = 0 if not nextSeasonIpyData else nextSeasonIpyData.GetSeasonID()
            zoneSeasonTimeDict[zoneID] = [seasonIpyData]
            GameWorld.Log("    赛季活动中! zoneID=%s,seasonID=%s,startDateStr=%s,endDateStr=%s,nextSeasonID=%s" % (zoneID, seasonID, startDateStr, endDateStr, nextSeasonID))
            break
    ZoneSeasonTimeInfo = IpyGameDataPY.SetConfigEx(key, [openServerDay, zoneSeasonTimeDict])
    GameWorld.Log("跨服PK赛季时间信息加载完毕!")
    GameWorld.Log("=============================================================")
    return ZoneSeasonTimeInfo[1]
def OnMinuteProcess():
    ## 每分钟处理
    if not GameWorld.IsCrossServer():
        return
    zoneSeasonTimeDict = __GetCrossPKZoneSeasonTimeInfo()
    if not zoneSeasonTimeDict:
        return
    gameWorld = GameWorld.GetGameWorld()
    serverTime = GameWorld.GetServerTime()
    for zoneID, seasonTimeInfo in zoneSeasonTimeDict.items():
        zoneIpyData = IpyGameDataPY.GetIpyGameData("CrossRealmPKZone", zoneID)
        if not zoneIpyData:
            continue
        curSeasonIpyData = seasonTimeInfo[0]
        if not curSeasonIpyData:
            continue
        seasonID = curSeasonIpyData.GetSeasonID()
        startDateStr = curSeasonIpyData.GetStartDate()
        endDateStr = curSeasonIpyData.GetEndDate()
        endTimeStr = curSeasonIpyData.GetEndTime()
        startDateTime = datetime.datetime.strptime("%s 00:00:00" % (startDateStr), ChConfig.TYPE_Time_Format)
        endDateTime = datetime.datetime.strptime("%s %s:00" % (endDateStr, endTimeStr), ChConfig.TYPE_Time_Format)
        seasonState = 0
        if startDateTime <= serverTime < endDateTime:
            seasonState = 1
        elif serverTime >= endDateTime:
            seasonState = 2
        zoneSeasonIDDictName = ChConfig.Def_WorldKey_CrossPKZoneSeasonID % zoneID
        seasonStateDictName = ChConfig.Def_WorldKey_CrossPKZoneSeasonState % zoneID
        dictSeasonID = gameWorld.GetDictByKey(zoneSeasonIDDictName)
        curSeasonState = gameWorld.GetDictByKey(seasonStateDictName)
        if curSeasonState == seasonState and dictSeasonID == seasonID:
            #已经是这个状态了
            continue
        gameWorld.SetDict(zoneSeasonIDDictName, seasonID)
        gameWorld.SetDict(seasonStateDictName, seasonState)
        GameWorld.Log("跨服PK赛季状态变更: zoneID=%s,seasonID=%s,seasonState=%s" % (zoneID, seasonID, seasonState))
        serverGroupIDList = zoneIpyData.GetServerGroupIDList()
        # 赛季总结算,为确保子服榜单的实时性,这里需再同步子服最终榜单信息,需在同步赛季状态之前同步
        if seasonState == 2:
            SyncPKSyncBillboardToClientServer(zoneID, seasonID, serverGroupIDList)
        # 广播当前赛区的所有子服跨服PK赛季状态变更
        matchState = gameWorld.GetDictByKey(ShareDefine.Def_Notify_WorldKey_CrossDailyActionState % ShareDefine.DailyActionID_CrossReamPK)
        seasonInfo = {"ZoneID":zoneID, "SeasonID":seasonID, "SeasonState":seasonState, "MatchState":matchState}
        CrossRealmMsg.SendMsgToClientServer(ShareDefine.CrossServerMsg_PKSeasonInfo, seasonInfo, serverGroupIDList)
    return
def OnCrossRealmPKDailyActionStateChange(isOpen):
    ## 跨服PK每日活动匹配状态变更
    if not GameWorld.IsCrossServer():
        return
    gameWorld = GameWorld.GetGameWorld()
    gameWorld.SetDict(ShareDefine.Def_Notify_WorldKey_CrossDailyActionState % ShareDefine.DailyActionID_CrossReamPK, isOpen)
    ipyDataMgr = IpyGameDataPY.IPY_Data()
    for index in xrange(ipyDataMgr.GetCrossRealmPKZoneCount()):
        zoneIpyData = ipyDataMgr.GetCrossRealmPKZoneByIndex(index)
        zoneID = zoneIpyData.GetZoneID()
        # 广播当前赛区的所有子服跨服PK赛季状态变更
        serverGroupIDList = zoneIpyData.GetServerGroupIDList()
        seasonID = gameWorld.GetDictByKey(ChConfig.Def_WorldKey_CrossPKZoneSeasonID % zoneID)
        seasonState = gameWorld.GetDictByKey(ChConfig.Def_WorldKey_CrossPKZoneSeasonState % zoneID)
        seasonInfo = {"ZoneID":zoneID, "SeasonID":seasonID, "SeasonState":seasonState, "MatchState":isOpen}
        GameWorld.Log("跨服PK匹配状态变更: zoneID=%s,seasonID=%s,seasonState=%s,matchState=%s" % (zoneID, seasonID, seasonState, isOpen))
        CrossRealmMsg.SendMsgToClientServer(ShareDefine.CrossServerMsg_PKSeasonInfo, seasonInfo, serverGroupIDList)
    return
def ClientServerMsg_ServerInitOK(serverGroupID, tick):
    ## 子服启动成功
    GameWorld.Log("子服启动成功,同步给子服对应的赛季信息: serverGroupID=%s" % (serverGroupID))
    zoneID = GetCrossPKServerGroupZoneID(serverGroupID)
    if not zoneID:
        GameWorld.Log("    该子服没有分配赛区,不同步!")
        return
    gameWorld = GameWorld.GetGameWorld()
    seasonID = gameWorld.GetDictByKey(ChConfig.Def_WorldKey_CrossPKZoneSeasonID % zoneID)
    seasonState = gameWorld.GetDictByKey(ChConfig.Def_WorldKey_CrossPKZoneSeasonState % zoneID)
    matchState = gameWorld.GetDictByKey(ShareDefine.Def_Notify_WorldKey_CrossDailyActionState % ShareDefine.DailyActionID_CrossReamPK)
    seasonInfo = {"ZoneID":zoneID, "SeasonID":seasonID, "SeasonState":seasonState, "MatchState":matchState}
    CrossRealmMsg.SendMsgToClientServer(ShareDefine.CrossServerMsg_PKSeasonInfo, seasonInfo, [serverGroupID])
    return
def GetCrossPKServerGroupZoneID(serverGroupID):
    ## 获取服务器组ID对应的跨服PK所属赛区,返回0代表该服务器没有分配赛区
    ipyDataMgr = IpyGameDataPY.IPY_Data()
    for index in xrange(ipyDataMgr.GetCrossRealmPKZoneCount()):
        zoneIpyData = ipyDataMgr.GetCrossRealmPKZoneByIndex(index)
        for groupInfo in zoneIpyData.GetServerGroupIDList():
            if (isinstance(groupInfo, int) and serverGroupID == groupInfo) \
                or (isinstance(groupInfo, tuple) and len(groupInfo) == 2 and groupInfo[0] <= serverGroupID <= groupInfo[1]):
                return zoneIpyData.GetZoneID()
    return 0
def OnPlayerLogin(curPlayer):
    # 本服登录处理
    if not GameWorld.IsCrossServer():
        # 本服没有分配赛区不处理
        if not GameWorld.GetGameWorld().GetDictByKey(ShareDefine.Def_Notify_WorldKey_CrossPKZoneID):
            return
        __OnLoginNotifyPKOverInfo(curPlayer)
        # 同步所有赛区赛季信息
        zoneSeasonInfo = ChPyNetSendPack.tagGCCrossRealmPKSeasonInfo()
        zoneSeasonInfo.ZoneList = []
        ipyDataMgr = IpyGameDataPY.IPY_Data()
        for index in xrange(ipyDataMgr.GetCrossRealmPKZoneCount()):
            zoneIpyData = ipyDataMgr.GetCrossRealmPKZoneByIndex(index)
            zoneID = zoneIpyData.GetZoneID()
            zoneInfo = ChPyNetSendPack.tagGCCrossRealmPKZone()
            zoneInfo.ZoneID = zoneID
            zoneInfo.ZoneName = zoneIpyData.GetZoneName().decode(ShareDefine.Def_Game_Character_Encoding).encode(GameWorld.GetCharacterEncoding())
            zoneInfo.ZoneNameLen = len(zoneInfo.ZoneName)
            zoneInfo.SeasonList = []
            seasonList = IpyGameDataPY.GetIpyGameDataList("CrossRealmPKSeason", zoneID)
            seasonList = [] if not seasonList else seasonList
            for seasonIpyData in seasonList:
                seasonInfo = ChPyNetSendPack.tagGCCrossRealmPKSeason()
                seasonInfo.SeasonID = seasonIpyData.GetSeasonID()
                seasonInfo.StartDate = seasonIpyData.GetStartDate()
                seasonInfo.EndDate = seasonIpyData.GetEndDate()
                seasonInfo.EndTime = seasonIpyData.GetEndTime()
                zoneInfo.SeasonList.append(seasonInfo)
            zoneInfo.SeasonCount = len(zoneInfo.SeasonList)
            zoneSeasonInfo.ZoneList.append(zoneInfo)
        zoneSeasonInfo.ZoneCount = len(zoneSeasonInfo.ZoneList)
        NetPackCommon.SendFakePack(curPlayer, zoneSeasonInfo)
        # 同步本服赛季状态
        gameWorld = GameWorld.GetGameWorld()
        seasonStatePack = ChPyNetSendPack.tagGCCrossRealmPKSeasonState()
        seasonStatePack.ZoneID = gameWorld.GetDictByKey(ShareDefine.Def_Notify_WorldKey_CrossPKZoneID)
        seasonStatePack.SeasonID = gameWorld.GetDictByKey(ShareDefine.Def_Notify_WorldKey_CrossPKSeasonID)
        seasonStatePack.SeasonState = gameWorld.GetDictByKey(ShareDefine.Def_Notify_WorldKey_CrossPKSeasonState)
        seasonStatePack.MatchState = gameWorld.GetDictByKey(ShareDefine.Def_Notify_WorldKey_CrossDailyActionState % ShareDefine.DailyActionID_CrossReamPK)
        NetPackCommon.SendFakePack(curPlayer, seasonStatePack)
    # 跨服登录处理
    else:
        # 比如验证房间ID是否合法
        pass
    return
## 玩家离线处理
@@ -81,17 +744,10 @@
    SendCancelCrossRealmPKMatch(curPlayer, "PlayerDisconnect")
    return
def IsCrossRealmPKOpen():
def IsCrossRealmPKMatchState():
    ## 跨服PK匹配赛是否开启
    return 1
    return GameWorld.GetGameWorld().GetDictByKey(ShareDefine.Def_Notify_WorldKey_MergePKState) == ChConfig.Def_Action_Open
def ClientServerMsg_ServerInitOK(serverGroupID, tick):
    ## 子服启动成功
    GameWorld.Log("同步跨服PK赛季信息及状态到子服: serverGroupID=%s" % (serverGroupID))
    seasonInfo = {"SeasonID":1, "SeasonState":1, "MatchState":1}
    CrossRealmMsg.SendMsgToClientServer(ShareDefine.CrossServerMsg_PKSeasonInfo, seasonInfo, [serverGroupID])
    return
    return GameWorld.GetGameWorld().GetDictByKey(ShareDefine.Def_Notify_WorldKey_CrossDailyActionState \
                                                 % ShareDefine.DailyActionID_CrossReamPK) == ChConfig.Def_Action_Open
def SendCancelCrossRealmPKMatch(curPlayer, reason):   
    ## 发送取消匹配
@@ -101,7 +757,7 @@
        return
    
    # 非活动中不处理
    if not IsCrossRealmPKOpen():
    if not IsCrossRealmPKMatchState():
        return
    
#    # 如果是要登陆到跨服服务器的,不发送取消
@@ -133,7 +789,7 @@
        GameWorld.ErrLog("非跨服服务器不处理跨服PK匹配请求!")
        return
    
    if not IsCrossRealmPKOpen():
    if not IsCrossRealmPKMatchState():
        GameWorld.Log("跨服匹配PK活动未开启,不允许请求匹配!")
        return
    
@@ -146,6 +802,7 @@
    playerLV = playerInfoDict["playerLV"] # ְҵ
    maxHP = playerInfoDict["maxHP"] # ְҵ
    fightPower = playerInfoDict["fightPower"] # 战斗力
    realmLV = playerInfoDict["realmLV"] # 境界
    pkScore = playerInfoDict["pkScore"] # 当前积分
    danLV = playerInfoDict["danLV"] # 当前段位
    cWinCount = playerInfoDict["cWinCount"] # 连胜次数
@@ -171,6 +828,7 @@
    pkPlayer.pkScore = pkScore
    pkPlayer.danLV = danLV
    pkPlayer.fightPower = fightPower
    pkPlayer.realmLV = realmLV
    pkPlayer.matchTick = tick
    pkPlayer.cWinCount = cWinCount
    pkPlayer.ondayScore = ondayScore
@@ -197,7 +855,7 @@
        return
    
    # 非活动中不处理
    if not IsCrossRealmPKOpen():
    if not IsCrossRealmPKMatchState():
        return
    
    accID = playerInfoDict["accID"] # 角色账号
@@ -327,11 +985,12 @@
    if not GameWorld.IsCrossServer():
        return
    
    if not IsCrossRealmPKOpen():
    if not IsCrossRealmPKMatchState():
        return
    
    # 同步子服排行榜
    #__SyncBillboardToClientServer(False, tick)
    # 定时更新排行榜
    crossPKBillboardMgr = PyDataManager.GetCrossPKBillboardManager()
    crossPKBillboardMgr.PKBillboardSortByTime(tick)
    
    processTick = IpyGameDataPY.GetFuncCfg("CrossRealmPKMatch", 1) * 1000
    processTickKey = "PKMatchLastTick"
@@ -528,6 +1187,7 @@
        
        newRoom = CrossPKRoom()
        newRoom.pkZoneID = pkZoneID
        newRoom.seasonID = aPlayer.seasonID # 因为匹在一起的玩家一定是同一赛区同一赛季的,所以随便取一个玩家的赛季ID信息即可
        newRoom.roomID = roomID
        newRoom.mapID = mapID
        newRoom.openTick = tick
@@ -570,8 +1230,7 @@
    
    timeoutRoomDict = {}
    serverGroupIDList = []
    #roomTimeout = IpyGameDataPY.GetFuncCfg("CheckRoomTimeout", 1) * 1000 # 这个时间尽量长点,目前暂时不确定玩家从准备好到进入到地图的时长
    roomTimeout = 180 * 1000 # 这个时间尽量长点,目前暂时不确定玩家从准备到进入到地图的时长
    roomTimeout = IpyGameDataPY.GetFuncCfg("CrossRealmPKCfg", 2) * 1000 # 这个时间尽量长点,目前暂时不确定玩家从准备到进入到地图的时长
    for roomID, pkRoom in PyGameData.g_crossPKRoomDict.items():
        if pkRoom.isMapOpen or not pkRoom.readyTick:
            continue
@@ -647,7 +1306,8 @@
    loser = PyGameData.g_crossPKPlayerDict.pop(loserID)
    #winner = PyGameData.g_crossPKPlayerDict[winnerID]
    #loser = PyGameData.g_crossPKPlayerDict[loserID]
    seasonID = winner.seasonID
    zoneID = vsRoom.pkZoneID
    seasonID = vsRoom.seasonID
    
    cWinCount = winner.cWinCount
    winnerScore, loserScore = winner.pkScore, loser.pkScore
@@ -693,6 +1353,9 @@
    GameWorld.Log("wBaseScore=%s,wExScore=%s,winnerAddScore=%s,updScore=%s,updDanLV=%s,updCWinCount=%s" % (wBaseScore, wExScore, winnerAddScore, winner.pkScore, winner.danLV, winner.cWinCount))
    GameWorld.Log("lBaseScore=%s,lExScore=%s,loserAddScore=%s,updScore=%s,updDanLV=%s,updCWinCount=%s" % (lBaseScore, lExScore, loserAddScore, loser.pkScore, loser.danLV, loser.cWinCount))
    
    # 更新排行榜
    UpdateCrossPKBillboard(zoneID, seasonID, winner, loser)
    timeStr = GameWorld.GetCurrentDataTimeStr()
    playerOverDict = {}
    # 通知客户端战斗结果
@@ -707,7 +1370,7 @@
        player = GameWorld.GetPlayerManager().FindPlayerByID(playerID)
        notifyState = True if player else False
        
        playerOverDict[playerID] = [roomID, seasonID, timeStr, overType, winnerID, roundWinnerIDList] \
        playerOverDict[playerID] = [roomID, zoneID, seasonID, timeStr, overType, winnerID, roundWinnerIDList] \
                                    + [serverGroupID, pkScore, danLV, cWinCount, addScore, tagPlayerID, tagPlayerName, notifyState]
        if not player:
            continue
@@ -737,6 +1400,69 @@
    return
##================================== 以下是子服逻辑 ==========================================
def OnMapServerInitOK():
    # 通知地图服务器状态
    if GameWorld.IsCrossServer():
        return
    gameWorld = GameWorld.GetGameWorld()
    zoneID = gameWorld.GetDictByKey(ShareDefine.Def_Notify_WorldKey_CrossPKZoneID)
    seasonID = gameWorld.GetDictByKey(ShareDefine.Def_Notify_WorldKey_CrossPKSeasonID)
    seasonState = gameWorld.GetDictByKey(ShareDefine.Def_Notify_WorldKey_CrossPKSeasonState)
    matchState = GameWorld.GetGameWorld().GetDictByKey(ShareDefine.Def_Notify_WorldKey_CrossDailyActionState % ShareDefine.DailyActionID_CrossReamPK)
    GameWorld.SendMapServerMsgEx(ShareDefine.Def_Notify_WorldKey_CrossPKZoneID, zoneID)
    GameWorld.SendMapServerMsgEx(ShareDefine.Def_Notify_WorldKey_CrossPKSeasonID, seasonID)
    GameWorld.SendMapServerMsgEx(ShareDefine.Def_Notify_WorldKey_CrossPKSeasonState, seasonState)
    GameWorld.SendMapServerMsgEx(ShareDefine.Def_Notify_WorldKey_CrossDailyActionState % ShareDefine.DailyActionID_CrossReamPK, matchState)
    return
def CrossServerMsg_PKSeasonInfo(seasonInfo):
    ## 收到跨服服务器同步的赛季信息
    #seasonInfo = {"ZoneID":zoneID, "SeasonID":seasonID, "SeasonState":seasonState, "MatchState":matchState}
    GameWorld.Log("收到跨服服务器同步的赛季信息...")
    if not seasonInfo:
        return
    zoneID = seasonInfo.get("ZoneID", 0)
    seasonID = seasonInfo.get("SeasonID", 0)
    seasonState = seasonInfo.get("SeasonState", 0)
    matchState = seasonInfo.get("MatchState", 0)
    GameWorld.Log("    zoneID=%s,seasonID=%s,seasonState=%s,matchState=%s" % (zoneID, seasonID, seasonState, matchState))
    if not zoneID:
        return
    gameWorld = GameWorld.GetGameWorld()
    curSeasonState = gameWorld.GetDictByKey(ShareDefine.Def_Notify_WorldKey_CrossPKSeasonState)
    gameWorld.SetDict(ShareDefine.Def_Notify_WorldKey_CrossPKZoneID, zoneID)
    gameWorld.SetDict(ShareDefine.Def_Notify_WorldKey_CrossPKSeasonID, seasonID)
    gameWorld.SetDict(ShareDefine.Def_Notify_WorldKey_CrossPKSeasonState, seasonState)
    gameWorld.SetDict(ShareDefine.Def_Notify_WorldKey_CrossDailyActionState % ShareDefine.DailyActionID_CrossReamPK, matchState)
    if curSeasonState == 1 and seasonState == 2:
        PlayerControl.WorldNotify(0, "NotifySeasonOver")
    # 通知地图服务器状态
    GameWorld.SendMapServerMsgEx(ShareDefine.Def_Notify_WorldKey_CrossPKZoneID, zoneID)
    GameWorld.SendMapServerMsgEx(ShareDefine.Def_Notify_WorldKey_CrossPKSeasonID, seasonID)
    GameWorld.SendMapServerMsgEx(ShareDefine.Def_Notify_WorldKey_CrossPKSeasonState, seasonState)
    GameWorld.SendMapServerMsgEx(ShareDefine.Def_Notify_WorldKey_CrossDailyActionState % ShareDefine.DailyActionID_CrossReamPK, matchState)
    # 广播玩家赛季相关状态变更
    seasonStatePack = ChPyNetSendPack.tagGCCrossRealmPKSeasonState()
    seasonStatePack.ZoneID = zoneID
    seasonStatePack.SeasonID = seasonID
    seasonStatePack.SeasonState = seasonState
    seasonStatePack.MatchState = matchState
    playerManager = GameWorld.GetPlayerManager()
    for i in xrange(playerManager.GetPlayerCount()):
        curPlayer = playerManager.GetPlayerByIndex(i)
        if curPlayer == None or not curPlayer.GetInitOK():
            continue
        NetPackCommon.SendFakePack(curPlayer, seasonStatePack)
    return
def CrossServerMsg_PKMatchReqRet(retInfo):
    ## 跨服PK匹配请求结果
@@ -876,13 +1602,13 @@
    GameWorld.Log("===收到跨服服务器同步的跨服PK结果=== curServerGroupID=%s" % curServerGroupID)
    
    for playerID, overInfo in playerOverDict.items():
        roomID, seasonID, timeStr, overType, winnerID, roundWinnerIDList, \
        roomID, zoneID, seasonID, timeStr, overType, winnerID, roundWinnerIDList, \
            serverGroupID, pkScore, danLV, cWinCount, addScore, tagPlayerID, tagPlayerName, notifyState = overInfo
        if serverGroupID != curServerGroupID:
            GameWorld.DebugLog("    不是本服玩家,不处理!playerID=%s,serverGroupID=%s" % (playerID, serverGroupID))
            continue
        
        sendMapOverInfo = [roomID, seasonID, timeStr, overType, winnerID, roundWinnerIDList, pkScore, danLV, cWinCount, addScore, tagPlayerID, tagPlayerName, notifyState]
        sendMapOverInfo = [roomID, zoneID, seasonID, timeStr, overType, winnerID, roundWinnerIDList, pkScore, danLV, cWinCount, addScore, tagPlayerID, tagPlayerName, notifyState]
        player = GameWorld.GetPlayerManager().FindPlayerByID(playerID)
        if not player or PlayerControl.GetIsTJG(player):
            GameWorld.Log("    玩家不在线 或脱机中,先缓存,玩家上线后再同步,playerID=%s" % (playerID))
@@ -891,8 +1617,8 @@
        
        sysMsg = str(sendMapOverInfo)
        player.MapServer_QueryPlayerResult(0, 0, "CrossPKOverInfo", sysMsg, len(sysMsg))
        GameWorld.Log("通知地图跨服PK结算: roomID=%s,seasonID=%s,timeStr=%s,overType=%s,winnerID=%s,roundWinnerIDList=%s, pkScore=%s,danLV=%s,cWinCount=%s,addScore=%s,tagPlayerID=%s,notifyState=%s,mapID=%s"
                      % (roomID, seasonID, timeStr, overType, winnerID, roundWinnerIDList, pkScore, danLV, cWinCount, addScore, tagPlayerID, notifyState, player.GetMapID()), playerID)
        GameWorld.Log("通知地图跨服PK结算: roomID=%s,zoneID=%s,seasonID=%s,timeStr=%s,overType=%s,winnerID=%s,roundWinnerIDList=%s, pkScore=%s,danLV=%s,cWinCount=%s,addScore=%s,tagPlayerID=%s,notifyState=%s,mapID=%s"
                      % (roomID, zoneID, seasonID, timeStr, overType, winnerID, roundWinnerIDList, pkScore, danLV, cWinCount, addScore, tagPlayerID, notifyState, player.GetMapID()), playerID)
    return
def __OnLoginNotifyPKOverInfo(curPlayer):