From 84f8b05044e64036c5abb6b840bf0fd96f8c3bc2 Mon Sep 17 00:00:00 2001
From: hxp <ale99527@vip.qq.com>
Date: 星期五, 21 十二月 2018 18:09:32 +0800
Subject: [PATCH] 5424 【后端】【1.4】跨服竞技场开发(流程调通版,可匹配、PK、结算,其他功能没有)

---
 ServerPython/CoreServerGroup/GameServer/Script/NetPackCommon.py                                                        |    8 
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorldLogic/FBLogic.py                          |    2 
 ServerPython/CoreServerGroup/GameServer/Script/GM/GMShell.py                                                           |    5 
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/RemoteQuery/GY_Query_CrossRealmReg.py       |   94 ++
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/RemoteQuery/GY_Query_SetPlayerAttr.py       |   59 +
 ServerPython/CoreServerGroup/GameServer/ServerCommScript.ini                                                           |   10 
 ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/CrossRealmPK.py                                          |  909 ++++++++++++++++++++++
 ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/GameWorldMergeKing.py                                    |    5 
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorldLogic/FBProcess/GameLogic_CrossRealmPK.py |  498 ++++++++++++
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/ChPlayer.py                                 |   15 
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerControl.py                            |   10 
 ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerControl.py                                                 |   64 
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/RemoteQuery/GY_Query_CrossPKOverInfo.py     |   50 +
 ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerQuery.py                                                   |   43 
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/CrossRealmPlayer.py                         |   80 +
 ServerPython/CoreServerGroup/GameServer/Script/Player/ChPlayer.py                                                      |    6 
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/NetPackCommon.py                                   |    4 
 ServerPython/CoreServerGroup/GameServer/Script/Player/CrossRealmPlayer.py                                              |  115 ++
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerCrossRealmPK.py                       |  229 +++++
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorldLogic/FBProcess/FBCommon.py               |    7 
 ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/CrossRealmMsg.py                                         |  143 +++
 ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/GameWorldProcess.py                                      |   22 
 ServerPython/CoreServerGroup/GameServer/Script/PyGameData.py                                                           |   10 
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/PyNetPack.ini                                             |   40 
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/ServerScript.ini                                          |    6 
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerEventCounter.py                       |    3 
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChConfig.py                                        |   18 
 27 files changed, 2,359 insertions(+), 96 deletions(-)

diff --git a/ServerPython/CoreServerGroup/GameServer/Script/GM/GMShell.py b/ServerPython/CoreServerGroup/GameServer/Script/GM/GMShell.py
index 943407b..e5c6737 100644
--- a/ServerPython/CoreServerGroup/GameServer/Script/GM/GMShell.py
+++ b/ServerPython/CoreServerGroup/GameServer/Script/GM/GMShell.py
@@ -23,6 +23,7 @@
 import PyGameData
 import traceback
 import GMCommon
+import ShareDefine
 import os
 #---------------------------------------------------------------------
 g_broadCastList = []
@@ -92,7 +93,7 @@
             if callFunc != None:
                 extendParamList = callFunc(curPlayer)
                 alist.extend(extendParamList)
-                MergeChildMsg.SendMergerChildToCenterStringData(ChConfig.Def_SendGMCMD, alist)
+                MergeChildMsg.SendMergerChildToCenterStringData(ShareDefine.ClientServerMsg_GMCMD, alist)
                 return
             
         callFunc = GameWorld.GetExecFunc(Commands, "%s.%s"%(callFunName, "OnExec"))
@@ -245,7 +246,7 @@
     return cmdDict
 
 ## 收到子服务器发送的GM命令
-def ClientServer_SendGMCMD(cmdMsgList, tick):
+def ClientServerMsg_GMCMD(cmdMsgList, tick):
     if len(cmdMsgList) == 0:
         return 
     
diff --git a/ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/CrossRealmMsg.py b/ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/CrossRealmMsg.py
new file mode 100644
index 0000000..db3b4d1
--- /dev/null
+++ b/ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/CrossRealmMsg.py
@@ -0,0 +1,143 @@
+#!/usr/bin/python
+# -*- coding: GBK -*-
+#-------------------------------------------------------------------------------
+#
+##@package CrossRealmMsg
+#
+# @todo:跨服信息管理
+# @author hxp
+# @date 2018-12-21
+# @version 1.0
+#
+# 详细描述: 跨服信息管理
+#
+#-------------------------------------------------------------------------------
+#"""Version = 2018-12-21 18:00"""
+#-------------------------------------------------------------------------------
+
+import GameWorld
+import ShareDefine
+import PlayerControl
+import IPY_GameServer
+import CrossRealmPlayer
+import CrossRealmPK
+import GMShell
+
+import traceback
+
+def SendMsgToCrossServer(msgType, dataMsg):
+    ## 发送信息到跨服服务器上
+    if GameWorld.IsCrossServer():
+        return
+    if not dataMsg:
+        return
+    sendMsg = str({"MsgType":msgType, "Data":dataMsg, "ServerGroupID":GameWorld.GetServerGroupID()})
+    GameWorld.Log("SendMsgToCrossServer => %s" % (sendMsg))   
+    GameWorld.GetGameWorld().SendMergerChildToCenterStringData(sendMsg, len(sendMsg))
+    return
+
+def OnCrossServerReceiveMsg(recvMsg, tick):
+    ## 跨服服务器收到信息处理
+    try:
+        GameWorld.Log("OnCrossServerReceiveMsg: %s" % recvMsg)
+        msgDict = eval(recvMsg)
+        
+        msgType = msgDict.get("MsgType", -1)    
+        msgData = msgDict.get("Data", "")
+        serverGroupID = msgDict.get("ServerGroupID", 0)
+            
+        if msgType == ShareDefine.ClientServerMsg_PKMatch:
+            CrossRealmPK.ClientServerMsg_PKMatch(serverGroupID, msgData, tick)
+            
+        elif msgType == ShareDefine.ClientServerMsg_PKCancel:
+            CrossRealmPK.ClientServerMsg_PKCancel(msgData, tick)
+            
+        elif msgType == ShareDefine.ClientServerMsg_PKPrepareOK:
+            CrossRealmPK.ClientServerMsg_PKPrepareOK(msgData, tick)
+                        
+        elif msgType == ShareDefine.ClientServerMsg_GMCMD:
+            GMShell.ClientServerMsg_GMCMD(msgData, tick)
+            
+        elif msgType == ShareDefine.ClientServerMsg_ServerInitOK:
+            ClientServerMsg_ServerInitOK(serverGroupID, msgData, tick)
+            
+        else:
+            GameWorld.ErrLog("没有该信息类型逻辑处理!")
+            
+    except:
+        GameWorld.ErrLog("OnCrossServerReceiveMsg:%s; except:%s" % (recvMsg, traceback.format_exc()))
+        if GameWorld.GetGameWorld().GetDebugLevel():
+            raise BaseException(str(traceback.format_exc()))
+    return
+
+def ClientServerMsg_ServerInitOK(serverGroupID, msgData, tick):
+    ''' 收到子服启动成功通知 
+         当子服启动成功后,可同步一次跨服服务器活动状态及活动数据给子服
+    '''
+    GameWorld.Log("收到跨服子服启动成功通知!")
+    CrossRealmPK.ClientServerMsg_ServerInitOK(serverGroupID, tick)
+    return
+
+## ================================================================================================
+
+def SendMsgToClientServer(msgType, dataMsg, serverGroupIDList=[]):
+    ''' 广播信息到子服务器上
+        @param serverGroupIDList: 发送指定的服务器组ID列表,内部已经针对列表中组ID去重,
+        所以外部逻辑可直接添加,不用考虑组ID重复问题,没有指定服务器组ID时,默认广播所有子服
+    '''
+    if not GameWorld.IsCrossServer():
+        return
+    if not dataMsg:
+        return
+    sendMsg = str({"MsgType":msgType, "Data":dataMsg})
+    GameWorld.Log("SendMsgToClientServer => serverGroupIDList=%s, sendMsg=%s" % (serverGroupIDList, sendMsg))
+    if not serverGroupIDList:
+        GameWorld.GetGameWorld().SendBroadcastMergeClient(sendMsg)
+    else:
+        serverGroupIDList = list(set(serverGroupIDList)) # 去重
+        for serverGroupID in serverGroupIDList:
+            GameWorld.GetGameWorld().SendMergeMsgToClientByGroupID(serverGroupID, sendMsg)
+    return
+
+def OnClientServerReceiveMsg(index, tick):
+    ## 子服收到跨服服务器信息
+    dataPack = IPY_GameServer.IPY_MGBroadcastMergeClient()
+    dataMsg = dataPack.GetData()
+    GameWorld.Log("OnClientServerReceiveMsg: %s" % dataMsg)
+    
+    try:
+        msgDict = eval(dataMsg)
+        msgType = msgDict.get("MsgType", -1)    
+        msgData = msgDict.get("Data", "")
+        
+        if msgType == ShareDefine.CrossServerMsg_ExitCrossServer:
+            CrossRealmPlayer.CrossServerMsg_ExitCrossServer(msgData)
+            
+        elif msgType == ShareDefine.CrossServerMsg_Notify:
+            PlayerControl.CrossServerMsg_Notify(msgData)
+            
+        elif msgType == ShareDefine.CrossServerMsg_PKMatchReqRet:
+            CrossRealmPK.CrossServerMsg_PKMatchReqRet(msgData)
+            
+        elif msgType == ShareDefine.CrossServerMsg_PKMatchResult:
+            CrossRealmPK.CrossServerMsg_PKMatchResult(msgData)
+            
+        elif msgType == ShareDefine.CrossServerMsg_PKReadyOKRoomList:
+            CrossRealmPK.CrossServerMsg_PKReadyOKRoomList(msgData)
+            
+        elif msgType == ShareDefine.CrossServerMsg_PKTimeoutRoomList:
+            CrossRealmPK.CrossServerMsg_PKTimeoutRoomList(msgData)
+            
+        elif msgType == ShareDefine.CrossServerMsg_PKOverInfo:
+            CrossRealmPK.CrossServerMsg_PKOverInfo(msgData)
+            
+        else:
+            GameWorld.ErrLog("没有该信息类型逻辑处理!")
+            
+    except:
+        GameWorld.ErrLog("OnClientServerReceiveMsg:%s; except:%s" % (dataMsg, traceback.format_exc()))
+        if GameWorld.GetGameWorld().GetDebugLevel():
+            raise BaseException(str(traceback.format_exc()))
+        
+    return
+
diff --git a/ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/CrossRealmPK.py b/ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/CrossRealmPK.py
new file mode 100644
index 0000000..f498649
--- /dev/null
+++ b/ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/CrossRealmPK.py
@@ -0,0 +1,909 @@
+#!/usr/bin/python
+# -*- coding: GBK -*-
+#-------------------------------------------------------------------------------
+#
+##@package CrossRealmPK
+#
+# @todo:跨服PK竞技场
+# @author hxp
+# @date 2018-12-21
+# @version 1.0
+#
+# 详细描述: 跨服PK竞技场
+#
+#-------------------------------------------------------------------------------
+#"""Version = 2018-12-21 18:00"""
+#-------------------------------------------------------------------------------
+
+import GameWorld
+import PlayerControl
+import CrossRealmMsg
+import CrossRealmPlayer
+import ChPyNetSendPack
+import NetPackCommon
+import IpyGameDataPY
+import ShareDefine
+import PyGameData
+import ChConfig
+
+import operator
+import random
+    
+PKPlayerState_Matching = 0
+PKPlayerState_Fighting = 1
+
+class CrossPKPlayer():
+    ## 跨服PK玩家类
+    
+    def __init__(self):
+        self.accID = ""
+        self.playerID = 0
+        self.playerName = ""
+        self.playerJob = 0
+        self.playerLV = 0
+        self.maxHP = 0
+        self.fightPower = 0
+        self.pkScore = 0
+        self.danLV = 0
+        self.matchTick = 0
+        self.cWinCount = 0 # 连胜次数
+        self.ondayScore = 0 # 过天时的积分
+        self.serverGroupID = 0 # 所属服务器ID,一个服务器ID由多个服组成
+        self.pkZoneID = 0 # 所属赛区ID,一个赛区由多个服务器ID组成
+        self.seasonID = 0 # 赛季ID
+        return
+    
+class CrossPKRoom():
+    ## 跨服PK房间类
+    
+    def __init__(self):
+        self.pkZoneID = 0
+        self.roomID = 0
+        self.mapID = 0
+        self.openTick = 0 # 开房时间
+        self.readyTick = 0 # 玩家都准备好的时间
+        self.roomState = ShareDefine.Def_VsRoom_State_WaitPlayer # 默认状态
+        self.roomPlayerIDList = [] # 对战玩家ID列表
+        self.readyPlayerIDList = [] # 已经准备好的玩家ID列表
+        self.isMapOpen = False # 地图是否已经开启该房间,未开启的房间超时后,本次匹配视为无效,有玩家进地图才会开启副本分线
+        return
+    
+################################################################################
+
+def OnPlayerLogin(curPlayer):
+    if not GameWorld.IsCrossServer():
+        __OnLoginNotifyPKOverInfo(curPlayer)
+    return
+
+## 玩家离线处理
+def OnLeaveServer(curPlayer):    
+    # 发送取消匹配
+    SendCancelCrossRealmPKMatch(curPlayer, "PlayerDisconnect")
+    return
+
+def IsCrossRealmPKOpen():
+    ## 跨服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
+
+def SendCancelCrossRealmPKMatch(curPlayer, reason):   
+    ## 发送取消匹配
+    
+    # 跨服服务器不处理
+    if GameWorld.IsCrossServer():
+        return
+    
+    # 非活动中不处理
+    if not IsCrossRealmPKOpen():
+        return
+    
+#    # 如果是要登陆到跨服服务器的,不发送取消
+#    if curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_IsLoginToMergeServer):
+#        GameWorld.DebugLog("本次离线为要登陆跨服服务器的自动离线行为,不发送取消匹配!", curPlayer.GetPlayerID())
+#        curPlayer.SetDict(ChConfig.Def_PlayerKey_IsLoginToMergeServer, 0)
+#        return
+
+    vsRoomID = curPlayer.GetVsRoomId()
+    if vsRoomID and PlayerControl.GetCrossRealmState(curPlayer) == 1:
+        GameWorld.DebugLog("玩家跨服PK状态,不能取消匹配!vsRoomID=%s" % vsRoomID, curPlayer.GetPlayerID())
+        return
+    
+    dataMsg = {"accID":curPlayer.GetAccID(), # 账号
+               "playerID":curPlayer.GetPlayerID(), # 玩家ID
+               "playerName":curPlayer.GetName(), # 跨服子服玩家名
+               "reason":reason, # 取消原因
+               "vsRoomID":vsRoomID, # 对战房间ID
+               }
+    CrossRealmMsg.SendMsgToCrossServer(ShareDefine.ClientServerMsg_PKCancel, dataMsg)
+    PlayerControl.SetVsRoomId(curPlayer, 0)
+    GameWorld.Log("发送取消跨服PK匹配到跨服服务器:dataMsg=%s" % str(dataMsg), curPlayer.GetPlayerID())
+    return
+
+def ClientServerMsg_PKMatch(serverGroupID, playerInfoDict, tick):
+    ## 请求匹配
+    
+    if not GameWorld.IsMergeServer():
+        GameWorld.ErrLog("非跨服服务器不处理跨服PK匹配请求!")
+        return
+    
+    if not IsCrossRealmPKOpen():
+        GameWorld.Log("跨服匹配PK活动未开启,不允许请求匹配!")
+        return
+    
+    seasonID = playerInfoDict["seasonID"] # 赛季ID
+    pkZoneID = playerInfoDict["pkZoneID"] # 所属赛区
+    accID = playerInfoDict["accID"] # 角色账号
+    playerID = playerInfoDict["playerID"] # 角色ID
+    playerName = playerInfoDict["playerName"] # 玩家名
+    job = playerInfoDict["playerJob"] # 职业
+    playerLV = playerInfoDict["playerLV"] # 职业
+    maxHP = playerInfoDict["maxHP"] # 职业
+    fightPower = playerInfoDict["fightPower"] # 战斗力
+    pkScore = playerInfoDict["pkScore"] # 当前积分
+    danLV = playerInfoDict["danLV"] # 当前段位
+    cWinCount = playerInfoDict["cWinCount"] # 连胜次数
+    ondayScore = playerInfoDict["ondayScore"] # 过天时的积分
+    
+    zoneMatchPlayerList = PyGameData.g_crossPKZoneMatchPlayerDict.get(pkZoneID, [])
+#    if playerID in zoneMatchPlayerList:
+#        GameWorld.Log("玩家正在匹配中,无法重复发起匹配!playerID=%s,accID=%s" % (playerID, accID))
+#        CrossRealmMsg.SendMsgToClientServer(ShareDefine.CrossServerMsg_PKMatchReqRet, [playerID, 1], [serverGroupID])
+#        return
+#    if playerID in PyGameData.g_crossPKPlayerDict:
+#        GameWorld.Log("玩家正在战斗中,无法重复发起匹配!playerID=%s,accID=%s" % (playerID, accID))
+#        CrossRealmMsg.SendMsgToClientServer(ShareDefine.CrossServerMsg_PKMatchReqRet, [playerID, -2], [serverGroupID])
+#        return
+    
+    pkPlayer = CrossPKPlayer()
+    pkPlayer.accID = accID
+    pkPlayer.playerID = playerID
+    pkPlayer.playerName = playerName
+    pkPlayer.playerJob = job
+    pkPlayer.playerLV = playerLV
+    pkPlayer.maxHP = maxHP
+    pkPlayer.pkScore = pkScore
+    pkPlayer.danLV = danLV
+    pkPlayer.fightPower = fightPower
+    pkPlayer.matchTick = tick
+    pkPlayer.cWinCount = cWinCount
+    pkPlayer.ondayScore = ondayScore
+    pkPlayer.serverGroupID = serverGroupID
+    pkPlayer.pkZoneID = pkZoneID
+    pkPlayer.seasonID = seasonID
+    PyGameData.g_crossPKPlayerDict[playerID] = pkPlayer
+    
+    # 加入赛区匹配列表
+    zoneMatchPlayerList.append(playerID)
+    PyGameData.g_crossPKZoneMatchPlayerDict[pkZoneID] = zoneMatchPlayerList
+    
+    GameWorld.Log("玩家加入匹配: seasonID=%s,pkZoneID=%s,serverGroupID=%s,accID=%s,playerID=%s,pkScore=%s,fightPower=%s,cWinCount=%s,len(zoneMatchPlayerList)=%s" 
+                  % (seasonID, pkZoneID, serverGroupID, accID, playerID, pkScore, fightPower, cWinCount, len(zoneMatchPlayerList)))
+    
+    CrossRealmMsg.SendMsgToClientServer(ShareDefine.CrossServerMsg_PKMatchReqRet, [playerID, 1], [serverGroupID])
+    return
+
+def ClientServerMsg_PKCancel(playerInfoDict, tick):
+    ## 取消匹配
+    
+    if not GameWorld.IsMergeServer():
+        GameWorld.ErrLog("非跨服服务器不处理取消跨服PK匹配!")
+        return
+    
+    # 非活动中不处理
+    if not IsCrossRealmPKOpen():
+        return
+    
+    accID = playerInfoDict["accID"] # 角色账号
+    playerID = playerInfoDict["playerID"] # 玩家ID
+    reason = playerInfoDict["reason"] # 取消原因
+    vsRoomID = playerInfoDict["vsRoomID"] # 所属对战房间ID
+    if vsRoomID in PyGameData.g_crossPKRoomDict:
+        pkRoom = PyGameData.g_crossPKRoomDict[vsRoomID]
+        if pkRoom.isMapOpen or pkRoom.readyTick:
+            GameWorld.Log("跨服对战房间已经开启了线路,或者双方数据都已传输完毕,不可再取消匹配!vsRoomID=%s" % vsRoomID)
+            return
+        
+    GameWorld.Log("玩家取消匹配: reason=%s,accID=%s,playerID=%s,vsRoomID=%s" % (reason, accID, playerID, vsRoomID))
+    
+    pkZoneID = 0
+    if playerID in PyGameData.g_crossPKPlayerDict:
+        pkPlayer = PyGameData.g_crossPKPlayerDict.pop(playerID)
+        pkZoneID = pkPlayer.pkZoneID
+        GameWorld.Log("    移除PK玩家: pkZoneID=%s,accID=%s,playerID=%s" % (pkZoneID, accID, playerID))
+        
+    zoneMatchPlayerList = PyGameData.g_crossPKZoneMatchPlayerDict.get(pkZoneID, [])
+    if playerID in zoneMatchPlayerList:
+        zoneMatchPlayerList.remove(playerID)
+        GameWorld.Log("    从匹配队列中删除,匹配队列剩余人数=%s" % (len(zoneMatchPlayerList)))
+        
+    #取消所有存在该玩家的房间,子服不一定知道玩家当前最新所属房间ID, 故只能通过遍历删除已经为玩家创建的房间
+    for roomID, pkRoom in PyGameData.g_crossPKRoomDict.items():
+        if playerID not in pkRoom.roomPlayerIDList:
+            continue
+        
+        for roomPlayerID in pkRoom.roomPlayerIDList:
+            if roomPlayerID == playerID:
+                GameWorld.Log("    自己不处理: roomID=%s,playerID=%s" % (roomID, playerID))
+                continue
+            
+            zoneMatchPlayerList = PyGameData.g_crossPKZoneMatchPlayerDict.get(pkZoneID, [])
+            zoneMatchPlayerList.append(roomPlayerID)
+            PyGameData.g_crossPKZoneMatchPlayerDict[pkZoneID] = zoneMatchPlayerList
+            GameWorld.Log("    将之前匹配的对手重新加入匹配队列: roomID=%s,roomPlayerID=%s,当前匹配人数=%s" 
+                          % (roomID, roomPlayerID, len(zoneMatchPlayerList)))
+            
+        PyGameData.g_crossPKRoomDict.pop(roomID)
+        GameWorld.Log("    移除房间: popRoomID=%s" % (roomID))
+        break
+    
+    return
+
+def ClientServerMsg_PKPrepareOK(playerInfoDict, tick):
+    ## 玩家跨服对战数据准备OK
+    
+    if not GameWorld.IsMergeServer():
+        GameWorld.ErrLog("非跨服服务器不处理取消跨服PK匹配!")
+        return
+    
+    accID = playerInfoDict["accID"] # 玩家账号
+    playerID = playerInfoDict["playerID"] # 玩家ID
+    vsRoomID = playerInfoDict["vsRoomID"] # 所属对战房间ID
+    if playerID not in PyGameData.g_crossPKPlayerDict:
+        GameWorld.ErrLog("玩家跨服对战数据准备OK, 但找不到该对战玩家信息!vsRoomID=%s,playerID=%s" % (vsRoomID, playerID))
+        return
+    #pkPlayer = PyGameData.g_crossPKPlayerDict[playerID]
+        
+    if vsRoomID not in PyGameData.g_crossPKRoomDict:
+        GameWorld.ErrLog("玩家跨服对战数据准备OK, 但找不到该对战房间(%s)!可能对手已取消!" % vsRoomID)
+        return
+    vsRoom = PyGameData.g_crossPKRoomDict[vsRoomID]
+    
+    if vsRoom.roomState != ShareDefine.Def_VsRoom_State_WaitPlayer:
+        GameWorld.ErrLog("玩家跨服对战数据准备OK, 但房间状态非等待状态, state=%s!" % vsRoom.roomState)
+        return
+    
+    if playerID not in vsRoom.readyPlayerIDList:
+        vsRoom.readyPlayerIDList.append(playerID)
+        
+    GameWorld.Log("玩家跨服PK准备完毕: accID=%s,playerID=%s,vsRoomID=%s" % (accID, playerID, vsRoomID))
+    return
+
+def __ReadyOKRoomPlayerProcess(tick):
+    ## 玩家跨服PK已准备好的房间处理
+    
+    #GameWorld.Log("===已准备好的对战房间处理===")
+    serverGroupIDList = []
+    sendReadyOKRoomList = []
+    for roomID, vsRoom in PyGameData.g_crossPKRoomDict.items():
+        
+        # 非等待状态的房间不处理
+        if vsRoom.roomState != ShareDefine.Def_VsRoom_State_WaitPlayer:
+            continue
+        
+        if not vsRoom.roomPlayerIDList:
+            continue
+        
+        pkZoneID = 0
+        isAllReady = True
+        roomGroupIDList = []
+        readyMemberDict = {} # 已准备好的玩家信息
+        for roomPlayerID in vsRoom.roomPlayerIDList:
+            if roomPlayerID not in vsRoom.readyPlayerIDList or roomPlayerID not in PyGameData.g_crossPKPlayerDict:
+                isAllReady = False
+                break
+            roomPlayer = PyGameData.g_crossPKPlayerDict[roomPlayerID]
+            pkZoneID = roomPlayer.pkZoneID
+            roomGroupIDList.append(roomPlayer.serverGroupID)
+            readyMemberDict[roomPlayerID] = {"ServerGroupID":roomPlayer.serverGroupID, "Name":roomPlayer.playerName, 
+                                             "Job":roomPlayer.playerJob, "LV":roomPlayer.playerLV, "MaxHP":roomPlayer.maxHP}
+                    
+        if not isAllReady:
+            continue
+        vsRoom.roomState = ShareDefine.Def_VsRoom_State_PrepareFight
+        vsRoom.readyTick = tick
+        GameWorld.Log("    准备好的房间: pkZoneID=%s,roomID=%s,mapID=%s,readyMemberDict=%s" % (pkZoneID, roomID, vsRoom.mapID, str(readyMemberDict)))
+        
+        sendReadyOKRoomList.append([roomID, readyMemberDict])
+        serverGroupIDList += roomGroupIDList
+        
+    # 将已准备好的房间广播到子服
+    if sendReadyOKRoomList:
+        GameWorld.Log("    已准备好的对战房间数: %s" % len(sendReadyOKRoomList))
+        CrossRealmMsg.SendMsgToClientServer(ShareDefine.CrossServerMsg_PKReadyOKRoomList, sendReadyOKRoomList, serverGroupIDList)
+        
+    return
+
+def OnPKMatchProcess(tick):
+    ## 玩家跨服PK匹配定时处理逻辑
+    
+    # 非跨服服务器不处理跨服PK匹配逻辑
+    if not GameWorld.IsMergeServer():
+        return
+    
+    if not IsCrossRealmPKOpen():
+        return
+    
+    # 同步子服排行榜
+    #__SyncBillboardToClientServer(False, tick)
+    
+    processTick = IpyGameDataPY.GetFuncCfg("CrossRealmPKMatch", 1)
+    processTickKey = "PKMatchLastTick"
+    lastProcessTick = GameWorld.GetGameWorld().GetDictByKey(processTickKey)
+    if tick - lastProcessTick < processTick:
+        return
+    GameWorld.GetGameWorld().SetDict(processTickKey, tick)
+    
+    # 处理超时的房间
+    __DoCheckRoomTimeout(tick)
+    # 通知已准备好的房间玩家可进入跨服
+    __ReadyOKRoomPlayerProcess(tick)
+    
+    maxGroupCnt = IpyGameDataPY.GetFuncCfg("CrossRealmPKMatch", 2)
+    outTimeTick = IpyGameDataPY.GetFuncCfg("CrossRealmPKMatch", 3)
+    
+    # 每个赛区单独匹配
+    for pkZoneID, matchPlayerIDList in PyGameData.g_crossPKZoneMatchPlayerDict.items():
+        matchPlayerCount = len(matchPlayerIDList)
+        if matchPlayerCount < 2:
+            #GameWorld.Log("匹配PK人数不足,不处理!pkZoneID=%s, 总人数:%s" % (pkZoneID, matchPlayerCount))
+            continue
+        
+        GameWorld.Log("★★★★★★★★★★开始跨服PK匹配(pkZoneID=%s, 总人数:%s)★★★★★★★★★★" % (pkZoneID, matchPlayerCount))
+        
+        matchPlayerList = []
+        for matchPlayerID in matchPlayerIDList:
+            if matchPlayerID not in PyGameData.g_crossPKPlayerDict:
+                continue
+            matchPlayerList.append(PyGameData.g_crossPKPlayerDict[matchPlayerID])
+        # 按匹配时间、积分升序排序
+        matchTickSortList = sorted(matchPlayerList, key=operator.attrgetter("matchTick"))
+        scoreSortList = sorted(matchPlayerList, key=operator.attrgetter("pkScore"))
+        
+        matchPlayerVSList = [] # 成功匹配玩家对战列表
+        
+        # 优先匹配等待超时玩家
+        __DoMatch_OutTimePlayer(matchTickSortList, scoreSortList, outTimeTick, matchPlayerVSList, tick)
+        
+        if len(matchPlayerVSList) < maxGroupCnt:
+            # 再按积分段匹配玩家
+            __DoMatch_DanScorePlayer(scoreSortList, maxGroupCnt, matchPlayerVSList)
+            
+        # 给成功匹配的玩家非配对战房间
+        matchPlayerVSList = matchPlayerVSList[:maxGroupCnt]
+        __DoSetVSRoom(pkZoneID, matchPlayerVSList, tick)
+        GameWorld.Log("==========匹配结束(总匹配队伍:%s)==========" % len(matchPlayerVSList))
+    return
+
+
+def __DoMatch_OutTimePlayer(matchTickSortList, scoreSortList, outTimeTick, matchPlayerVSList, tick):
+    '''匹配超时玩家
+        匹配中的玩家按积分排序,最后一个默认匹配上一个,第一个默认匹配下一个,其他匹配前后积分差绝对值较小的一个
+    '''
+    GameWorld.Log(" ==优先匹配超时等待玩家==最大等待时间:%s, tick=%s" % (outTimeTick, tick))
+    GameWorld.Log(" scoreSortListLen=%s" % len(scoreSortList))
+    for i, matchPlayer in enumerate(matchTickSortList):        
+        # 只有一个玩家
+        if len(scoreSortList) <= 1:
+            GameWorld.Log("    当前玩家数%s<=1,不再匹配!" % len(scoreSortList))
+            break
+        
+        if tick - matchPlayer.matchTick < outTimeTick:
+            GameWorld.Log("    i=%s,玩家未超时,不再匹配!" % (i))
+            break
+        
+        GameWorld.Log("    i=%s,超时玩家, %s-%s=%s >= outTimeTick(%s)" 
+                      % (i, tick, matchPlayer.matchTick, tick - matchPlayer.matchTick, outTimeTick))
+        # 已经被匹配走了
+        if matchPlayer not in scoreSortList:
+            GameWorld.Log("        已经被匹配走了!")
+            continue
+        
+        outTimeIndex = scoreSortList.index(matchPlayer)
+        # 最后一个默认匹配上一个
+        if outTimeIndex == len(scoreSortList) - 1: 
+            vsIndex = outTimeIndex - 1
+            GameWorld.Log("        超时玩家积分排序索引%s,最后一个,默认匹配上一个索引%s!" % (outTimeIndex, vsIndex))
+        # 第一个默认匹配下一个
+        elif outTimeIndex == 0:
+            vsIndex = outTimeIndex + 1
+            GameWorld.Log("        超时玩家积分排序索引%s,第一个,默认匹配下一个索引%s!" % (outTimeIndex, vsIndex))
+        # 其他情况匹配积分较近的一个
+        else:
+            preIndex = outTimeIndex - 1
+            nextIndex = outTimeIndex + 1
+            prePlayer = scoreSortList[preIndex]
+            nextPlayer = scoreSortList[nextIndex]
+            preDiff = abs(prePlayer.pkScore - matchPlayer.pkScore)
+            nextDiff = abs(matchPlayer.pkScore - nextPlayer.pkScore)
+            vsIndex = preIndex if preDiff <= nextDiff else nextIndex
+            GameWorld.Log("        超时玩家积分排序索引-积分(%s-%s),上一个(%s-%s),下一个(%s-%s),preDiff=%s,nextDiff=%s,vsIndex=%s" 
+                          % (outTimeIndex, matchPlayer.pkScore, preIndex, prePlayer.pkScore,
+                             nextIndex, nextPlayer.pkScore, preDiff, nextDiff, vsIndex))
+            
+        if outTimeIndex > vsIndex: 
+            scoreSortList.pop(outTimeIndex)
+            vsPlayer = scoreSortList.pop(vsIndex)
+        elif outTimeIndex < vsIndex:
+            vsPlayer = scoreSortList.pop(vsIndex)
+            scoreSortList.pop(outTimeIndex)
+        else:
+            continue
+        
+        # 加入成功匹配列表
+        matchPlayerVSList.append([matchPlayer, vsPlayer])
+        
+    return
+
+def __DoMatch_DanScorePlayer(scoreSortList, maxGroupCnt, matchPlayerVSList):
+    ''' 匹配积分分段玩家
+            匹配中的玩家按段位积分归组,归组后,随机段位顺序,每个段位组中的玩家随机两两PK
+    '''
+    GameWorld.Log(" ==匹配积分分段玩家== maxGroupCnt=%s,scoreSortListLen=%s" % (maxGroupCnt, len(scoreSortList)))
+    danPlayerListDict = {} # 按积分分段列表分散玩家
+    for matchPlayer in scoreSortList:
+        danLV = matchPlayer.danLV
+        danPlayerList = danPlayerListDict.get(danLV, [])
+        danPlayerList.append(matchPlayer)
+        danPlayerListDict[danLV] = danPlayerList
+        
+    # 按分段玩家随机匹配
+    danList = danPlayerListDict.keys()
+    random.shuffle(danList) # 打乱段位顺序
+    
+    GameWorld.Log("    积分分段个数: %s, %s" % (len(danList), danList))
+    
+    # 日志输出分组明细
+    for danLV in danList:
+        strList = []
+        for player in danPlayerListDict[danLV]:
+            strList.append((player.playerID, player.pkScore, player.fightPower))
+        GameWorld.Log("        积分段组, danLV=%s, %s" % (danLV, str(strList)))
+        
+    doCount = 0
+    while len(matchPlayerVSList) < maxGroupCnt and doCount < maxGroupCnt:
+        doCount += 1
+        isMatchOK = False
+        for danLV in danList:
+            danPlayerList = danPlayerListDict[danLV]
+            danPlayerCount = len(danPlayerList)
+            if danPlayerCount < 2:
+                GameWorld.Log("    段位人数少于2个,此段位本轮轮空!doCount=%s,danLV=%s" % (doCount, danLV))
+                continue
+            
+            vsIndexList = random.sample(xrange(danPlayerCount), 2) # 随机取两个索引对战
+            vsIndexList.sort()
+            aPlayer = danPlayerList.pop(vsIndexList[1])
+            bPlayer = danPlayerList.pop(vsIndexList[0])
+            
+            matchPlayerVSList.append([aPlayer, bPlayer])
+            isMatchOK = True
+            GameWorld.Log("    成功匹配玩家: aPlayerID=%s,aScore=%s,aFP=%s VS bPlayerID=%s,bScore=%s,bFP=%s" 
+                          % (aPlayer.playerID, aPlayer.pkScore, aPlayer.fightPower, bPlayer.playerID, bPlayer.pkScore, bPlayer.fightPower))
+            
+            if len(matchPlayerVSList) >= maxGroupCnt:
+                GameWorld.Log("    已经达到最大匹配数! 已匹配对战数=%s, 不再匹配!doCount=%s" % (len(matchPlayerVSList), doCount))
+                break
+            
+        if not isMatchOK:
+            GameWorld.Log("    已经没有满足匹配条件的玩家! 不再匹配!doCount=%s" % (doCount))
+            break
+        
+    return
+
+def __DoSetVSRoom(pkZoneID, matchPlayerVSList, tick):
+    ## 设置对战房间
+    
+    if not matchPlayerVSList:
+        return
+    
+    vsRoomDict = {}
+    serverGroupIDList = []
+    zoneMatchPlayerList = PyGameData.g_crossPKZoneMatchPlayerDict.get(pkZoneID, [])
+    
+    mapIDList = IpyGameDataPY.GetFuncCfg("CrossRealmPKMatch", 4)
+    GameWorld.Log("===给配对的玩家开房间(pkZoneID=%s,配对数:%s)===" % (pkZoneID, len(matchPlayerVSList)))
+    for aPlayer, bPlayer in matchPlayerVSList:
+        
+        if not aPlayer or not bPlayer:
+            continue
+        
+        aPlayerID = aPlayer.playerID
+        bPlayerID = bPlayer.playerID
+        if aPlayerID not in PyGameData.g_crossPKPlayerDict or bPlayerID not in PyGameData.g_crossPKPlayerDict:
+            GameWorld.ErrLog("玩家匹配数据异常!aPlayerID=%s,bPlayerID=%s" % (aPlayerID, bPlayerID))
+            continue
+        
+        roomID = __GetNewRoomID()
+        if not roomID:
+            GameWorld.ErrLog("无法创建房间!该房间已经存在!PyGameData.g_crossPKRoomID=%s" % PyGameData.g_crossPKRoomID)
+            continue
+        mapID = random.choice(mapIDList)
+        
+        newRoom = CrossPKRoom()
+        newRoom.pkZoneID = pkZoneID
+        newRoom.roomID = roomID
+        newRoom.mapID = mapID
+        newRoom.openTick = tick
+        newRoom.roomPlayerIDList = [aPlayerID, bPlayerID]
+        PyGameData.g_crossPKRoomDict[roomID] = newRoom
+        
+        aServerGroupID, bServerGroupID = aPlayer.serverGroupID, bPlayer.serverGroupID
+        GameWorld.Log("    开房:pkZoneID=%s,mapID=%s,roomID=%s,aPlayerID=%s,bPlayerID=%s" % (pkZoneID, mapID, roomID, aPlayerID, bPlayerID))
+        vsRoomDict[roomID] = [mapID, [[aServerGroupID, aPlayerID], [bServerGroupID, bPlayerID]]]
+        
+        serverGroupIDList.append(aServerGroupID)
+        serverGroupIDList.append(bServerGroupID)
+        
+        # 移除匹配队列
+        if aPlayerID in zoneMatchPlayerList:
+            zoneMatchPlayerList.remove(aPlayerID)
+        if bPlayerID in zoneMatchPlayerList:
+            zoneMatchPlayerList.remove(bPlayerID)
+        PyGameData.g_crossPKZoneMatchPlayerDict[pkZoneID] = zoneMatchPlayerList
+        
+    # 将匹配结果广播到子服
+    if vsRoomDict:
+        CrossRealmMsg.SendMsgToClientServer(ShareDefine.CrossServerMsg_PKMatchResult, vsRoomDict, serverGroupIDList)
+        
+    return
+
+def __GetNewRoomID():
+    ## 获取新房间ID, 房间号直接自增,一定不会重复,除非自增一轮后房间ID还没有释放
+    for _ in xrange(100):
+        newRoomID = PyGameData.g_crossPKRoomID + 1
+        if newRoomID > 65530:
+            newRoomID = 1
+        PyGameData.g_crossPKRoomID = newRoomID
+        if newRoomID not in PyGameData.g_crossPKRoomDict:
+            return newRoomID
+    return 0
+
+def __DoCheckRoomTimeout(tick):
+    ## 处理超时的房间
+    
+    timeoutRoomDict = {}
+    serverGroupIDList = []
+    #roomTimeout = IpyGameDataPY.GetFuncCfg("CheckRoomTimeout", 1) * 1000 # 这个时间尽量长点,目前暂时不确定玩家从准备好到进入到地图的时长
+    roomTimeout = 180 * 1000 # 这个时间尽量长点,目前暂时不确定玩家从准备到进入到地图的时长
+    for roomID, pkRoom in PyGameData.g_crossPKRoomDict.items():
+        if pkRoom.isMapOpen or not pkRoom.readyTick:
+            continue
+        if tick - pkRoom.readyTick <= roomTimeout:
+            continue
+        pkZoneID = pkRoom.pkZoneID
+        GameWorld.Log("PK房间等待玩家进来超时,没有玩家进来,关闭该房间!pkZoneID=%s,roomID=%s,openTick=%s,readyTick=%s,tick=%s" 
+                      % (pkZoneID, roomID, pkRoom.openTick, pkRoom.readyTick, tick))
+        roomPlayerInfo = []
+        for roomPlayerID in pkRoom.roomPlayerIDList:
+            pkPlayer = PyGameData.g_crossPKPlayerDict.pop(roomPlayerID, None)
+            if not pkPlayer:
+                continue
+            serverGroupID = pkPlayer.serverGroupID
+            GameWorld.Log("    移除玩家,玩家需重新手动匹配,serverGroupID=%s,roomPlayerID=%s" % (serverGroupID, roomPlayerID))
+            serverGroupIDList.append(serverGroupID)
+            roomPlayerInfo.append([serverGroupID, roomPlayerID])
+        timeoutRoomDict[roomID] = roomPlayerInfo
+        PyGameData.g_crossPKRoomDict.pop(roomID)
+        
+    # 将超时房间广播到子服
+    if timeoutRoomDict:
+        CrossRealmMsg.SendMsgToClientServer(ShareDefine.CrossServerMsg_PKTimeoutRoomList, timeoutRoomDict, serverGroupIDList)
+    return
+
+def MapServer_CrossPKRoomOpen(msgList):
+    roomID = msgList[0]
+    if roomID not in PyGameData.g_crossPKRoomDict:
+        GameWorld.ErrLog("MapServer_CrossPKRoomOpen => PK房间不存在!roomID=%s" % roomID)
+        return
+    pkRoom = PyGameData.g_crossPKRoomDict[roomID]
+    pkRoom.isMapOpen = True
+    GameWorld.Log("MapServer_CrossPKRoomOpen => roomID=%s" % roomID)
+    return
+
+def MapServer_MergePKOver(infoList):
+    ## 收到MapServer副本跨服PK结果同步
+    
+    GameWorld.Log("收到MapServer_跨服PK战斗结果: %s" % str(infoList))
+    
+    roomID, winnerID, loserID, roundWinnerIDList, overType = infoList
+    
+    if roomID not in PyGameData.g_crossPKRoomDict:
+        GameWorld.ErrLog("跨服PK房间数据不存在!roomID=%s" % roomID)
+        return
+    vsRoom = PyGameData.g_crossPKRoomDict.pop(roomID)
+    #vsRoom = PyGameData.g_crossPKRoomDict[roomID]
+    roomPlayerIDList = vsRoom.roomPlayerIDList
+    if not winnerID and not loserID:
+        GameWorld.ErrLog("地图没有结算跨服PK胜负玩家,随机玩家获胜!")
+        if not roomPlayerIDList or len(roomPlayerIDList) != 2:
+            return
+        winnerID, loserID = roomPlayerIDList
+    elif not loserID:
+        for roomPlayerID in roomPlayerIDList:
+            if roomPlayerID != winnerID:
+                loserID = roomPlayerID
+                break
+            
+    if winnerID not in roomPlayerIDList or loserID not in roomPlayerIDList:
+        GameWorld.ErrLog("跨服PK房间及玩家不匹配,不结算!roomID=%s,winnerID=%s,loserID=%s,roomPlayerIDList=%s" 
+                         % (roomID, winnerID, loserID, vsRoom.roomPlayerIDList))
+        return
+    
+    if winnerID not in PyGameData.g_crossPKPlayerDict:
+        GameWorld.ErrLog("跨服PK房间获取不到玩家PK数据, roomID=%s,winnerID=%s" % (roomID, winnerID))
+        return
+    if loserID not in PyGameData.g_crossPKPlayerDict:
+        GameWorld.ErrLog("跨服PK房间获取不到玩家PK数据, roomID=%s,loserID=%s" % (roomID, loserID))
+        return
+    
+    winner = PyGameData.g_crossPKPlayerDict.pop(winnerID)
+    loser = PyGameData.g_crossPKPlayerDict.pop(loserID)
+    #winner = PyGameData.g_crossPKPlayerDict[winnerID]
+    #loser = PyGameData.g_crossPKPlayerDict[loserID]
+    seasonID = winner.seasonID
+    
+    cWinCount = winner.cWinCount
+    winnerScore, loserScore = winner.pkScore, loser.pkScore
+    winnerDanLV, loserDanLV = winner.danLV, loser.danLV
+    winnerDayScore, loserDayScore = max(0, winnerScore - winner.ondayScore), max(0, loserScore - loser.ondayScore) # 今日已获得积分,正积分
+    
+    GameWorld.Log("winnerDayScore=%s,winnerScore=%s,winnerDanLV=%s,cWinCount=%s" % (winnerDayScore, winnerScore, winnerDanLV, cWinCount))
+    GameWorld.Log("loserDayScore=%s,loserScore=%s,loserDanLV=%s" % (loserDayScore, loserScore, loserDanLV))
+    
+    winIpyData = IpyGameDataPY.GetIpyGameData("CrossRealmPKDan", winnerDanLV)
+    loseIpyData = IpyGameDataPY.GetIpyGameData("CrossRealmPKDan", loserDanLV)
+    if not winIpyData or not loseIpyData:
+        GameWorld.ErrLog("跨服PK房间段位数据异常! roomID=%s,winnerDanLV=%s,loserDanLV=%s" % (roomID, winnerDanLV, loserDanLV))
+        
+    baseScoreList = IpyGameDataPY.GetFuncEvalCfg("CrossRealmPKScore", 2) # 胜负保底分
+    wBaseScore = baseScoreList[0] if len(baseScoreList) > 0 else 0
+    lBaseScore = baseScoreList[1] if len(baseScoreList) > 1 else 0
+    wExScore = eval(IpyGameDataPY.GetFuncCompileCfg("CrossRealmPKScore", 3)) # 胜方附加分
+    lExScore = 0
+    
+    winnerAddScore = wBaseScore + wExScore
+    loserAddScore = lBaseScore + lExScore
+    
+    dayMaxScore = IpyGameDataPY.GetFuncCfg("CrossRealmPKScore", 1) # 每日获得积分上限,0为不限制
+    if dayMaxScore:
+        if winnerAddScore > 0:
+            winnerAddScore = min(dayMaxScore - winnerDayScore, winnerAddScore)
+        if loserAddScore > 0:
+            loserAddScore = min(dayMaxScore - loserDayScore, loserAddScore)
+    
+    winner.pkScore += winnerAddScore
+    loser.pkScore += loserAddScore
+    
+    winner.cWinCount += 1
+    loser.cWinCount = 0
+    
+    if winIpyData and winIpyData.GetLVUpScore() and winner.pkScore >= winIpyData.GetLVUpScore():
+        winner.danLV += 1
+            
+    if loseIpyData and loseIpyData.GetLVUpScore() and loser.pkScore >= loseIpyData.GetLVUpScore():
+        loser.danLV += 1
+        
+    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))
+    
+    timeStr = GameWorld.GetCurrentDataTimeStr()
+    playerOverDict = {}
+    # 通知客户端战斗结果
+    for playerID in [winnerID, loserID]:
+        if playerID == winnerID:
+            serverGroupID, pkScore, danLV, cWinCount, addScore, tagPlayerID, tagPlayerName = \
+                winner.serverGroupID, winner.pkScore, winner.danLV, winner.cWinCount, winnerAddScore, loser.playerID, loser.playerName
+        else:
+            serverGroupID, pkScore, danLV, cWinCount, addScore, tagPlayerID, tagPlayerName = \
+                loser.serverGroupID, loser.pkScore, loser.danLV, loser.cWinCount, loserAddScore, winner.playerID, winner.playerName
+                
+        player = GameWorld.GetPlayerManager().FindPlayerByID(playerID)
+        notifyState = True if player else False
+        
+        playerOverDict[playerID] = [roomID, seasonID, timeStr, overType, winnerID, roundWinnerIDList] \
+                                    + [serverGroupID, pkScore, danLV, cWinCount, addScore, tagPlayerID, tagPlayerName, notifyState]
+        if not player:
+            continue
+        
+        overPack = ChPyNetSendPack.tagGCCrossRealmPKOverInfo()
+        overPack.TimeStr = timeStr
+        overPack.OverType = overType
+        overPack.WinnerID = winnerID
+        overPack.RoundWinnerID = roundWinnerIDList
+        overPack.RoundCount = len(overPack.RoundWinnerID)
+        overPack.AddScore = addScore
+        overPack.Score = pkScore
+        overPack.DanLV = danLV
+        overPack.CWinCnt = cWinCount
+        overPack.TagName = tagPlayerName
+        overPack.TagNameLen = len(overPack.TagName)
+        NetPackCommon.SendFakePack(player, overPack)
+        
+        GameWorld.Log("同步玩家PK结果: serverGroupID=%s,roomID=%s,addScore=%s,pkScore=%s,danLV=%s,cWinCount=%s,tagPlayerID=%s" 
+                      % (serverGroupID, roomID, addScore, pkScore, danLV, cWinCount, tagPlayerID), playerID)
+        
+    serverGroupIDList = [winner.serverGroupID, loser.serverGroupID]
+    GameWorld.Log("同步子服战斗结果: seasonID=%s,timeStr=%s,roomID=%s,overType=%s,winnerID=%s,roundWinnerIDList=%s" 
+                  % (seasonID, timeStr, roomID, overType, winnerID, roundWinnerIDList))
+    # 同步子服
+    CrossRealmMsg.SendMsgToClientServer(ShareDefine.CrossServerMsg_PKOverInfo, playerOverDict, serverGroupIDList)
+    return
+
+##================================== 以下是子服逻辑 ==========================================
+
+def CrossServerMsg_PKMatchReqRet(retInfo):
+    ## 跨服PK匹配请求结果
+    playerID, result = retInfo
+    curPlayer = GameWorld.GetPlayerManager().FindPlayerByID(playerID)
+    if not curPlayer:
+        return
+    
+    if result == -2:
+        PlayerControl.NotifyCode(curPlayer, "InCrossPKing")
+        return
+    
+    if result == 1:
+        NetPackCommon.SendFakePack(curPlayer, ChPyNetSendPack.tagGCCrossRealmPKStartMatch())
+        
+    return
+
+def CrossServerMsg_PKMatchResult(vsRoomDict):
+    ## 跨服PK匹配结果
+    curServerGroupID = GameWorld.GetServerGroupID()
+    actionType = ShareDefine.Def_MergeAction_MergePK
+    mapPosList = IpyGameDataPY.GetFuncEvalCfg("CrossRealmPKMatch", 5)
+    GameWorld.Log("=== 收到PK匹配结果处理  === curServerGroupID=%s" % curServerGroupID)
+    if not mapPosList:
+        GameWorld.ErrLog("没有配置对战地图进入坐标!")
+        return
+    
+    for roomID, roomInfo in vsRoomDict.items():
+        mapID, playerList = roomInfo
+        GameWorld.Log("    roomID=%s,playerList=%s" % (roomID, playerList))
+        for i, playerInfo in enumerate(playerList):
+            serverGroupID, playerID = playerInfo
+            if serverGroupID != curServerGroupID:
+                GameWorld.DebugLog("        不是本服玩家,不处理!playerID=%s,serverGroupID=%s" % (playerID, serverGroupID))
+                continue
+            player = GameWorld.GetPlayerManager().FindPlayerByID(playerID)
+            if not player:
+                GameWorld.DebugLog("        玩家不在线, playerID=%s" % (playerID))
+                continue
+            if PlayerControl.GetIsTJG(player):
+                GameWorld.DebugLog("        玩家脱机中, playerID=%s" % (playerID))
+                continue
+            PlayerControl.SetVsRoomId(player, roomID, True)
+            # 通知地图玩家匹配成功, 上传数据, 准备进入跨服服务器
+            posX, posY = mapPosList[i] if len(mapPosList) > i else mapPosList[0]
+            CrossRealmPlayer.SendCrossRealmReg(player, actionType, mapID, mapID, 0, posX, posY)
+            
+    return
+
+def CrossServerMsg_PKReadyOKRoomList(readyOKRoomList):
+    ## 子服接收玩家已准备好的PK房间信息, 此房间里的玩家可传送进入跨服
+    
+    curServerGroupID = GameWorld.GetServerGroupID()
+    GameWorld.Log("===收到跨服服务器通知已准备好的对战PK房间信息处理=== curServerGroupID=%s" % curServerGroupID)
+    # serverGroupID, playerName, playerJob
+    
+    for roomID, readyMemberDict in readyOKRoomList:
+        for playerID, playerInfo in readyMemberDict.items():
+            serverGroupID = playerInfo["ServerGroupID"]
+            playerName = playerInfo["Name"]
+            
+            if serverGroupID != curServerGroupID:
+                GameWorld.DebugLog("    不是本服玩家,不处理!playerID=%s,serverGroupID=%s" % (playerID, serverGroupID))
+                continue
+            
+            player = GameWorld.GetPlayerManager().FindPlayerByID(playerID)
+            if not player:
+                GameWorld.DebugLog("    玩家不在线 , playerID=%s" % (playerID))
+                continue
+            if PlayerControl.GetIsTJG(player):
+                GameWorld.DebugLog("    玩家脱机中, playerID=%s" % (playerID))
+                continue
+            player.SetDict(ChConfig.Def_PlayerKey_IsLoginToMergeServer, 1)
+            
+            matchPlayer = ChPyNetSendPack.tagGCCrossRealmPKMatchPlayer()
+            for readyPlayerID, readyPlayerInfo in readyMemberDict.items():
+                if readyPlayerID != playerID:
+                    matchPlayer.PlayerID = readyPlayerID
+                    matchPlayer.PlayerName = readyPlayerInfo["Name"]
+                    matchPlayer.NameLen = len(matchPlayer.PlayerName)
+                    matchPlayer.Job = readyPlayerInfo["Job"]
+                    matchPlayer.LV = readyPlayerInfo["LV"]
+                    matchPlayer.MaxHP = readyPlayerInfo["MaxHP"]
+                    break
+                
+            PlayerControl.SetCrossRealmState(player, 1)
+            
+            # 通知匹配成功,可进入跨服
+            matchOKPack = ChPyNetSendPack.tagGCCrossRealmPKMatchOK()
+            matchOKPack.RoomID = roomID
+            matchOKPack.PlayerName = playerName
+            matchOKPack.NameLen = len(matchOKPack.PlayerName)
+            matchOKPack.MatchPlayer = [matchPlayer]
+            matchOKPack.MatchPlayerCount = len(matchOKPack.MatchPlayer)
+            NetPackCommon.SendFakePack(player, matchOKPack)
+            GameWorld.Log("    通知玩家进入跨服PK对战房间! roomID=%s,playerID=%s,matchPlayerID=%s" % (roomID, playerID, matchPlayer.PlayerID))
+            
+            # 到这里默认认为一定会有结果的,所以本服直接增加次数
+            #player.MapServer_QueryPlayerResult(0, 0, 'MergePKAddCnt', "", 0)
+    return
+
+def CrossServerMsg_PKTimeoutRoomList(timeoutRoomDict):
+    ## 子服接收已超时的PK房间信息, 此房间里的玩家重置跨服状态
+    
+    curServerGroupID = GameWorld.GetServerGroupID()
+    GameWorld.Log("===收到跨服服务器通知已超时的对战PK房间信息处理=== curServerGroupID=%s" % curServerGroupID)
+    
+    for roomID, roomPlayerInfo in timeoutRoomDict.items():
+        if not roomPlayerInfo:
+            continue
+        serverGroupID, playerID = roomPlayerInfo
+        
+        if serverGroupID != curServerGroupID:
+            GameWorld.DebugLog("    不是本服玩家,不处理!playerID=%s,serverGroupID=%s" % (playerID, serverGroupID))
+            continue
+        
+        player = GameWorld.GetPlayerManager().FindPlayerByID(playerID)
+        if not player:
+            GameWorld.DebugLog("    玩家不在线 , playerID=%s" % (playerID))
+            continue
+        if PlayerControl.GetIsTJG(player):
+            GameWorld.DebugLog("    玩家脱机中, playerID=%s" % (playerID))
+            continue
+        playerVSRoomID = player.GetVsRoomId()
+        if playerVSRoomID and playerVSRoomID != roomID:
+            GameWorld.DebugLog("    房间ID不同, playerID=%s" % (playerID))
+            continue
+        player.SetDict(ChConfig.Def_PlayerKey_IsLoginToMergeServer, 0)
+        PlayerControl.SetCrossRealmState(player, 0)
+        
+    return
+
+def CrossServerMsg_PKOverInfo(playerOverDict):
+    ## 子服接收跨服PK结果信息
+    
+    curServerGroupID = GameWorld.GetServerGroupID()
+    GameWorld.Log("===收到跨服服务器同步的跨服PK结果=== curServerGroupID=%s" % curServerGroupID)
+    
+    for playerID, overInfo in playerOverDict.items():
+        roomID, 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]
+        player = GameWorld.GetPlayerManager().FindPlayerByID(playerID)
+        if not player or PlayerControl.GetIsTJG(player):
+            GameWorld.Log("    玩家不在线 或脱机中,先缓存,玩家上线后再同步,playerID=%s" % (playerID))
+            PyGameData.g_crossPKUnNotifyOverInfo[playerID] = sendMapOverInfo
+            continue
+        
+        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)
+    return
+
+def __OnLoginNotifyPKOverInfo(curPlayer):
+    playerID = curPlayer.GetPlayerID()
+    if playerID not in PyGameData.g_crossPKUnNotifyOverInfo:
+        return
+    overInfo = PyGameData.g_crossPKUnNotifyOverInfo.pop(playerID)
+    PlayerControl.SetCrossRealmState(curPlayer, 0)
+    sysMsg = str(overInfo)
+    curPlayer.MapServer_QueryPlayerResult(0, 0, "CrossPKOverInfo", sysMsg, len(sysMsg))
+    GameWorld.Log("玩家上线通知地图未结算的跨服PK结算: mapID=%s,overInfo=%s" % (curPlayer.GetMapID(), overInfo), playerID)
+    return
+
+
diff --git a/ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/GameWorldMergeKing.py b/ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/GameWorldMergeKing.py
index 00f9a11..7a13142 100644
--- a/ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/GameWorldMergeKing.py
+++ b/ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/GameWorldMergeKing.py
@@ -14,7 +14,7 @@
 # 详细描述: 王者争霸(跨服PK赛周积分排名前32可获得争霸资格)
 #
 #---------------------------------------------------------------------
-"""Version = 2015-11-19 14:00"""
+#"""Version = 2015-11-19 14:00"""
 #---------------------------------------------------------------------
 import ReadChConfig
 import PlayerControl
@@ -23,6 +23,7 @@
 import PlayerCompensation
 import PlayerUniversalGameRec
 import PlayerMergeRegister
+import CrossRealmPlayer
 import GameWorldMergePK
 import PlayerDBGSEvent
 import MergeBroadcast
@@ -644,7 +645,7 @@
         lastNotifyTime = gameWorld.GetDictByKey(notifyTimeKey)
         if tick - lastNotifyTime >= notifyCD * 1000:
             mark = loginNotifyDict[playerRecRank]
-            mergeName = PlayerControl.GetMergePlayerName(accID, curPlayer.GetName())
+            mergeName = CrossRealmPlayer.GetCrossPlayerName(curPlayer)
             PlayerControl.MergeWorldNotify(0, mark, [mergeName])
             gameWorld.SetDict(notifyTimeKey, tick)
         else:
diff --git a/ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/GameWorldProcess.py b/ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/GameWorldProcess.py
index 52c8054..4e9df57 100644
--- a/ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/GameWorldProcess.py
+++ b/ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/GameWorldProcess.py
@@ -86,7 +86,6 @@
 #import MergeBroadcast
 #import GameWorldMixServerCampaign
 #import GameWorldMergeKing
-#import GameWorldMergePK
 #import PlayerManorWar
 import GameWorldBoss
 #import GameWorldActionTeHui
@@ -96,7 +95,8 @@
 import ReadChConfig
 import EventReport
 #import ReloadModule
-import MergeChildMsg
+import CrossRealmMsg
+import CrossRealmPK
 #import MergePlayer
 import PlayerFBHelpBattle
 import PlayerFamilyRedPacket
@@ -298,7 +298,7 @@
     #跨服广播
     #MergeBroadcast.OnBroadcastProccee(tick)
     #跨服PK匹配
-    #GameWorldMergePK.OnPKMatchProcess(tick)
+    CrossRealmPK.OnPKMatchProcess(tick)
     #跨服王者争霸
     #GameWorldMergeKing.OnMergeKingProcess(tick)
     
@@ -1251,15 +1251,13 @@
     #GameWorldBoss.CheckResetBossKilledCntOnServerInit()
     #GameWorldActionTeHui.OnGameServerInitOK() # 特惠活动初始化
     #子服启动成功告知跨服主服
-    #===========================================================================
-    # serverGroupID = GameWorld.GetServerGroupID()
-    # if GameWorld.IsMergeOpen() and not GameWorld.IsMergeServer():
-    #    GameWorld.Log("通知跨服主服务器启动成功, 可接收最新跨服活动状态及数据...")
-    #    dataMsg = {"Platform":GameWorld.GetPlatform(), "ServerID":GameWorld.GetServerSID(), "ServerGroupID":serverGroupID}
-    #    MergeChildMsg.SendMergerChildToCenterStringData(ChConfig.Def_ClientServerInitOK, dataMsg)
-    #    
-    # GameWorld.Log("服务器启动成功: ServerGroupID=%s" % serverGroupID)
-    #===========================================================================
+    serverGroupID = GameWorld.GetServerGroupID()
+    if GameWorld.IsCrossRealmOpen() and not GameWorld.IsCrossServer():
+        GameWorld.Log("通知跨服主服务器启动成功, 可接收最新跨服活动状态及数据...")
+        dataMsg = {"ServerGroupID":serverGroupID}
+        CrossRealmMsg.SendMsgToCrossServer(ShareDefine.ClientServerMsg_ServerInitOK, dataMsg)
+        
+    GameWorld.Log("服务器启动成功: ServerGroupID=%s" % serverGroupID)
     return
 
 def DoCheckNewServerOpen(tick):
diff --git a/ServerPython/CoreServerGroup/GameServer/Script/NetPackCommon.py b/ServerPython/CoreServerGroup/GameServer/Script/NetPackCommon.py
index ef9b24e..214aff0 100644
--- a/ServerPython/CoreServerGroup/GameServer/Script/NetPackCommon.py
+++ b/ServerPython/CoreServerGroup/GameServer/Script/NetPackCommon.py
@@ -29,7 +29,7 @@
 import ChPyNetSendPack
 import traceback
 import ChMapToGamePyPack
-import MergeChildMsg
+import CrossRealmMsg
 #-------------------------------------------------------------------------------
 #---全局变量---
 
@@ -95,9 +95,13 @@
 #        Log("ReadPyPackTable: moudle: %s"%dir(moudle))
         
         for index in range(regCnt):
+            if not config.get(section, "PacketCMD_%s"%(index + 1)):
+                continue
             cmd = config.get(section, "PacketCMD_%s"%(index + 1))
             subCmd = config.get(section, "PacketSubCMD_%s"%(index + 1))
             callFunc = config.get(section, "PacketCallFunc_%s"%(index + 1))
+            if not cmd or not subCmd or not callFunc:
+                continue
             
             cmd = int(cmd, 16)
             subCmd = int(subCmd, 16)
@@ -302,7 +306,7 @@
         #以下添加后续处理函数
         #...
         #...
-        MergeChildMsg.Recv_MergerChildToCenterProcess(packData, tick)
+        CrossRealmMsg.OnCrossServerReceiveMsg(packData, tick)
     except Exception:
         Log("跨服子服自定义封包消息处理失败")
     return
diff --git a/ServerPython/CoreServerGroup/GameServer/Script/Player/ChPlayer.py b/ServerPython/CoreServerGroup/GameServer/Script/Player/ChPlayer.py
index 18b0890..148aff8 100644
--- a/ServerPython/CoreServerGroup/GameServer/Script/Player/ChPlayer.py
+++ b/ServerPython/CoreServerGroup/GameServer/Script/Player/ChPlayer.py
@@ -41,7 +41,6 @@
 import PlayerBourse
 import GameWorldActionTeHui
 import PlayerXMZZ
-import GameWorldMergePK
 import GameWorldShopItem
 import MergeChildMsg
 import PlayerTruck
@@ -70,6 +69,7 @@
 import PyGameData
 import GMShell
 import IPY_PlayerDefine
+import CrossRealmPK
 #---------------------------------------------------------------------
 
 #---------------------------------------------------------------------
@@ -172,6 +172,8 @@
         PyGameData.g_todayPlayerLVDict[curPlayer.GetID()] = curPlayer.GetLV()
         #副本助战
         PlayerFBHelpBattle.OnHelpPlayerLogin(curPlayer)
+        #跨服PK
+        CrossRealmPK.OnPlayerLogin(curPlayer)
         
         GMShell.OnPlayerLogin(curPlayer)
         GMT_CTG.OnPlayerLogin(curPlayer)
@@ -515,7 +517,7 @@
 def __Func_PlayerDisconnect(curPlayer, tick):
     
     #跨服匹配PK
-    #GameWorldMergePK.OnLeaveServer(curPlayer)
+    CrossRealmPK.OnLeaveServer(curPlayer)
     
     #组队玩家离线
     PlayerTeam.DoPlayerLogOffTeamLogic(curPlayer, tick)
diff --git a/ServerPython/CoreServerGroup/GameServer/Script/Player/CrossRealmPlayer.py b/ServerPython/CoreServerGroup/GameServer/Script/Player/CrossRealmPlayer.py
new file mode 100644
index 0000000..df2e73b
--- /dev/null
+++ b/ServerPython/CoreServerGroup/GameServer/Script/Player/CrossRealmPlayer.py
@@ -0,0 +1,115 @@
+#!/usr/bin/python
+# -*- coding: GBK -*-
+#-------------------------------------------------------------------------------
+#
+##@package CrossRealmPlayer
+#
+# @todo:跨服玩家
+# @author hxp
+# @date 2018-12-21
+# @version 1.0
+#
+# 详细描述: 跨服玩家
+#
+#-------------------------------------------------------------------------------
+#"""Version = 2018-12-21 18:00"""
+#-------------------------------------------------------------------------------
+
+import GameWorld
+import ShareDefine
+import CrossRealmMsg
+import ReadChConfig
+import ChConfig
+import PlayerControl
+
+# 获取玩家跨服服务器上的名字
+def GetCrossPlayerName(curPlayer):
+    # 通过游戏账号中的平台标志获取名称,目前为spid
+    playerName = curPlayer.GetPlayerName()
+    nameFormat = ReadChConfig.GetPyMongoConfig("Merge", "NameFormat", True)
+    if not nameFormat:
+        return playerName
+    
+    opName = ReadChConfig.GetPyMongoConfig("Merge", "OpName_%s" % GameWorld.GetPlayerPlatform(curPlayer))
+
+    return (nameFormat%{"opname":opName, "sid":GameWorld.GetPlayerServerID(curPlayer)}).decode('gbk').encode(GameWorld.GetCharacterEncoding()) + playerName
+
+def CrossServerMsg_ExitCrossServer(msgData):
+    ## 收到跨服服务器同步的玩家退出跨服服务器
+    playerID = msgData
+    curPlayer = GameWorld.GetPlayerManager().FindPlayerByID(playerID)
+    if not curPlayer:
+        return
+    PlayerControl.SetCrossRealmState(curPlayer, 0)
+    return
+
+def SendCrossRealmReg(curPlayer, actionType, mapID=0, dataMapID=0, copyMapID=0, posX=0, posY=0):
+    # 发送跨服账号注册上传数据
+    
+    # 设置上传数据的活动类型
+    curPlayer.SetDict(ChConfig.Def_PlayerKey_MergeRegisterType, actionType)
+    sysMsg = str([actionType, mapID, dataMapID, copyMapID, posX, posY])
+    curPlayer.MapServer_QueryPlayerResult(0, 0, "CrossRealmReg", sysMsg, len(sysMsg))            
+    GameWorld.Log("SendCrossRealmReg actionType=%s,mapID=%s,dataMapID=%s,copyMapID=%s,posX=%s,posY=%s" 
+                  % (actionType, mapID, dataMapID, copyMapID, posX, posY), curPlayer.GetPlayerID())
+    return
+
+def OnCrossRealmRegOK(playerID, msgList, tick): 
+    ## 跨服报名结果
+    
+    curPlayer = GameWorld.GetPlayerManager().FindPlayerByID(playerID)
+    if not curPlayer:
+        return
+    
+    #newAccount, newName = msgList
+    
+    actionType = curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_MergeRegisterType)
+    GameWorld.Log("跨服报名成功 , actionType=%s" % (actionType), playerID)
+    
+    # 跨服PK上传数据完毕,通知跨服服务器,准备完毕
+    if actionType == ShareDefine.Def_MergeAction_MergePK:
+        regVSRoomID = curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_MergeRegisterRoomID) 
+        vsRoomID = curPlayer.GetVsRoomId()
+        
+        if regVSRoomID != vsRoomID:
+            GameWorld.Log("上传跨服服务器的 regVSRoomID=%s 与玩家当前的 roomID=%s 不同!不发送准备完毕!" 
+                          % (regVSRoomID, vsRoomID), playerID)
+            return
+        
+        dataMsg = {
+                   "accID":curPlayer.GetAccID(), # 角色账号ID
+                   "playerID":playerID, # 角色ID
+                   "vsRoomID":vsRoomID, # 所属对战房间ID
+                   }
+        CrossRealmMsg.SendMsgToCrossServer(ShareDefine.ClientServerMsg_PKPrepareOK, dataMsg)
+        GameWorld.Log("通知跨服服务器, 玩家匹配PK准备完毕!%s" % str(dataMsg), playerID)
+        
+    # 其他的,在上传数据完毕后,使用通用的通知可进入跨服
+    else:
+        NotifyCanEnterMergeServer(curPlayer, actionType)
+        
+    # hxp 2015.09.10 跨服boss,后面的暂时不需要
+    return
+
+
+def NotifyCanEnterMergeServer(curPlayer, actionType):
+    # 通用包,通知客户端可进入跨服服务器
+#    mapID, lineID = 0, 0
+#    mapPosInfo = GetMergeActionMapPos(actionType)
+#    if mapPosInfo:
+#        mapID = mapPosInfo[0]
+#        lineID = mapPosInfo[2]
+#        
+#    canEnterMServer = ChPyNetSendPack.tagCanEnterMergeServer()
+#    canEnterMServer.Clear()
+#    canEnterMServer.ActionType = actionType
+#    canEnterMServer.MapID = mapID
+#    canEnterMServer.LineID = lineID
+#    canEnterMServer.NewAccID = newAccID
+#    canEnterMServer.NewAccIDLen = len(canEnterMServer.NewAccID)
+#    canEnterMServer.NewPsw = newPwd
+#    canEnterMServer.NewPswLen = len(canEnterMServer.NewPsw)
+#    NetPackCommon.SendFakePack(curPlayer, canEnterMServer)
+    return
+
+
diff --git a/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerControl.py b/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerControl.py
index ee31aa5..dbdc17d 100644
--- a/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerControl.py
+++ b/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerControl.py
@@ -23,7 +23,6 @@
 # @change: "2015-07-14 21:00" xdh 聊天信息原附加值改为Extras
 # @change: "2015-10-28 00:00" hxp 增加设置对战房间ID
 # @change: "2015-11-05 12:00" hxp 增加跨服全服广播
-# @change: "2015-11-06 16:30" hxp 增加GetMergePlayerName
 # @change: "2017-06-22 15:00" hxp 跨服广播增加条件过滤子服是否提醒;跨服服务器全服广播同步子服
 #---------------------------------------------------------------------
 #"""Version = 2017-06-22 15:00"""
@@ -32,6 +31,7 @@
 import IPY_GameServer
 import MergeBroadcast
 import IpyGameDataPY
+import CrossRealmMsg
 import ShareDefine
 import ChConfig
 import types
@@ -52,7 +52,22 @@
       
     curPlayer.NotifyCode(msgMark, __GetNotifyCodeList(msgParamList))
     return
-    
+
+def NotifyCodeToClientServer(serverGroupID, playerID, msgMark, msgParamList=[]):
+    dataMsg = {"Type":"Player", "ID":playerID, "Mark":msgMark, "Param":msgParamList}
+    CrossRealmMsg.SendMsgToClientServer(ShareDefine.CrossServerMsg_Notify, dataMsg, [serverGroupID])
+    return
+
+def CrossServerMsg_Notify(notifyInfoDict):
+    notifyType = notifyInfoDict["Type"]
+    notifyID = notifyInfoDict["ID"]
+    if notifyType == "Player":
+        curPlayer = GameWorld.GetPlayerManager().FindPlayerByID(notifyID)
+        if not curPlayer:
+            return
+        NotifyCode(curPlayer, notifyInfoDict["Mark"], notifyInfoDict["Param"])
+    return
+
 ## 跨服世界广播
 #  @param country 提示的国家
 #  @param msgMark 提示信息Mark
@@ -288,38 +303,25 @@
     curPlayer.SetVsRoomId(roomID)
     if isSetMergeRegRoomID:
         curPlayer.SetDict(ChConfig.Def_PlayerKey_MergeRegisterRoomID, roomID) 
-    
-    battleIDStr = str(roomID)
     GameWorld.Log("SetVSRoomID playerID=%s, roomID=%s" % (curPlayer.GetPlayerID(), roomID))
-    curPlayer.MapServer_QueryPlayerResult(0, 0, 'CreatePlayerRoomID', battleIDStr, len(battleIDStr))
+    SetMapServerPlayerAttrValue(curPlayer, "SetVsRoomId", roomID)
     return
 
-## 根据子服账号及名称获取跨服角色名
-def GetMergePlayerName(playerAccID, playerName):
-    orgPlayerName = playerName.strip()
-    
-    #取帐号后缀作为区服标识
-    parserList = playerAccID.split('@')
-    serverSign = ""
-    if len(parserList) >= 2:
-        serverSign = parserList[-1]               
-    
-    parserList2 = orgPlayerName.split('-')
-    orgNameServerSign = ""
-    nameNotServerSign = parserList2[0]
-    if len(parserList2) >= 2:
-        orgNameServerSign = parserList2[-1]
-        
-    if orgNameServerSign:
-        if orgNameServerSign == serverSign:
-            return orgPlayerName
-        else:
-            return "%s-%s" % (nameNotServerSign, serverSign)
-    
-    if serverSign:
-        return "%s-%s" % (nameNotServerSign, serverSign)
-    
-    return orgPlayerName
+## 跨服状态: 0-非跨服状态,1-跨服状态
+def GetCrossRealmState(curPlayer): return curPlayer.GetExAttr5()
+def SetCrossRealmState(curPlayer, value):
+    ''' 设置玩家跨服状态
+    @param isExitCrossRealm: 非跨服状态时是否通知前端退出跨服服务器
+    '''
+    curPlayer.SetExAttr5(value)
+    SetMapServerPlayerAttrValue(curPlayer, "SetExAttr5", value)
+    return
+
+def SetMapServerPlayerAttrValue(curPlayer, attrName, value, exData=[]):
+    ## 设置地图服务器玩家对应属性值
+    setAttrInfo = str([attrName, value] + exData)
+    curPlayer.MapServer_QueryPlayerResult(0, 0, "SetPlayerAttr", setAttrInfo, len(setAttrInfo))
+    return
 
 ## 地图服务器扣物品
 #  @param curPlayer
diff --git a/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerQuery.py b/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerQuery.py
index e5909fc..2f5eb69 100644
--- a/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerQuery.py
+++ b/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerQuery.py
@@ -74,6 +74,9 @@
 import PyGameData
 import PlayerTalk
 import PlayerStore
+import CrossRealmPlayer
+import CrossRealmMsg
+import CrossRealmPK
 
 import time
 import datetime
@@ -426,12 +429,14 @@
         PlayerCompensation.SendPersonalItemMailBatch(eval(resultName))
         return
     
-    if callName == 'SendMergerChildMsg':
-        operType, dataMsg = eval(resultName)
-        MergeChildMsg.SendMergerChildToCenterStringData(operType, dataMsg)
-        # 如果是恢复跨服PK连胜的,先记录恢复的玩家ID, 等待成功后同步最新结果给玩家
-        if operType == ChConfig.Def_RecoverMergePKWin:
-            GameWorldMergePK.Add_RecoverMergePKWinPlayer(srcPlayerID)
+    if callName == "SendMsgToCrossServer":
+        msgType, dataMsg = eval(resultName)
+        CrossRealmMsg.SendMsgToCrossServer(msgType, dataMsg)
+        return
+    
+    if callName == "SendMsgToClientServer":
+        msgType, dataMsg, serverGroupIDList = eval(resultName)
+        CrossRealmMsg.SendMsgToClientServer(msgType, dataMsg, serverGroupIDList)
         return
     
     if callName == 'MergeWorldNotify':
@@ -534,26 +539,36 @@
         return
 
     #跨服赛报名获得新账号
-    if callName == 'MergeRegister':
-        PlayerMergeRegister.MergeWarRegisterNewAcc(srcPlayerID, eval(resultName), tick)
-        return    
+    #if callName == 'MergeRegister':
+    #    PlayerMergeRegister.MergeWarRegisterNewAcc(srcPlayerID, eval(resultName), tick)
+    #    return    
     
     #跨服王者争霸
     if callName == 'MergeKingFB':
         GameWorldMergeKing.MapServer_MergeKingFB(eval(resultName))
         return
     
-    #跨服匹配PK
-    if callName == 'MergePKOver':
-        GameWorldMergePK.MapServer_MergePKOver(eval(resultName))
+    #跨服匹配PK战斗结算
+    if callName == "CrossPKOver":
+        CrossRealmPK.MapServer_MergePKOver(eval(resultName))
+        return
+    
+    #跨服匹配房间开启
+    if callName == "CrossPKRoomOpen":
+        CrossRealmPK.MapServer_CrossPKRoomOpen(eval(resultName))
         return
     
     #跨服匹配PK取消匹配
-    if callName == 'MergePKCancel':
+    if callName == "CrossRealmPKCancel":
         curPlayer = GameWorld.GetPlayerManager().FindPlayerByID(srcPlayerID)
         if not curPlayer:
             return
-        GameWorldMergePK.SendCancelMergePKMatch(curPlayer, resultName)
+        CrossRealmPK.SendCancelCrossRealmPKMatch(curPlayer, resultName)
+        return
+    
+    #跨服注册结果
+    if callName == "CrossRealmReg":
+        CrossRealmPlayer.OnCrossRealmRegOK(srcPlayerID, eval(resultName), tick)
         return
     
     #py喇叭聊天
diff --git a/ServerPython/CoreServerGroup/GameServer/Script/PyGameData.py b/ServerPython/CoreServerGroup/GameServer/Script/PyGameData.py
index aa54042..7a1d26a 100644
--- a/ServerPython/CoreServerGroup/GameServer/Script/PyGameData.py
+++ b/ServerPython/CoreServerGroup/GameServer/Script/PyGameData.py
@@ -84,4 +84,12 @@
 g_fbHelpBattleRecord = {} # 未同步的副本助战记录 {playerID:[FBHelpBattleRecord, ...], ...}
 
 g_autoViceleaderDict = {}#自动安排副盟主的玩家记录{familyID:[]}
-g_forbidAutoViceleaderFamily = [] #禁止自动安排副盟主的仙盟[familyID,..]
\ No newline at end of file
+g_forbidAutoViceleaderFamily = [] #禁止自动安排副盟主的仙盟[familyID,..]
+
+g_crossPKPlayerDict = {} # 跨服PK玩家字典  {playerID:PKPlayer, ...}
+g_crossPKZoneMatchPlayerDict = {} # 跨服PK匹配中的玩家字典 {zoneID:[playerID, ...], ...}
+g_crossPKRoomDict = {} # 跨服PK房间字典 {roomID:PKRoom, ...}
+g_crossPKRoomID = 0 # 跨服PK当前已经创建到的房间ID,自增创建
+
+g_crossPKUnNotifyOverInfo = {} # 跨服PK未同步的结算信息 {player:[overInfo], ...}
+
diff --git a/ServerPython/CoreServerGroup/GameServer/ServerCommScript.ini b/ServerPython/CoreServerGroup/GameServer/ServerCommScript.ini
index 9ca368e..dba229f 100644
--- a/ServerPython/CoreServerGroup/GameServer/ServerCommScript.ini
+++ b/ServerPython/CoreServerGroup/GameServer/ServerCommScript.ini
@@ -114,15 +114,15 @@
 PacketSubCMD_1=0x4
 PacketCallFunc_1=GetDGDBOperResultInfo
 
-[MergeBroadCast]
-ScriptName = Player\MergeBroadCastRecive.py
-Writer = wdb
-Releaser = wdb
+[CrossRealmMsg]
+ScriptName = GameWorldLogic\CrossRealmMsg.py
+Writer = hxp
+Releaser = hxp
 RegType = 0
 RegisterPackCount = 1
 PacketCMD_1=0x4
 PacketSubCMD_1=0x5
-PacketCallFunc_1=OnMergeBroadCastPack
+PacketCallFunc_1=OnClientServerReceiveMsg
 
 ;家族
 [PlayerFamily]
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/PyNetPack.ini b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/PyNetPack.ini
index 8a31ebd..b0859b9 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/PyNetPack.ini
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/PyNetPack.ini
@@ -368,9 +368,9 @@
 PacketSubCMD_8=0x03
 PacketCallFunc_8=PySetAdult
 
-PacketCMD_9=0xC1
-PacketSubCMD_9=0x03
-PacketCallFunc_9=ClientPlayerGetReward
+PacketCMD_9=
+PacketSubCMD_9=
+PacketCallFunc_9=
 
 PacketCMD_10=0xB4
 PacketSubCMD_10=0x04
@@ -551,21 +551,37 @@
 PacketCallFunc_2 = OnGetManorWarDailyAward
 
 
-;跨服匹配PK
-[PlayerMergePK]
-ScriptName = Player\PlayerMergePK.py
+;跨服PK竞技场
+[PlayerCrossRealmPK]
+ScriptName = Player\PlayerCrossRealmPK.py
 Writer = hxp
 Releaser = hxp
 RegType = 0
-RegisterPackCount = 2
+RegisterPackCount = 3
 
 PacketCMD_1=0xC1
-PacketSubCMD_1=0x09
-PacketCallFunc_1=OnRequestMergePK
+PacketSubCMD_1=0x01
+PacketCallFunc_1=OnCrossRealmPKMatch
 
-PacketCMD_2=0xC1
-PacketSubCMD_2=0x10
-PacketCallFunc_2=OnRequestRecoverMergePKWin
+PacketCMD_1=0xC1
+PacketSubCMD_1=0x02
+PacketCallFunc_1=OnCrossRealmPKBuy
+
+PacketCMD_1=0xC1
+PacketSubCMD_1=0x03
+PacketCallFunc_1=OnCrossRealmPKGetAward
+
+;跨服玩家
+[CrossRealmPlayer]
+ScriptName = Player\CrossRealmPlayer.py
+Writer = hxp
+Releaser = hxp
+RegType = 0
+RegisterPackCount = 1
+
+PacketCMD_1=0xC1
+PacketSubCMD_1=0x04
+PacketCallFunc_1=OnExitCrossRealm
 
 ;王者争霸
 [PlayerMergeKing]
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChConfig.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChConfig.py
index 4e11f33..0f27dab 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChConfig.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChConfig.py
@@ -1781,6 +1781,8 @@
 Def_FBMapID_Dogz = 21110
 #聚魂副本
 Def_FBMapID_GatherSoul = 31340
+#跨服竞技场
+Def_FBMapID_CrossRealmPK = 32010
 #副本关闭时未拾取的物品邮件发放给玩家
 #这里只有需要的副本才配置,不做默认逻辑,防止某些副本实际不能给导致刷物品,如麒麟之府
 Def_SendUnPickItemMailMapIDList = [Def_FBMapID_IceLode, Def_FBMapID_PersonalBoss, Def_FBMapID_MunekadoTrial, 
@@ -1868,7 +1870,7 @@
                 'SealDemon':[Def_FBMapID_SealDemon, Def_FBMapID_SealDemonEx], #封魔坛
                 'XMZZ':[Def_FBMapID_XMZZ], #仙魔之争
                 'Dogz':[Def_FBMapID_Dogz], #神兽副本
-                'GatherSoul':[Def_FBMapID_GatherSoul],#聚魂副本
+                'CrossRealmPK':[Def_FBMapID_CrossRealmPK], #跨服竞技场
                 }
 
 #特殊副本ID, 由系统分配, 进入时候不验证IsMapCopyFull
@@ -3832,6 +3834,16 @@
 Def_PDict_MergeKing_SupportAward = "PD_MergePK_SupportAward" # 跨服王者争霸玩家竞猜积分奖励领取记录
 Def_PDict_MergeKing_Worship = "PD_MergePK_Worship" # 跨服王者争霸玩家每日膜拜记录
 
+# 跨服竞技场
+Def_PDict_CrossPK_TotalScore = "CrossPK_TotalScore" # 当前总积分
+Def_PDict_CrossPK_OnDayScore = "CrossPK_OnDayScore" # 今天过天时的积分
+Def_PDict_CrossPK_DanLV = "CrossPK_DanLV" # 当前段位
+Def_PDict_CrossPK_PKCount = "CrossPK_PKCount" # 当前总PK次数
+Def_PDict_CrossPK_WinCount = "CrossPK_WinCount" # 当前胜利次数
+Def_PDict_CrossPK_CWinCount = "CrossPK_CWinCount" # 跨当前连胜次数
+Def_PDict_CrossPK_TodayPKCount = "CrossPK_TodayPKCount" # 今日已PK次数
+Def_PDict_CrossPK_TodayBuyCount = "CrossPK_TodayBuyCount" # 今日已购买PK次数
+
 #自动战斗设置记录
 Def_PDict_AutoFightSetting = "AFSetting_%s_%s"
 
@@ -5110,8 +5122,10 @@
 tttFBAddTime, # 可挑战下一关倒计时 6
 tttDeadTime, # 死亡倒计时(古神禁地) 7
 tttPickupItem, # 拾取物品倒计时 8
+tttWaitPlayer, # 等待对手倒计时 9
+tttPlayerLeave, # 对手掉线倒计时 10
 tttMax,
-) = range(10)
+) = range(12)
 
 Def_FBPickupItemTime = 30000
 
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorldLogic/FBLogic.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorldLogic/FBLogic.py
index 8fc44ee..d226d1e 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorldLogic/FBLogic.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorldLogic/FBLogic.py
@@ -1229,7 +1229,7 @@
 def PlayerLoginInFBCheck(curPlayer, tick):
     gameMap = GameWorld.GetMap()
     #如果此地图是自动释放的, 需要检查这个玩家
-    if gameMap.GetMapFBType() == 0:
+    if gameMap.GetMapFBType() in [IPY_GameWorld.fbtNull, IPY_GameWorld.fbtCrossVSRoom]:
         return False
     
     #玩家 在副本中,并且副本不踢出玩家下线
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorldLogic/FBProcess/FBCommon.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorldLogic/FBProcess/FBCommon.py
index b99b32d..9b8a408 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorldLogic/FBProcess/FBCommon.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorldLogic/FBProcess/FBCommon.py
@@ -630,7 +630,7 @@
 #---------------------------------------------------------------------
 def SyncDynamicBarrierState(barrierPointList, state, curPlayer=None):
     '''同步动态障碍物是否有效性
-    @param barrierPointList: 障碍物点列表 [[aPosX,aPosY,bPosX,bPosY], [aPosX,aPosY,bPosX,bPosY], ...]
+    @param barrierPointList: 障碍物点列表 [[aPosX,aPosY,bPosX,bPosY,angle可选], [aPosX,aPosY,bPosX,bPosY,angle可选], ...]
     @param state: 是否有效
     @param curPlayer: 指定通知目标玩家,为None时广播本地图所有玩家
     '''
@@ -638,12 +638,15 @@
     barrierStatePack.Clear()
     barrierStatePack.State = state
     barrierStatePack.BarrierList = []
-    for aPosX, aPosY, bPosX, bPosY in barrierPointList:
+    for posInfo in barrierPointList:
+        aPosX, aPosY, bPosX, bPosY = posInfo[:4]
+        angle = posInfo[4] if len(posInfo) > 4 else 0
         barrier = ChPyNetSendPack.tagMCDynamicBarrier()
         barrier.APosX = aPosX
         barrier.APosY = aPosY
         barrier.BPosX = bPosX
         barrier.BPosY = bPosY
+        barrier.Angle = angle
         barrierStatePack.BarrierList.append(barrier)
     barrierStatePack.Count = len(barrierStatePack.BarrierList)
     if curPlayer:
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorldLogic/FBProcess/GameLogic_CrossRealmPK.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorldLogic/FBProcess/GameLogic_CrossRealmPK.py
new file mode 100644
index 0000000..44efd77
--- /dev/null
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorldLogic/FBProcess/GameLogic_CrossRealmPK.py
@@ -0,0 +1,498 @@
+#!/usr/bin/python
+# -*- coding: GBK -*-
+#-------------------------------------------------------------------------------
+#
+##@package GameWorldLogic.FBProcess.GameLogic_CrossRealmPK
+#
+# @todo:跨服匹配PK
+# @author hxp
+# @date 2018-12-21
+# @version 1.0
+#
+# 详细描述: 跨服匹配PK
+#
+#-------------------------------------------------------------------------------
+#"""Version = 2018-12-21 18:00"""
+#-------------------------------------------------------------------------------
+
+import ChPlayer
+import GameWorld
+import IPY_GameWorld
+import PlayerControl
+import GameWorldProcess
+import IpyGameDataPY
+import SkillCommon
+import FBCommon
+import ChConfig
+
+
+(
+Def_Time_MaxWait, # 最长等待时间, 秒
+Def_Time_MapPrepare, # 准备时间, 秒
+Def_Time_Fight, # 战斗时间, 秒
+Def_Time_Protect, # 保护时间,秒,玩家战斗中掉线保护时长
+Def_Time_Leave, # 结束退出时间, 秒
+) = range(5)
+
+# 当前副本地图的状态
+(
+FB_State_Open,
+FB_State_Waiting, # 等待对手阶段
+FB_State_MapPrepare, # 地图准备
+FB_State_Fight, # 战斗阶段
+FB_State_Reborn, # 复活阶段
+FB_State_Leave, # 离开阶段
+FB_State_Close, # 关闭阶段
+) = range(7)
+
+# 对战结束类型定义
+(
+Def_OverType_LackPlayer, # 缺少对手
+Def_OverType_PlayerExit, # 对手退出(视为认输)
+Def_OverType_Kill, # 击杀对手
+Def_OverType_TimeOut, # PK时间超时
+) = range(4)
+
+# 副本相关字典key
+GameFBDict_FBPlayerID = "FBD_FBPlayerID_%s" # 玩家ID, 参数, 进入顺序
+GameFBDict_PlayerWinCnt = "FBD_PlayerWinCnt_%s" # 玩家已获胜次数, 参数[playerID]
+GameFBDict_PlayerLeaveTick = "FBD_PlayerLeaveTick_%s" # 玩家已获胜次数, 参数[playerID]
+
+FBPDict_PVPDamage = "FBPD_PVPDamage" # 玩家伤害输出
+FBPDict_PVPDamUpdTick = "FBPD_PVPDamUpdTick" # 更新伤害tick
+FBPDict_ResetPosX = "FBPD_ResetPosX" # 玩家重置坐标X
+FBPDict_ResetPosY = "FBPD_ResetPosY" # 玩家重置坐标Y
+FBPDict_RoundNum = "FBPD_RoundNum" # 玩家当前所属回合数
+
+FB_RoundNum = "FB_RoundNum" # 副本当前回合数
+FB_RoundWinPlayerID = "FB_RoundWinPlayerID_%s" # 回合获胜玩家ID, 参数[回合数]
+
+## 是否能够通过活动查询进入
+def OnEnterFBEvent(curPlayer, mapID, lineID, tick):
+    return True
+
+#def OnGetFBEnterPos(curPlayer, mapID, lineId, ipyEnterPosInfo, tick):
+#    posDict = {117401:(40,37), 117403:(10, 7)}
+#    return posDict.get(curPlayer.GetPlayerID())
+
+## 玩家进入副本
+def DoEnterFB(curPlayer, tick):
+    playerID = curPlayer.GetPlayerID()
+    playerVSRoomID = curPlayer.GetVsRoomId()
+    roomID = GameWorld.GetGameWorld().GetPropertyID()        
+    gameFB = GameWorld.GetGameFB()
+    fbStep = gameFB.GetFBStep()
+    GameWorld.Log("DoEnterFB fbRoomID=%s,playerVSRoomID=%s,fbStep=%s" % (roomID, playerVSRoomID, fbStep), playerID)
+    
+    gameFB.SetGameFBDict(GameFBDict_PlayerLeaveTick % playerID, 0)
+
+    fbRoundNum = gameFB.GetGameFBDictByKey(FB_RoundNum)
+    playerRoundNum = gameFB.GetPlayerGameFBDictByKey(playerID, FBPDict_RoundNum)
+    if playerRoundNum and fbRoundNum and playerRoundNum != fbRoundNum:
+        # 一般是掉线时上个回合已经结束了
+        GameWorld.DebugLog("玩家进入副本时与当前副本回合数不一致时,重置状态!fbRoundNum=%s,playerRoundNum=%s" 
+                           % (fbRoundNum, playerRoundNum), playerID)
+        gameFB.SetPlayerGameFBDict(playerID, FBPDict_RoundNum, fbRoundNum)
+        __ResetPlayerState(gameFB, curPlayer, playerID)
+        
+    if fbStep >= FB_State_Leave or not roomID or not playerVSRoomID or roomID != playerVSRoomID:
+        PlayerControl.PlayerLeaveFB(curPlayer)
+        return
+    
+    # 非战斗阶段,通知动态障碍点
+    if fbStep < FB_State_Fight:
+        FBCommon.SyncDynamicBarrierState(IpyGameDataPY.GetFuncEvalCfg("CrossRealmPKFB", 2), 1, curPlayer) # 准备期间有动态障碍点
+        
+    fbTimeList = IpyGameDataPY.GetFuncEvalCfg("CrossRealmPKFB", 1)
+    
+    if fbStep == FB_State_Open:
+        gameFB.SetGameFBDict(GameFBDict_FBPlayerID % 1, playerID)
+        gameFB.SetPlayerGameFBDict(playerID, FBPDict_ResetPosX, curPlayer.GetPosX())
+        gameFB.SetPlayerGameFBDict(playerID, FBPDict_ResetPosY, curPlayer.GetPosY())
+        gameFB.SetPlayerGameFBDict(playerID, FBPDict_RoundNum, 1)
+        FBCommon.SetFBStep(FB_State_Waiting, tick)
+        GameWorld.Log("    第一个进入,设置副本进入等待对手阶段!roomID=%s" % (roomID), playerID)
+        __ResetPlayerState(gameFB, curPlayer, playerID, False)
+        curPlayer.Sync_TimeTick(ChConfig.tttWaitPlayer, 0, fbTimeList[Def_Time_MaxWait] * 1000, True)
+        sendMsg = str([roomID])
+        GameWorld.GetPlayerManager().GameServer_QueryPlayerResult(0, 0, 0, "CrossPKRoomOpen", sendMsg, len(sendMsg))
+        
+    elif fbStep == FB_State_Waiting:
+        playerIDA = gameFB.GetGameFBDictByKey(GameFBDict_FBPlayerID % 1)
+        playerIDB = gameFB.GetGameFBDictByKey(GameFBDict_FBPlayerID % 2)
+        if not playerIDB and playerIDA != playerID:
+            gameFB.SetGameFBDict(GameFBDict_FBPlayerID % 2, playerID)
+            gameFB.SetPlayerGameFBDict(playerID, FBPDict_ResetPosX, curPlayer.GetPosX())
+            gameFB.SetPlayerGameFBDict(playerID, FBPDict_ResetPosY, curPlayer.GetPosY())
+            gameFB.SetPlayerGameFBDict(playerID, FBPDict_RoundNum, 1)
+            GameWorld.Log("    第二个进入的玩家!roomID=%s" % (roomID), playerID)
+            __ResetPlayerState(gameFB, curPlayer, playerID, False)
+            
+        if GameWorld.GetMapCopyPlayerManager().GetPlayerCount() == 2:
+            GameWorld.Log("    两个人都在,设置副本进入战斗倒计时阶段!roomID=%s" % (roomID), playerID)
+            FBCommon.SetFBStep(FB_State_MapPrepare, tick)
+            FBCommon.Sync_Player_TimeTick(ChConfig.tttWaitStart, fbTimeList[Def_Time_MapPrepare] * 1000)
+            gameFB.SetGameFBDict(FB_RoundNum, 1)
+        else:
+            GameWorld.Log("    对手不在,继续等待!roomID=%s" % (roomID), playerID)
+            
+    elif fbStep == FB_State_MapPrepare:
+        notify_tick = fbTimeList[Def_Time_MapPrepare] * 1000 - (tick - GameWorld.GetGameFB().GetFBStepTick())
+        curPlayer.Sync_TimeTick(ChConfig.tttWaitStart, 0, max(notify_tick, 0), True)
+        
+    elif fbStep == FB_State_Fight:
+        notify_tick = fbTimeList[Def_Time_Fight] * 1000 - (tick - GameWorld.GetGameFB().GetFBStepTick())
+        curPlayer.Sync_TimeTick(ChConfig.tttTowerTake, 0, max(notify_tick, 0), True)
+        
+    FBCommon.Notify_FBHelp(curPlayer, __GetFBHelpInfo())
+    return
+
+def __GetFBHelpInfo():
+    gameFB = GameWorld.GetGameFB()
+    roundWinerIDList = []
+    roundNum = gameFB.GetGameFBDictByKey(FB_RoundNum)
+    for roundNum in xrange(1, roundNum + 1):
+        winnerID = gameFB.GetGameFBDictByKey(FB_RoundWinPlayerID % roundNum)
+        if not winnerID:
+            break
+        roundWinerIDList.append(winnerID)
+        
+    return {"roundNum":roundNum, "roundWinerIDList":roundWinerIDList}
+
+
+## 玩家退出副本
+def DoExitFB(curPlayer, tick):
+    # 结算时间
+    gameFB = GameWorld.GetGameFB()
+    fbStep = gameFB.GetFBStep()
+    
+    if fbStep >= FB_State_Leave:
+        return
+    
+    playerID = curPlayer.GetPlayerID()
+    gameFB.SetGameFBDict(GameFBDict_PlayerLeaveTick % playerID, tick)
+    GameWorld.Log("玩家战斗阶段下线!playerID=%s,waitPlayerID=%s" % (playerID, playerID))
+    return
+
+## 获得副本帮助信息
+def DoFBHelp(curPlayer, tick):
+    return
+
+## 副本总逻辑计时器
+def OnProcess(tick):
+    gameFB = GameWorld.GetGameFB()
+    fbStep = gameFB.GetFBStep()
+    
+    if fbStep == FB_State_Waiting:
+        __DoLogic_Waiting(tick)
+    elif fbStep == FB_State_MapPrepare:
+        if not __CheckLeaveProtectTimeout(tick):
+            __DoLogic_MapPrepare(tick)
+    elif fbStep == FB_State_Fight:
+        if not __CheckLeaveProtectTimeout(tick):
+            __DoLogic_MapFight(tick)
+    elif fbStep == FB_State_Reborn:
+        __DoLogic_Reborn(tick)
+    elif fbStep == FB_State_Leave:
+        __DoLogic_LeaveTime(tick)
+        
+    return
+
+##等待玩家进入阶段处理
+def __DoLogic_Waiting(tick):
+    fbTimeList = IpyGameDataPY.GetFuncEvalCfg("CrossRealmPKFB", 1)
+    if tick - GameWorld.GetGameFB().GetFBStepTick() < fbTimeList[Def_Time_MaxWait] * 1000:
+        return
+    
+    winner, winnerID, loser, loserID = __GetTimeoutWinerInfo(tick)
+    # 对手没来,直接获胜
+    roomID = GameWorld.GetGameWorld().GetPropertyID()
+    GameWorld.Log("战前等待对手阶段超时,直接结束!roomID=%s,winnerID=%s,loserID=%s" % (roomID, winnerID, loserID))
+    __DoFBPKAllOver(winner, winnerID, loser, loserID, Def_OverType_LackPlayer, tick)
+    return
+
+def __CheckLeaveProtectTimeout(tick):
+    gameFB = GameWorld.GetGameFB()
+    playerIDA = gameFB.GetGameFBDictByKey(GameFBDict_FBPlayerID % 1)
+    playerIDB = gameFB.GetGameFBDictByKey(GameFBDict_FBPlayerID % 2)
+    playerLeaveTickA = gameFB.GetGameFBDictByKey(GameFBDict_PlayerLeaveTick % playerIDA)
+    playerLeaveTickB = gameFB.GetGameFBDictByKey(GameFBDict_PlayerLeaveTick % playerIDB)
+    if not playerLeaveTickA and not playerLeaveTickB:
+        return
+    
+    fbTimeList = IpyGameDataPY.GetFuncEvalCfg("CrossRealmPKFB", 1)
+    if playerLeaveTickA > playerLeaveTickB:
+        if tick - playerLeaveTickA < fbTimeList[Def_Time_Protect] * 1000:
+            return
+    else:
+        if tick - playerLeaveTickB < fbTimeList[Def_Time_Protect] * 1000:
+            return
+        
+    winner, winnerID, loser, loserID = __GetTimeoutWinerInfo(tick)
+    # 对手没来,直接获胜
+    roomID = GameWorld.GetGameWorld().GetPropertyID()
+    GameWorld.Log("战斗中对手离线超时,直接结束!roomID=%s,winnerID=%s,loserID=%s" % (roomID, winnerID, loserID))
+    __DoFBPKAllOver(winner, winnerID, loser, loserID, Def_OverType_PlayerExit, tick)
+    return True
+
+def __GetTimeoutWinerInfo(tick):
+    ''' 时间超时,获取获胜的玩家
+                    战斗阶段有两个玩家时优先比较输出
+                    其他情况则在线玩家获胜,如果没有玩家在线,则最迟离线的获胜
+    '''
+    winner, winnerID, loser, loserID = None, 0, None, 0
+    gameFB = GameWorld.GetGameFB()
+    fbStep = gameFB.GetFBStep()
+    copyMapPlayerManager = GameWorld.GetMapCopyPlayerManager()
+    playerIDA = gameFB.GetGameFBDictByKey(GameFBDict_FBPlayerID % 1)
+    playerIDB = gameFB.GetGameFBDictByKey(GameFBDict_FBPlayerID % 2)
+    
+    # 战斗阶段有两个玩家时优先比较输出
+    if fbStep == FB_State_Fight and copyMapPlayerManager.GetPlayerCount() == 2:
+        # 时间到还没分出胜负, 根据以下规则决定胜负,这里用玩家ID处理,防止结算时都掉线了导致没有结果
+        # 伤害输出 > 优先到达时间 > 剩余HP > 最大HP > playerID
+        
+        playerInfoList = []
+        for playerID in [playerIDA, playerIDB]:
+            player = copyMapPlayerManager.FindPlayerByID(playerID)
+            pvpDamage = gameFB.GetPlayerGameFBDictByKey(playerID, FBPDict_PVPDamage)
+            pvpDamTick = gameFB.GetPlayerGameFBDictByKey(playerID, FBPDict_PVPDamUpdTick)
+            sortTick = tick - pvpDamTick
+            curHP = 0 if not player else player.GetHP()
+            curMaxHP = 0 if not player else player.GetMaxHP()
+            playerInfoList.append([pvpDamage, sortTick, curHP, curMaxHP, playerID, player])
+            GameWorld.Log("PK超时: pvpDamge=%s,pvpDamTick=%s,tick=%s,sortTick=%s,HP=%s/%s" 
+                          % (pvpDamage, pvpDamTick, tick, sortTick, curHP, curMaxHP), playerID)
+            
+        playerInfoList.sort(reverse=True)
+        GameWorld.Log("PK超时, 进入结算!playerInfoList=%s" % str(playerInfoList))
+        winner = playerInfoList[0][-1] if len(playerInfoList) > 0 else None
+        loser = playerInfoList[1][-1] if len(playerInfoList) > 1 else None
+        winnerID = 0 if not winner else winner.GetPlayerID()
+        loserID = 0 if not loser else loser.GetPlayerID()
+        return winner, winnerID, loser, loserID
+    
+    # 其他情况则在线玩家获胜,如果没有玩家在线,则最迟离线的获胜
+    for i in xrange(copyMapPlayerManager.GetPlayerCount()):
+        player = copyMapPlayerManager.GetPlayerByIndex(i)
+        if player == None or player.IsEmpty():
+            continue
+        winner = player
+        winnerID = player.GetPlayerID()
+        break
+    
+    if not winner:
+        playerLeaveTickA = gameFB.GetGameFBDictByKey(GameFBDict_PlayerLeaveTick % playerIDA)
+        playerLeaveTickB = gameFB.GetGameFBDictByKey(GameFBDict_PlayerLeaveTick % playerIDB)
+        # 离线tick较大的就是比较晚离线的
+        if playerLeaveTickA > playerLeaveTickB:
+            winnerID = playerIDA
+            loserID = playerIDB
+        else:
+            winnerID = playerIDB
+            loserID = playerIDA
+    else:
+        loserID = playerIDB if playerIDA == winnerID else playerIDA
+    return winner, winnerID, loser, loserID
+
+##副本准备时间
+def __DoLogic_MapPrepare(tick):
+    fbTimeList = IpyGameDataPY.GetFuncEvalCfg("CrossRealmPKFB", 1)
+    GameWorld.DebugLog("__DoLogic_MapPrepare ... %s" % fbTimeList[Def_Time_MapPrepare])
+    if tick - GameWorld.GetGameFB().GetFBStepTick() < fbTimeList[Def_Time_MapPrepare] * 1000:
+        return
+    
+    FBCommon.SetFBStep(FB_State_Fight, tick)
+    FBCommon.Sync_Player_TimeTick(ChConfig.tttTowerTake, fbTimeList[Def_Time_Fight] * 1000)
+    FBCommon.SyncDynamicBarrierState(IpyGameDataPY.GetFuncEvalCfg("CrossRealmPKFB", 2), 0)
+    
+    # 通知回合开始
+    helpDict = __GetFBHelpInfo()
+    helpDict["isStart"] = 1
+    copyMapPlayerManager = GameWorld.GetMapCopyPlayerManager()
+    for i in xrange(copyMapPlayerManager.GetPlayerCount()):
+        player = copyMapPlayerManager.GetPlayerByIndex(i)
+        if player == None or player.IsEmpty():
+            continue
+        FBCommon.Notify_FBHelp(player, helpDict)
+        
+    return
+
+##战斗阶段
+def __DoLogic_MapFight(tick):
+    fbTimeList = IpyGameDataPY.GetFuncEvalCfg("CrossRealmPKFB", 1)
+    if tick - GameWorld.GetGameFB().GetFBStepTick() < fbTimeList[Def_Time_Fight] * 1000:
+        return
+    
+    winner, winnerID, loser, loserID = __GetTimeoutWinerInfo(tick)
+    roomID = GameWorld.GetGameWorld().GetPropertyID()
+    GameWorld.Log("PK超时, 进入结算! roomID=%s,winnerID=%s,loserID=%s" % (roomID, winnerID, loserID))
+    __DoLogicAddPlayerWinCnt(winner, winnerID, loser, loserID, Def_OverType_TimeOut, tick)
+    return
+
+##复活阶段阶段
+def __DoLogic_Reborn(tick):
+    gameFB = GameWorld.GetGameFB()
+    
+    helpDict = __GetFBHelpInfo()
+    
+    fbTimeList = IpyGameDataPY.GetFuncEvalCfg("CrossRealmPKFB", 1)
+    prepareTime = fbTimeList[Def_Time_MapPrepare] * 1000
+    helpDict["prepareTime"] = prepareTime
+    
+    nextRoundNum = gameFB.GetGameFBDictByKey(FB_RoundNum) + 1
+    gameFB.SetGameFBDict(FB_RoundNum, nextRoundNum)
+    
+    isWinnerResetState = False
+    copyMapPlayerManager = GameWorld.GetMapCopyPlayerManager()
+    for i in xrange(copyMapPlayerManager.GetPlayerCount()):
+        player = copyMapPlayerManager.GetPlayerByIndex(i)
+        if player == None or player.IsEmpty():
+            continue
+        
+        playerID = player.GetPlayerID()
+        gameFB.SetPlayerGameFBDict(playerID, FBPDict_RoundNum, nextRoundNum)
+        
+        if player.GetPlayerAction() == IPY_GameWorld.paDie or player.GetHP() <= 0:
+            GameWorld.DebugLog("复活玩家...", player.GetPlayerID())
+            ChPlayer.PlayerRebornByType(player, ChConfig.rebornType_System, tick)
+            __ResetPlayerState(gameFB, player, playerID)
+        else:
+            if isWinnerResetState:
+                __ResetPlayerState(gameFB, player, playerID)
+                
+        FBCommon.Notify_FBHelp(player, helpDict)
+        
+    GameWorld.Log("开始下一回合: nextRoundNum=%s" % (nextRoundNum))
+    
+    # 重置伤害输出
+    playerIDA = gameFB.GetGameFBDictByKey(GameFBDict_FBPlayerID % 1)
+    playerIDB = gameFB.GetGameFBDictByKey(GameFBDict_FBPlayerID % 2)
+    gameFB.SetPlayerGameFBDict(playerIDA, FBPDict_PVPDamage, 0)
+    gameFB.SetPlayerGameFBDict(playerIDA, FBPDict_PVPDamUpdTick, tick)
+    gameFB.SetPlayerGameFBDict(playerIDB, FBPDict_PVPDamage, 0)
+    gameFB.SetPlayerGameFBDict(playerIDB, FBPDict_PVPDamUpdTick, tick)
+    
+    # 进入准备倒计时,开始下一局准备
+    FBCommon.SetFBStep(FB_State_MapPrepare, tick)
+    #FBCommon.Sync_Player_TimeTick(ChConfig.tttWaitStart, prepareTime)
+    return
+
+##比赛结束的空闲时间
+def __DoLogic_LeaveTime(tick):
+    fbTimeList = IpyGameDataPY.GetFuncEvalCfg("CrossRealmPKFB", 1)
+    if tick - GameWorld.GetGameFB().GetFBStepTick() < fbTimeList[Def_Time_Leave] * 1000:
+        return
+    FBCommon.SetFBStep(FB_State_Close, tick)
+    GameWorldProcess.CloseFB(tick)
+    return
+
+## PVP伤害相关
+def OnPVPDamage(curPlayer, damageValue, tagPlayer, tick):
+    playerID = curPlayer.GetPlayerID()
+    tagPlayerID = tagPlayer.GetPlayerID()
+    
+    gameFB = GameWorld.GetGameFB()
+    curPlayerDamage = gameFB.GetPlayerGameFBDictByKey(playerID, FBPDict_PVPDamage)
+    updDamage = min(ChConfig.Def_UpperLimit_DWord, curPlayerDamage + damageValue)
+    gameFB.SetPlayerGameFBDict(playerID, FBPDict_PVPDamage, updDamage)
+    gameFB.SetPlayerGameFBDict(playerID, FBPDict_PVPDamUpdTick, tick)
+    GameWorld.DebugLog("OnPVPDamage playerID=%s,tagPlayerID=%s,damageValue=%s,updDamage=%s,tick=%s" 
+                       % (playerID, tagPlayerID, damageValue, updDamage, tick))
+    
+    #helpDict = {"PVPDamage":[playerID, updDamage, tick]}
+    #FBCommon.Notify_FBHelp(curPlayer, helpDict)
+    #FBCommon.Notify_FBHelp(tagPlayer, helpDict)
+    return
+
+##处理副本中杀死玩家逻辑
+def DoFBOnKill_Player(curPlayer, defender, tick):
+    winnerID = curPlayer.GetPlayerID()
+    loserID = defender.GetPlayerID()
+    roomID = GameWorld.GetGameWorld().GetPropertyID()
+    
+    GameWorld.Log("DoFBOnKill_Player roomID=%s,winnerID=%s,loserID=%s" % (roomID, winnerID, loserID), winnerID)
+    if GameWorld.GetGameFB().GetFBStep() != FB_State_Fight:
+        return
+    
+    __DoLogicAddPlayerWinCnt(curPlayer, winnerID, defender, loserID, Def_OverType_Kill, tick)
+    return True
+
+def __DoLogicAddPlayerWinCnt(winner, winnerID, loser, loserID, overType, tick):
+        
+    gameFB = GameWorld.GetGameFB()
+    roomID = GameWorld.GetGameWorld().GetPropertyID()
+    
+    winnerWinCnt = gameFB.GetGameFBDictByKey(GameFBDict_PlayerWinCnt % winnerID)
+    updWinCnt = winnerWinCnt + 1
+    gameFB.SetGameFBDict(GameFBDict_PlayerWinCnt % winnerID, updWinCnt)
+    
+    roundNum = gameFB.GetGameFBDictByKey(FB_RoundNum)
+    gameFB.SetGameFBDict(FB_RoundWinPlayerID % roundNum, winnerID)
+    
+    GameWorld.Log("回合结束: roomID=%s,roundNum=%s,winnerID=%s,loserID=%s,updWinCnt=%s" % (roomID, roundNum, winnerID, loserID, updWinCnt))
+    isOver = (updWinCnt >= IpyGameDataPY.GetFuncCfg("CrossRealmPKFB", 3))
+    if not isOver:
+        FBCommon.SetFBStep(FB_State_Reborn, tick)
+        return
+    
+    GameWorld.Log("    已达到最大胜场,获得最终胜利!winnerID=%s" % winnerID)
+    __DoFBPKAllOver(winner, winnerID, loser, loserID, overType, tick)
+    return
+
+def __ResetPlayerState(gameFB, player, playerID, resetPos=True):
+    if resetPos:
+        posX = gameFB.GetPlayerGameFBDictByKey(playerID, FBPDict_ResetPosX)
+        posY = gameFB.GetPlayerGameFBDictByKey(playerID, FBPDict_ResetPosY)
+        player.ResetPos(posX, posY)
+        
+    if player.GetHP() != player.GetMaxHP():
+        player.SetHP(player.GetMaxHP())
+        
+    if PlayerControl.GetProDef(player) != PlayerControl.GetMaxProDef(player):
+        PlayerControl.SetProDef(player, PlayerControl.GetMaxProDef(player))
+        
+    SkillCommon.ResetAllSkillCD(player)
+    return
+
+## 跨服PK结束处理
+def __DoFBPKAllOver(winner, winnerID, loser, loserID, overType, tick):
+    gameFB = GameWorld.GetGameFB()
+    
+    roundWinerIDList = []
+    roundNum = gameFB.GetGameFBDictByKey(FB_RoundNum)
+    for roundNum in xrange(1, roundNum + 1):
+        roundWinerIDList.append(gameFB.GetGameFBDictByKey(FB_RoundWinPlayerID % roundNum))
+        
+    #副本状态进入关闭倒计时
+    fbTimeList = IpyGameDataPY.GetFuncEvalCfg("CrossRealmPKFB", 1)
+    FBCommon.Sync_Player_TimeTick(ChConfig.tttLeaveMap, fbTimeList[Def_Time_Leave] * 1000)
+    FBCommon.SetFBStep(FB_State_Leave, tick)
+    
+    #发送一条消息到GameServer通知PK对战结束,因为地图可能对手没来导致没有失败玩家ID,所以结算统一在GameServer处理
+    overType = 1 if overType in [Def_OverType_LackPlayer, Def_OverType_PlayerExit] else 0
+    roomID = GameWorld.GetGameWorld().GetPropertyID()
+    sendMsg = str([roomID, winnerID, loserID, roundWinerIDList, overType])
+    GameWorld.GetPlayerManager().GameServer_QueryPlayerResult(0, 0, 0, "CrossPKOver", sendMsg, len(sendMsg))
+    GameWorld.Log("PK结算SendToGameServer: roomID=%s,winnerID=%s,loserID=%s,roundWinerIDList=%s,overType=%s" 
+                  % (roomID, winnerID, loserID, roundWinerIDList, overType))
+    return
+
+#关系有3层,无-友好-敌人
+def CheckPlayersRelation_IsFriend(curPlayer, curTagPlayer):
+    return not CanAttackPlayer(curPlayer, curTagPlayer)
+
+##副本中,攻击队友逻辑
+def DoCanAttackTeamer(curPlayer, curTagPlayer):
+    return CanAttackPlayer(curPlayer, curTagPlayer)
+
+##副本中,是否可攻击
+def CanAttackPlayer(curPlayer, curTagPlayer):
+    fbStep = GameWorld.GetGameFB().GetFBStep()
+    
+    if fbStep != FB_State_Fight:
+        GameWorld.DebugLog("非战斗阶段,不可攻击!")
+        return False
+    
+    return True
+
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/NetPackCommon.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/NetPackCommon.py
index 2eeab27..c85c028 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/NetPackCommon.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/NetPackCommon.py
@@ -95,9 +95,13 @@
 #        Log("ReadPyPackTable: moudle: %s"%dir(moudle))
         
         for index in range(regCnt):
+            if not config.has_option(section, "PacketCMD_%s"%(index + 1)):
+                continue
             cmd = config.get(section, "PacketCMD_%s"%(index + 1))
             subCmd = config.get(section, "PacketSubCMD_%s"%(index + 1))
             callFunc = config.get(section, "PacketCallFunc_%s"%(index + 1))
+            if not cmd or not subCmd or not callFunc:
+                continue
             
             cmd = int(cmd, 16)
             subCmd = int(subCmd, 16)
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/ChPlayer.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/ChPlayer.py
index f869d0c..9f9f3ca 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/ChPlayer.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/ChPlayer.py
@@ -108,6 +108,7 @@
 import PlayerActTotalRecharge
 import PlayerSpringSale
 import PlayerFairyCeremony
+import CrossRealmPlayer
 import ChNetSendPack
 import FamilyRobBoss
 import FBHelpBattle
@@ -249,7 +250,7 @@
     
     # 屏蔽跨服下关闭和子服重复的数据的发送 pushsend接口, notifyall正常发送
     # !!!必要发送的数据要注意位置
-    if GameWorld.IsMergeServer():
+    if GameWorld.IsCrossServer():
         curPlayer.SetForbiddenSyncClientState(True)
     
     SyncGuideState(curPlayer)
@@ -308,7 +309,10 @@
         PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_Player_Dict_FuncChangeLineID, 0)
         PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_Player_Dict_HighChangeLineID, 0)
         #GameWorld.DebugLog("离线超过10秒重置切线临时保存的相关记录值!leaveServerSecond=%s" % leaveServerSecond, curPlayer.GetPlayerID())
-        
+        # 离线过久恢复为非跨服状态
+        if PlayerControl.GetCrossRealmState(curPlayer):
+            PlayerControl.SetCrossRealmState(curPlayer, 0)
+            
     # 合服首登处理
     __DoMixServerFirstLogin(curPlayer)
     PlayerBillboard.BillboardOnLogin(curPlayer)
@@ -578,8 +582,9 @@
         
     # 屏蔽跨服下关闭和子服重复的数据的发送 pushsend接口, notifyall正常发送
     # !!!必要发送的数据要注意位置
-    if GameWorld.IsMergeServer():
+    if GameWorld.IsCrossServer():
         curPlayer.SetForbiddenSyncClientState(False)
+        PlayerControl.SetCrossRealmState(curPlayer, 1) # 因为主服上传数据之前该值为1,所以登录跨服后在跨服服务器要设置为1
         
     return
 
@@ -835,7 +840,7 @@
 
 def UpdatePlayerServerGroupID(curPlayer):
     # 更新自己的服务器组ID, 跨服服务器不处理
-    if GameWorld.IsMergeServer():
+    if GameWorld.IsCrossServer():
         return
     serverGroupID = GameWorld.GetServerGroupID()
     if not serverGroupID:
@@ -3828,7 +3833,7 @@
     #复活冷却时间(秒)
     rebornTime = GetRebronTime(curPlayer, playerRebornType)    
     #冷却时间到了
-    if not CanRebornByTimeOver(curPlayer, rebornTime):
+    if playerRebornType != ChConfig.rebornType_System and not CanRebornByTimeOver(curPlayer, rebornTime):
         PlayerControl.NotifyCode(curPlayer, 'RebornCD')
         return False
     
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/CrossRealmPlayer.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/CrossRealmPlayer.py
new file mode 100644
index 0000000..dc048da
--- /dev/null
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/CrossRealmPlayer.py
@@ -0,0 +1,80 @@
+#!/usr/bin/python
+# -*- coding: GBK -*-
+#-------------------------------------------------------------------------------
+#
+##@package Player.CrossRealmPlayer
+#
+# @todo:跨服玩家
+# @author hxp
+# @date 2018-12-21
+# @version 1.0
+#
+# 详细描述: 跨服玩家
+#
+#-------------------------------------------------------------------------------
+#"""Version = 2018-12-21 18:00"""
+#-------------------------------------------------------------------------------
+import GameWorld
+import ReadChConfig
+import PlayerControl
+import IPY_GameWorld
+import ShareDefine
+import ChConfig
+import FBLogic
+
+# 获取玩家跨服服务器上的名字
+def GetCrossPlayerName(curPlayer):
+    # 通过游戏账号中的平台标志获取名称,目前为spid
+    playerName = curPlayer.GetPlayerName()
+    nameFormat = ReadChConfig.GetPyMongoConfig("Merge", "NameFormat", True)
+    if not nameFormat:
+        return playerName
+    
+    opName = ReadChConfig.GetPyMongoConfig("Merge", "OpName_%s" % GameWorld.GetPlayerPlatform(curPlayer))
+    
+    return (nameFormat%{"opname":opName, "sid":GameWorld.GetPlayerServerID(curPlayer)}).decode('gbk').encode(GameWorld.GetCharacterEncoding()) + playerName
+
+#// C1 04 主动退出跨服 #tagCMExitCrossRealm
+#
+#struct    tagCMExitCrossRealm
+#{
+#    tagHead        Head;
+#};
+def OnExitCrossRealm(index, curPackData, tick):
+    curPlayer = GameWorld.GetPlayerManager().GetPlayerByIndex(index)
+    
+    if not GameWorld.IsCrossServer():
+        return
+    
+    FBLogic.DoPlayerLeaveFB(curPlayer, tick)
+    
+    PlayerExitCrossServer(curPlayer)
+    return
+
+def PlayerExitCrossServer(curPlayer):
+    ## 玩家退出跨服服务器
+    
+    # 通知子服玩家退出跨服服务器
+    playerID = curPlayer.GetPlayerID()
+    serverGroupID = curPlayer.NomalDictGetProperty(ChConfig.Def_Player_Dict_ServerGroupID)
+    GameWorld.SendMsgToClientServer(ShareDefine.CrossServerMsg_ExitCrossServer, playerID, [serverGroupID])
+    
+    # 设置非跨服状态,踢下线
+    PlayerControl.SetCrossRealmState(curPlayer, 0)
+    curPlayer.Kick(IPY_GameWorld.disMapServerClose)
+    GameWorld.Log("PlayerExitCrossServer...", curPlayer.GetPlayerID())
+    return
+
+def DoEnterCrossRealm(curPlayer):
+    ## 玩家进入跨服处理,本服的逻辑处理
+    curPlayer.SetVisible(False)
+    return
+
+def DoExitCrossRealm(curPlayer):
+    ## 玩家退出跨服处理,本服的逻辑处理
+    GameWorld.Log("DoExitCrossRealm...", curPlayer.GetPlayerID())
+    curPlayer.SetVisible(True)
+    if PlayerControl.GetCrossRealmState(curPlayer):
+        PlayerControl.SetCrossRealmState(curPlayer, 0)
+        
+    return
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerControl.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerControl.py
index 327f133..16775d0 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerControl.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerControl.py
@@ -84,6 +84,7 @@
 import PlayerCostRebate
 import PlayerFairyCeremony
 import FunctionNPCCommon
+import CrossRealmPlayer
 import ChNetSendPack
 import PlayerState
 import QuestCommon
@@ -1498,6 +1499,11 @@
     if not curPlayer.NomalDictGetProperty(ChConfig.Def_Player_Dict_RouteServerInitOK):
         #RouteServer未初始化不允许切换地图, 缓存处理
         GameServerRefresh.Set_PlayerRouteServerInitOK_OnLeaveFB(curPlayer, 1)
+        return
+    
+    GameWorld.Log("PlayerLeaveFB...", curPlayer.GetPlayerID())
+    if GameWorld.IsCrossServer():
+        CrossRealmPlayer.PlayerExitCrossServer(curPlayer)
         return
 
     #中立地图回到上一次非中立常规地图    
@@ -5708,6 +5714,10 @@
 def SetFBFuncLineID(curPlayer, funcLineID): return curPlayer.SetExAttr3(funcLineID, False, False)
 def GetFBFuncLineID(curPlayer): return curPlayer.GetExAttr3()
 
+## 跨服状态: 0-非跨服状态,1-跨服状态
+def GetCrossRealmState(curPlayer): return curPlayer.GetExAttr5()
+def SetCrossRealmState(curPlayer, value): curPlayer.SetExAttr5(value, False, True)
+
 ## 铜钱点, 支持铜钱超20亿
 def GetSilver(curPlayer): return curPlayer.GetExAttr6() * ChConfig.Def_PerPointValue + curPlayer.GetSilver()
 def SetSilver(curPlayer, totalSilver):
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerCrossRealmPK.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerCrossRealmPK.py
new file mode 100644
index 0000000..a354518
--- /dev/null
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerCrossRealmPK.py
@@ -0,0 +1,229 @@
+#!/usr/bin/python
+# -*- coding: GBK -*-
+#-------------------------------------------------------------------------------
+#
+##@package Player.PlayerCrossRealmPK
+#
+# @todo:跨服PK竞技场
+# @author hxp
+# @date 2018-12-21
+# @version 1.0
+#
+# 详细描述: 跨服PK竞技场
+#
+#-------------------------------------------------------------------------------
+#"""Version = 2018-12-21 18:00"""
+#-------------------------------------------------------------------------------
+
+import ShareDefine
+import PlayerControl
+import CrossRealmPlayer
+import ChPyNetSendPack
+import NetPackCommon
+import GameWorld
+import ChConfig
+
+def DoPlayerOnDay(curPlayer):
+    totalScore = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_CrossPK_TotalScore)
+    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_CrossPK_OnDayScore, totalScore)
+    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_CrossPK_TodayPKCount, 0)
+    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_CrossPK_TodayBuyCount, 0)
+    return
+
+def IsCrossRealmPKOpen():
+    ## 跨服PK匹配赛是否开启
+    return 1
+    return GameWorld.GetGameWorld().GetGameWorldDictByKey(ShareDefine.Def_Notify_WorldKey_MergePKState) == ChConfig.Def_Action_Open
+
+def GetCrossPKZoneID():
+    ## 获取本服跨服PK所属赛区
+    return 1
+
+def GetSeasonID():
+    ## 获取当前赛季ID
+    return 1
+
+def IsCrossRealmPKSeasonOpen():
+    return True
+
+#// C1 01 跨服PK匹配 #tagCMCrossRealmPKMatch
+#
+#struct    tagCMCrossRealmPKMatch
+#{
+#    tagHead        Head;
+#    BYTE        Type;    // 0-取消匹配; 1-进行匹配
+#};
+def OnCrossRealmPKMatch(index, clientData, tick):
+    curPlayer = GameWorld.GetPlayerManager().GetPlayerByIndex(index)
+    accID = curPlayer.GetAccID()
+    playerID = curPlayer.GetPlayerID()
+    requestType = clientData.Type
+    
+    if GameWorld.IsCrossServer():
+        return
+        
+    if not IsCrossRealmPKOpen():
+        GameWorld.Log("OnRequestMergePK 跨服活动未开启,不可进行匹配!", playerID)
+        PlayerControl.NotifyCode(curPlayer, "GeRen_hgg_21675")
+        return
+    
+    GameWorld.Log("收到跨服PK匹配: type=%s,accID=%s" % (requestType, accID), playerID)
+    
+    # 进行匹配
+    if requestType == 1:
+#        pkCnt = __GetMergePKPDictValue(curPlayer, ChConfig.Def_PDict_MergePK_Cnt)
+#        buyCnt = __GetMergePKPDictValue(curPlayer, ChConfig.Def_PDict_MergePK_BuyCnt)
+#        unUsedBuyCnt = __GetMergePKPDictValue(curPlayer, ChConfig.Def_PDict_MergePK_UnUsedBuyCnt)
+#        freeCnt, maxBuyCnt, moneyType, buyCostFormat = ReadChConfig.GetEvalChConfig("MergePK_BuyCost")
+#        
+#        # 超出免费次数 且 无可用的已购买次数  则需购买次数
+#        if pkCnt >= freeCnt and unUsedBuyCnt <= 0:
+#            
+#            if buyCnt >= maxBuyCnt:
+#                GameWorld.Log("    已达到最大可购买PK次数,不可再买!:buyCnt=%s,maxBuyCnt=%s,pkCnt=%s,unUsedBuyCnt=%s" 
+#                              % (buyCnt, maxBuyCnt, pkCnt, unUsedBuyCnt), playerID)
+#                return
+#            
+#            buyCost = eval(buyCostFormat)
+#            infoDict = {"pkCnt":pkCnt, "freeCnt":freeCnt, "buyCnt":buyCnt, "buyCost":buyCost}
+#            if not PlayerControl.PayMoney(curPlayer, moneyType, buyCost, ChConfig.Def_Cost_BuyMergePKCnt, infoDict):
+#                return
+#            
+#            # 增加购买次数 及 未使用的购买次数
+#            __SetMergePKPDictValue(curPlayer, ChConfig.Def_PDict_MergePK_BuyCnt, buyCnt + 1)
+#            __SetMergePKPDictValue(curPlayer, ChConfig.Def_PDict_MergePK_UnUsedBuyCnt, unUsedBuyCnt + 1)
+#            Sync_MergePKCnt(curPlayer)
+#        
+#            GameWorld.Log("    购买PK次数消耗: pkCnt=%s,freeCnt=%s,buyCnt=%s,moneyType=%s,buyCost=%s" 
+#                              % (pkCnt, freeCnt, buyCnt, moneyType, buyCost), playerID)
+        
+        dataMsg = {
+                   "seasonID":GetSeasonID(), # 赛季ID
+                   "pkZoneID":GetCrossPKZoneID(), # PK赛区
+                   "accID":accID,
+                   "playerID":playerID,
+                   "playerName":CrossRealmPlayer.GetCrossPlayerName(curPlayer),
+                   "playerJob":curPlayer.GetJob(),
+                   "playerLV":curPlayer.GetLV(),
+                   "maxHP":curPlayer.GetMaxHP(),
+                   "fightPower":curPlayer.GetFightPower(),
+                   "pkScore":curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_CrossPK_TotalScore), # 当前积分
+                   "danLV":1, #curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_CrossPK_DanLV), # 当前段位
+                   "cWinCount":curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_CrossPK_CWinCount), # 连胜次数
+                   "ondayScore":curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_CrossPK_OnDayScore), # 过天时的积分
+                   }
+        GameWorld.SendMsgToCrossServer(ShareDefine.ClientServerMsg_PKMatch, dataMsg)
+        GameWorld.Log("    发送请求匹配到跨服服务器 dataMsg=%s" % str(dataMsg), playerID)
+        
+    # 取消匹配
+    else:
+        sendMsg = "Client Cancel!"
+        GameWorld.GetPlayerManager().GameServer_QueryPlayerResult(playerID, 0, 0, "CrossRealmPKCancel", sendMsg, len(sendMsg))
+        GameWorld.Log("    发送取消匹配到GameServer sendMsg=%s" % str(sendMsg), playerID)
+        
+    return
+
+def CrossServerMsg_PKOverInfo(curPlayer, overInfo):
+    ## 收到跨服服务器的PK结算信息
+    playerID = curPlayer.GetPlayerID()
+    roomID, seasonID, timeStr, overType, winnerID, roundWinnerIDList, pkScore, danLV, cWinCount, addScore, tagPlayerID, tagPlayerName, notifyState = overInfo
+    isWinner = winnerID == playerID
+    GameWorld.Log("地图收到跨服PK结算: isWinner=%s,roomID=%s,seasonID=%s,timeStr=%s,overType=%s,winnerID=%s,roundWinnerIDList=%s,pkScore=%s,danLV=%s,cWinCount=%s,addScore=%s,tagPlayerID=%s,notifyState=%s" 
+                  % (isWinner, roomID, seasonID, timeStr, overType, winnerID, roundWinnerIDList, pkScore, danLV, cWinCount, addScore, tagPlayerID, notifyState), playerID)
+    curSeasonID = GetSeasonID()
+    if curSeasonID != seasonID:
+        GameWorld.Log("    非本赛季的结算信息,不处理!curSeasonID=%s,seasonID=%s" % (curSeasonID, seasonID), playerID)
+        return
+    
+    # 赛季是否已结算
+    if not IsCrossRealmPKSeasonOpen():
+        GameWorld.Log("    赛季已经结算过了,不处理!seasonID=%s" % (seasonID), playerID)
+        return
+    
+    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_CrossPK_TotalScore, pkScore)
+    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_CrossPK_DanLV, danLV)
+    
+    pkCount = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_CrossPK_PKCount) + 1
+    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_CrossPK_PKCount, pkCount)
+    if isWinner:
+        winCount = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_CrossPK_WinCount) + 1
+        PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_CrossPK_WinCount, winCount)
+        PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_CrossPK_CWinCount, cWinCount)
+    else:
+        PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_CrossPK_CWinCount, 0)
+    
+    # 同一天的话增加当日PK次数
+    if GameWorld.CheckTimeIsSameServerDayEx(GameWorld.ChangeTimeStrToNum(timeStr)):
+        todayPKCount = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_CrossPK_TodayPKCount) + 1
+        PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_CrossPK_TodayPKCount, todayPKCount)
+        
+    ## 跨服已经通知过了,证明还在跨服服务器,不做以下的处理
+    if notifyState:
+        return
+    
+    overPack = ChPyNetSendPack.tagGCCrossRealmPKOverInfo()
+    overPack.TimeStr = timeStr
+    overPack.OverType = overType
+    overPack.WinnerID = winnerID
+    overPack.RoundWinnerID = roundWinnerIDList
+    overPack.RoundCount = len(overPack.RoundWinnerID)
+    overPack.AddScore = addScore
+    overPack.Score = pkScore
+    overPack.DanLV = danLV
+    overPack.CWinCnt = cWinCount
+    overPack.TagName = tagPlayerName
+    overPack.TagNameLen = len(overPack.TagName)
+    NetPackCommon.SendFakePack(curPlayer, overPack)
+    return
+
+
+#// C1 02 跨服PK购买次数 #tagCMCrossRealmPKBuy
+#
+#struct    tagCMCrossRealmPKBuy
+#{
+#    tagHead        Head;
+#};
+def OnCrossRealmPKBuy(index, clientData, tick):
+    curPlayer = GameWorld.GetPlayerManager().GetPlayerByIndex(index)
+    
+    return
+
+
+#// C1 03 跨服PK领取奖励 #tagCMCrossRealmPKGetAward
+#
+#struct    tagCMCrossRealmPKGetAward
+#{
+#    tagHead        Head;
+#    BYTE        AwardType;    // 奖励类型;1-每日匹配奖励,2-每日胜利奖励,3-段位达标奖励,4-赛季结算奖励
+#    BYTE        AwardData;    // 奖励类型对应领取值;每日匹配奖励时为匹配次数,每日胜利奖励时为胜利次数,段位达标奖励时为领取的段位
+#};
+def OnCrossRealmPKGetAward(index, clientData, tick):
+    curPlayer = GameWorld.GetPlayerManager().GetPlayerByIndex(index)
+    
+    return
+
+
+def SyncCrossRealmPKPlayerInfo(curPlayer):
+#    DWORD        Score;    // 当前积分
+#    BYTE        DanLV;    // 当前段位
+#    WORD        PKCount;    // PK次数
+#    WORD        WinCount;    // 胜利次数
+#    WORD        CWinCount;    // 连胜次数
+#    BYTE        DayPKCount;    // 当日已PK次数
+#    BYTE        DayWinCount;    // 当日已胜利次数
+#    BYTE        DayBuyCount; // 当日已购买次数
+    pkPlayerInfo = ChPyNetSendPack.tagMCCrossRealmPKPlayerInfo()
+    pkPlayerInfo.Score = 0
+    pkPlayerInfo.DanLV = 0
+    return
+    
+def SyncCrossRealmPKAwardState(curPlayer):
+#    DWORD        DayPKCountAwardState;    // 每日匹配次数奖励记录,二进制位存储是否已领取,按匹配次数升序排序索引代表奖励位
+#    DWORD        DayWinCountAwardState;    // 每日胜利次数奖励记录,二进制位存储是否已领取,按胜利次数升序排序索引代表奖励位
+#    DWORD        DanLVAwardState;        // 段位达标奖励记录,二进制位存储是否已领取,按段位代表奖励位
+#    BYTE        SeasonAwardState;    // 赛季结算奖励是否已领取
+    return
+
+
+
+
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerEventCounter.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerEventCounter.py
index f38e738..89b4bae 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerEventCounter.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerEventCounter.py
@@ -73,6 +73,7 @@
 import PlayerNewGuyCard
 import PlayerMergeKing
 import PlayerMergePK
+import PlayerCrossRealmPK
 import PlayerPet
 import ReloadModule
 import BossHurtMng
@@ -548,6 +549,8 @@
         NPCCommon.CollNPCTimeOnDay(curPlayer)
         #副本助战
         FBHelpBattle.DoPlayerOnDay(curPlayer)
+        #跨服竞技场
+        PlayerCrossRealmPK.DoPlayerOnDay(curPlayer)
         
     PlayerTJG.TJGOnDay(curPlayer, onEventType)
     # 以下为支持两种重置模式切换配置的
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/RemoteQuery/GY_Query_CrossPKOverInfo.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/RemoteQuery/GY_Query_CrossPKOverInfo.py
new file mode 100644
index 0000000..127c5d2
--- /dev/null
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/RemoteQuery/GY_Query_CrossPKOverInfo.py
@@ -0,0 +1,50 @@
+#!/usr/bin/python
+# -*- coding: GBK -*-
+#-------------------------------------------------------------------------------
+#
+##@package Player.RemoteQuery.GY_Query_CrossPKOverInfo
+#
+# @todo:跨服PK结果同步
+# @author hxp
+# @date 2018-12-21
+# @version 1.0
+#
+# 详细描述: 跨服PK结果同步
+#
+#-------------------------------------------------------------------------------
+#"""Version = 2018-12-21 18:00"""
+#-------------------------------------------------------------------------------
+
+import GameWorld
+import PlayerCrossRealmPK
+
+
+#------------------------------------------------------------------------------ 
+## 跨服赛报名调用接口
+#  @param query_Type 请求类型
+#  @param query_ID 请求的玩家ID
+#  @param packCMDList 发包命令
+#  @param tick 当前时间
+#  @return "True" or "False" or ""
+#  @remarks 函数详细说明.
+def DoLogic(query_Type, query_ID, packCMDList, tick): 
+    return
+
+
+#------------------------------------------------------------------------------ 
+## 执行结果
+#  @param curPlayer 发出请求的玩家
+#  @param callFunName 功能名称
+#  @param funResult 查询的结果
+#  @param tick 当前时间
+#  @return None
+#  @remarks 函数详细说明.
+def DoResult(curPlayer, callFunName, funResult, tick):
+    overInfo = eval(funResult)
+    playerID = curPlayer.GetPlayerID()
+    GameWorld.Log("GY_Query_CrossPKOverInfo overInfo=%s" % (overInfo), playerID)
+    PlayerCrossRealmPK.CrossServerMsg_PKOverInfo(curPlayer, overInfo)
+    return
+    
+    
+    
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/RemoteQuery/GY_Query_CrossRealmReg.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/RemoteQuery/GY_Query_CrossRealmReg.py
new file mode 100644
index 0000000..b4d8357
--- /dev/null
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/RemoteQuery/GY_Query_CrossRealmReg.py
@@ -0,0 +1,94 @@
+#!/usr/bin/python
+# -*- coding: GBK -*-
+#-------------------------------------------------------------------------------
+#
+##@package Player.RemoteQuery.GY_Query_CrossRealmReg
+#
+# @todo:跨服活动玩家注册
+# @author hxp
+# @date 2018-12-21
+# @version 1.0
+#
+# 详细描述: 跨服活动玩家注册
+#
+#-------------------------------------------------------------------------------
+#"""Version = 2018-12-21 18:00"""
+#-------------------------------------------------------------------------------
+
+import GameWorld
+import CrossRealmPlayer
+import IPY_GameWorld
+import ChPlayer
+
+
+#------------------------------------------------------------------------------ 
+## 跨服赛报名调用接口
+#  @param query_Type 请求类型
+#  @param query_ID 请求的玩家ID
+#  @param packCMDList 发包命令
+#  @param tick 当前时间
+#  @return "True" or "False" or ""
+#  @remarks 函数详细说明.
+def DoLogic(query_Type, query_ID, packCMDList, tick): 
+    return
+
+
+#------------------------------------------------------------------------------ 
+## 执行结果
+#  @param curPlayer 发出请求的玩家
+#  @param callFunName 功能名称
+#  @param funResult 查询的结果
+#  @param tick 当前时间
+#  @return None
+#  @remarks 函数详细说明.
+def DoResult(curPlayer, callFunName, funResult, tick):
+    resultInfo = eval(funResult)
+    actionType = resultInfo[0]
+    mapPosInfo = resultInfo[1:]
+    if not curPlayer:
+        return
+    
+    playerID = curPlayer.GetPlayerID()
+    GameWorld.Log("GY_Query_CrossRealmReg DoResult %s" % funResult, playerID)
+
+    if GameWorld.IsMergeServer():
+        GameWorld.Log("    跨服服务器不允许上传报名数据!", playerID)
+        return
+    
+    if not mapPosInfo:
+        return
+    
+    #跨服前更新自己所属服务器组ID
+    ChPlayer.UpdatePlayerServerGroupID(curPlayer)
+    
+    mapID, dataMapID, copyMapID, posX, posY = mapPosInfo
+    #curPlayer.SendMergeRegisterPlayer(mapID, dataMapID, copyMapID, posX, posY)
+    curPlayer.SendMergeRegisterPlayerAfterChange(CrossRealmPlayer.GetCrossPlayerName(curPlayer), mapID, dataMapID, copyMapID, posX, posY)
+    GameWorld.Log("    发送跨服玩家数据注册: actionType=%s,mapID=%s,dataMapID=%s,copyMapID=%s,posX=%s,posY=%s,GetVsRoomId=%s" 
+                  % (actionType, mapID, dataMapID, copyMapID, posX, posY, curPlayer.GetVsRoomId()), playerID)
+    return
+
+## 跨服赛报名结果(上传数据)
+#  @param index 玩家索引
+#  @param tick 当前时间
+#  @return None
+def GameServer_MergeRegisterResult(index, tick):
+    registerResult = IPY_GameWorld.IPY_GMMergeRegisterPlayerResult()
+    curPlayer = GameWorld.GetPlayerManager().GetPlayerByIndex(index)
+    playerID = curPlayer.GetPlayerID()
+    result = registerResult.GetResult()
+    if not result:
+        errorMsg = registerResult.GetErrorMsg()
+        GameWorld.Log("CrossRealmReg result Error:%s" % errorMsg, playerID)
+        return
+    
+    #newAccount = registerResult.GetAccount()
+    #newName = registerResult.GetPwd()
+    
+    msgList = str([]) 
+    GameWorld.GetPlayerManager().GameServer_QueryPlayerResult(curPlayer.GetID(), 0, 0, "CrossRealmReg", msgList, len(msgList))    
+    GameWorld.Log("GameServer_MergeRegisterResult msgList=%s" % msgList, playerID)
+    return
+    
+    
+    
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/RemoteQuery/GY_Query_SetPlayerAttr.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/RemoteQuery/GY_Query_SetPlayerAttr.py
new file mode 100644
index 0000000..d579639
--- /dev/null
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/RemoteQuery/GY_Query_SetPlayerAttr.py
@@ -0,0 +1,59 @@
+#!/usr/bin/python
+# -*- coding: GBK -*-
+#-------------------------------------------------------------------------------
+#
+##@package Player.RemoteQuery.GY_Query_SetPlayerAttr
+#
+# @todo:设置玩家属性
+# @author hxp
+# @date 2018-12-21
+# @version 1.0
+#
+# 详细描述: 设置玩家属性
+#
+#-------------------------------------------------------------------------------
+#"""Version = 2018-12-21 18:00"""
+#-------------------------------------------------------------------------------
+
+import GameWorld
+import PlayerControl
+import CrossRealmPlayer
+
+## 执行结果
+#  @param curPlayer 发出请求的玩家
+#  @param callFunName 功能名称
+#  @param funResult 查询的结果
+#  @param tick 当前时间
+#  @return None
+#  @remarks 函数详细说明.
+def DoResult(curPlayer, callFunName, funResult, tick):
+    if not funResult:
+        return
+    setInfo = eval(funResult)
+    if not isinstance(setInfo, list) or len(setInfo) < 2:
+        return
+    
+    attrName, value = setInfo[:2]
+    if hasattr(curPlayer, attrName):
+        # 要在更新值之前处理
+        if attrName == "SetExAttr5":
+            if value:
+                CrossRealmPlayer.DoEnterCrossRealm(curPlayer)
+            elif PlayerControl.GetCrossRealmState(curPlayer):
+                CrossRealmPlayer.DoExitCrossRealm(curPlayer)
+                
+        callObj = getattr(curPlayer, attrName)
+        callObj(value)
+        GameWorld.Log("SetPlayerAttr curPlayer.%s, value=%s" % (attrName, value), curPlayer.GetPlayerID())
+        
+    elif hasattr(PlayerControl, attrName):
+        callObj = getattr(PlayerControl, attrName)
+        callObj(curPlayer, value)
+        GameWorld.Log("SetPlayerAttr PlayerControl.%s, value=%s" % (attrName, value), curPlayer.GetPlayerID())
+        
+    return 
+
+
+
+
+
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/ServerScript.ini b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/ServerScript.ini
index 4a60daf..14ded03 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/ServerScript.ini
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/ServerScript.ini
@@ -174,9 +174,9 @@
 PacketCallFunc_1=GameSever_PlayerCountByCountry
 
 [PlayerMergeWar]
-ScriptName = Player\RemoteQuery\GY_Query_MergeWarRegister.py
-Writer = wdb
-Releaser = wdb
+ScriptName = Player\RemoteQuery\GY_Query_CrossRealmReg.py
+Writer = hxp
+Releaser = hxp
 RegType = 0
 RegisterPackCount = 1
 PacketCMD_1=0x9

--
Gitblit v1.8.0