From 4bcef0ba119712bcd00064516062480f4b46bb51 Mon Sep 17 00:00:00 2001
From: hxp <ale99527@vip.qq.com>
Date: 星期五, 23 九月 2022 14:22:33 +0800
Subject: [PATCH] 9701 【后端】【越南】【BT7】【主干】跨服竞技64位排位赛(初版)

---
 ServerPython/CoreServerGroup/GameServer/Script/IpyGameDataPY.py                                                             |   92 
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorldLogic/FBLogic.py                               |    3 
 ServerPython/CoreServerGroup/GameServer/Script/GM/Commands/Championship.py                                                  |  251 +
 ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/CrossChampionship.py                                          | 2971 +++++++++++++++++++++
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerCrossChampionship.py                       |  240 +
 ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerFB.py                                                           |   61 
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetPack.py                                          |  484 +++
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetSendPack.py                                      | 1391 ++++++++++
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GM/Commands/SetMoney.py                                 |    2 
 ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerEventCounter.py                                                 |    5 
 ServerPython/CoreServerGroup/GameServer/Script/ChPyNetPack.py                                                               |  484 +++
 ServerPython/CoreServerGroup/GameServer/Script/ChPyNetSendPack.py                                                           | 1391 ++++++++++
 ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerDBGSEvent.py                                                    |    6 
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/RemoteQuery/GY_Query_Championship.py             |   51 
 ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerViewCache.py                                                    |   13 
 ServerPython/CoreServerGroup/GameServer/Script/ChConfig.py                                                                  |   13 
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/ChPlayer.py                                      |    2 
 ServerPython/CoreServerGroup/GameServer/PyNetPack.ini                                                                       |   23 
 ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerQuery.py                                                        |    6 
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/CrossRealmPlayer.py                              |   11 
 ServerPython/CoreServerGroup/GameServer/Script/Player/ChPlayer.py                                                           |    3 
 ServerPython/CoreServerGroup/GameServer/Script/Player/CrossRealmPlayer.py                                                   |    3 
 ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/CrossRealmMsg.py                                              |   44 
 ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/GameWorldProcess.py                                           |    6 
 ServerPython/CoreServerGroup/GameServer/Script/PyGameData.py                                                                |    2 
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/PyNetPack.ini                                                  |   24 
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorldLogic/FBProcess/GameLogic_CrossChampionship.py |  581 ++++
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/RemoteQuery/GY_Query_OpenFBEx.py                 |   71 
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerEventCounter.py                            |    3 
 PySysDB/PySysDBG.h                                                                                                          |   36 
 30 files changed, 8,267 insertions(+), 6 deletions(-)

diff --git a/PySysDB/PySysDBG.h b/PySysDB/PySysDBG.h
index 26ad42b..2421f8a 100644
--- a/PySysDB/PySysDBG.h
+++ b/PySysDB/PySysDBG.h
@@ -760,13 +760,47 @@
 	list		ServerGroupIDList;	//赛区服务器组ID列表
 };
 
+//跨服排位赛流程表
+
+struct tagChampionshipTime
+{
+	DWORD		_ID;
+	BYTE		StartDay;	//开始天
+	BYTE		StartHour;	//开始时
+	BYTE		StartMinute;	//开始分
+	BYTE		EndDay;	//结束天
+	BYTE		EndHour;	//结束时
+	BYTE		EndMinute;	//结束分
+	WORD		StateValue;	//状态值
+	dict		NotifyInfo;	//广播提示信息
+};
+
+//跨服排位奖励表
+
+struct tagChampionshipRank
+{
+	BYTE		_Rank;	// 名次
+	list		RankAwardItemList;	//名次奖励物品列表
+	WORD		MainOfficialID;	//主官职ID
+};
+
+//跨服排位官职表
+
+struct tagChampionshipOfficial
+{
+	WORD		_OfficialID;	// 官职ID
+	list		JuniorOfficialIDList;	//下级官职ID列表
+	list		DailyAwardItemList;	//官职每日邮件奖励物品列表
+	BYTE		CanBeReplace;	//是否可被挑战替换
+};
+
 //跨服竞技场赛季表
 
 struct tagCrossRealmPKSeason
 {
 	char		_CrossZoneName;	//跨服分区名
 	BYTE		_ZoneID;	//赛区ID
-	BYTE		SeasonID;	//赛季ID
+	WORD		SeasonID;	//赛季ID
 	char		StartDate;	//开始日期	yyyy-MM-dd
 	char		EndDate;	//结束日期	yyyy-MM-dd
 	char		EndTime;	//结算时间	hh:mm
diff --git a/ServerPython/CoreServerGroup/GameServer/PyNetPack.ini b/ServerPython/CoreServerGroup/GameServer/PyNetPack.ini
index fcb48c2..cfc70b8 100644
--- a/ServerPython/CoreServerGroup/GameServer/PyNetPack.ini
+++ b/ServerPython/CoreServerGroup/GameServer/PyNetPack.ini
@@ -383,6 +383,29 @@
 PacketSubCMD_3=0x09
 PacketCallFunc_3=OnCrossBattlefieldCallChange
 
+[CrossChampionship]
+ScriptName = GameWorldLogic\CrossChampionship.py
+Writer = hxp
+Releaser = hxp
+RegType = 0
+RegisterPackCount = 4
+
+PacketCMD_1=0xC0
+PacketSubCMD_1=0x21
+PacketCallFunc_1=OnChampionshipOfficialApplyReply
+
+PacketCMD_2=0xC0
+PacketSubCMD_2=0x23
+PacketCallFunc_2=OnChampionshipOfficialChallengeQuery
+
+PacketCMD_3=0xC0
+PacketSubCMD_3=0x24
+PacketCallFunc_3=OnChampionshipOfficialKick
+
+PacketCMD_4=0xC0
+PacketSubCMD_4=0x25
+PacketCallFunc_4=OnChampionshipOfficialLeave
+
 [CrossRealmPK]
 ScriptName = GameWorldLogic\CrossRealmPK.py
 Writer = hxp
diff --git a/ServerPython/CoreServerGroup/GameServer/Script/ChConfig.py b/ServerPython/CoreServerGroup/GameServer/Script/ChConfig.py
index 8b8846e..ff8dcbe 100644
--- a/ServerPython/CoreServerGroup/GameServer/Script/ChConfig.py
+++ b/ServerPython/CoreServerGroup/GameServer/Script/ChConfig.py
@@ -688,6 +688,8 @@
 Def_FBMapID_QueenRelics = 51010
 #跨服竞技场
 Def_FBMapID_CrossRealmPK = 32010
+#跨服排位
+Def_FBMapID_CrossChampionship = 32070
 #跨服蓬莱仙境
 Def_FBMapID_CrossPenglai = 32020
 #跨服魔化之地
@@ -720,6 +722,7 @@
                          Def_FBMapID_CrossGrasslandLing:"CrossZonePK",
                          Def_FBMapID_CrossGrasslandXian:"CrossZonePK",
                          Def_FBMapID_CrossBattlefield:"CrossZonePK",
+                         Def_FBMapID_CrossChampionship:"CrossZonePK",
                          }
 #跨服分区对应地图配置表名 - 仅适用于固定地图及虚拟分线的跨服玩法
 Def_CrossZoneMapTableName = {Def_FBMapID_CrossPenglai:"CrossPenglaiZoneMap",
@@ -860,3 +863,13 @@
 Def_GiveMoney_AuctionBidReturn, #拍卖竞价返还
 Def_GiveMoney_AuctionGain, #拍卖获得利润
 ) = range(1000, 1000 + 29)
+
+Def_ItemID_GoldMoney = 20               # 直接给仙玉
+Def_ItemID_GoldPaper = 30               # 直接给绑玉/灵石
+Def_ItemID_SilverPaper = 500               # 直接给金票物品
+# 货币类型对应直接给货币物品ID
+MoneyItemIDDict = {IPY_GameServer.TYPE_Price_Gold_Money:Def_ItemID_GoldMoney,
+                   IPY_GameServer.TYPE_Price_Gold_Paper:Def_ItemID_GoldPaper,
+                   IPY_GameServer.TYPE_Price_Silver_Paper:Def_ItemID_SilverPaper,
+                   }
+
diff --git a/ServerPython/CoreServerGroup/GameServer/Script/ChPyNetPack.py b/ServerPython/CoreServerGroup/GameServer/Script/ChPyNetPack.py
index 0482b74..f894f03 100644
--- a/ServerPython/CoreServerGroup/GameServer/Script/ChPyNetPack.py
+++ b/ServerPython/CoreServerGroup/GameServer/Script/ChPyNetPack.py
@@ -3987,6 +3987,242 @@
 
 
 #------------------------------------------------------
+# C0 21 跨服排位仙官申请回应 #tagCGChampionshipOfficialApplyReply
+
+class  tagCGChampionshipOfficialApplyReply(Structure):
+    _pack_ = 1
+    _fields_ = [
+                  ("Cmd", c_ubyte),
+                  ("SubCmd", c_ubyte),
+                  ("MainOfficialID", c_ushort),    #界主官职ID
+                  ("OfficialID", c_ushort),    #申请官职ID
+                  ("PlayerID", c_int),    #申请的玩家ID
+                  ("IsOK", c_ubyte),    #是否同意;1-是;0-否
+                  ]
+
+    def __init__(self):
+        self.Clear()
+        self.Cmd = 0xC0
+        self.SubCmd = 0x21
+        return
+
+    def ReadData(self, stringData, _pos=0, _len=0):
+        self.Clear()
+        memmove(addressof(self), stringData[_pos:], self.GetLength())
+        return _pos + self.GetLength()
+
+    def Clear(self):
+        self.Cmd = 0xC0
+        self.SubCmd = 0x21
+        self.MainOfficialID = 0
+        self.OfficialID = 0
+        self.PlayerID = 0
+        self.IsOK = 0
+        return
+
+    def GetLength(self):
+        return sizeof(tagCGChampionshipOfficialApplyReply)
+
+    def GetBuffer(self):
+        return string_at(addressof(self), self.GetLength())
+
+    def OutputString(self):
+        DumpString = '''// C0 21 跨服排位仙官申请回应 //tagCGChampionshipOfficialApplyReply:
+                                Cmd:%s,
+                                SubCmd:%s,
+                                MainOfficialID:%d,
+                                OfficialID:%d,
+                                PlayerID:%d,
+                                IsOK:%d
+                                '''\
+                                %(
+                                self.Cmd,
+                                self.SubCmd,
+                                self.MainOfficialID,
+                                self.OfficialID,
+                                self.PlayerID,
+                                self.IsOK
+                                )
+        return DumpString
+
+
+m_NAtagCGChampionshipOfficialApplyReply=tagCGChampionshipOfficialApplyReply()
+ChNetPackDict[eval("0x%02x%02x"%(m_NAtagCGChampionshipOfficialApplyReply.Cmd,m_NAtagCGChampionshipOfficialApplyReply.SubCmd))] = m_NAtagCGChampionshipOfficialApplyReply
+
+
+#------------------------------------------------------
+# C0 23 跨服排位仙官挑战记录查询 #tagCGChampionshipOfficialChallengeQuery
+
+class  tagCGChampionshipOfficialChallengeQuery(Structure):
+    _pack_ = 1
+    _fields_ = [
+                  ("Cmd", c_ubyte),
+                  ("SubCmd", c_ubyte),
+                  ("MainOfficialID", c_ushort),    #界主官职ID
+                  ("OfficialID", c_ushort),    #查询官职ID
+                  ]
+
+    def __init__(self):
+        self.Clear()
+        self.Cmd = 0xC0
+        self.SubCmd = 0x23
+        return
+
+    def ReadData(self, stringData, _pos=0, _len=0):
+        self.Clear()
+        memmove(addressof(self), stringData[_pos:], self.GetLength())
+        return _pos + self.GetLength()
+
+    def Clear(self):
+        self.Cmd = 0xC0
+        self.SubCmd = 0x23
+        self.MainOfficialID = 0
+        self.OfficialID = 0
+        return
+
+    def GetLength(self):
+        return sizeof(tagCGChampionshipOfficialChallengeQuery)
+
+    def GetBuffer(self):
+        return string_at(addressof(self), self.GetLength())
+
+    def OutputString(self):
+        DumpString = '''// C0 23 跨服排位仙官挑战记录查询 //tagCGChampionshipOfficialChallengeQuery:
+                                Cmd:%s,
+                                SubCmd:%s,
+                                MainOfficialID:%d,
+                                OfficialID:%d
+                                '''\
+                                %(
+                                self.Cmd,
+                                self.SubCmd,
+                                self.MainOfficialID,
+                                self.OfficialID
+                                )
+        return DumpString
+
+
+m_NAtagCGChampionshipOfficialChallengeQuery=tagCGChampionshipOfficialChallengeQuery()
+ChNetPackDict[eval("0x%02x%02x"%(m_NAtagCGChampionshipOfficialChallengeQuery.Cmd,m_NAtagCGChampionshipOfficialChallengeQuery.SubCmd))] = m_NAtagCGChampionshipOfficialChallengeQuery
+
+
+#------------------------------------------------------
+# C0 24 跨服排位辞退下级仙官 #tagCGChampionshipOfficialKick
+
+class  tagCGChampionshipOfficialKick(Structure):
+    _pack_ = 1
+    _fields_ = [
+                  ("Cmd", c_ubyte),
+                  ("SubCmd", c_ubyte),
+                  ("MainOfficialID", c_ushort),    #界主官职ID
+                  ("OfficialID", c_ushort),    #目标官职ID
+                  ("PlayerID", c_int),    #目标玩家ID
+                  ]
+
+    def __init__(self):
+        self.Clear()
+        self.Cmd = 0xC0
+        self.SubCmd = 0x24
+        return
+
+    def ReadData(self, stringData, _pos=0, _len=0):
+        self.Clear()
+        memmove(addressof(self), stringData[_pos:], self.GetLength())
+        return _pos + self.GetLength()
+
+    def Clear(self):
+        self.Cmd = 0xC0
+        self.SubCmd = 0x24
+        self.MainOfficialID = 0
+        self.OfficialID = 0
+        self.PlayerID = 0
+        return
+
+    def GetLength(self):
+        return sizeof(tagCGChampionshipOfficialKick)
+
+    def GetBuffer(self):
+        return string_at(addressof(self), self.GetLength())
+
+    def OutputString(self):
+        DumpString = '''// C0 24 跨服排位辞退下级仙官 //tagCGChampionshipOfficialKick:
+                                Cmd:%s,
+                                SubCmd:%s,
+                                MainOfficialID:%d,
+                                OfficialID:%d,
+                                PlayerID:%d
+                                '''\
+                                %(
+                                self.Cmd,
+                                self.SubCmd,
+                                self.MainOfficialID,
+                                self.OfficialID,
+                                self.PlayerID
+                                )
+        return DumpString
+
+
+m_NAtagCGChampionshipOfficialKick=tagCGChampionshipOfficialKick()
+ChNetPackDict[eval("0x%02x%02x"%(m_NAtagCGChampionshipOfficialKick.Cmd,m_NAtagCGChampionshipOfficialKick.SubCmd))] = m_NAtagCGChampionshipOfficialKick
+
+
+#------------------------------------------------------
+# C0 25 跨服排位主动离任仙官 #tagCGChampionshipOfficialLeave
+
+class  tagCGChampionshipOfficialLeave(Structure):
+    _pack_ = 1
+    _fields_ = [
+                  ("Cmd", c_ubyte),
+                  ("SubCmd", c_ubyte),
+                  ("MainOfficialID", c_ushort),    #界主官职ID
+                  ("OfficialID", c_ushort),    #离任官职ID
+                  ]
+
+    def __init__(self):
+        self.Clear()
+        self.Cmd = 0xC0
+        self.SubCmd = 0x25
+        return
+
+    def ReadData(self, stringData, _pos=0, _len=0):
+        self.Clear()
+        memmove(addressof(self), stringData[_pos:], self.GetLength())
+        return _pos + self.GetLength()
+
+    def Clear(self):
+        self.Cmd = 0xC0
+        self.SubCmd = 0x25
+        self.MainOfficialID = 0
+        self.OfficialID = 0
+        return
+
+    def GetLength(self):
+        return sizeof(tagCGChampionshipOfficialLeave)
+
+    def GetBuffer(self):
+        return string_at(addressof(self), self.GetLength())
+
+    def OutputString(self):
+        DumpString = '''// C0 25 跨服排位主动离任仙官 //tagCGChampionshipOfficialLeave:
+                                Cmd:%s,
+                                SubCmd:%s,
+                                MainOfficialID:%d,
+                                OfficialID:%d
+                                '''\
+                                %(
+                                self.Cmd,
+                                self.SubCmd,
+                                self.MainOfficialID,
+                                self.OfficialID
+                                )
+        return DumpString
+
+
+m_NAtagCGChampionshipOfficialLeave=tagCGChampionshipOfficialLeave()
+ChNetPackDict[eval("0x%02x%02x"%(m_NAtagCGChampionshipOfficialLeave.Cmd,m_NAtagCGChampionshipOfficialLeave.SubCmd))] = m_NAtagCGChampionshipOfficialLeave
+
+
+#------------------------------------------------------
 # C0 09 跨服战场召集场次修改 #tagCGCrossBattlefieldCallChange
 
 class  tagCGCrossBattlefieldCallChange(Structure):
@@ -19225,6 +19461,254 @@
 
 
 #------------------------------------------------------
+# C1 22 跨服排位竞猜 #tagCMChampionshipGuess
+
+class  tagCMChampionshipGuess(Structure):
+    _pack_ = 1
+    _fields_ = [
+                  ("Cmd", c_ubyte),
+                  ("SubCmd", c_ubyte),
+                  ("ZoneID", c_ubyte),    #排位数据分区ID
+                  ("GuessType", c_ubyte),    #竞猜类型 8-8强;4-4强排位
+                  ("PlayerID", c_int),    #目标玩家ID
+                  ("GuessCount", c_ubyte),    #投注/追加份数
+                  ("GuessRank", c_ubyte),    # 竞猜名次,没有名次的竞猜默认0;1-代表第一名
+                  ]
+
+    def __init__(self):
+        self.Clear()
+        self.Cmd = 0xC1
+        self.SubCmd = 0x22
+        return
+
+    def ReadData(self, stringData, _pos=0, _len=0):
+        self.Clear()
+        memmove(addressof(self), stringData[_pos:], self.GetLength())
+        return _pos + self.GetLength()
+
+    def Clear(self):
+        self.Cmd = 0xC1
+        self.SubCmd = 0x22
+        self.ZoneID = 0
+        self.GuessType = 0
+        self.PlayerID = 0
+        self.GuessCount = 0
+        self.GuessRank = 0
+        return
+
+    def GetLength(self):
+        return sizeof(tagCMChampionshipGuess)
+
+    def GetBuffer(self):
+        return string_at(addressof(self), self.GetLength())
+
+    def OutputString(self):
+        DumpString = '''// C1 22 跨服排位竞猜 //tagCMChampionshipGuess:
+                                Cmd:%s,
+                                SubCmd:%s,
+                                ZoneID:%d,
+                                GuessType:%d,
+                                PlayerID:%d,
+                                GuessCount:%d,
+                                GuessRank:%d
+                                '''\
+                                %(
+                                self.Cmd,
+                                self.SubCmd,
+                                self.ZoneID,
+                                self.GuessType,
+                                self.PlayerID,
+                                self.GuessCount,
+                                self.GuessRank
+                                )
+        return DumpString
+
+
+m_NAtagCMChampionshipGuess=tagCMChampionshipGuess()
+ChNetPackDict[eval("0x%02x%02x"%(m_NAtagCMChampionshipGuess.Cmd,m_NAtagCMChampionshipGuess.SubCmd))] = m_NAtagCMChampionshipGuess
+
+
+#------------------------------------------------------
+# C1 20 跨服排位仙官申请 #tagCMChampionshipOfficialApply
+
+class  tagCMChampionshipOfficialApply(Structure):
+    _pack_ = 1
+    _fields_ = [
+                  ("Cmd", c_ubyte),
+                  ("SubCmd", c_ubyte),
+                  ("ZoneID", c_ubyte),    #仙官数据分区ID
+                  ("MainOfficialID", c_ushort),    #界主官职ID
+                  ("OfficialID", c_ushort),    #申请官职ID
+                  ]
+
+    def __init__(self):
+        self.Clear()
+        self.Cmd = 0xC1
+        self.SubCmd = 0x20
+        return
+
+    def ReadData(self, stringData, _pos=0, _len=0):
+        self.Clear()
+        memmove(addressof(self), stringData[_pos:], self.GetLength())
+        return _pos + self.GetLength()
+
+    def Clear(self):
+        self.Cmd = 0xC1
+        self.SubCmd = 0x20
+        self.ZoneID = 0
+        self.MainOfficialID = 0
+        self.OfficialID = 0
+        return
+
+    def GetLength(self):
+        return sizeof(tagCMChampionshipOfficialApply)
+
+    def GetBuffer(self):
+        return string_at(addressof(self), self.GetLength())
+
+    def OutputString(self):
+        DumpString = '''// C1 20 跨服排位仙官申请 //tagCMChampionshipOfficialApply:
+                                Cmd:%s,
+                                SubCmd:%s,
+                                ZoneID:%d,
+                                MainOfficialID:%d,
+                                OfficialID:%d
+                                '''\
+                                %(
+                                self.Cmd,
+                                self.SubCmd,
+                                self.ZoneID,
+                                self.MainOfficialID,
+                                self.OfficialID
+                                )
+        return DumpString
+
+
+m_NAtagCMChampionshipOfficialApply=tagCMChampionshipOfficialApply()
+ChNetPackDict[eval("0x%02x%02x"%(m_NAtagCMChampionshipOfficialApply.Cmd,m_NAtagCMChampionshipOfficialApply.SubCmd))] = m_NAtagCMChampionshipOfficialApply
+
+
+#------------------------------------------------------
+# C1 21 跨服排位仙官挑战 #tagCMChampionshipOfficialChallenge
+
+class  tagCMChampionshipOfficialChallenge(Structure):
+    _pack_ = 1
+    _fields_ = [
+                  ("Cmd", c_ubyte),
+                  ("SubCmd", c_ubyte),
+                  ("ZoneID", c_ubyte),    #仙官数据分区ID
+                  ("MainOfficialID", c_ushort),    #界主官职ID
+                  ("OfficialID", c_ushort),    #挑战的目标官职ID
+                  ("PlayerID", c_int),    #挑战时的目标玩家ID
+                  ]
+
+    def __init__(self):
+        self.Clear()
+        self.Cmd = 0xC1
+        self.SubCmd = 0x21
+        return
+
+    def ReadData(self, stringData, _pos=0, _len=0):
+        self.Clear()
+        memmove(addressof(self), stringData[_pos:], self.GetLength())
+        return _pos + self.GetLength()
+
+    def Clear(self):
+        self.Cmd = 0xC1
+        self.SubCmd = 0x21
+        self.ZoneID = 0
+        self.MainOfficialID = 0
+        self.OfficialID = 0
+        self.PlayerID = 0
+        return
+
+    def GetLength(self):
+        return sizeof(tagCMChampionshipOfficialChallenge)
+
+    def GetBuffer(self):
+        return string_at(addressof(self), self.GetLength())
+
+    def OutputString(self):
+        DumpString = '''// C1 21 跨服排位仙官挑战 //tagCMChampionshipOfficialChallenge:
+                                Cmd:%s,
+                                SubCmd:%s,
+                                ZoneID:%d,
+                                MainOfficialID:%d,
+                                OfficialID:%d,
+                                PlayerID:%d
+                                '''\
+                                %(
+                                self.Cmd,
+                                self.SubCmd,
+                                self.ZoneID,
+                                self.MainOfficialID,
+                                self.OfficialID,
+                                self.PlayerID
+                                )
+        return DumpString
+
+
+m_NAtagCMChampionshipOfficialChallenge=tagCMChampionshipOfficialChallenge()
+ChNetPackDict[eval("0x%02x%02x"%(m_NAtagCMChampionshipOfficialChallenge.Cmd,m_NAtagCMChampionshipOfficialChallenge.SubCmd))] = m_NAtagCMChampionshipOfficialChallenge
+
+
+#------------------------------------------------------
+# C1 23 跨服排位膜拜 #tagCMChampionshipWorship
+
+class  tagCMChampionshipWorship(Structure):
+    _pack_ = 1
+    _fields_ = [
+                  ("Cmd", c_ubyte),
+                  ("SubCmd", c_ubyte),
+                  ("ZoneID", c_ubyte),    #仙官数据分区ID
+                  ("PlayerID", c_int),    #目标玩家ID
+                  ]
+
+    def __init__(self):
+        self.Clear()
+        self.Cmd = 0xC1
+        self.SubCmd = 0x23
+        return
+
+    def ReadData(self, stringData, _pos=0, _len=0):
+        self.Clear()
+        memmove(addressof(self), stringData[_pos:], self.GetLength())
+        return _pos + self.GetLength()
+
+    def Clear(self):
+        self.Cmd = 0xC1
+        self.SubCmd = 0x23
+        self.ZoneID = 0
+        self.PlayerID = 0
+        return
+
+    def GetLength(self):
+        return sizeof(tagCMChampionshipWorship)
+
+    def GetBuffer(self):
+        return string_at(addressof(self), self.GetLength())
+
+    def OutputString(self):
+        DumpString = '''// C1 23 跨服排位膜拜 //tagCMChampionshipWorship:
+                                Cmd:%s,
+                                SubCmd:%s,
+                                ZoneID:%d,
+                                PlayerID:%d
+                                '''\
+                                %(
+                                self.Cmd,
+                                self.SubCmd,
+                                self.ZoneID,
+                                self.PlayerID
+                                )
+        return DumpString
+
+
+m_NAtagCMChampionshipWorship=tagCMChampionshipWorship()
+ChNetPackDict[eval("0x%02x%02x"%(m_NAtagCMChampionshipWorship.Cmd,m_NAtagCMChampionshipWorship.SubCmd))] = m_NAtagCMChampionshipWorship
+
+
+#------------------------------------------------------
 # C1 09 跨服战场购买开启场次 #tagCMCrossBattlefieldBuyOpen
 
 class  tagCMCrossBattlefieldBuyOpen(Structure):
diff --git a/ServerPython/CoreServerGroup/GameServer/Script/ChPyNetSendPack.py b/ServerPython/CoreServerGroup/GameServer/Script/ChPyNetSendPack.py
index 14ebe55..934c504 100644
--- a/ServerPython/CoreServerGroup/GameServer/Script/ChPyNetSendPack.py
+++ b/ServerPython/CoreServerGroup/GameServer/Script/ChPyNetSendPack.py
@@ -12288,6 +12288,922 @@
 
 
 #------------------------------------------------------
+# C0 23 跨服排位竞猜个人信息 #tagGCChampionshipGuessPriInfo
+
+class  tagGCChampionshipGuessPlayerPri(Structure):
+    _pack_ = 1
+    _fields_ = [
+                  ("PlayerID", c_int),    # 目标玩家ID
+                  ("MoneyTotal", c_int),    # 已投注该玩家货币总数
+                  ("GuessRank", c_ubyte),    # 竞猜名次,没有名次的竞猜默认0;1-代表第一名
+                  ]
+
+    def __init__(self):
+        self.Clear()
+        return
+
+    def ReadData(self, stringData, _pos=0, _len=0):
+        self.Clear()
+        memmove(addressof(self), stringData[_pos:], self.GetLength())
+        return _pos + self.GetLength()
+
+    def Clear(self):
+        self.PlayerID = 0
+        self.MoneyTotal = 0
+        self.GuessRank = 0
+        return
+
+    def GetLength(self):
+        return sizeof(tagGCChampionshipGuessPlayerPri)
+
+    def GetBuffer(self):
+        return string_at(addressof(self), self.GetLength())
+
+    def OutputString(self):
+        DumpString = '''// C0 23 跨服排位竞猜个人信息 //tagGCChampionshipGuessPriInfo:
+                                PlayerID:%d,
+                                MoneyTotal:%d,
+                                GuessRank:%d
+                                '''\
+                                %(
+                                self.PlayerID,
+                                self.MoneyTotal,
+                                self.GuessRank
+                                )
+        return DumpString
+
+
+class  tagGCChampionshipGuessPriList(Structure):
+    GuessType = 0    #(BYTE GuessType)//竞猜类型 8-8强;4-4强排位
+    PlayerCount = 0    #(BYTE PlayerCount)
+    GuessPlayerList = list()    #(vector<tagGCChampionshipGuessPlayerPri> GuessPlayerList)// 被竞猜玩家列表
+    data = None
+
+    def __init__(self):
+        self.Clear()
+        return
+
+    def ReadData(self, _lpData, _pos=0, _Len=0):
+        self.Clear()
+        self.GuessType,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        self.PlayerCount,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        for i in range(self.PlayerCount):
+            temGuessPlayerList = tagGCChampionshipGuessPlayerPri()
+            _pos = temGuessPlayerList.ReadData(_lpData, _pos)
+            self.GuessPlayerList.append(temGuessPlayerList)
+        return _pos
+
+    def Clear(self):
+        self.GuessType = 0
+        self.PlayerCount = 0
+        self.GuessPlayerList = list()
+        return
+
+    def GetLength(self):
+        length = 0
+        length += 1
+        length += 1
+        for i in range(self.PlayerCount):
+            length += self.GuessPlayerList[i].GetLength()
+
+        return length
+
+    def GetBuffer(self):
+        data = ''
+        data = CommFunc.WriteBYTE(data, self.GuessType)
+        data = CommFunc.WriteBYTE(data, self.PlayerCount)
+        for i in range(self.PlayerCount):
+            data = CommFunc.WriteString(data, self.GuessPlayerList[i].GetLength(), self.GuessPlayerList[i].GetBuffer())
+        return data
+
+    def OutputString(self):
+        DumpString = '''
+                                GuessType:%d,
+                                PlayerCount:%d,
+                                GuessPlayerList:%s
+                                '''\
+                                %(
+                                self.GuessType,
+                                self.PlayerCount,
+                                "..."
+                                )
+        return DumpString
+
+
+class  tagGCChampionshipGuessPriInfo(Structure):
+    Head = tagHead()
+    ZoneID = 0    #(BYTE ZoneID)// 排位数据分区ID
+    Count = 0    #(BYTE Count)
+    GuessList = list()    #(vector<tagGCChampionshipGuessPriList> GuessList)
+    data = None
+
+    def __init__(self):
+        self.Clear()
+        self.Head.Cmd = 0xC0
+        self.Head.SubCmd = 0x23
+        return
+
+    def ReadData(self, _lpData, _pos=0, _Len=0):
+        self.Clear()
+        _pos = self.Head.ReadData(_lpData, _pos)
+        self.ZoneID,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        self.Count,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        for i in range(self.Count):
+            temGuessList = tagGCChampionshipGuessPriList()
+            _pos = temGuessList.ReadData(_lpData, _pos)
+            self.GuessList.append(temGuessList)
+        return _pos
+
+    def Clear(self):
+        self.Head = tagHead()
+        self.Head.Clear()
+        self.Head.Cmd = 0xC0
+        self.Head.SubCmd = 0x23
+        self.ZoneID = 0
+        self.Count = 0
+        self.GuessList = list()
+        return
+
+    def GetLength(self):
+        length = 0
+        length += self.Head.GetLength()
+        length += 1
+        length += 1
+        for i in range(self.Count):
+            length += self.GuessList[i].GetLength()
+
+        return length
+
+    def GetBuffer(self):
+        data = ''
+        data = CommFunc.WriteString(data, self.Head.GetLength(), self.Head.GetBuffer())
+        data = CommFunc.WriteBYTE(data, self.ZoneID)
+        data = CommFunc.WriteBYTE(data, self.Count)
+        for i in range(self.Count):
+            data = CommFunc.WriteString(data, self.GuessList[i].GetLength(), self.GuessList[i].GetBuffer())
+        return data
+
+    def OutputString(self):
+        DumpString = '''
+                                Head:%s,
+                                ZoneID:%d,
+                                Count:%d,
+                                GuessList:%s
+                                '''\
+                                %(
+                                self.Head.OutputString(),
+                                self.ZoneID,
+                                self.Count,
+                                "..."
+                                )
+        return DumpString
+
+
+m_NAtagGCChampionshipGuessPriInfo=tagGCChampionshipGuessPriInfo()
+ChNetPackDict[eval("0x%02x%02x"%(m_NAtagGCChampionshipGuessPriInfo.Head.Cmd,m_NAtagGCChampionshipGuessPriInfo.Head.SubCmd))] = m_NAtagGCChampionshipGuessPriInfo
+
+
+#------------------------------------------------------
+# C0 22 跨服排位竞猜公共信息 #tagGCChampionshipGuessPubInfo
+
+class  tagGCChampionshipGuessPlayerPub(Structure):
+    _pack_ = 1
+    _fields_ = [
+                  ("PlayerID", c_int),    # 目标玩家ID
+                  ("SupportCount", c_int),    # 支持人数
+                  ]
+
+    def __init__(self):
+        self.Clear()
+        return
+
+    def ReadData(self, stringData, _pos=0, _len=0):
+        self.Clear()
+        memmove(addressof(self), stringData[_pos:], self.GetLength())
+        return _pos + self.GetLength()
+
+    def Clear(self):
+        self.PlayerID = 0
+        self.SupportCount = 0
+        return
+
+    def GetLength(self):
+        return sizeof(tagGCChampionshipGuessPlayerPub)
+
+    def GetBuffer(self):
+        return string_at(addressof(self), self.GetLength())
+
+    def OutputString(self):
+        DumpString = '''// C0 22 跨服排位竞猜公共信息 //tagGCChampionshipGuessPubInfo:
+                                PlayerID:%d,
+                                SupportCount:%d
+                                '''\
+                                %(
+                                self.PlayerID,
+                                self.SupportCount
+                                )
+        return DumpString
+
+
+class  tagGCChampionshipGuessPubList(Structure):
+    GuessType = 0    #(BYTE GuessType)//竞猜类型 8-8强;4-4强排位
+    PlayerCount = 0    #(BYTE PlayerCount)
+    GuessPlayerList = list()    #(vector<tagGCChampionshipGuessPlayerPub> GuessPlayerList)// 被竞猜玩家列表
+    data = None
+
+    def __init__(self):
+        self.Clear()
+        return
+
+    def ReadData(self, _lpData, _pos=0, _Len=0):
+        self.Clear()
+        self.GuessType,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        self.PlayerCount,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        for i in range(self.PlayerCount):
+            temGuessPlayerList = tagGCChampionshipGuessPlayerPub()
+            _pos = temGuessPlayerList.ReadData(_lpData, _pos)
+            self.GuessPlayerList.append(temGuessPlayerList)
+        return _pos
+
+    def Clear(self):
+        self.GuessType = 0
+        self.PlayerCount = 0
+        self.GuessPlayerList = list()
+        return
+
+    def GetLength(self):
+        length = 0
+        length += 1
+        length += 1
+        for i in range(self.PlayerCount):
+            length += self.GuessPlayerList[i].GetLength()
+
+        return length
+
+    def GetBuffer(self):
+        data = ''
+        data = CommFunc.WriteBYTE(data, self.GuessType)
+        data = CommFunc.WriteBYTE(data, self.PlayerCount)
+        for i in range(self.PlayerCount):
+            data = CommFunc.WriteString(data, self.GuessPlayerList[i].GetLength(), self.GuessPlayerList[i].GetBuffer())
+        return data
+
+    def OutputString(self):
+        DumpString = '''
+                                GuessType:%d,
+                                PlayerCount:%d,
+                                GuessPlayerList:%s
+                                '''\
+                                %(
+                                self.GuessType,
+                                self.PlayerCount,
+                                "..."
+                                )
+        return DumpString
+
+
+class  tagGCChampionshipGuessPubInfo(Structure):
+    Head = tagHead()
+    ZoneID = 0    #(BYTE ZoneID)// 排位数据分区ID
+    Count = 0    #(BYTE Count)
+    GuessList = list()    #(vector<tagGCChampionshipGuessPubList> GuessList)
+    data = None
+
+    def __init__(self):
+        self.Clear()
+        self.Head.Cmd = 0xC0
+        self.Head.SubCmd = 0x22
+        return
+
+    def ReadData(self, _lpData, _pos=0, _Len=0):
+        self.Clear()
+        _pos = self.Head.ReadData(_lpData, _pos)
+        self.ZoneID,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        self.Count,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        for i in range(self.Count):
+            temGuessList = tagGCChampionshipGuessPubList()
+            _pos = temGuessList.ReadData(_lpData, _pos)
+            self.GuessList.append(temGuessList)
+        return _pos
+
+    def Clear(self):
+        self.Head = tagHead()
+        self.Head.Clear()
+        self.Head.Cmd = 0xC0
+        self.Head.SubCmd = 0x22
+        self.ZoneID = 0
+        self.Count = 0
+        self.GuessList = list()
+        return
+
+    def GetLength(self):
+        length = 0
+        length += self.Head.GetLength()
+        length += 1
+        length += 1
+        for i in range(self.Count):
+            length += self.GuessList[i].GetLength()
+
+        return length
+
+    def GetBuffer(self):
+        data = ''
+        data = CommFunc.WriteString(data, self.Head.GetLength(), self.Head.GetBuffer())
+        data = CommFunc.WriteBYTE(data, self.ZoneID)
+        data = CommFunc.WriteBYTE(data, self.Count)
+        for i in range(self.Count):
+            data = CommFunc.WriteString(data, self.GuessList[i].GetLength(), self.GuessList[i].GetBuffer())
+        return data
+
+    def OutputString(self):
+        DumpString = '''
+                                Head:%s,
+                                ZoneID:%d,
+                                Count:%d,
+                                GuessList:%s
+                                '''\
+                                %(
+                                self.Head.OutputString(),
+                                self.ZoneID,
+                                self.Count,
+                                "..."
+                                )
+        return DumpString
+
+
+m_NAtagGCChampionshipGuessPubInfo=tagGCChampionshipGuessPubInfo()
+ChNetPackDict[eval("0x%02x%02x"%(m_NAtagGCChampionshipGuessPubInfo.Head.Cmd,m_NAtagGCChampionshipGuessPubInfo.Head.SubCmd))] = m_NAtagGCChampionshipGuessPubInfo
+
+
+#------------------------------------------------------
+# C0 19 跨服排位仙官申请回应结果 #tagGCChampionshipOfficialApplyReplyRet
+
+class  tagGCChampionshipOfficialApplyReplyRet(Structure):
+    Head = tagHead()
+    NameLen = 0    #(BYTE NameLen)
+    PlayerName = ""    #(String PlayerName)// 界主玩家名
+    MainOfficialID = 0    #(WORD MainOfficialID)//界主官职ID
+    OfficialID = 0    #(WORD OfficialID)//申请官职ID
+    IsOK = 0    #(BYTE IsOK)//是否同意;1-是;0-否
+    data = None
+
+    def __init__(self):
+        self.Clear()
+        self.Head.Cmd = 0xC0
+        self.Head.SubCmd = 0x19
+        return
+
+    def ReadData(self, _lpData, _pos=0, _Len=0):
+        self.Clear()
+        _pos = self.Head.ReadData(_lpData, _pos)
+        self.NameLen,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        self.PlayerName,_pos = CommFunc.ReadString(_lpData, _pos,self.NameLen)
+        self.MainOfficialID,_pos = CommFunc.ReadWORD(_lpData, _pos)
+        self.OfficialID,_pos = CommFunc.ReadWORD(_lpData, _pos)
+        self.IsOK,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        return _pos
+
+    def Clear(self):
+        self.Head = tagHead()
+        self.Head.Clear()
+        self.Head.Cmd = 0xC0
+        self.Head.SubCmd = 0x19
+        self.NameLen = 0
+        self.PlayerName = ""
+        self.MainOfficialID = 0
+        self.OfficialID = 0
+        self.IsOK = 0
+        return
+
+    def GetLength(self):
+        length = 0
+        length += self.Head.GetLength()
+        length += 1
+        length += len(self.PlayerName)
+        length += 2
+        length += 2
+        length += 1
+
+        return length
+
+    def GetBuffer(self):
+        data = ''
+        data = CommFunc.WriteString(data, self.Head.GetLength(), self.Head.GetBuffer())
+        data = CommFunc.WriteBYTE(data, self.NameLen)
+        data = CommFunc.WriteString(data, self.NameLen, self.PlayerName)
+        data = CommFunc.WriteWORD(data, self.MainOfficialID)
+        data = CommFunc.WriteWORD(data, self.OfficialID)
+        data = CommFunc.WriteBYTE(data, self.IsOK)
+        return data
+
+    def OutputString(self):
+        DumpString = '''
+                                Head:%s,
+                                NameLen:%d,
+                                PlayerName:%s,
+                                MainOfficialID:%d,
+                                OfficialID:%d,
+                                IsOK:%d
+                                '''\
+                                %(
+                                self.Head.OutputString(),
+                                self.NameLen,
+                                self.PlayerName,
+                                self.MainOfficialID,
+                                self.OfficialID,
+                                self.IsOK
+                                )
+        return DumpString
+
+
+m_NAtagGCChampionshipOfficialApplyReplyRet=tagGCChampionshipOfficialApplyReplyRet()
+ChNetPackDict[eval("0x%02x%02x"%(m_NAtagGCChampionshipOfficialApplyReplyRet.Head.Cmd,m_NAtagGCChampionshipOfficialApplyReplyRet.Head.SubCmd))] = m_NAtagGCChampionshipOfficialApplyReplyRet
+
+
+#------------------------------------------------------
+# C0 21 跨服排位仙官挑战记录 #tagGCChampionshipOfficialChallengeRecordInfo
+
+class  tagGCChampionshipOfficialChallengeRecord(Structure):
+    NameLen = 0    #(BYTE NameLen)
+    PlayerName = ""    #(String PlayerName)
+    ChallengeTime = 0    #(DWORD ChallengeTime)//挑战时间戳
+    Ret = 0    #(BYTE Ret)//挑战结果;0-失败;1-获胜;
+    data = None
+
+    def __init__(self):
+        self.Clear()
+        return
+
+    def ReadData(self, _lpData, _pos=0, _Len=0):
+        self.Clear()
+        self.NameLen,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        self.PlayerName,_pos = CommFunc.ReadString(_lpData, _pos,self.NameLen)
+        self.ChallengeTime,_pos = CommFunc.ReadDWORD(_lpData, _pos)
+        self.Ret,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        return _pos
+
+    def Clear(self):
+        self.NameLen = 0
+        self.PlayerName = ""
+        self.ChallengeTime = 0
+        self.Ret = 0
+        return
+
+    def GetLength(self):
+        length = 0
+        length += 1
+        length += len(self.PlayerName)
+        length += 4
+        length += 1
+
+        return length
+
+    def GetBuffer(self):
+        data = ''
+        data = CommFunc.WriteBYTE(data, self.NameLen)
+        data = CommFunc.WriteString(data, self.NameLen, self.PlayerName)
+        data = CommFunc.WriteDWORD(data, self.ChallengeTime)
+        data = CommFunc.WriteBYTE(data, self.Ret)
+        return data
+
+    def OutputString(self):
+        DumpString = '''
+                                NameLen:%d,
+                                PlayerName:%s,
+                                ChallengeTime:%d,
+                                Ret:%d
+                                '''\
+                                %(
+                                self.NameLen,
+                                self.PlayerName,
+                                self.ChallengeTime,
+                                self.Ret
+                                )
+        return DumpString
+
+
+class  tagGCChampionshipOfficialChallengeRecordInfo(Structure):
+    Head = tagHead()
+    ZoneID = 0    #(BYTE ZoneID)// 分区ID
+    MainOfficialID = 0    #(WORD MainOfficialID)// 界主官职ID
+    OfficialID = 0    #(WORD OfficialID)// 记录的官职ID
+    RecordCount = 0    #(BYTE RecordCount)// 挑战记录数
+    RecordList = list()    #(vector<tagGCChampionshipOfficialChallengeRecord> RecordList)
+    data = None
+
+    def __init__(self):
+        self.Clear()
+        self.Head.Cmd = 0xC0
+        self.Head.SubCmd = 0x21
+        return
+
+    def ReadData(self, _lpData, _pos=0, _Len=0):
+        self.Clear()
+        _pos = self.Head.ReadData(_lpData, _pos)
+        self.ZoneID,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        self.MainOfficialID,_pos = CommFunc.ReadWORD(_lpData, _pos)
+        self.OfficialID,_pos = CommFunc.ReadWORD(_lpData, _pos)
+        self.RecordCount,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        for i in range(self.RecordCount):
+            temRecordList = tagGCChampionshipOfficialChallengeRecord()
+            _pos = temRecordList.ReadData(_lpData, _pos)
+            self.RecordList.append(temRecordList)
+        return _pos
+
+    def Clear(self):
+        self.Head = tagHead()
+        self.Head.Clear()
+        self.Head.Cmd = 0xC0
+        self.Head.SubCmd = 0x21
+        self.ZoneID = 0
+        self.MainOfficialID = 0
+        self.OfficialID = 0
+        self.RecordCount = 0
+        self.RecordList = list()
+        return
+
+    def GetLength(self):
+        length = 0
+        length += self.Head.GetLength()
+        length += 1
+        length += 2
+        length += 2
+        length += 1
+        for i in range(self.RecordCount):
+            length += self.RecordList[i].GetLength()
+
+        return length
+
+    def GetBuffer(self):
+        data = ''
+        data = CommFunc.WriteString(data, self.Head.GetLength(), self.Head.GetBuffer())
+        data = CommFunc.WriteBYTE(data, self.ZoneID)
+        data = CommFunc.WriteWORD(data, self.MainOfficialID)
+        data = CommFunc.WriteWORD(data, self.OfficialID)
+        data = CommFunc.WriteBYTE(data, self.RecordCount)
+        for i in range(self.RecordCount):
+            data = CommFunc.WriteString(data, self.RecordList[i].GetLength(), self.RecordList[i].GetBuffer())
+        return data
+
+    def OutputString(self):
+        DumpString = '''
+                                Head:%s,
+                                ZoneID:%d,
+                                MainOfficialID:%d,
+                                OfficialID:%d,
+                                RecordCount:%d,
+                                RecordList:%s
+                                '''\
+                                %(
+                                self.Head.OutputString(),
+                                self.ZoneID,
+                                self.MainOfficialID,
+                                self.OfficialID,
+                                self.RecordCount,
+                                "..."
+                                )
+        return DumpString
+
+
+m_NAtagGCChampionshipOfficialChallengeRecordInfo=tagGCChampionshipOfficialChallengeRecordInfo()
+ChNetPackDict[eval("0x%02x%02x"%(m_NAtagGCChampionshipOfficialChallengeRecordInfo.Head.Cmd,m_NAtagGCChampionshipOfficialChallengeRecordInfo.Head.SubCmd))] = m_NAtagGCChampionshipOfficialChallengeRecordInfo
+
+
+#------------------------------------------------------
+# C0 20 跨服排位仙官挑战结果 #tagGCChampionshipOfficialChallengeRet
+
+class  tagGCChampionshipOfficialChallengeRet(Structure):
+    Head = tagHead()
+    NameLen = 0    #(BYTE NameLen)
+    PlayerName = ""    #(String PlayerName)// 原仙官玩家名,可能为空,代表本来无玩家
+    MainOfficialID = 0    #(WORD MainOfficialID)//界主官职ID
+    OfficialID = 0    #(WORD OfficialID)//挑战的官职ID
+    Ret = 0    #(BYTE Ret)//挑战结果;0-失败;1-获胜;2-目标仙官玩家ID已变更,可刷新后重试
+    data = None
+
+    def __init__(self):
+        self.Clear()
+        self.Head.Cmd = 0xC0
+        self.Head.SubCmd = 0x20
+        return
+
+    def ReadData(self, _lpData, _pos=0, _Len=0):
+        self.Clear()
+        _pos = self.Head.ReadData(_lpData, _pos)
+        self.NameLen,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        self.PlayerName,_pos = CommFunc.ReadString(_lpData, _pos,self.NameLen)
+        self.MainOfficialID,_pos = CommFunc.ReadWORD(_lpData, _pos)
+        self.OfficialID,_pos = CommFunc.ReadWORD(_lpData, _pos)
+        self.Ret,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        return _pos
+
+    def Clear(self):
+        self.Head = tagHead()
+        self.Head.Clear()
+        self.Head.Cmd = 0xC0
+        self.Head.SubCmd = 0x20
+        self.NameLen = 0
+        self.PlayerName = ""
+        self.MainOfficialID = 0
+        self.OfficialID = 0
+        self.Ret = 0
+        return
+
+    def GetLength(self):
+        length = 0
+        length += self.Head.GetLength()
+        length += 1
+        length += len(self.PlayerName)
+        length += 2
+        length += 2
+        length += 1
+
+        return length
+
+    def GetBuffer(self):
+        data = ''
+        data = CommFunc.WriteString(data, self.Head.GetLength(), self.Head.GetBuffer())
+        data = CommFunc.WriteBYTE(data, self.NameLen)
+        data = CommFunc.WriteString(data, self.NameLen, self.PlayerName)
+        data = CommFunc.WriteWORD(data, self.MainOfficialID)
+        data = CommFunc.WriteWORD(data, self.OfficialID)
+        data = CommFunc.WriteBYTE(data, self.Ret)
+        return data
+
+    def OutputString(self):
+        DumpString = '''
+                                Head:%s,
+                                NameLen:%d,
+                                PlayerName:%s,
+                                MainOfficialID:%d,
+                                OfficialID:%d,
+                                Ret:%d
+                                '''\
+                                %(
+                                self.Head.OutputString(),
+                                self.NameLen,
+                                self.PlayerName,
+                                self.MainOfficialID,
+                                self.OfficialID,
+                                self.Ret
+                                )
+        return DumpString
+
+
+m_NAtagGCChampionshipOfficialChallengeRet=tagGCChampionshipOfficialChallengeRet()
+ChNetPackDict[eval("0x%02x%02x"%(m_NAtagGCChampionshipOfficialChallengeRet.Head.Cmd,m_NAtagGCChampionshipOfficialChallengeRet.Head.SubCmd))] = m_NAtagGCChampionshipOfficialChallengeRet
+
+
+#------------------------------------------------------
+# C0 18 跨服排位官职信息 #tagGCChampionshipOfficialInfo
+
+class  tagGCChampionshipOfficialPlayer(Structure):
+    PlayerID = 0    #(DWORD PlayerID)// 玩家ID
+    NameLen = 0    #(BYTE NameLen)
+    PlayerName = ""    #(String PlayerName)
+    Job = 0    #(BYTE Job)
+    LV = 0    #(WORD LV)
+    FightPower = 0    #(DWORD FightPower)// 战力求余亿部分
+    FightPowerEx = 0    #(DWORD FightPowerEx)// 战力整除亿部分
+    RealmLV = 0    #(WORD RealmLV)
+    data = None
+
+    def __init__(self):
+        self.Clear()
+        return
+
+    def ReadData(self, _lpData, _pos=0, _Len=0):
+        self.Clear()
+        self.PlayerID,_pos = CommFunc.ReadDWORD(_lpData, _pos)
+        self.NameLen,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        self.PlayerName,_pos = CommFunc.ReadString(_lpData, _pos,self.NameLen)
+        self.Job,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        self.LV,_pos = CommFunc.ReadWORD(_lpData, _pos)
+        self.FightPower,_pos = CommFunc.ReadDWORD(_lpData, _pos)
+        self.FightPowerEx,_pos = CommFunc.ReadDWORD(_lpData, _pos)
+        self.RealmLV,_pos = CommFunc.ReadWORD(_lpData, _pos)
+        return _pos
+
+    def Clear(self):
+        self.PlayerID = 0
+        self.NameLen = 0
+        self.PlayerName = ""
+        self.Job = 0
+        self.LV = 0
+        self.FightPower = 0
+        self.FightPowerEx = 0
+        self.RealmLV = 0
+        return
+
+    def GetLength(self):
+        length = 0
+        length += 4
+        length += 1
+        length += len(self.PlayerName)
+        length += 1
+        length += 2
+        length += 4
+        length += 4
+        length += 2
+
+        return length
+
+    def GetBuffer(self):
+        data = ''
+        data = CommFunc.WriteDWORD(data, self.PlayerID)
+        data = CommFunc.WriteBYTE(data, self.NameLen)
+        data = CommFunc.WriteString(data, self.NameLen, self.PlayerName)
+        data = CommFunc.WriteBYTE(data, self.Job)
+        data = CommFunc.WriteWORD(data, self.LV)
+        data = CommFunc.WriteDWORD(data, self.FightPower)
+        data = CommFunc.WriteDWORD(data, self.FightPowerEx)
+        data = CommFunc.WriteWORD(data, self.RealmLV)
+        return data
+
+    def OutputString(self):
+        DumpString = '''
+                                PlayerID:%d,
+                                NameLen:%d,
+                                PlayerName:%s,
+                                Job:%d,
+                                LV:%d,
+                                FightPower:%d,
+                                FightPowerEx:%d,
+                                RealmLV:%d
+                                '''\
+                                %(
+                                self.PlayerID,
+                                self.NameLen,
+                                self.PlayerName,
+                                self.Job,
+                                self.LV,
+                                self.FightPower,
+                                self.FightPowerEx,
+                                self.RealmLV
+                                )
+        return DumpString
+
+
+class  tagGCChampionshipOfficial(Structure):
+    OfficialID = 0    #(DWORD OfficialID)// 官职ID
+    LastDismissJuniorTime = 0    #(DWORD LastDismissJuniorTime)// 上次辞退下级仙官时间戳,跨服时间,如果自己是本界主时,用于计算辞退CD
+    WorshipCount = 0    #(DWORD WorshipCount)// 被膜拜次数
+    WorshipDouble = 0    #(BYTE WorshipDouble)// 今日是否双倍膜拜,仅在规定时间点内有用
+    OfficialPlayer=tagGCChampionshipOfficialPlayer()    #(tagGCChampionshipOfficialPlayer OfficialPlayer)// 任职玩家信息,可能没有
+    ApplyPlayerCount = 0    #(BYTE ApplyPlayerCount)// 申请该仙官玩家数
+    ApplyPlayerList = list()    #(vector<tagGCChampionshipOfficialPlayer> ApplyPlayerList)// 申请该仙官玩家列表
+    data = None
+
+    def __init__(self):
+        self.Clear()
+        return
+
+    def ReadData(self, _lpData, _pos=0, _Len=0):
+        self.Clear()
+        self.OfficialID,_pos = CommFunc.ReadDWORD(_lpData, _pos)
+        self.LastDismissJuniorTime,_pos = CommFunc.ReadDWORD(_lpData, _pos)
+        self.WorshipCount,_pos = CommFunc.ReadDWORD(_lpData, _pos)
+        self.WorshipDouble,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        _pos = self.OfficialPlayer.ReadData(_lpData,_pos)
+        self.ApplyPlayerCount,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        for i in range(self.ApplyPlayerCount):
+            temApplyPlayerList = tagGCChampionshipOfficialPlayer()
+            _pos = temApplyPlayerList.ReadData(_lpData, _pos)
+            self.ApplyPlayerList.append(temApplyPlayerList)
+        return _pos
+
+    def Clear(self):
+        self.OfficialID = 0
+        self.LastDismissJuniorTime = 0
+        self.WorshipCount = 0
+        self.WorshipDouble = 0
+        self.OfficialPlayer=tagGCChampionshipOfficialPlayer()
+        self.OfficialPlayer.Clear()
+        self.ApplyPlayerCount = 0
+        self.ApplyPlayerList = list()
+        return
+
+    def GetLength(self):
+        length = 0
+        length += 4
+        length += 4
+        length += 4
+        length += 1
+        length += self.OfficialPlayer.GetLength()
+        length += 1
+        for i in range(self.ApplyPlayerCount):
+            length += self.ApplyPlayerList[i].GetLength()
+
+        return length
+
+    def GetBuffer(self):
+        data = ''
+        data = CommFunc.WriteDWORD(data, self.OfficialID)
+        data = CommFunc.WriteDWORD(data, self.LastDismissJuniorTime)
+        data = CommFunc.WriteDWORD(data, self.WorshipCount)
+        data = CommFunc.WriteBYTE(data, self.WorshipDouble)
+        data = CommFunc.WriteString(data,self.OfficialPlayer.GetLength(),self.OfficialPlayer.GetBuffer())
+        data = CommFunc.WriteBYTE(data, self.ApplyPlayerCount)
+        for i in range(self.ApplyPlayerCount):
+            data = CommFunc.WriteString(data, self.ApplyPlayerList[i].GetLength(), self.ApplyPlayerList[i].GetBuffer())
+        return data
+
+    def OutputString(self):
+        DumpString = '''
+                                OfficialID:%d,
+                                LastDismissJuniorTime:%d,
+                                WorshipCount:%d,
+                                WorshipDouble:%d,
+                                OfficialPlayer:%s,
+                                ApplyPlayerCount:%d,
+                                ApplyPlayerList:%s
+                                '''\
+                                %(
+                                self.OfficialID,
+                                self.LastDismissJuniorTime,
+                                self.WorshipCount,
+                                self.WorshipDouble,
+                                self.OfficialPlayer.OutputString(),
+                                self.ApplyPlayerCount,
+                                "..."
+                                )
+        return DumpString
+
+
+class  tagGCChampionshipOfficialInfo(Structure):
+    Head = tagHead()
+    ZoneID = 0    #(BYTE ZoneID)// 官职数据分区ID
+    OfficialCount = 0    #(BYTE OfficialCount)// 官职数,包含界主及所有仙官
+    OfficialList = list()    #(vector<tagGCChampionshipOfficial> OfficialList)
+    data = None
+
+    def __init__(self):
+        self.Clear()
+        self.Head.Cmd = 0xC0
+        self.Head.SubCmd = 0x18
+        return
+
+    def ReadData(self, _lpData, _pos=0, _Len=0):
+        self.Clear()
+        _pos = self.Head.ReadData(_lpData, _pos)
+        self.ZoneID,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        self.OfficialCount,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        for i in range(self.OfficialCount):
+            temOfficialList = tagGCChampionshipOfficial()
+            _pos = temOfficialList.ReadData(_lpData, _pos)
+            self.OfficialList.append(temOfficialList)
+        return _pos
+
+    def Clear(self):
+        self.Head = tagHead()
+        self.Head.Clear()
+        self.Head.Cmd = 0xC0
+        self.Head.SubCmd = 0x18
+        self.ZoneID = 0
+        self.OfficialCount = 0
+        self.OfficialList = list()
+        return
+
+    def GetLength(self):
+        length = 0
+        length += self.Head.GetLength()
+        length += 1
+        length += 1
+        for i in range(self.OfficialCount):
+            length += self.OfficialList[i].GetLength()
+
+        return length
+
+    def GetBuffer(self):
+        data = ''
+        data = CommFunc.WriteString(data, self.Head.GetLength(), self.Head.GetBuffer())
+        data = CommFunc.WriteBYTE(data, self.ZoneID)
+        data = CommFunc.WriteBYTE(data, self.OfficialCount)
+        for i in range(self.OfficialCount):
+            data = CommFunc.WriteString(data, self.OfficialList[i].GetLength(), self.OfficialList[i].GetBuffer())
+        return data
+
+    def OutputString(self):
+        DumpString = '''
+                                Head:%s,
+                                ZoneID:%d,
+                                OfficialCount:%d,
+                                OfficialList:%s
+                                '''\
+                                %(
+                                self.Head.OutputString(),
+                                self.ZoneID,
+                                self.OfficialCount,
+                                "..."
+                                )
+        return DumpString
+
+
+m_NAtagGCChampionshipOfficialInfo=tagGCChampionshipOfficialInfo()
+ChNetPackDict[eval("0x%02x%02x"%(m_NAtagGCChampionshipOfficialInfo.Head.Cmd,m_NAtagGCChampionshipOfficialInfo.Head.SubCmd))] = m_NAtagGCChampionshipOfficialInfo
+
+
+#------------------------------------------------------
 # C0 09 跨服战场玩家购买战场信息 #tagGCCrossBattlefieldBuyInfo
 
 class  tagGCCrossBattlefieldPlayer(Structure):
@@ -12753,6 +13669,429 @@
 
 m_NAtagGCCrossBillboardInfo=tagGCCrossBillboardInfo()
 ChNetPackDict[eval("0x%02x%02x"%(m_NAtagGCCrossBillboardInfo.Head.Cmd,m_NAtagGCCrossBillboardInfo.Head.SubCmd))] = m_NAtagGCCrossBillboardInfo
+
+
+#------------------------------------------------------
+# C0 16 跨服排位战斗结果 #tagGCCrossChampionshipPKOver
+
+class  tagGCCrossChampionshipPKOver(Structure):
+    Head = tagHead()
+    GroupMark = 0    #(DWORD GroupMark)// 分组标识:64、32、16、8 - 64、32、16、8强赛;4 - 半决赛; 2 - 决赛
+    TimeStr = ""    #(char TimeStr[19])// 结算时间,格式 yyyy-MM-dd HH:mm:ss
+    OverType = 0    #(BYTE OverType)// 0-正常,1-有人离线
+    WinnerID = 0    #(DWORD WinnerID)// 胜方ID
+    LoserID = 0    #(DWORD LoserID)// 败方ID
+    RoundCount = 0    #(BYTE RoundCount)// PK回合数
+    RoundWinnerID = list()    #(vector<DWORD> RoundWinnerID)// 回合获胜ID列表
+    TagNameLen = 0    #(BYTE TagNameLen)
+    TagName = ""    #(String TagName)
+    Rank = 0    #(BYTE Rank)// 最终名次,决赛才有
+    data = None
+
+    def __init__(self):
+        self.Clear()
+        self.Head.Cmd = 0xC0
+        self.Head.SubCmd = 0x16
+        return
+
+    def ReadData(self, _lpData, _pos=0, _Len=0):
+        self.Clear()
+        _pos = self.Head.ReadData(_lpData, _pos)
+        self.GroupMark,_pos = CommFunc.ReadDWORD(_lpData, _pos)
+        self.TimeStr,_pos = CommFunc.ReadString(_lpData, _pos,19)
+        self.OverType,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        self.WinnerID,_pos = CommFunc.ReadDWORD(_lpData, _pos)
+        self.LoserID,_pos = CommFunc.ReadDWORD(_lpData, _pos)
+        self.RoundCount,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        for i in range(self.RoundCount):
+            value,_pos=CommFunc.ReadDWORD(_lpData,_pos)
+            self.RoundWinnerID.append(value)
+        self.TagNameLen,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        self.TagName,_pos = CommFunc.ReadString(_lpData, _pos,self.TagNameLen)
+        self.Rank,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        return _pos
+
+    def Clear(self):
+        self.Head = tagHead()
+        self.Head.Clear()
+        self.Head.Cmd = 0xC0
+        self.Head.SubCmd = 0x16
+        self.GroupMark = 0
+        self.TimeStr = ""
+        self.OverType = 0
+        self.WinnerID = 0
+        self.LoserID = 0
+        self.RoundCount = 0
+        self.RoundWinnerID = list()
+        self.TagNameLen = 0
+        self.TagName = ""
+        self.Rank = 0
+        return
+
+    def GetLength(self):
+        length = 0
+        length += self.Head.GetLength()
+        length += 4
+        length += 19
+        length += 1
+        length += 4
+        length += 4
+        length += 1
+        length += 4 * self.RoundCount
+        length += 1
+        length += len(self.TagName)
+        length += 1
+
+        return length
+
+    def GetBuffer(self):
+        data = ''
+        data = CommFunc.WriteString(data, self.Head.GetLength(), self.Head.GetBuffer())
+        data = CommFunc.WriteDWORD(data, self.GroupMark)
+        data = CommFunc.WriteString(data, 19, self.TimeStr)
+        data = CommFunc.WriteBYTE(data, self.OverType)
+        data = CommFunc.WriteDWORD(data, self.WinnerID)
+        data = CommFunc.WriteDWORD(data, self.LoserID)
+        data = CommFunc.WriteBYTE(data, self.RoundCount)
+        for i in range(self.RoundCount):
+            data = CommFunc.WriteDWORD(data, self.RoundWinnerID[i])
+        data = CommFunc.WriteBYTE(data, self.TagNameLen)
+        data = CommFunc.WriteString(data, self.TagNameLen, self.TagName)
+        data = CommFunc.WriteBYTE(data, self.Rank)
+        return data
+
+    def OutputString(self):
+        DumpString = '''
+                                Head:%s,
+                                GroupMark:%d,
+                                TimeStr:%s,
+                                OverType:%d,
+                                WinnerID:%d,
+                                LoserID:%d,
+                                RoundCount:%d,
+                                RoundWinnerID:%s,
+                                TagNameLen:%d,
+                                TagName:%s,
+                                Rank:%d
+                                '''\
+                                %(
+                                self.Head.OutputString(),
+                                self.GroupMark,
+                                self.TimeStr,
+                                self.OverType,
+                                self.WinnerID,
+                                self.LoserID,
+                                self.RoundCount,
+                                "...",
+                                self.TagNameLen,
+                                self.TagName,
+                                self.Rank
+                                )
+        return DumpString
+
+
+m_NAtagGCCrossChampionshipPKOver=tagGCCrossChampionshipPKOver()
+ChNetPackDict[eval("0x%02x%02x"%(m_NAtagGCCrossChampionshipPKOver.Head.Cmd,m_NAtagGCCrossChampionshipPKOver.Head.SubCmd))] = m_NAtagGCCrossChampionshipPKOver
+
+
+#------------------------------------------------------
+# C0 15 跨服排位分区分组信息 #tagGCCrossChampionshipPKZoneGroupInfo
+
+class  tagGCCrossChampionshipPKBattle(Structure):
+    _pack_ = 1
+    _fields_ = [
+                  ("BattleNum", c_ubyte),    # 对战组编号 1~n
+                  ("WinPlayerID", c_int),    # 获胜玩家ID
+                  ("PlayerIDA", c_int),    # 玩家IDA
+                  ("PlayerIDB", c_int),    # 玩家IDB
+                  ]
+
+    def __init__(self):
+        self.Clear()
+        return
+
+    def ReadData(self, stringData, _pos=0, _len=0):
+        self.Clear()
+        memmove(addressof(self), stringData[_pos:], self.GetLength())
+        return _pos + self.GetLength()
+
+    def Clear(self):
+        self.BattleNum = 0
+        self.WinPlayerID = 0
+        self.PlayerIDA = 0
+        self.PlayerIDB = 0
+        return
+
+    def GetLength(self):
+        return sizeof(tagGCCrossChampionshipPKBattle)
+
+    def GetBuffer(self):
+        return string_at(addressof(self), self.GetLength())
+
+    def OutputString(self):
+        DumpString = '''// C0 15 跨服排位分区分组信息 //tagGCCrossChampionshipPKZoneGroupInfo:
+                                BattleNum:%d,
+                                WinPlayerID:%d,
+                                PlayerIDA:%d,
+                                PlayerIDB:%d
+                                '''\
+                                %(
+                                self.BattleNum,
+                                self.WinPlayerID,
+                                self.PlayerIDA,
+                                self.PlayerIDB
+                                )
+        return DumpString
+
+
+class  tagGCCrossChampionshipPKGroup(Structure):
+    GroupMark = 0    #(DWORD GroupMark)// 战斗分区mark, 如 64、32、16、8、4-半决赛、2-决赛;
+    BattleCount = 0    #(BYTE BattleCount)// 对战组数
+    BattleList = list()    #(vector<tagGCCrossChampionshipPKBattle> BattleList)// 对战组列表
+    data = None
+
+    def __init__(self):
+        self.Clear()
+        return
+
+    def ReadData(self, _lpData, _pos=0, _Len=0):
+        self.Clear()
+        self.GroupMark,_pos = CommFunc.ReadDWORD(_lpData, _pos)
+        self.BattleCount,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        for i in range(self.BattleCount):
+            temBattleList = tagGCCrossChampionshipPKBattle()
+            _pos = temBattleList.ReadData(_lpData, _pos)
+            self.BattleList.append(temBattleList)
+        return _pos
+
+    def Clear(self):
+        self.GroupMark = 0
+        self.BattleCount = 0
+        self.BattleList = list()
+        return
+
+    def GetLength(self):
+        length = 0
+        length += 4
+        length += 1
+        for i in range(self.BattleCount):
+            length += self.BattleList[i].GetLength()
+
+        return length
+
+    def GetBuffer(self):
+        data = ''
+        data = CommFunc.WriteDWORD(data, self.GroupMark)
+        data = CommFunc.WriteBYTE(data, self.BattleCount)
+        for i in range(self.BattleCount):
+            data = CommFunc.WriteString(data, self.BattleList[i].GetLength(), self.BattleList[i].GetBuffer())
+        return data
+
+    def OutputString(self):
+        DumpString = '''
+                                GroupMark:%d,
+                                BattleCount:%d,
+                                BattleList:%s
+                                '''\
+                                %(
+                                self.GroupMark,
+                                self.BattleCount,
+                                "..."
+                                )
+        return DumpString
+
+
+class  tagGCCrossChampionshipPKPlayer(Structure):
+    PlayerID = 0    #(DWORD PlayerID)// 玩家ID
+    NameLen = 0    #(BYTE NameLen)
+    PlayerName = ""    #(String PlayerName)
+    Job = 0    #(BYTE Job)
+    LV = 0    #(WORD LV)
+    FightPower = 0    #(DWORD FightPower)// 战力求余亿部分
+    FightPowerEx = 0    #(DWORD FightPowerEx)// 战力整除亿部分
+    RealmLV = 0    #(WORD RealmLV)
+    data = None
+
+    def __init__(self):
+        self.Clear()
+        return
+
+    def ReadData(self, _lpData, _pos=0, _Len=0):
+        self.Clear()
+        self.PlayerID,_pos = CommFunc.ReadDWORD(_lpData, _pos)
+        self.NameLen,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        self.PlayerName,_pos = CommFunc.ReadString(_lpData, _pos,self.NameLen)
+        self.Job,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        self.LV,_pos = CommFunc.ReadWORD(_lpData, _pos)
+        self.FightPower,_pos = CommFunc.ReadDWORD(_lpData, _pos)
+        self.FightPowerEx,_pos = CommFunc.ReadDWORD(_lpData, _pos)
+        self.RealmLV,_pos = CommFunc.ReadWORD(_lpData, _pos)
+        return _pos
+
+    def Clear(self):
+        self.PlayerID = 0
+        self.NameLen = 0
+        self.PlayerName = ""
+        self.Job = 0
+        self.LV = 0
+        self.FightPower = 0
+        self.FightPowerEx = 0
+        self.RealmLV = 0
+        return
+
+    def GetLength(self):
+        length = 0
+        length += 4
+        length += 1
+        length += len(self.PlayerName)
+        length += 1
+        length += 2
+        length += 4
+        length += 4
+        length += 2
+
+        return length
+
+    def GetBuffer(self):
+        data = ''
+        data = CommFunc.WriteDWORD(data, self.PlayerID)
+        data = CommFunc.WriteBYTE(data, self.NameLen)
+        data = CommFunc.WriteString(data, self.NameLen, self.PlayerName)
+        data = CommFunc.WriteBYTE(data, self.Job)
+        data = CommFunc.WriteWORD(data, self.LV)
+        data = CommFunc.WriteDWORD(data, self.FightPower)
+        data = CommFunc.WriteDWORD(data, self.FightPowerEx)
+        data = CommFunc.WriteWORD(data, self.RealmLV)
+        return data
+
+    def OutputString(self):
+        DumpString = '''
+                                PlayerID:%d,
+                                NameLen:%d,
+                                PlayerName:%s,
+                                Job:%d,
+                                LV:%d,
+                                FightPower:%d,
+                                FightPowerEx:%d,
+                                RealmLV:%d
+                                '''\
+                                %(
+                                self.PlayerID,
+                                self.NameLen,
+                                self.PlayerName,
+                                self.Job,
+                                self.LV,
+                                self.FightPower,
+                                self.FightPowerEx,
+                                self.RealmLV
+                                )
+        return DumpString
+
+
+class  tagGCCrossChampionshipPKZoneGroupInfo(Structure):
+    Head = tagHead()
+    ActID = 0    #(DWORD ActID)// 活动ID,活动ID不同则可重置前端排位赛相关缓存数据
+    StateError = 0    #(BYTE StateError)// 本次活动是否已经出现流程状态异常;如服务器异常或维护服务器导致跳过步骤,则会废弃该次比赛,直到下次新活动;
+    ZoneID = 0    #(BYTE ZoneID)// 排位分区ID
+    PlayerCount = 0    #(BYTE PlayerCount)// 参赛玩家数
+    PlayerList = list()    #(vector<tagGCCrossChampionshipPKPlayer> PlayerList)
+    GroupCount = 0    #(WORD GroupCount)
+    GroupList = list()    #(vector<tagGCCrossChampionshipPKGroup> GroupList)
+    data = None
+
+    def __init__(self):
+        self.Clear()
+        self.Head.Cmd = 0xC0
+        self.Head.SubCmd = 0x15
+        return
+
+    def ReadData(self, _lpData, _pos=0, _Len=0):
+        self.Clear()
+        _pos = self.Head.ReadData(_lpData, _pos)
+        self.ActID,_pos = CommFunc.ReadDWORD(_lpData, _pos)
+        self.StateError,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        self.ZoneID,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        self.PlayerCount,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        for i in range(self.PlayerCount):
+            temPlayerList = tagGCCrossChampionshipPKPlayer()
+            _pos = temPlayerList.ReadData(_lpData, _pos)
+            self.PlayerList.append(temPlayerList)
+        self.GroupCount,_pos = CommFunc.ReadWORD(_lpData, _pos)
+        for i in range(self.GroupCount):
+            temGroupList = tagGCCrossChampionshipPKGroup()
+            _pos = temGroupList.ReadData(_lpData, _pos)
+            self.GroupList.append(temGroupList)
+        return _pos
+
+    def Clear(self):
+        self.Head = tagHead()
+        self.Head.Clear()
+        self.Head.Cmd = 0xC0
+        self.Head.SubCmd = 0x15
+        self.ActID = 0
+        self.StateError = 0
+        self.ZoneID = 0
+        self.PlayerCount = 0
+        self.PlayerList = list()
+        self.GroupCount = 0
+        self.GroupList = list()
+        return
+
+    def GetLength(self):
+        length = 0
+        length += self.Head.GetLength()
+        length += 4
+        length += 1
+        length += 1
+        length += 1
+        for i in range(self.PlayerCount):
+            length += self.PlayerList[i].GetLength()
+        length += 2
+        for i in range(self.GroupCount):
+            length += self.GroupList[i].GetLength()
+
+        return length
+
+    def GetBuffer(self):
+        data = ''
+        data = CommFunc.WriteString(data, self.Head.GetLength(), self.Head.GetBuffer())
+        data = CommFunc.WriteDWORD(data, self.ActID)
+        data = CommFunc.WriteBYTE(data, self.StateError)
+        data = CommFunc.WriteBYTE(data, self.ZoneID)
+        data = CommFunc.WriteBYTE(data, self.PlayerCount)
+        for i in range(self.PlayerCount):
+            data = CommFunc.WriteString(data, self.PlayerList[i].GetLength(), self.PlayerList[i].GetBuffer())
+        data = CommFunc.WriteWORD(data, self.GroupCount)
+        for i in range(self.GroupCount):
+            data = CommFunc.WriteString(data, self.GroupList[i].GetLength(), self.GroupList[i].GetBuffer())
+        return data
+
+    def OutputString(self):
+        DumpString = '''
+                                Head:%s,
+                                ActID:%d,
+                                StateError:%d,
+                                ZoneID:%d,
+                                PlayerCount:%d,
+                                PlayerList:%s,
+                                GroupCount:%d,
+                                GroupList:%s
+                                '''\
+                                %(
+                                self.Head.OutputString(),
+                                self.ActID,
+                                self.StateError,
+                                self.ZoneID,
+                                self.PlayerCount,
+                                "...",
+                                self.GroupCount,
+                                "..."
+                                )
+        return DumpString
+
+
+m_NAtagGCCrossChampionshipPKZoneGroupInfo=tagGCCrossChampionshipPKZoneGroupInfo()
+ChNetPackDict[eval("0x%02x%02x"%(m_NAtagGCCrossChampionshipPKZoneGroupInfo.Head.Cmd,m_NAtagGCCrossChampionshipPKZoneGroupInfo.Head.SubCmd))] = m_NAtagGCCrossChampionshipPKZoneGroupInfo
 
 
 #------------------------------------------------------
@@ -41311,6 +42650,58 @@
 
 
 #------------------------------------------------------
+# C1 09 跨服排位玩家信息 #tagMCChampionshipPlayerInfo
+
+class  tagMCChampionshipPlayerInfo(Structure):
+    _pack_ = 1
+    _fields_ = [
+                  ("Cmd", c_ubyte),
+                  ("SubCmd", c_ubyte),
+                  ("WorshipCount", c_ubyte),    # 今日已膜拜次数
+                  ]
+
+    def __init__(self):
+        self.Clear()
+        self.Cmd = 0xC1
+        self.SubCmd = 0x09
+        return
+
+    def ReadData(self, stringData, _pos=0, _len=0):
+        self.Clear()
+        memmove(addressof(self), stringData[_pos:], self.GetLength())
+        return _pos + self.GetLength()
+
+    def Clear(self):
+        self.Cmd = 0xC1
+        self.SubCmd = 0x09
+        self.WorshipCount = 0
+        return
+
+    def GetLength(self):
+        return sizeof(tagMCChampionshipPlayerInfo)
+
+    def GetBuffer(self):
+        return string_at(addressof(self), self.GetLength())
+
+    def OutputString(self):
+        DumpString = '''// C1 09 跨服排位玩家信息 //tagMCChampionshipPlayerInfo:
+                                Cmd:%s,
+                                SubCmd:%s,
+                                WorshipCount:%d
+                                '''\
+                                %(
+                                self.Cmd,
+                                self.SubCmd,
+                                self.WorshipCount
+                                )
+        return DumpString
+
+
+m_NAtagMCChampionshipPlayerInfo=tagMCChampionshipPlayerInfo()
+ChNetPackDict[eval("0x%02x%02x"%(m_NAtagMCChampionshipPlayerInfo.Cmd,m_NAtagMCChampionshipPlayerInfo.SubCmd))] = m_NAtagMCChampionshipPlayerInfo
+
+
+#------------------------------------------------------
 # C1 07 跨服战场玩家信息 #tagMCCrossBattlefieldPlayerInfo
 
 class  tagMCCrossBattlefieldPlayerInfo(Structure):
diff --git a/ServerPython/CoreServerGroup/GameServer/Script/GM/Commands/Championship.py b/ServerPython/CoreServerGroup/GameServer/Script/GM/Commands/Championship.py
new file mode 100644
index 0000000..ed55d47
--- /dev/null
+++ b/ServerPython/CoreServerGroup/GameServer/Script/GM/Commands/Championship.py
@@ -0,0 +1,251 @@
+#!/usr/bin/python
+# -*- coding: GBK -*-
+#-------------------------------------------------------------------------------
+#
+##@package GM.Commands.Championship
+#
+# @todo:跨服排位争霸赛
+# @author hxp
+# @date 2022-09-21
+# @version 1.0
+#
+# 详细描述: 跨服排位争霸赛
+#
+#-------------------------------------------------------------------------------
+#"""Version = 2022-09-21 21:30"""
+#-------------------------------------------------------------------------------
+
+import GameWorld
+import CrossChampionship
+import PlayerDBGSEvent
+import ShareDefine
+
+
+#逻辑实现
+## 执行逻辑
+#  @param curPlayer 当前玩家
+#  @param gmList [cmdIndex gmAccID msg]
+#  @return None
+#  @remarks 函数详细说明.
+def OnExec(curPlayer, gmList):
+    ## 本服处理
+    GameWorld.DebugAnswer(curPlayer, "----------------------------")
+    if not gmList:
+        champMgr = CrossChampionship.GetChampionshipMgr()
+        ID = PlayerDBGSEvent.GetDBGSTrig_ByKey(PlayerDBGSEvent.Def_CrossChampionshipID)
+        State = PlayerDBGSEvent.GetDBGSTrig_ByKey(PlayerDBGSEvent.Def_CrossChampionshipState)
+        GameWorld.DebugAnswer(curPlayer, "跨服排位争霸:ID:%s,State:%s,%s" % (ID, State, champMgr.GetChampPKZoneIDList()))
+        GameWorld.DebugAnswer(curPlayer, "重置活动数据: Championship 0 是否重置仙官")
+        GameWorld.DebugAnswer(curPlayer, "输出活动数据: Championship print")
+        GameWorld.DebugAnswer(curPlayer, "设置参赛玩家: Championship 80 分区 人数 玩家ID1 ...")
+        GameWorld.DebugAnswer(curPlayer, "人数最大64,不足则可能有轮空的组,指定玩家ID不足人数则以假人代替")
+        GameWorld.DebugAnswer(curPlayer, "指定玩家分组: Championship 分组状态 分区ID 玩家ID1 ID2 ...")
+        GameWorld.DebugAnswer(curPlayer, "分组状态:641-64强;321-32强;161-16强;81-8强;ID1ID2两两分在一组")
+        GameWorld.DebugAnswer(curPlayer, "命令需在对应的阶段设置才有效;")
+        GameWorld.DebugAnswer(curPlayer, "重置活动数据需在非活动时间重置,不然可能导致活动状态异常")
+        
+    else:
+        value1 = gmList[0]
+        
+        if value1 == "print":
+            __PrintChampionshipInfo()
+            return
+        
+    return
+
+def OnGetMergeParam(curPlayer):
+    playerID = curPlayer.GetPlayerID()
+    serverGroupID = GameWorld.GetServerGroupID()
+    return [serverGroupID, playerID]
+
+def OnMergeServerExec(gmList, tick):
+    ## 跨服处理
+    
+    serverGroupID = gmList[-2]
+    playerID = gmList[-1]
+    
+    gmList = gmList[:-2]
+    if not gmList:
+        return
+    
+    value1 = gmList[0]
+    
+    if value1 == "print":
+        __PrintChampionshipInfo()
+        GameWorld.DebugAnswerCross(playerID, serverGroupID, "输出完毕,请查看跨服GameServer日志")
+        return
+    
+    state = PlayerDBGSEvent.GetDBGSTrig_ByKey(PlayerDBGSEvent.Def_CrossChampionshipState)
+    champMgr = CrossChampionship.GetChampionshipMgr()
+    pkZoneIDList = champMgr.GetChampPKZoneIDList()
+    if value1 == 0:
+        if state in ShareDefine.CrossChampionshipStateList and state != ShareDefine.CrossChampionshipStateList[0]:
+            GameWorld.DebugAnswerCross(playerID, serverGroupID, "重置数据需在非活动中或64强分组前")
+            return
+        
+        isResetOfficial = gmList[1] if len(gmList) > 1 else 0
+        
+        PlayerDBGSEvent.SetDBGSTrig_ByKey(PlayerDBGSEvent.Def_CrossChampionshipID, 0)
+        PlayerDBGSEvent.SetDBGSTrig_ByKey(PlayerDBGSEvent.Def_CrossChampionshipState, 0)
+        PlayerDBGSEvent.SetDBGSTrig_ByKey(PlayerDBGSEvent.Def_CrossChampionshipStateError, 0)
+        
+        champMgr.ClearPKZone()
+        if isResetOfficial:
+            champMgr.ClearOfficialZone()
+            
+        GameWorld.DebugAnswerCross(playerID, serverGroupID, "重置数据成功")
+        
+        CrossChampionship.Sync_CrossChampionshipDataToClientServer()
+        CrossChampionship.OnMinuteProcess()
+        return
+    
+    stateError = PlayerDBGSEvent.GetDBGSTrig_ByKey(PlayerDBGSEvent.Def_CrossChampionshipStateError)
+    if stateError:
+        GameWorld.DebugAnswerCross(playerID, serverGroupID, "活动数据状态顺序已经异常,无法处理")
+        return
+    
+    if value1 in ShareDefine.CrossChampionshipStateList:
+        if state != value1:
+            GameWorld.DebugAnswerCross(playerID, serverGroupID, "非对应活动状态中,无法设置,当前状态%s" % state)
+            return
+        
+    maxPlayerCount = CrossChampionship.Def_CrossChampionshipPlayerMax
+    # 设置参赛玩家
+    if value1 == ShareDefine.CrossChampionshipState_Guess8:
+        if len(gmList) < 3:
+            GameWorld.DebugAnswerCross(playerID, serverGroupID, "参数错误,详见命令说明")
+            return
+        zoneID = gmList[1]
+        batPlayerCount = min(maxPlayerCount, gmList[2])
+        setPlayerIDList = gmList[3:]
+        if zoneID not in pkZoneIDList:
+            GameWorld.DebugAnswerCross(playerID, serverGroupID, "不存在该分区!zoneID=%s" % zoneID)
+            return
+        if len(setPlayerIDList) < batPlayerCount:
+            # 不足的机器人补足
+            setPlayerIDList += range(1001, 1001 + (batPlayerCount - len(setPlayerIDList)))
+        pkZoneMgr = champMgr.GetChampPKZoneMgr(zoneID)
+        pkZoneMgr.playerDict = {} # 清空玩家,重新设置
+        CrossChampionship.Send_CrossServerMsg_ChampionshipPlayer(isSync=True)
+        for pID in setPlayerIDList:
+            batPlayer = CrossChampionship.ChampionshipBatPlayer()
+            batPlayer.zoneID = zoneID
+            batPlayer.playerID = pID
+            pkZoneMgr.playerDict[pID] = batPlayer
+            
+        GameWorld.DebugAnswerCross(playerID, serverGroupID, "设置参赛玩家成功:zoneID=%s,人数=%s" % (zoneID, len(setPlayerIDList)))
+        CrossChampionship.Send_CrossServerMsg_ChampionshipPlayer(isSync=True)
+        return
+    
+    # 指定玩家分组
+    canSetGroupStateList = [ShareDefine.CrossChampionshipState_Group64, ShareDefine.CrossChampionshipState_Group32, 
+                            ShareDefine.CrossChampionshipState_Group16, ShareDefine.CrossChampionshipState_Group8]
+    if value1 in canSetGroupStateList:
+        if len(gmList) < 2:
+            GameWorld.DebugAnswerCross(playerID, serverGroupID, "分组参数错误,详见命令说明")
+            return
+        groupMark = value1 / 10
+        zoneID = gmList[1]
+        groupPlayerIDList = gmList[2:]
+        
+        pkZoneMgr = champMgr.GetChampPKZoneMgr(zoneID)
+        for i in range(len(groupPlayerIDList))[::2]:
+            vsI = i + 1
+            if len(groupPlayerIDList) < vsI:
+                GameWorld.DebugAnswerCross(playerID, serverGroupID, "设置分组玩家ID数不匹配")
+                break
+            APlayerID = groupPlayerIDList[i]
+            BPlayerID = groupPlayerIDList[vsI]
+            
+            changeBatNum = None
+            vsPlayerIDList = [APlayerID, BPlayerID]
+            chPlayerIDList = []
+            
+            battleDict = pkZoneMgr.battleInfo.get(groupMark, {})
+            for battleNum in battleDict.keys():
+                batObj = pkZoneMgr.GetBattle(groupMark, battleNum)
+                if not batObj:
+                    continue
+                playerIDList = [batObj.playerIDA, batObj.playerIDB]
+                if APlayerID in playerIDList and BPlayerID in playerIDList:
+                    GameWorld.DebugAnswerCross(playerID, serverGroupID, "设置成功:%s VS %s" % (APlayerID, BPlayerID))
+                    break
+                if APlayerID not in playerIDList and BPlayerID not in playerIDList:
+                    continue
+                
+                for pID in playerIDList:
+                    if pID not in vsPlayerIDList:
+                        chPlayerIDList.append(pID)
+                        
+                if changeBatNum == None:
+                    changeBatNum = battleNum
+                    continue
+                
+                changeBatObj = pkZoneMgr.GetBattle(groupMark, changeBatNum)
+                changeBatObj.playerIDA = vsPlayerIDList[0]
+                changeBatObj.playerIDB = vsPlayerIDList[1]
+                
+                batObj.playerIDA = chPlayerIDList[0] if len(chPlayerIDList) > 0 else 0
+                batObj.playerIDB = chPlayerIDList[1] if len(chPlayerIDList) > 1 else 0
+                GameWorld.DebugAnswerCross(playerID, serverGroupID, "设置成功:%s VS %s" % (APlayerID, BPlayerID))
+                GameWorld.DebugAnswerCross(playerID, serverGroupID, "交换成功:%s VS %s" % (batObj.playerIDA, batObj.playerIDB))
+                changeBatNum = "OK"
+                
+            if changeBatNum != "OK":
+                GameWorld.DebugAnswerCross(playerID, serverGroupID, "分组失败,检查玩家是否在本分组:%s VS %s" % (APlayerID, BPlayerID))
+                
+        CrossChampionship.Send_CrossServerMsg_ChampionshipGroup(groupMark)
+        return
+    
+    GameWorld.DebugAnswerCross(playerID, serverGroupID, "命令参数错误,详见命令说明")
+    return
+
+def __PrintChampionshipInfo():
+    GameWorld.Log("================ 跨服排位当前信息 ==================")
+    ID = PlayerDBGSEvent.GetDBGSTrig_ByKey(PlayerDBGSEvent.Def_CrossChampionshipID)
+    state = PlayerDBGSEvent.GetDBGSTrig_ByKey(PlayerDBGSEvent.Def_CrossChampionshipState)
+    stateError = PlayerDBGSEvent.GetDBGSTrig_ByKey(PlayerDBGSEvent.Def_CrossChampionshipStateError)
+    champMgr = CrossChampionship.GetChampionshipMgr()
+    pkZoneIDList = champMgr.GetChampPKZoneIDList()
+    GameWorld.Log("ID=%s,state=%s,stateError=%s,pkZoneIDList=%s" % (ID, state, stateError, pkZoneIDList))
+    for zoneID in pkZoneIDList:
+        pkZoneMgr = champMgr.GetChampPKZoneMgr(zoneID)
+        
+#            self.guessInfo = {} # 竞猜信息 {竞猜类型:[ChampionshipGuess, ...], ...}
+#            self.superPlayerCountInfo = {} # {竞猜类型:{playerID:支持人数, ...}, ...}
+        
+        batPlayerIDList = pkZoneMgr.GetBatPlayerIDList()
+        GameWorld.Log("=== 参赛玩家 === zoneID=%s,playerCount=%s" % (zoneID, len(batPlayerIDList)))
+        for i, playerID in enumerate(batPlayerIDList, 1):
+            batPlayer = pkZoneMgr.GetBatPlayer(playerID)
+            if not batPlayer:
+                continue
+            GameWorld.Log("    %s,playerID=%s,fightPower=%s,accID=%s" % (i, batPlayer.playerID, batPlayer.fightPower, batPlayer.accID))
+            
+        groupMarkKeys = pkZoneMgr.battleInfo.keys()
+        GameWorld.Log("=== 分组信息 === zoneID=%s,%s" % (zoneID, groupMarkKeys))
+        for groupMark, battleDict in pkZoneMgr.battleInfo.items():
+            GameWorld.Log("    groupMark=%s,battleCount=%s" % (groupMark, len(battleDict)))
+            for battleNum in battleDict.keys():
+                batObj = pkZoneMgr.GetBattle(groupMark, battleNum)
+                if not batObj:
+                    continue
+                GameWorld.Log("        groupMark=%s,battleNum=%s,playerIDA=%s,playerIDB=%s,winPlayerID=%s" 
+                              % (groupMark, battleNum, batObj.playerIDA, batObj.playerIDB, batObj.winPlayerID))
+                
+    offZoneIDList = champMgr.GetChampOfficialZoneIDList()
+    GameWorld.Log("仙官分区: offZoneIDList=%s" % offZoneIDList)
+    for zoneID in offZoneIDList:
+        offZoneMgr = champMgr.GetChampOfficialZoneMgr(zoneID)
+        officialIDList = offZoneMgr.officialInfo.keys()
+        GameWorld.Log("=== 仙官信息 === zoneID=%s,%s" % (zoneID, officialIDList))
+        for officialID in officialIDList:
+            offObj = offZoneMgr.GetOfficialObj(officialID)
+            if not offObj:
+                continue
+            GameWorld.Log("    officialID=%s,playerID=%s,rank=%s,worshipCount=%s,applyPlayerIDList=%s,challengeCount=%s" 
+                          % (officialID, offObj.playerID, offObj.rank, offObj.worshipCount, offObj.applyPlayerInfo.keys(), len(offObj.challengeList)))
+            
+    GameWorld.Log("==================================================")
+    return
+
diff --git a/ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/CrossChampionship.py b/ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/CrossChampionship.py
new file mode 100644
index 0000000..06ca95c
--- /dev/null
+++ b/ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/CrossChampionship.py
@@ -0,0 +1,2971 @@
+#!/usr/bin/python
+# -*- coding: GBK -*-
+#-------------------------------------------------------------------------------
+#
+##@package CrossChampionship
+#
+# @todo:跨服排位争霸赛
+# @author hxp
+# @date 2022-09-21
+# @version 1.0
+#
+# 详细描述: 跨服排位争霸赛
+#
+#-------------------------------------------------------------------------------
+#"""Version = 2022-09-21 21:30"""
+#-------------------------------------------------------------------------------
+
+import GameWorld
+import ShareDefine
+import IpyGameDataPY
+import PlayerViewCache
+import PlayerDBGSEvent
+import ChPyNetSendPack
+import IPY_PlayerDefine
+import PlayerCompensation
+import CrossRealmPlayer
+import DataRecordPack
+import CrossRealmMsg
+import PlayerControl
+import PyDataManager
+import NetPackCommon
+import PyGameData
+import ChConfig
+import PlayerFB
+
+import datetime
+import random
+import time
+
+Def_CrossChampionshipPlayerMax = 64 # 最大玩家数
+Def_CrossChampionshipPlayerWFCount = 8 # 胜负排位所需玩家数
+
+Def_RecType_CrossChampionshipGroup = ShareDefine.Def_UniversalGameRecType_CrossChampionshipGroup
+'''
+跨服排位争霸赛分组信息
+ShareDefine.Def_UniversalGameRecType_CrossChampionshipGroup
+time:time                战斗结算时间
+value1:zoneID            分区ID
+value2:groupInfo         分组标识*100+对战编号
+value3:playerIDA        玩家IDA
+value4:playerIDB        玩家IDB
+value5:winPlayerID      获胜玩家ID
+'''
+
+Def_RecType_CrossChampionshipGuess = ShareDefine.Def_UniversalGameRecType_CrossChampionshipGuess
+'''
+跨服排位争霸赛竞猜记录信息
+ShareDefine.Def_UniversalGameRecType_CrossChampionshipGuess
+value1:zoneID            分区ID
+value2:guessInfo         竞猜类型*100 + 竞猜值:  类型:8-8强;4-4强; 值:对应排名
+value3:guessPlayerID     竞猜玩家ID
+value4:tagPlayerID       目标玩家ID
+value5:moneyTotal        投注总货币值
+'''
+
+Def_RecType_CrossChampionshipOfficial = ShareDefine.Def_UniversalGameRecType_CrossChampionshipOfficial
+'''
+跨服排位争霸赛最终排名官职信息
+ShareDefine.Def_UniversalGameRecType_CrossChampionshipOfficial
+time:time                上一次辞退下级仙官时间
+value1:zoneID官职ID      官职ID*10 + 分区ID
+value2:playerID          玩家ID,可能为0
+value3:worshipValue      被膜拜次数*10 + 是否双倍
+value4:rank              排名
+StrValue3:               [申请该官职玩家ID,...]
+'''
+
+Def_RecType_CrossChampionshipOffChallenge = ShareDefine.Def_UniversalGameRecType_CrossChampionshipOffChallenge
+'''
+跨服排位争霸赛官职挑战信息
+ShareDefine.Def_UniversalGameRecType_CrossChampionshipOffChallenge
+value1:zoneID官职ID      官职ID*10 + 分区ID
+StrValue3:               {挑战玩家信息key:value, ...}
+'''
+
+class ChampionshipOfficial():
+    ## 争霸赛官爵玩家
+    
+    def __init__(self):
+        self.zoneID = 0
+        self.officialID = 0 # 官职ID
+        self.lastDismissJuniorTime = 0 # 上次辞退下级仙官时间戳
+        
+        self.rank = 0 # 名次
+        self.worshipCount = 0 # 被膜拜次数,人气值
+        self.applyPlayerInfo = {} # 申请该官职玩家信息 {playerID:{玩家简短信息字典}, ...}
+        self.challengeList = [] # 挑战记录信息 [{挑战玩家信息key:value, ...}, ...] key: Ret,AccID,Name,Time
+        
+        self.ResetPlayer()
+        
+        self.worshipDouble = 0 # 膜拜是否双倍 
+        return
+    
+    def ResetPlayer(self):
+        self.playerID = 0
+        self.accID = ""
+        self.playerName = ""
+        self.job = 0
+        self.lv = 0
+        self.fightPower = 0
+        self.realmLV = 0
+        return
+    
+    def GetString(self):
+        for applyPlayerID in self.applyPlayerInfo.keys():
+            curCache = PlayerViewCache.FindViewCache(applyPlayerID)
+            if curCache:
+                playerShortInfo = {}
+                cacheDict = PlayerViewCache.GetCachePropDataDict(curCache)
+                playerShortInfo["AccID"] = cacheDict.get("AccID", "")
+                playerShortInfo["Name"] = cacheDict.get("Name", str(applyPlayerID))
+                playerShortInfo["Job"] = cacheDict.get("Job", 1)
+                playerShortInfo["LV"] = cacheDict.get("LV", 1)
+                playerShortInfo["FightPower"] = cacheDict.get("FightPower", 0)
+                playerShortInfo["RealmLV"] = cacheDict.get("RealmLV", 0)
+                self.applyPlayerInfo[applyPlayerID] = playerShortInfo
+        return {"zoneID":self.zoneID, "officialID":self.officialID, "lastDismissJuniorTime":self.lastDismissJuniorTime,
+                "accID":self.accID, "playerID":self.playerID, "playerName":self.playerName,
+                "job":self.job, "lv":self.lv, "fightPower":self.fightPower, "realmLV":self.realmLV, "rank":self.rank,
+                "worshipCount":self.worshipCount, "applyPlayerInfo":self.applyPlayerInfo, "challengeList":self.challengeList,
+                "worshipDouble":self.worshipDouble
+                }
+        
+    def SetAttr(self, attrDict):
+        for k, v in attrDict.items():
+            setattr(self, k, v)
+        return
+    
+class ChampionshipOfficialZoneMgr():
+    ## 争霸赛排位分区管理
+    
+    def __init__(self, zoneID):
+        self.zoneID = zoneID
+        self.officialInfo = {} # 官爵信息 {officialID:ChampionshipOfficial, ...}
+        return
+    
+    def GetOfficialObj(self, officialID):
+        officialObj = None
+        if officialID in self.officialInfo:
+            officialObj = self.officialInfo[officialID]
+            if GameWorld.IsCrossServer() and officialObj.playerID:
+                UpdCachePlayerInfo(officialObj, officialObj.playerID)
+        else:
+            ipyData = IpyGameDataPY.GetIpyGameData("ChampionshipOfficial", officialID)
+            if ipyData:
+                officialObj = ChampionshipOfficial()
+                officialObj.zoneID = self.zoneID
+                officialObj.officialID = officialID
+                
+                self.officialInfo[officialID] = officialObj
+                
+        if not officialObj:
+            GameWorld.ErrLog("仙官官职数据信息不存在! officialID=%s" % officialID)
+            
+        return officialObj
+    
+    def GetPlayerOfficial(self, playerID):
+        for offObj in self.officialInfo.values():
+            if offObj.playerID == playerID:
+                return offObj
+        return
+    
+class ChampionshipGuess():
+    ## 争霸赛竞猜
+    
+    def __init__(self):
+        self.zoneID = 0
+        self.guessType = 0 # 竞猜类型:8-8强;4-4强
+        self.guessPlayerID = 0 # 竞猜玩家ID
+        self.tagPlayerID = 0 # 目标玩家ID
+        self.moneyTotal = 0 # 投注总货币值
+        self.guessRank = 0 # 竞猜名次,没有名次的竞猜默认0;1-代表第一名
+        return
+    
+    def GetString(self):
+        return {"zoneID":self.zoneID, "guessType":self.guessType, "guessRank":self.guessRank, 
+                "guessPlayerID":self.guessPlayerID, "tagPlayerID":self.tagPlayerID, "moneyTotal":self.moneyTotal}
+        
+    def SetAttr(self, attrDict):
+        for k, v in attrDict.items():
+            setattr(self, k, v)
+        return
+    
+    
+class ChampionshipBatPlayer():
+    ## 争霸赛玩家
+    
+    def __init__(self):
+        self.zoneID = 0
+        self.accID = ""
+        self.playerID = 0
+        self.playerName = ""
+        self.job = 0
+        self.lv = 0
+        self.fightPower = 0
+        self.realmLV = 0
+        return
+    
+    def GetString(self):
+        return {"zoneID":self.zoneID, "accID":self.accID, "playerID":self.playerID, "playerName":self.playerName,
+                "job":self.job, "lv":self.lv, "fightPower":self.fightPower, "realmLV":self.realmLV}
+    
+    def SetAttr(self, attrDict):
+        for k, v in attrDict.items():
+            setattr(self, k, v)
+        return
+    
+class ChampionshipBattle():
+    ## 争霸赛对战
+    
+    def __init__(self):
+        self.overTime = 0 # 战斗结算时间
+        self.zoneID = 0
+        self.groupMark = 0 # 分组标识,如 64 32 16 8 4 2
+        self.battleNum = 0 # 对战编号,如 1 ~ 32
+        self.playerIDA = 0
+        self.playerIDB = 0
+        self.winPlayerID = 0
+        
+        # 不存档
+        self.roomID = 0
+        self.mapID = 0
+        self.copyMapID = 0
+        return
+    
+    def GetString(self):
+        return {"overTime":self.overTime, "zoneID":self.zoneID, "groupMark":self.groupMark, "battleNum":self.battleNum,
+                "playerIDA":self.playerIDA, "playerIDB":self.playerIDB, "winPlayerID":self.winPlayerID}
+        
+    def SetAttr(self, attrDict):
+        for k, v in attrDict.items():
+            setattr(self, k, v)
+        return
+    
+class ChampionshipPKZoneMgr():
+    ## 争霸赛PK分区管理
+    
+    def __init__(self, zoneID):
+        self.zoneID = zoneID
+        self.playerDict = {} # 参赛玩家 {playerID:ChampionshipBatPlayer, ...}
+        self.battleInfo = {} # 分组对战信息 {分组标识:{对战编号:ChampionshipBattle, ...}, ...}
+        self.guessInfo = {} # 竞猜信息 {竞猜类型:{竞猜玩家ID:[ChampionshipGuess, ...]}, ...}
+        self.supportCountInfo = {} # {竞猜类型:{被竞猜玩家ID:支持人数, ...}, ...}
+        
+        # 子服
+        self.syncGuessPlayerIDInfo = {} # 同步过竞猜信息的玩家ID {playerID:tick, ...}
+        return
+    
+    def AddBattle(self, groupMark, battleNum, battle):
+        if groupMark not in self.battleInfo:
+            self.battleInfo[groupMark] = {}
+        battleDict = self.battleInfo[groupMark]
+        battleDict[battleNum] = battle
+        self.battleInfo[groupMark] = battleDict
+        return
+    
+    def GetBattle(self, groupMark, battleNum):
+        battle = None
+        if groupMark in self.battleInfo:
+            battleDict = self.battleInfo[groupMark]
+            if battleNum in battleDict:
+                battle = battleDict[battleNum]
+                
+        if not battle:
+            GameWorld.Log("无该跨服排位争霸赛对战场次信息: groupMark=%s,battleNum=%s" % (groupMark, battleNum))
+            
+        # 不可能执行的代码,方便 . 出提示代码
+        if False:
+            battle = ChampionshipBattle()
+        return battle
+    
+    def GetBatPlayerIDList(self): return self.playerDict.keys()
+    def GetBatPlayer(self, playerID):
+        batPlayer = None
+        if playerID in self.playerDict:
+            batPlayer = self.playerDict[playerID]
+            if GameWorld.IsCrossServer():
+                UpdCachePlayerInfo(batPlayer, playerID)
+                
+        # 不可能执行的代码,方便 . 出提示代码
+        if False:
+            batPlayer = ChampionshipBatPlayer()
+        return batPlayer
+    
+    def GetPlayerGuessList(self, playerID, guessType):
+        ## 获取玩家竞猜列表
+        if guessType not in self.guessInfo:
+            self.guessInfo[guessType] = {}
+        playerGuessDict = self.guessInfo[guessType]
+        if playerID not in playerGuessDict:
+            playerGuessDict[playerID] = []
+        return playerGuessDict[playerID]
+    
+    def GetTop8PlayerIDList(self):
+        ## 获取前8强玩家ID列表
+        top8PlayerIDList = []
+        preGroupMark = 16 # 取16强战斗胜者
+        battleNumList = self.battleInfo.get(preGroupMark, {}).keys()
+        for battleNum in battleNumList:
+            batObj = self.GetBattle(preGroupMark, battleNum)
+            if not batObj:
+                continue
+            if batObj.overTime and batObj.winPlayerID:
+                top8PlayerIDList.append(batObj.winPlayerID)
+        return top8PlayerIDList
+    
+def UpdCachePlayerInfo(obj, playerID):
+    ## 更新玩家缓存信息
+    
+    # 机器人
+    if not obj or not hasattr(obj, "playerName"):
+        return
+    
+    if playerID < 10000:
+        if obj.playerName:
+            return
+        obj.accID = "accID%s@robot@s1" % (playerID)
+        obj.playerName = "name%s" % playerID
+        obj.job = random.randint(1, 2)
+        obj.lv = random.randint(200, 300)
+        obj.fightPower = random.randint(100000, 1000000)
+        obj.realmLV = random.randint(10, 20)
+        return
+    curCache = PlayerViewCache.FindViewCache(playerID)
+    if curCache:
+        cacheDict = PlayerViewCache.GetCachePropDataDict(curCache)
+        obj.accID = cacheDict.get("AccID", obj.accID)
+        obj.playerName = cacheDict.get("Name", obj.playerName)
+        obj.job = cacheDict.get("Job", obj.job)
+        obj.lv = cacheDict.get("LV", obj.lv)
+        obj.fightPower = cacheDict.get("FightPower", obj.fightPower)
+        obj.realmLV = cacheDict.get("RealmLV", obj.realmLV)
+        
+    return
+
+class ChampionshipMgr():
+    ## 争霸赛管理
+    
+    def __init__(self):
+        '''注意区分跨服匹配分区、排位分区、仙官分区,三者不一样
+                                        匹配分区:当前进行中的跨服匹配PK分区 CrossRealmPK
+                                        排位分区:取上一赛季的跨服匹配PK分区排名前64作为PK分区,可能与当前进行中的跨服PK分区不一样
+                                        仙官分区:由排位分区PK决出的结果做为仙官分区,可能与当前进行中的排位PK分区不一样
+        '''
+        self._pkZoneInfo = {} # 排位对战分区 {zoneID:ChampionshipZoneMgr, ...}
+        self._officialZoneInfo = {} # 仙官分区 {zoneID:ChampionshipOfficialZoneMgr, ...}
+        return
+    
+    def ClearPKZone(self):
+        self._pkZoneInfo = {}
+        return
+    
+    def GetChampPKZoneIDList(self): return self._pkZoneInfo.keys()
+    def GetChampPKZoneMgr(self, zoneID):
+        if zoneID in self._pkZoneInfo:
+            pkZoneMgr = self._pkZoneInfo[zoneID]
+        else:
+            pkZoneMgr = ChampionshipPKZoneMgr(zoneID)
+            self._pkZoneInfo[zoneID] = pkZoneMgr
+        return pkZoneMgr
+    
+    def GetPlayerPKZoneID(self, playerID):
+        ## 获取玩家排位玩法所属分区 - 子服专用
+        # @return: 如果在排位中则返回所在排位分区,否则返回当前服务器所在跨服匹配PK分区
+        for zoneID in self._pkZoneInfo.keys():
+            pkZoneMgr = self.GetChampPKZoneMgr(zoneID)
+            if playerID in pkZoneMgr.GetBatPlayerIDList():
+                return zoneID
+        return GameWorld.GetGameWorld().GetDictByKey(ShareDefine.Def_Notify_WorldKey_CrossPKZoneID)
+    
+    ##=============================================================================================
+    
+    def ClearOfficialZone(self):
+        self._officialZoneInfo = {}
+        return
+    
+    def GetChampOfficialZoneIDList(self): return self._officialZoneInfo.keys()
+    def GetChampOfficialZoneMgr(self, zoneID):
+        if zoneID in self._officialZoneInfo:
+            offZoneMgr = self._officialZoneInfo[zoneID]
+        else:
+            offZoneMgr = ChampionshipOfficialZoneMgr(zoneID)
+            self._officialZoneInfo[zoneID] = offZoneMgr
+        return offZoneMgr
+    
+    def GetPlayerOfficialZoneID(self, playerID):
+        ## 获取玩家排位玩法所属分区 - 子服专用
+        # @return: 如果在分区任职中则返回所在排位分区,否则返回当前服务器所在跨服匹配PK分区
+        for zoneID in self._officialZoneInfo.keys():
+            offZoneMgr = self.GetChampOfficialZoneMgr(zoneID)
+            if offZoneMgr.GetPlayerOfficial(playerID):
+                return zoneID
+        return GameWorld.GetGameWorld().GetDictByKey(ShareDefine.Def_Notify_WorldKey_CrossPKZoneID)
+    
+def GetChampionshipMgr():
+    mgr = PyGameData.g_championshipMgr
+    if mgr == None:
+        mgr = ChampionshipMgr()
+        PyGameData.g_championshipMgr = mgr
+    return mgr
+
+def OnServerStart():
+    
+    if not GameWorld.IsCrossServer():
+        return
+    
+    champMgr = GetChampionshipMgr()
+    
+    universalRecMgr = GameWorld.GetUniversalRecMgr()
+    groupRecDataList = universalRecMgr.GetTypeList(Def_RecType_CrossChampionshipGroup)
+    GameWorld.Log("加载跨服排位玩家分组记录! %s" % groupRecDataList.Count())
+    groupMarkList = ShareDefine.CrossChampionshipEnterStateInfo.values()
+    
+    for index in xrange(groupRecDataList.Count()):
+        recData = groupRecDataList.At(index)
+        overTime = recData.GetTime()
+        zoneID = recData.GetValue1()
+        groupInfo = recData.GetValue2()
+        playerIDA = recData.GetValue3()
+        playerIDB = recData.GetValue4()
+        winPlayerID = recData.GetValue5()
+        
+        #if not playerIDA and not playerIDB:
+        #    continue
+        
+        groupMark = groupInfo / 100
+        battleNum = groupInfo % 100
+        
+        pkZoneMgr = champMgr.GetChampPKZoneMgr(zoneID)
+        
+        if groupMark in groupMarkList and battleNum:
+            battle = ChampionshipBattle()
+            battle.overTime = overTime
+            battle.zoneID = zoneID
+            battle.groupMark = groupMark
+            battle.battleNum = battleNum
+            battle.playerIDA = playerIDA
+            battle.playerIDB = playerIDB
+            battle.winPlayerID = winPlayerID
+            pkZoneMgr.AddBattle(groupMark, battleNum, battle)
+            GameWorld.Log("分组玩家: zoneID=%s,groupMark=%s,battleNum=%s,playerIDA=%s,playerIDB=%s,winPlayerID=%s" 
+                          % (zoneID, groupMark, battleNum, playerIDA, playerIDB, winPlayerID))
+            
+        # 非分组数据为参赛玩家数据
+        elif playerIDA:
+            playerID = playerIDA
+            batPlayer = ChampionshipBatPlayer()
+            batPlayer.zoneID = zoneID
+            batPlayer.playerID = playerID
+            pkZoneMgr.playerDict[playerID] = batPlayer
+            GameWorld.Log("参赛玩家: zoneID=%s,playerID=%s" % (zoneID, playerID))
+            
+    guessRecDataList = universalRecMgr.GetTypeList(Def_RecType_CrossChampionshipGuess)
+    GameWorld.Log("加载跨服排位玩家竞猜记录! %s" % guessRecDataList.Count())
+    for index in xrange(guessRecDataList.Count()):
+        recData = guessRecDataList.At(index)
+        zoneID = recData.GetValue1()
+        guessInfo = recData.GetValue2()
+        guessType = guessInfo / 100
+        guessRank = guessInfo % 100
+        guessPlayerID = recData.GetValue3()
+        tagPlayerID = recData.GetValue4()
+        moneyTotal = recData.GetValue5()
+        
+        pkZoneMgr = champMgr.GetChampPKZoneMgr(zoneID)
+        playerGuessList = pkZoneMgr.GetPlayerGuessList(guessPlayerID, guessType)
+        guessObj = ChampionshipGuess()
+        guessObj.zoneID = zoneID
+        guessObj.guessType = guessType
+        guessObj.guessRank = guessRank
+        guessObj.guessPlayerID = guessPlayerID
+        guessObj.tagPlayerID = tagPlayerID
+        guessObj.moneyTotal = moneyTotal
+        playerGuessList.append(guessObj)
+        
+        if guessType not in pkZoneMgr.supportCountInfo:
+            pkZoneMgr.supportCountInfo[guessType] = {}
+        playerSupportCountDict = pkZoneMgr.supportCountInfo[guessType]
+        playerSupportCountDict[tagPlayerID] = playerSupportCountDict.get(tagPlayerID, 0) + 1
+        
+    officialRecDataList = universalRecMgr.GetTypeList(Def_RecType_CrossChampionshipOfficial)
+    GameWorld.Log("加载跨服排位玩家官职信息! %s" % officialRecDataList.Count())
+    for index in xrange(officialRecDataList.Count()):
+        recData = officialRecDataList.At(index)
+        lastDismissJuniorTime = recData.GetTime()
+        value1 = recData.GetValue1()
+        officialID = value1 / 10
+        zoneID = value1 % 10
+        playerID = recData.GetValue2()
+        worshipValue = recData.GetValue3()
+        worshipCount = worshipValue / 10
+        worshipDouble = worshipValue % 10
+        rank = recData.GetValue4()
+        strValue3 = recData.GetStrValue3()
+        try:
+            applyPlayerIDList = eval(strValue3) if strValue3 else []
+        except:
+            applyPlayerIDList = []
+            
+        offZoneMgr = champMgr.GetChampOfficialZoneMgr(zoneID)
+        
+        offObj = ChampionshipOfficial()
+        offObj.zoneID = zoneID
+        offObj.officialID = officialID
+        offObj.lastDismissJuniorTime = lastDismissJuniorTime
+        offObj.playerID = playerID
+        offObj.worshipCount = worshipCount
+        offObj.worshipDouble = worshipDouble
+        offObj.rank = rank
+        offObj.applyPlayerInfo = {applyPlayerID:{} for applyPlayerID in applyPlayerIDList}
+        
+        offZoneMgr.officialInfo[officialID] = offObj
+        GameWorld.Log("    zoneID=%s,officialID=%s,playerID=%s,rank=%s" % (zoneID, officialID, playerID, rank))
+        
+    challengeRecDataList = universalRecMgr.GetTypeList(Def_RecType_CrossChampionshipOffChallenge)
+    GameWorld.Log("加载跨服排位官职挑战记录信息! %s" % challengeRecDataList.Count())
+    for index in xrange(challengeRecDataList.Count()):
+        recData = challengeRecDataList.At(index)
+        value1 = recData.GetValue1()
+        officialID = value1 / 10
+        zoneID = value1 % 10
+        strValue3 = recData.GetStrValue3()
+        if not strValue3:
+            continue
+        try:
+            challengeDict = eval(strValue3)
+        except:
+            continue
+        
+        offZoneMgr = champMgr.GetChampOfficialZoneMgr(zoneID)
+        offObj = offZoneMgr.GetOfficialObj(officialID)
+        if not offObj:
+            continue
+        offObj.challengeList.append(challengeDict)
+        GameWorld.Log("    zoneID=%s,officialID=%s,挑战记录=%s" % (zoneID, officialID, challengeDict))
+        
+    return
+
+def OnServerClose():
+    
+    if not GameWorld.IsCrossServer():
+        return
+    
+    champMgr = GetChampionshipMgr()
+    universalRecMgr = GameWorld.GetUniversalRecMgr()
+    
+    pkZoneIDList = champMgr.GetChampPKZoneIDList()
+    GameWorld.Log("保存跨服排位玩家分组记录! pkZoneIDList=%s" % pkZoneIDList)
+    universalRecMgr.Delete(Def_RecType_CrossChampionshipGroup)
+    groupRecDataList = universalRecMgr.GetTypeList(Def_RecType_CrossChampionshipGroup)
+    for zoneID in pkZoneIDList:
+        pkZoneMgr = champMgr.GetChampPKZoneMgr(zoneID)
+        
+        # 保存参赛玩家名单
+        batPlayerIDList = pkZoneMgr.GetBatPlayerIDList()
+        GameWorld.Log("    zoneID=%s,batPlayerIDCount=%s, %s" % (zoneID, len(batPlayerIDList), batPlayerIDList))
+        for playerID in batPlayerIDList:
+            recData = groupRecDataList.AddRec()
+            recData.SetValue1(zoneID)
+            recData.SetValue2(0) # 无分组玩家,代表参赛玩家分组信息存0
+            recData.SetValue3(playerID)
+            
+        # 保存分组记录
+        GameWorld.Log("    zoneID=%s,battleInfoKey=%s" % (zoneID, pkZoneMgr.battleInfo.keys()))
+        for groupMark, groupDict in pkZoneMgr.battleInfo.items():
+            GameWorld.Log("        zoneID=%s,groupMark=%s,count=%s" % (zoneID, groupMark, len(groupDict)))
+            for battleNum, batObj in groupDict.items():
+                groupInfo = groupMark * 100 + battleNum # 分组标识*100+对战编号
+                recData = groupRecDataList.AddRec()
+                recData.SetTime(batObj.overTime)
+                recData.SetValue1(zoneID)
+                recData.SetValue2(groupInfo) # 无分组玩家,代表参赛玩家分组信息存0
+                recData.SetValue3(batObj.playerIDA)
+                recData.SetValue4(batObj.playerIDB)
+                recData.SetValue5(batObj.winPlayerID)
+                
+    GameWorld.Log("保存跨服排位玩家竞猜记录!")
+    universalRecMgr.Delete(Def_RecType_CrossChampionshipGuess)
+    guessRecDataList = universalRecMgr.GetTypeList(Def_RecType_CrossChampionshipGuess)
+    for zoneID in pkZoneIDList:
+        pkZoneMgr = champMgr.GetChampPKZoneMgr(zoneID)
+        for guessType, playerGuessDict in pkZoneMgr.guessInfo.items():
+            for guessPlayerID, guessObjList in playerGuessDict.items():
+                GameWorld.Log("    zoneID=%s,guessType=%s,guessPlayerID=%s,guessCount=%s" % (zoneID, guessType, guessPlayerID, len(guessObjList)))
+                for guessObj in guessObjList:
+                    recData = guessRecDataList.AddRec()
+                    recData.SetValue1(zoneID)
+                    recData.SetValue2(guessType * 100 + guessObj.guessRank)
+                    recData.SetValue3(guessPlayerID)
+                    recData.SetValue4(guessObj.tagPlayerID)
+                    recData.SetValue5(guessObj.moneyTotal)
+                    
+    offZoneIDList = champMgr.GetChampOfficialZoneIDList()
+    GameWorld.Log("保存跨服排位玩家官职信息! offZoneIDList=%s" % offZoneIDList)
+    universalRecMgr.Delete(Def_RecType_CrossChampionshipOfficial)
+    officialRecDataList = universalRecMgr.GetTypeList(Def_RecType_CrossChampionshipOfficial)
+    universalRecMgr.Delete(Def_RecType_CrossChampionshipOffChallenge)
+    challengeRecDataList = universalRecMgr.GetTypeList(Def_RecType_CrossChampionshipOffChallenge)
+    for zoneID in offZoneIDList:
+        offZoneMgr = champMgr.GetChampOfficialZoneMgr(zoneID)
+        GameWorld.Log("    zoneID=%s,officialInfoKey=%s" % (zoneID, offZoneMgr.officialInfo.keys()))
+        for officialID in offZoneMgr.officialInfo.keys():
+            offObj = offZoneMgr.GetOfficialObj(officialID)
+            if not offObj:
+                continue
+            value1 = offObj.officialID * 10 + zoneID
+            recData = officialRecDataList.AddRec()
+            recData.SetTime(offObj.lastDismissJuniorTime)
+            recData.SetValue1(value1)
+            recData.SetValue2(offObj.playerID)
+            recData.SetValue3(offObj.worshipCount * 10 + offObj.worshipDouble)
+            recData.SetValue4(offObj.rank)
+            strValue3 = "%s" % offObj.applyPlayerInfo.keys()
+            strValue3 = strValue3.replace(" ", "")
+            recData.SetStrValue3(strValue3)
+            
+            GameWorld.Log("        zoneID=%s,officialID=%s,playerID=%s,rank=%s,challengeCount=%s" 
+                          % (zoneID, officialID, offObj.playerID, offObj.rank, len(offObj.challengeList)))
+            for challengeDict in offObj.challengeList:
+                challRecData = challengeRecDataList.AddRec()
+                challRecData.SetValue1(value1)
+                strValue3 = str(challengeDict)
+                strValue3 = strValue3.replace(" ", "")
+                challRecData.SetStrValue3(strValue3)
+                
+    return
+
+def DoOnDay():
+    
+    if not GameWorld.IsCrossServer():
+        return
+    
+    dailyOfficialInfo = {}
+    champMgr = GetChampionshipMgr()
+    for zoneID in champMgr.GetChampOfficialZoneIDList():
+        offZoneMgr = champMgr.GetChampOfficialZoneMgr(zoneID)
+        for officialID in offZoneMgr.officialInfo.keys():
+            offObj = offZoneMgr.GetOfficialObj(officialID)
+            if not offObj:
+                continue
+            if not offObj.playerID:
+                continue
+            dailyOfficialInfo[offObj.playerID] = officialID
+            
+    if dailyOfficialInfo:
+        serverGroupIDList = []
+        CrossRealmMsg.SendMsgToClientServer(ShareDefine.CrossServerMsg_ChampionshipDailyOfficial, dailyOfficialInfo, serverGroupIDList)
+        
+    return
+
+def DoOnDayEx():
+    
+    if not GameWorld.IsCrossServer():
+        return
+    
+    champMgr = GetChampionshipMgr()
+    for zoneID in champMgr.GetChampOfficialZoneIDList():
+        syncOfficialIDList = []
+        mainOfficialList = [] # 仅主仙官可被膜拜
+        offZoneMgr = champMgr.GetChampOfficialZoneMgr(zoneID)
+        for officialID in offZoneMgr.officialInfo.keys():
+            offObj = offZoneMgr.GetOfficialObj(officialID)
+            if not offObj:
+                continue
+            if not offObj.playerID:
+                continue
+            
+            if offObj.worshipDouble:
+                offObj.worshipDouble = 0 # 重置每日双倍膜拜
+                syncOfficialIDList.append(officialID)
+                GameWorld.Log("重置今日双倍膜拜特权仙官: zoneID=%s,officialID=%s,playerID=%s" 
+                              % (zoneID, officialID, offObj.playerID), zoneID)
+                
+            mainIpyData = IpyGameDataPY.GetIpyGameData("ChampionshipOfficial", officialID)
+            if mainIpyData and mainIpyData.GetJuniorOfficialIDList():
+                mainOfficialList.append(offObj)
+                
+        if mainOfficialList:
+            offObj = random.choice(mainOfficialList)
+            officialID = offObj.officialID
+            offObj.worshipDouble = 1 # 随机某个仙官获得今日双倍特权
+            GameWorld.Log("随机今日双倍膜拜特权仙官: zoneID=%s,officialID=%s,playerID=%s" 
+                          % (zoneID, officialID, offObj.playerID), zoneID)
+            if officialID not in syncOfficialIDList:
+                syncOfficialIDList.append(officialID)
+                
+        if syncOfficialIDList:
+            Send_CrossServerMsg_ChampionshipOfficial(zoneID, syncOfficialIDList)
+            
+    return
+
+def IsChampionshipPlayer(playerID):
+    ## 是否排位赛相关玩家
+    
+    champMgr = GetChampionshipMgr()
+    for zoneID in champMgr.GetChampPKZoneIDList():
+        pkZoneMgr = champMgr.GetChampPKZoneMgr(zoneID)
+        if playerID in pkZoneMgr.GetBatPlayerIDList():
+            # 是参赛玩家
+            return True
+        
+    for zoneID in champMgr.GetChampOfficialZoneIDList():
+        offZoneMgr = champMgr.GetChampOfficialZoneMgr(zoneID)
+        for offObj in offZoneMgr.officialInfo.values():
+            if playerID == offObj.playerID:
+                # 是仙官
+                return True
+            if playerID in offObj.applyPlayerInfo:
+                # 申请仙官中
+                return True
+    return False
+
+def CrossServerMsg_ChampionshipDailyOfficial(msgData):
+    ## 收到跨服服务器信息 - 每日官爵玩家信息
+    
+    for playerID, officialID in msgData.items():
+        if not PlayerControl.GetDBPlayerAccIDByID(playerID):
+            # 非本服玩家
+            continue
+        ipyData = IpyGameDataPY.GetIpyGameData("ChampionshipOfficial", officialID)
+        if not ipyData:
+            continue
+        awardItemList = ipyData.GetDailyAwardItemList()
+        if not awardItemList:
+            continue
+        paramList = [officialID]
+        PlayerCompensation.SendMailByKey("CrossChampionshipOfficialDaily", [playerID], awardItemList, paramList)
+        
+    return
+
+def OnPlayerLogin(curPlayer, tick):
+    
+    if GameWorld.IsCrossServer():
+        return
+    
+    playerID = curPlayer.GetPlayerID()
+    champMgr = GetChampionshipMgr()
+    pkZoneIDList = champMgr.GetChampPKZoneIDList()
+    for zoneID in pkZoneIDList:
+        Sync_ChampionshipPKZoneGroupInfo(zoneID, curPlayer=curPlayer)
+    for zoneID in champMgr.GetChampOfficialZoneIDList():
+        Sync_ChampionshipOfficialInfo(zoneID, curPlayer=curPlayer)
+        
+    if pkZoneIDList:
+        playerZoneID = champMgr.GetPlayerPKZoneID(playerID)
+        pkZoneMgr = champMgr.GetChampPKZoneMgr(playerZoneID)
+        if playerID not in pkZoneMgr.syncGuessPlayerIDInfo:
+            sendMsg = {"zoneID":playerZoneID, "playerID":playerID, "exDataType":"ChampionshipGuessQuery"}
+            CrossRealmMsg.SendMsgToCrossServer(ShareDefine.ClientServerMsg_ChampionshipGuess, sendMsg)
+            
+    return
+
+def OnMinuteProcess():
+    if not GameWorld.IsCrossServer():
+        return
+    
+    Dispose_CrossChampionshipState()
+    return
+
+def __GetChampionshipStartDate():
+    ## 获取排位赛开始日期
+    
+    key = "ChampionshipStartDate"
+    openServerDay = PlayerDBGSEvent.GetDBGSTrig_ByKey(PlayerDBGSEvent.Def_ServerDay) + 1
+    loadSign = openServerDay
+    ChampionshipStartDateInfo = IpyGameDataPY.GetConfigEx(key)
+    if ChampionshipStartDateInfo and ChampionshipStartDateInfo[0] == loadSign:
+        GameWorld.DebugLog("已经加载过本日跨服排位争霸赛开始日期!loadSign=%s" % loadSign)
+        return False, ChampionshipStartDateInfo[1]
+    
+    ipyDataMgr = IpyGameDataPY.IPY_Data()
+    count = ipyDataMgr.GetChampionshipTimeCount()
+    if count < 2:
+        return True, ""
+    
+    firstIpyData = ipyDataMgr.GetChampionshipTimeByIndex(0)
+    lastIpyData = ipyDataMgr.GetChampionshipTimeByIndex(count - 1)
+    if not firstIpyData or not lastIpyData:
+        return False, ""
+    fristDay, firstHour, firstMinute = firstIpyData.GetStartDay(), firstIpyData.GetStartHour(), firstIpyData.GetStartMinute()
+    lastDay, lastHour, lastMinute = lastIpyData.GetEndDay(), lastIpyData.GetEndHour(), lastIpyData.GetEndMinute()
+    startSeconds = ((fristDay - 1) * 24 + firstHour) * 3600 + firstMinute * 60
+    endSeconds = ((lastDay - 1) * 24 + lastHour) * 3600 + lastMinute * 60
+    
+    curDateTime = GameWorld.GetServerTime()
+    GameWorld.Log("===== 加载今天跨服排位争霸赛时间 =====")
+    CrossChamDateList = IpyGameDataPY.GetFuncEvalCfg("CrossChamFB", 1)    
+    GameWorld.Log("开启日期列表: %s" % CrossChamDateList)
+    GameWorld.Log("fristDay=%s,firstHour=%s,firstMinute=%s,startSeconds=%s" % (fristDay, firstHour, firstMinute, startSeconds))
+    GameWorld.Log("lastDay=%s,lastHour=%s,lastMinute=%s,endSeconds=%s" % (lastDay, lastHour, lastMinute, endSeconds))
+    
+    nowStartDate = ""
+    for startDate in CrossChamDateList:
+        startDateTime0 = datetime.datetime.strptime(startDate, ChConfig.TYPE_Time_YmdFormat) # 开始日期0点
+        startDateTime = startDateTime0 + datetime.timedelta(seconds=startSeconds)
+        endDateTime = startDateTime0 + datetime.timedelta(seconds=endSeconds)
+        if curDateTime >= startDateTime and curDateTime <= endDateTime:
+            nowStartDate = startDate # 全部遍历完,以最新的满足条件时间为准
+            
+    GameWorld.Log("nowStartDate=%s" % nowStartDate)
+    
+    ChampionshipStartDateInfo = IpyGameDataPY.SetConfigEx(key, [loadSign, nowStartDate])
+    GameWorld.Log("跨服排位争霸赛开始日期加载完毕! loadSign=%s,nowStartDate=%s" % (loadSign, nowStartDate))
+    GameWorld.Log("=============================================================")
+    return True, ChampionshipStartDateInfo[1]
+
+def Dispose_CrossChampionshipState(reloadRefresh=False):
+    
+    isReload, startDate = __GetChampionshipStartDate()
+    isReload = isReload or reloadRefresh
+    
+    gameWorld = GameWorld.GetGameWorld()
+    # 此活动严格按照流程状态一个个来,不能跳,所以使用db保存状态,防止临时维护导致状态为0
+    befState = PlayerDBGSEvent.GetDBGSTrig_ByKey(PlayerDBGSEvent.Def_CrossChampionshipState)
+    dbCrossChampionshipID = PlayerDBGSEvent.GetDBGSTrig_ByKey(PlayerDBGSEvent.Def_CrossChampionshipID)
+    stateError = PlayerDBGSEvent.GetDBGSTrig_ByKey(PlayerDBGSEvent.Def_CrossChampionshipStateError)
+    
+    updState = 0
+    crossChampionshipID = 0
+    
+    # 这里时间需精确到分钟,不然后面的比较会匹配不到
+    curDateTime = GameWorld.GetServerTime()
+    curDateTime = datetime.datetime.strptime("%d-%d-%d %d:%d:00" % (curDateTime.year, curDateTime.month, curDateTime.day,
+                                                                    curDateTime.hour, curDateTime.minute), ChConfig.TYPE_Time_Format)
+    
+    serverGroupIDList = [] # 全服统一逻辑
+    if startDate:
+        crossChampionshipID = GameWorld.ChangeTimeStrToNum(startDate, ChConfig.TYPE_Time_YmdFormat)
+        startDateTime0 = datetime.datetime.strptime(startDate, ChConfig.TYPE_Time_YmdFormat) # 开始日期0点
+        ipyDataMgr = IpyGameDataPY.IPY_Data()
+        for index in xrange(ipyDataMgr.GetChampionshipTimeCount()):
+            timeIpyData = ipyDataMgr.GetChampionshipTimeByIndex(index)
+            #dataID = timeIpyData.GetID()
+            startDay, startHour, startMinute = timeIpyData.GetStartDay(), timeIpyData.GetStartHour(), timeIpyData.GetStartMinute()
+            endDay, endHour, endMinute = timeIpyData.GetEndDay(), timeIpyData.GetEndHour(), timeIpyData.GetEndMinute()
+            
+            startSeconds = ((startDay - 1) * 24 + startHour) * 3600 + startMinute * 60
+            endSeconds = ((endDay - 1) * 24 + endHour) * 3600 + endMinute * 60
+            startDateTime = startDateTime0 + datetime.timedelta(seconds=startSeconds)
+            endDateTime = startDateTime0 + datetime.timedelta(seconds=endSeconds)
+            if curDateTime < startDateTime or curDateTime > endDateTime:
+                continue
+            
+            updState = timeIpyData.GetStateValue()
+            notifyInfoDict = timeIpyData.GetNotifyInfo()
+            if not stateError and notifyInfoDict:
+                diffDateTime = curDateTime - startDateTime
+                diffMinute = (diffDateTime.days * 24 * 3600 + diffDateTime.seconds) / 60 # 当前时间与开始时间相差分钟数
+                GameWorld.DebugLog("    广播判断: curDateTime=%s,startDateTime=%s,diffDays=%s,diffSeconds=%s,diffMinute=%s" 
+                                   % (curDateTime, startDateTime, diffDateTime.days, diffDateTime.seconds, diffMinute))
+                if diffMinute in notifyInfoDict:
+                    notifyKey, paramList = notifyInfoDict[diffMinute]
+                    PlayerControl.WorldNotifyCross(serverGroupIDList, 0, notifyKey, paramList)
+            break
+        
+    if not isReload and befState == updState:
+        #已经是这个状态了
+        return
+    
+    GameWorld.Log("跨服排位争霸赛状态变更: befState=%s,updState=%s,stateError=%s" % (befState, updState, stateError))
+    
+    # 判断活动重置,该活动只考虑正常流程状态,任何流程跳过的都不处理;异常情况维护服务器导致跳过流程的可配置新日期开始新活动,并做补偿
+    GameWorld.Log("crossChampionshipID=%s,dbCrossChampionshipID=%s" % (crossChampionshipID, dbCrossChampionshipID))
+    gameWorld.SetDict(PlayerDBGSEvent.Def_CrossChampionshipState, updState)
+    gameWorld.SetDict(PlayerDBGSEvent.Def_CrossChampionshipID, crossChampionshipID)
+    
+    PlayerDBGSEvent.SetDBGSTrig_ByKey(PlayerDBGSEvent.Def_CrossChampionshipID, crossChampionshipID)
+    PlayerDBGSEvent.SetDBGSTrig_ByKey(PlayerDBGSEvent.Def_CrossChampionshipState, updState)
+    
+    isNewStart = False
+    if crossChampionshipID != dbCrossChampionshipID:            
+        # 新活动 - 必须从第一个状态开始才算
+        if crossChampionshipID:
+            if updState == ShareDefine.CrossChampionshipStateList[0]:
+                isNewStart = True
+                DoCrossChampionshipStart(crossChampionshipID, updState)
+            else:
+                GameWorld.ErrLog("跨服排位争霸赛重置活动时非首个状态,异常不处理: crossChampionshipID=%s,dbCrossChampionshipID=%s,updState=%s" 
+                                 % (crossChampionshipID, dbCrossChampionshipID, updState))
+                PlayerDBGSEvent.SetDBGSTrig_ByKey(PlayerDBGSEvent.Def_CrossChampionshipStateError, 1)
+                
+    # 非开启新排位活动的,优先统一广播子服状态,再做后续处理
+    if not isNewStart:
+        Send_CrossServerMsg_ChampionshipState()
+        
+    if isNewStart:
+        pass
+    elif not crossChampionshipID:
+        GameWorld.Log("跨服排位争霸赛非活动中,不处理!")
+    elif stateError:
+        GameWorld.ErrLog("跨服排位争霸赛活动状态已经异常,不处理!")
+    elif crossChampionshipID == dbCrossChampionshipID:
+        if befState == updState:
+            GameWorld.Log("跨服排位争霸赛状态不变不处理: befState=%s,updState=%s" % (befState, updState))
+            
+        elif befState and befState in ShareDefine.CrossChampionshipStateList \
+            and updState and updState in ShareDefine.CrossChampionshipStateList:
+            befStateIndex = ShareDefine.CrossChampionshipStateList.index(befState)
+            updStateIndex = ShareDefine.CrossChampionshipStateList.index(updState)
+            # 该活动必须按状态流程一个个来,存DB的确保每个状态值逻辑处理只会触发一次
+            if befStateIndex + 1 == updStateIndex:
+                if updState == ShareDefine.CrossChampionshipState_Group64:
+                    DoCrossChampionshipGroupRand(64)
+                elif updState == ShareDefine.CrossChampionshipState_Group32:
+                    DoCrossChampionshipGroupRand(32)
+                elif updState == ShareDefine.CrossChampionshipState_Group16:
+                    DoCrossChampionshipGroupRand(16)
+                elif updState == ShareDefine.CrossChampionshipState_Guess4:
+                    DoCrossChampionshipTopPlayer8()
+                elif updState == ShareDefine.CrossChampionshipState_Group8:
+                    DoCrossChampionshipGroupRand(8)
+                elif updState == ShareDefine.CrossChampionshipState_GroupSemi:
+                    DoCrossChampionshipGroupByWF(4)
+                elif updState == ShareDefine.CrossChampionshipState_GroupFinal:
+                    DoCrossChampionshipGroupByWF(2)
+                # 处理进场状态
+                elif updState in ShareDefine.CrossChampionshipEnterStateInfo:
+                    DoCrossChampionshipStartEnter(updState)
+            else:
+                GameWorld.ErrLog("跨服排位争霸赛状态流程异常: befState=%s,updState=%s,befStateIndex=%s,updStateIndex=%s" 
+                                 % (befState, updState, befStateIndex, updStateIndex))
+                PlayerDBGSEvent.SetDBGSTrig_ByKey(PlayerDBGSEvent.Def_CrossChampionshipStateError, 1)
+                Send_CrossServerMsg_ChampionshipState()
+        
+        # 从最后一个状态到0,代表整个流程结束,需要处理下结算
+        elif befState == ShareDefine.CrossChampionshipStateList[-1] and not updState:
+            DoCrossChampionshipFinalOver()
+            
+        else:
+            GameWorld.ErrLog("跨服排位争霸赛状态异常: updState=%s" % updState)
+            PlayerDBGSEvent.SetDBGSTrig_ByKey(PlayerDBGSEvent.Def_CrossChampionshipStateError, 1)
+            Send_CrossServerMsg_ChampionshipState()
+            
+    return
+
+def DoCrossChampionshipStart(crossChampionshipID, updState):
+    ## 新活动开始
+    GameWorld.Log("=== 跨服排位争霸赛新活动开始 ===")
+    GameWorld.Log("crossChampionshipID=%s,updState=%s" % (crossChampionshipID, updState))
+    
+    hisZoneIDList = [] # 因为分区可能调整增删,这里要取历史配置过的所有分区
+    championshipSeason = 0 # 排位赛数据取非活动中的最高赛季
+    crossZoneName = GameWorld.GetCrossZoneName()
+    ipyDataMgr = IpyGameDataPY.IPY_Data()
+    for index in range(ipyDataMgr.GetCrossRealmPKSeasonCount()):
+        seasonIpyData = ipyDataMgr.GetCrossRealmPKSeasonByIndex(index)
+        if crossZoneName != seasonIpyData.GetCrossZoneName():
+            continue
+        zoneID = seasonIpyData.GetZoneID()
+        if zoneID not in hisZoneIDList:
+            hisZoneIDList.append(zoneID)
+            
+    gameWorld = GameWorld.GetGameWorld()
+    for zoneID in hisZoneIDList:
+        seasonID = gameWorld.GetDictByKey(ChConfig.Def_WorldKey_CrossPKZoneSeasonID % zoneID)
+        seasonState = gameWorld.GetDictByKey(ChConfig.Def_WorldKey_CrossPKZoneSeasonState % zoneID)
+        if seasonState == 1:
+            checkSeason = seasonID - 1 # 赛季中的取上一个赛季
+        else:
+            checkSeason = seasonID
+        if championshipSeason < checkSeason:
+            championshipSeason = checkSeason
+    GameWorld.Log("hisZoneIDList=%s,championshipSeason=%s" % (hisZoneIDList, championshipSeason))
+    
+    # 清空上次活动记录
+    universalRecMgr = GameWorld.GetUniversalRecMgr()
+    universalRecMgr.Delete(Def_RecType_CrossChampionshipGroup)
+    universalRecMgr.Delete(Def_RecType_CrossChampionshipGuess)
+    universalRecMgr.Delete(Def_RecType_CrossChampionshipOfficial)
+    universalRecMgr.Delete(Def_RecType_CrossChampionshipOffChallenge)
+    
+    PlayerDBGSEvent.SetDBGSTrig_ByKey(PlayerDBGSEvent.Def_CrossChampionshipID, crossChampionshipID)
+    PlayerDBGSEvent.SetDBGSTrig_ByKey(PlayerDBGSEvent.Def_CrossChampionshipState, updState)
+    PlayerDBGSEvent.SetDBGSTrig_ByKey(PlayerDBGSEvent.Def_CrossChampionshipStateError, 0)
+    
+    champMgr = GetChampionshipMgr()
+    champMgr.ClearPKZone() # 仅清理PK分区信息,仙官信息不变
+    
+    # 生成参赛玩家名单: 取跨服PK所有分区 championshipSeason 赛季的数据
+    if championshipSeason:
+        crossPKBillboardMgr = PyDataManager.GetCrossPKBillboardManager()
+        for zoneID in hisZoneIDList:
+            billboardList = crossPKBillboardMgr.GetCrossPKBillboardInfo(zoneID, championshipSeason)[0]
+            GameWorld.Log("zoneID=%s,billboardListLen=%s" % (zoneID, len(billboardList)))
+            if not billboardList:
+                # 没有玩家上榜的不处理
+                continue
+            pkZoneMgr = champMgr.GetChampPKZoneMgr(zoneID)
+            battlePlayerList = billboardList[:Def_CrossChampionshipPlayerMax]
+            for num, billboardData in enumerate(battlePlayerList, 1):
+                playerID = billboardData.PlayerID
+                batPlayer = ChampionshipBatPlayer()
+                batPlayer.zoneID = zoneID
+                batPlayer.playerID = playerID
+                batPlayer.playerName = billboardData.PlayerName
+                batPlayer.job = billboardData.Job
+                batPlayer.fightPower = billboardData.FightPower
+                batPlayer.realmLV = billboardData.RealmLV
+                pkZoneMgr.playerDict[playerID] = batPlayer
+                
+                getPlayer = pkZoneMgr.GetBatPlayer(playerID)
+                dataDict = {"zoneID":zoneID, "playerID":playerID, "accID":getPlayer.accID, "fightPower":getPlayer.fightPower}
+                DR_CrossChampionshipPK("StartPlayer", dataDict)
+                
+                GameWorld.Log("    AddBattlePlayer num=%s,playerID=%s,accID=%s,fightPower=%s" % (num, playerID, getPlayer.accID, getPlayer.fightPower))
+                
+    GameWorld.Log("=============================================================")
+    Send_CrossServerMsg_ChampionshipState(newAct=True)
+    Send_CrossServerMsg_ChampionshipPlayer(isSync=True)
+    return
+
+def DoCrossChampionshipGroupRand(groupMark):
+    ## 随机两两分组
+    
+    battleCount = int(groupMark / 2) # 对战组数
+    preGroupMark = 0 if groupMark == 64 else groupMark * 2 # 上一轮分组标识
+    
+    GameWorld.Log("=== 跨服排位争霸赛随机分组 === groupMark=%s,battleCount=%s,preGroupMark=%s" % (groupMark, battleCount, preGroupMark))
+    
+    syncPlayerIDList = []
+    champMgr = GetChampionshipMgr()
+    for zoneID in champMgr.GetChampPKZoneIDList():
+        pkZoneMgr = champMgr.GetChampPKZoneMgr(zoneID)
+        # 首轮取所有参赛玩家
+        if preGroupMark == 0:
+            batPlayerIDList = pkZoneMgr.GetBatPlayerIDList()
+        # 取上一轮获胜者
+        else:
+            batPlayerIDList = []
+            battleNumList = pkZoneMgr.battleInfo.get(preGroupMark, {}).keys()
+            for battleNum in battleNumList:
+                batObj = pkZoneMgr.GetBattle(preGroupMark, battleNum)
+                if not batObj:
+                    continue
+                # 如果上一轮战斗没结算,则强制结算
+                if not batObj.overTime:
+                    GameWorld.ErrLog("上一轮战斗未结算,执行强制结算! zoneID=%s,preGroupMark=%s,battleNum=%s,mapID=%s,copyMapID=%s" 
+                                     % (zoneID, preGroupMark, battleNum, batObj.mapID, batObj.copyMapID), batObj.roomID)
+                    DoBattleOverLogic(zoneID, preGroupMark, battleNum)
+                    
+                if not batObj.winPlayerID:
+                    continue
+                if batObj.winPlayerID not in batPlayerIDList:
+                    batPlayerIDList.append(batObj.winPlayerID)
+                    
+        # 进入决赛的随机分组,玩家不足的补0,确保分组后顺序一致
+        if groupMark == 8 and len(batPlayerIDList) < Def_CrossChampionshipPlayerWFCount:
+            batPlayerIDList += [0] * (Def_CrossChampionshipPlayerWFCount - len(batPlayerIDList))
+        batPlayerCount = len(batPlayerIDList)
+        GameWorld.Log("zoneID=%s,batPlayerCount=%s" % (zoneID, batPlayerCount), zoneID)
+        if not batPlayerIDList:
+            continue
+        
+        # 打乱顺序
+        random.shuffle(batPlayerIDList)
+        GameWorld.Log("batPlayerIDList=%s" % batPlayerIDList)
+        
+        battleDict = {}
+        for num, playerID in enumerate(batPlayerIDList, 1):
+            if playerID and playerID not in syncPlayerIDList:
+                syncPlayerIDList.append(playerID)
+            #batPlayer = zoneMgr.GetBatPlayer(playerID)
+            # 1.先确保每组有人
+            if num <= battleCount:
+                battle = ChampionshipBattle()
+                battle.zoneID = zoneID
+                battle.groupMark = groupMark
+                battle.battleNum = num
+                battle.playerIDA = playerID
+                
+                battleDict[num] = battle
+                pkZoneMgr.battleInfo[groupMark] = battleDict
+                
+            else:
+                battle = pkZoneMgr.GetBattle(groupMark, num - battleCount)
+                # 一般不可能为None,防一下
+                if not battle:
+                    continue
+                battle.playerIDB = playerID
+                
+        for battleNum in range(1, 1 + battleCount):
+            batObj = pkZoneMgr.GetBattle(groupMark, battleNum)
+            if not batObj:
+                continue
+            playerIDA = batObj.playerIDA
+            playerIDB = batObj.playerIDB
+            playerObjA = pkZoneMgr.GetBatPlayer(playerIDA)
+            playerObjB = pkZoneMgr.GetBatPlayer(playerIDB)
+            accIDA = "" if not playerObjA else playerObjA.accID
+            accIDB = "" if not playerObjB else playerObjB.accID
+            fightPowerA = 0 if not playerObjA else playerObjA.fightPower
+            fightPowerB = 0 if not playerObjB else playerObjB.fightPower
+            GameWorld.Log("    对战组信息: zoneID=%s,groupMark=%s,battleNum=%s,playerIDA=%s(%s),playerIDB=%s(%s),fightPowerA=%s,fightPowerB=%s" 
+                          % (zoneID, batObj.groupMark, batObj.battleNum, playerIDA, accIDA, playerIDB, accIDB, fightPowerA, fightPowerB), zoneID)
+            
+            dataDict = {"zoneID":zoneID, "groupMark":groupMark, "battleNum":battleNum, 
+                        "playerIDA":playerIDA, "accIDA":accIDA, "fightPowerA":fightPowerA,
+                        "playerIDB":playerIDB, "accIDB":accIDB, "fightPowerB":fightPowerB,
+                        }
+            DR_CrossChampionshipPK("Group", dataDict)
+    GameWorld.Log("=============================================================")
+    
+    # 广播子服
+    Send_CrossServerMsg_ChampionshipPlayer(syncPlayerIDList)
+    Send_CrossServerMsg_ChampionshipGroup(groupMark)
+    return
+
+def DoCrossChampionshipGroupByWF(groupMark):
+    ## 按胜负组分组,由上一轮的胜负分组及顺序决定本轮次的分组,需要确保顺序一致
+    
+    if groupMark == 4:
+        preGroupMark = 8
+    elif groupMark == 2:
+        preGroupMark = 4
+    else:
+        return
+    battleCount = int(Def_CrossChampionshipPlayerWFCount / 2) # 对战组数,也是胜负组每组所需人数
+    GameWorld.Log("=== 跨服排位争霸赛胜负分组 === groupMark=%s,battleCount=%s,preGroupMark=%s" % (groupMark, battleCount, preGroupMark))
+    
+    syncPlayerIDList = []
+    champMgr = GetChampionshipMgr()
+    for zoneID in champMgr.GetChampPKZoneIDList():
+        pkZoneMgr = champMgr.GetChampPKZoneMgr(zoneID)
+        
+        winPlayerIDList, losePlayerIDList = [], [] # 胜者组、败者组
+        battleNumList = pkZoneMgr.battleInfo.get(preGroupMark, {}).keys()
+        battleNumList.sort() # 对战编号按之前的分组顺序排序,确保分组顺序一致
+        for battleNum in battleNumList:
+            batObj = pkZoneMgr.GetBattle(preGroupMark, battleNum)
+            if not batObj:
+                continue
+            
+            # 如果上一轮战斗没结算,则强制结算
+            if not batObj.overTime:
+                GameWorld.ErrLog("上一轮战斗未结算,执行强制结算! zoneID=%s,preGroupMark=%s,battleNum=%s,mapID=%s,copyMapID=%s" 
+                                 % (zoneID, preGroupMark, battleNum, batObj.mapID, batObj.copyMapID), batObj.roomID)
+                DoBattleOverLogic(zoneID, preGroupMark, battleNum)
+                
+            # 为确保多轮次对战顺序一致,当无胜利玩家时(一般是没有玩家或结算异常导致没有胜者,一律当做无玩家处理),无玩家需要补0,确保后续匹配分组顺序一致
+            if not batObj.winPlayerID:
+                winPlayerIDList.append(0)
+                losePlayerIDList.append(0)
+            else:
+                winPlayerID = batObj.playerIDA if batObj.winPlayerID == batObj.playerIDA else batObj.playerIDB
+                losePlayerID = batObj.playerIDB if batObj.winPlayerID == batObj.playerIDA else batObj.playerIDA
+                winPlayerIDList.append(winPlayerID)
+                losePlayerIDList.append(losePlayerID)
+                
+        if len(winPlayerIDList) < battleCount:
+            winPlayerIDList += [0] * (battleCount - len(winPlayerIDList))
+        winPlayerIDList = winPlayerIDList[:battleCount]
+        if len(losePlayerIDList) < battleCount:
+            losePlayerIDList += [0] * (battleCount - len(losePlayerIDList))
+        losePlayerIDList = losePlayerIDList[:battleCount]
+        GameWorld.Log("zoneID=%s,groupMark=%s,winPlayerIDList=%s,losePlayerIDList=%s" 
+                      % (zoneID, groupMark, winPlayerIDList, losePlayerIDList), zoneID)
+        
+        battleNum = 0
+        battleDict = {}
+        batPlayerIDList = winPlayerIDList + losePlayerIDList
+        for i in range(Def_CrossChampionshipPlayerWFCount)[::2]:
+            playerIDA = batPlayerIDList[i]
+            playerIDB = batPlayerIDList[i + 1]
+            battleNum += 1
+            battle = ChampionshipBattle()
+            battle.zoneID = zoneID
+            battle.groupMark = groupMark
+            battle.battleNum = battleNum
+            battle.playerIDA = playerIDA
+            battle.playerIDB = playerIDB
+            
+            battleDict[battleNum] = battle
+            pkZoneMgr.battleInfo[groupMark] = battleDict
+            
+            if playerIDA and playerIDA not in syncPlayerIDList:
+                syncPlayerIDList.append(playerIDA)
+            if playerIDB and playerIDB not in syncPlayerIDList:
+                syncPlayerIDList.append(playerIDB)
+                
+            playerObjA = pkZoneMgr.GetBatPlayer(playerIDA)
+            playerObjB = pkZoneMgr.GetBatPlayer(playerIDB)
+            accIDA = "" if not playerObjA else playerObjA.accID
+            accIDB = "" if not playerObjB else playerObjB.accID
+            fightPowerA = 0 if not playerObjA else playerObjA.fightPower
+            fightPowerB = 0 if not playerObjB else playerObjB.fightPower
+            GameWorld.Log("    对战组信息: zoneID=%s,groupMark=%s,battleNum=%s,playerIDA=%s(%s),playerIDB=%s(%s),fightPowerA=%s,fightPowerB=%s" 
+                          % (zoneID, groupMark, battleNum, playerIDA, accIDA, playerIDB, accIDB, fightPowerA, fightPowerB), zoneID)
+            
+            dataDict = {"zoneID":zoneID, "groupMark":groupMark, "battleNum":battleNum, 
+                        "playerIDA":playerIDA, "accIDA":accIDA, "fightPowerA":fightPowerA,
+                        "playerIDB":playerIDB, "accIDB":accIDB, "fightPowerB":fightPowerB,
+                        }
+            DR_CrossChampionshipPK("Group", dataDict)
+            
+    GameWorld.Log("=============================================================")
+    
+    # 广播子服
+    Send_CrossServerMsg_ChampionshipPlayer(syncPlayerIDList)
+    Send_CrossServerMsg_ChampionshipGroup(groupMark)
+    return
+
+def DoCrossChampionshipTopPlayer8():
+    ## 产出前8强
+    
+    preGroupMark = 16
+    GameWorld.Log("=== 跨服排位争霸赛产出前8强  === preGroupMark=%s" % preGroupMark)
+    
+    champMgr = GetChampionshipMgr()
+    for zoneID in champMgr.GetChampPKZoneIDList():
+        pkZoneMgr = champMgr.GetChampPKZoneMgr(zoneID)
+        
+        battleNumList = pkZoneMgr.battleInfo.get(preGroupMark, {}).keys()
+        battleNumList.sort() # 对战编号按之前的分组顺序排序,确保分组顺序一致
+        for battleNum in battleNumList:
+            batObj = pkZoneMgr.GetBattle(preGroupMark, battleNum)
+            if not batObj:
+                continue
+            
+            # 如果上一轮战斗没结算,则强制结算
+            if not batObj.overTime:
+                GameWorld.ErrLog("上一轮战斗未结算,执行强制结算! zoneID=%s,preGroupMark=%s,battleNum=%s,mapID=%s,copyMapID=%s" 
+                                 % (zoneID, preGroupMark, battleNum, batObj.mapID, batObj.copyMapID), batObj.roomID)
+                DoBattleOverLogic(zoneID, preGroupMark, battleNum)
+                
+        top8PlayerIDList = pkZoneMgr.GetTop8PlayerIDList()
+        GameWorld.Log("排位分区8强玩家ID列表: zoneID=%s, %s" % (zoneID, top8PlayerIDList), zoneID)
+        
+        # 处理8强竞猜发奖励
+        guessType = 8
+        moneyType, _ = IpyGameDataPY.GetFuncEvalCfg("CrossChamGuess", 1)
+        multiPrice = IpyGameDataPY.GetFuncCfg("CrossChamGuess", 3) # 猜中奖励倍值
+        moneyItemID = ChConfig.MoneyItemIDDict.get(moneyType)
+        GameWorld.Log("竞猜返利货币类型: moneyType=%s,moneyItemID=%s,multiPrice=%s" % (moneyType, moneyItemID, multiPrice), zoneID)
+        playerGuessDict = pkZoneMgr.guessInfo.get(guessType, {})
+        for guessPlayerID, guessList in playerGuessDict.items():
+            guessCorrectCount = 0 # 猜中人数
+            guessCorrectMoney = 0 # 猜中总投入货币
+            for guessObj in guessList:
+                if guessObj.guessType != guessType or guessObj.guessPlayerID != guessPlayerID:
+                    continue
+                tagPlayerID = guessObj.tagPlayerID
+                moneyTotal = guessObj.moneyTotal
+                if not tagPlayerID or tagPlayerID not in top8PlayerIDList:
+                    continue
+                guessCorrectCount += 1
+                guessCorrectMoney += moneyTotal
+                
+            if guessCorrectMoney <= 0 or multiPrice <= 0 or not moneyItemID:
+                continue
+            moneyPriceTotal = guessCorrectMoney * multiPrice # 总收益
+            paramList = [guessCorrectCount, multiPrice]
+            addItemList = [[moneyItemID, moneyPriceTotal, 0]]
+            PlayerCompensation.SendMailByKey("CrossChampionshipGuess8", [guessPlayerID], addItemList, paramList, crossMail=True)
+            
+    GameWorld.Log("=============================================================")
+    return
+
+def DoCrossChampionshipStartEnter(state):
+    ## 开启进场处理逻辑
+    if state not in ShareDefine.CrossChampionshipEnterStateInfo:
+        return
+    groupMark = ShareDefine.CrossChampionshipEnterStateInfo[state]
+    mapIDList = IpyGameDataPY.GetFuncEvalCfg("CrossChamFB", 3)
+    GameWorld.Log("跨服排位争霸赛开启进场副本: groupMark=%s,mapIDList=%s" % (groupMark, mapIDList))
+    champMgr = GetChampionshipMgr()
+    pkZoneIDList = champMgr.GetChampPKZoneIDList()
+    for index, zoneID in enumerate(pkZoneIDList):
+        if index >= len(mapIDList):
+            GameWorld.ErrLog("该跨服排位争霸赛分区没有分配对战地图! zoneID=%s,index=%s" % (zoneID, index), zoneID)
+            continue
+        mapID = mapIDList[index]
+        pkZoneMgr = champMgr.GetChampPKZoneMgr(zoneID)
+        if groupMark not in pkZoneMgr.battleInfo:
+            GameWorld.Log("该跨服排位争霸赛分区没有对战组! zoneID=%s,groupMark=%s" % (zoneID, groupMark), zoneID)
+            continue
+        copyMapID = 0
+        copyPropertyList = []
+        battleDict = pkZoneMgr.battleInfo[groupMark]
+        for battleNum in battleDict.keys():
+            batObj = pkZoneMgr.GetBattle(groupMark, battleNum)
+            if not batObj:
+                continue
+            roomID = GetChampionshipPKRoomID(zoneID, groupMark, battleNum)
+            copyPropertyList.append([copyMapID, roomID])
+            batObj.mapID = mapID
+            batObj.roomID = roomID
+            batObj.copyMapID = copyMapID
+            
+            # 添加开启分线数据
+            realMapID = mapID
+            copyMapObj = PlayerFB.CrossCopyMapInfo(zoneID, 0)
+            copyMapObj.realMapID = realMapID
+            copyMapObj.copyMapID = copyMapID
+            key = (realMapID, copyMapID)
+            PyGameData.g_crossDynamicLineCopyMapInfo[key] = copyMapObj
+            GameWorld.Log("    对战房间! zoneID=%s,groupMark=%s,battleNum=%s,playerIDA=%s,playerIDB=%s,roomID=%s,mapID=%s,copyMapID=%s" 
+                          % (zoneID, groupMark, battleNum, batObj.playerIDA, batObj.playerIDB, roomID, mapID, copyMapID))
+            copyMapID += 1
+            
+        PlayerFB.SendMapOpenFBEx(mapID, copyPropertyList)
+        
+    return
+
+def Sync_CrossChampionshipDataToClientServer(serverGroupID=0):
+    ''' 同步跨服排位争霸赛数据到子服务器
+    @param serverGroupID: 为0时同步所有子服
+    '''
+    GameWorld.Log("同步给子服排位争霸赛数据: syncServerGroupID=%s" % (serverGroupID))
+    # 通知全区
+    Send_CrossServerMsg_ChampionshipState(serverGroupID)
+    Send_CrossServerMsg_ChampionshipPlayer(serverGroupID=serverGroupID)
+    Send_CrossServerMsg_ChampionshipGroup(serverGroupID=serverGroupID)
+    Send_CrossServerMsg_ChampionshipGuess(serverGroupID=serverGroupID)
+    Send_CrossServerMsg_ChampionshipOfficial(serverGroupID=serverGroupID)
+    return
+
+def Send_CrossServerMsg_ChampionshipState(serverGroupID=0, newAct=False):
+    # 通知状态 
+    champMgr = GetChampionshipMgr()
+    pkZoneIDList = champMgr.GetChampPKZoneIDList()
+    ID = PlayerDBGSEvent.GetDBGSTrig_ByKey(PlayerDBGSEvent.Def_CrossChampionshipID)
+    State = PlayerDBGSEvent.GetDBGSTrig_ByKey(PlayerDBGSEvent.Def_CrossChampionshipState)
+    StateError = PlayerDBGSEvent.GetDBGSTrig_ByKey(PlayerDBGSEvent.Def_CrossChampionshipStateError)
+    dataMsg = {"ID":ID, "State":State, "StateError":StateError, "PKZoneIDList":pkZoneIDList, "NewAct":newAct}
+    serverGroupIDList = [serverGroupID] if serverGroupID else []
+    CrossRealmMsg.SendMsgToClientServer(ShareDefine.CrossServerMsg_ChampionshipState, dataMsg, serverGroupIDList)
+    return
+
+def Send_CrossServerMsg_ChampionshipPlayer(syncPlayerIDList=None, serverGroupID=0, isSync=False):
+    # 通知参赛玩家
+    
+    zoneBatPlayerInfo = {}
+    champMgr = GetChampionshipMgr()
+    for zoneID in champMgr.GetChampPKZoneIDList():
+        batPlayerList = []
+        pkZoneMgr = champMgr.GetChampPKZoneMgr(zoneID)
+        if syncPlayerIDList == None:
+            syncPlayerIDList = pkZoneMgr.GetBatPlayerIDList()
+        for playerID in syncPlayerIDList:
+            batPlayer = pkZoneMgr.GetBatPlayer(playerID)
+            if not batPlayer:
+                continue
+            batPlayerList.append(batPlayer.GetString())
+        zoneBatPlayerInfo[zoneID] = batPlayerList
+        
+    dataMsg = {"isSync":isSync, "zoneBatPlayerInfo":zoneBatPlayerInfo}
+    serverGroupIDList = [serverGroupID] if serverGroupID else []
+    CrossRealmMsg.SendMsgToClientServer(ShareDefine.CrossServerMsg_ChampionshipPlayer, dataMsg, serverGroupIDList)
+    return
+
+def Send_CrossServerMsg_ChampionshipGroup(groupMark=None, battleObj=None, serverGroupID=0):
+    # 通知分组
+    dataMsg = []
+    if battleObj != None:
+        dataMsg.append(battleObj.GetString())
+    else:
+        syncGroupMarkList = [groupMark] if groupMark != None else ShareDefine.CrossChampionshipEnterStateInfo.values()
+        champMgr = GetChampionshipMgr()
+        for zoneID in champMgr.GetChampPKZoneIDList():
+            pkZoneMgr = champMgr.GetChampPKZoneMgr(zoneID)
+            for gMark in syncGroupMarkList:
+                battleDict = pkZoneMgr.battleInfo.get(gMark, {})
+                if not battleDict:
+                    continue
+                for num in battleDict.keys():
+                    battleObj = pkZoneMgr.GetBattle(gMark, num)
+                    dataMsg.append(battleObj.GetString())
+                    
+    serverGroupIDList = [serverGroupID] if serverGroupID else []
+    CrossRealmMsg.SendMsgToClientServer(ShareDefine.CrossServerMsg_ChampionshipGroup, dataMsg, serverGroupIDList)
+    return
+
+def Send_CrossServerMsg_ChampionshipGuess(syncZoneID=None, playerID=0, guessObj=None, serverGroupID=0, exData=None, syncPub=True):
+    ## 通知竞猜
+    
+    champMgr = GetChampionshipMgr()
+    
+    # 因为竞猜是面向全服的玩家,所以只能针对每个玩家单独同步自己参与过的竞猜
+    guessList = []
+    if syncZoneID and playerID:
+        if guessObj != None and guessObj.guessPlayerID == playerID:
+            guessList.append(guessObj.GetString())
+        else:
+            pkZoneMgr = champMgr.GetChampPKZoneMgr(syncZoneID)
+            for playerGuessDict in pkZoneMgr.guessInfo.values():
+                if playerID not in playerGuessDict:
+                    continue
+                playerGuessList = playerGuessDict[playerID]
+                for guess in playerGuessList:
+                    guessList.append(guess.GetString())
+                    
+    dataMsg = {"exData":exData if exData else {}, "guessList":guessList}
+    if syncPub:
+        zoneSupportCountInfo = {}
+        syncZoneIDList = [syncZoneID] if syncZoneID else champMgr.GetChampPKZoneIDList()
+        for zoneID in syncZoneIDList:
+            pkZoneMgr = champMgr.GetChampPKZoneMgr(zoneID)
+            zoneSupportCountInfo[zoneID] = pkZoneMgr.supportCountInfo
+        dataMsg["pubInfo"] = {"zoneSupportCountInfo":zoneSupportCountInfo}
+        
+    serverGroupIDList = [serverGroupID] if serverGroupID else []
+    if syncPub:
+        serverGroupIDList = [] # 同步公共信息时,默认全服广播
+    CrossRealmMsg.SendMsgToClientServer(ShareDefine.CrossServerMsg_ChampionshipGuess, dataMsg, serverGroupIDList)
+    return
+
+def CrossServerMsg_ChampionshipState(msgData):
+    ## 收到跨服服务器同步的信息  - 跨服排位争霸赛状态
+    
+    ID = msgData["ID"]
+    State = msgData["State"]
+    StateError = msgData["StateError"]
+    PKZoneIDList = msgData["PKZoneIDList"]
+    newAct = msgData["NewAct"]
+    
+    dbID = PlayerDBGSEvent.GetDBGSTrig_ByKey(PlayerDBGSEvent.Def_CrossChampionshipID)
+    
+    PlayerDBGSEvent.SetDBGSTrig_ByKey(PlayerDBGSEvent.Def_CrossChampionshipID, ID)
+    PlayerDBGSEvent.SetDBGSTrig_ByKey(PlayerDBGSEvent.Def_CrossChampionshipState, State)
+    PlayerDBGSEvent.SetDBGSTrig_ByKey(PlayerDBGSEvent.Def_CrossChampionshipStateError, StateError)
+    
+    # 子服数据重置
+    if dbID != ID or newAct:
+        champMgr = GetChampionshipMgr()
+        prePKZoneIDList = champMgr.GetChampPKZoneIDList()
+        champMgr.ClearPKZone()
+        GameWorld.Log("子服重置跨服排位争霸赛对战数据! dbID=%s,ID=%s,PKZoneIDList=%s,prePKZoneIDList=%s" % (dbID, ID, PKZoneIDList, prePKZoneIDList))
+        for zoneID in PKZoneIDList:
+            champMgr.GetChampPKZoneMgr(zoneID)
+    return
+
+def CrossServerMsg_ChampionshipPlayer(msgData):
+    ## 收到跨服服务器同步的信息  - 参赛玩家信息
+    
+    isSync = msgData["isSync"]
+    zoneBatPlayerInfo = msgData["zoneBatPlayerInfo"]
+    
+    champMgr = GetChampionshipMgr()
+    for zoneID, batPlayerList in zoneBatPlayerInfo.items():
+        pkZoneMgr = champMgr.GetChampPKZoneMgr(zoneID)
+        
+        if not batPlayerList:
+            pkZoneMgr.playerDict = {}
+        else:
+            for attrDict in batPlayerList:
+                zoneID = attrDict["zoneID"]
+                playerID = attrDict["playerID"]
+                batPlayer = pkZoneMgr.GetBatPlayer(playerID)
+                if not batPlayer:
+                    batPlayer = ChampionshipBatPlayer()
+                    pkZoneMgr.playerDict[playerID] = batPlayer
+                batPlayer.SetAttr(attrDict)
+                
+        if isSync:
+            Sync_ChampionshipPKZoneGroupInfo(zoneID)
+            
+    return
+
+def CrossServerMsg_ChampionshipGroup(msgData):
+    ## 收到跨服服务器同步的信息  - 分组信息
+    
+    syncGroupInfo = {}
+    champMgr = GetChampionshipMgr()
+    for attrDict in msgData:
+        zoneID = attrDict["zoneID"]
+        groupMark = attrDict["groupMark"]
+        battleNum = attrDict["battleNum"]
+        
+        pkZoneMgr = champMgr.GetChampPKZoneMgr(zoneID)
+        battle = pkZoneMgr.GetBattle(groupMark, battleNum)
+        if not battle:
+            battle = ChampionshipBattle()
+            pkZoneMgr.AddBattle(groupMark, battleNum, battle)
+        battle.SetAttr(attrDict)
+        
+        if zoneID not in syncGroupInfo:
+            syncGroupInfo[zoneID] = {}
+        groupMarkDict = syncGroupInfo[zoneID]
+        if groupMark not in groupMarkDict:
+            groupMarkDict[groupMark] = []
+        battleNumList = groupMarkDict[groupMark]
+        if battleNum not in battleNumList:
+            battleNumList.append(battleNum)
+            
+    for zoneID, groupMarkDict in syncGroupInfo.items():
+        Sync_ChampionshipPKZoneGroupInfo(zoneID, groupMarkDict)
+        
+    return
+
+def CrossServerMsg_ChampionshipGuess(msgData, tick):
+    ## 收到跨服服务器同步的信息  - 竞猜信息
+    
+    exData = msgData["exData"]
+    guessList = msgData["guessList"]
+    pubInfo = msgData.get("pubInfo", None)
+    
+    if not exData or not isinstance(exData, dict):
+        exData = {}
+    exDataType = exData.get("exDataType", "")
+    playerID = exData.get("playerID", 0)
+    
+    champMgr = GetChampionshipMgr()
+    
+    syncKeyList = []
+    for attrDict in guessList:
+        zoneID = attrDict["zoneID"]
+        guessType = attrDict["guessType"]
+        guessPlayerID = attrDict["guessPlayerID"]
+        tagPlayerID = attrDict["tagPlayerID"]
+        
+        syncKey = [guessType, tagPlayerID]
+        if syncKey not in syncKeyList:
+            syncKeyList.append(syncKey)
+            
+        # 竞猜列表仅针对玩家个人,所以不是请求方玩家或本服玩家则不处理个人信息,仅处理公共信息
+        if playerID != guessPlayerID:
+            continue
+        
+        if not PlayerControl.GetDBPlayerAccIDByID(guessPlayerID):
+            # 非本服玩家
+            continue
+        
+        pkZoneMgr = champMgr.GetChampPKZoneMgr(zoneID)
+        
+        guessObj = None
+        playerGuessList = pkZoneMgr.GetPlayerGuessList(guessPlayerID, guessType)
+        for guess in playerGuessList:
+            if guess.tagPlayerID == tagPlayerID:
+                guessObj = guess
+                break
+            
+        if not guessObj:
+            guessObj = ChampionshipGuess()
+            playerGuessList.append(guessObj)
+        guessObj.SetAttr(attrDict)
+        
+    pubZoneIDList = []
+    if pubInfo != None:
+        zoneSupportCountInfo = pubInfo["zoneSupportCountInfo"]
+        for zoneID, supportCountInfo in zoneSupportCountInfo.items():
+            pkZoneMgr = champMgr.GetChampPKZoneMgr(zoneID)
+            pkZoneMgr.supportCountInfo = supportCountInfo
+            pubZoneIDList.append(zoneID)
+            
+    if exDataType == "ChampionshipGuessQuery":
+        # 查询的只处理本服玩家
+        if not playerID:
+            return
+        if not PlayerControl.GetDBPlayerAccIDByID(playerID):
+            # 非本服玩家
+            return
+        zoneID = exData.get("zoneID", 0)
+        pkZoneMgr = champMgr.GetChampPKZoneMgr(zoneID)
+        pkZoneMgr.syncGuessPlayerIDInfo[playerID] = tick
+        curPlayer = GameWorld.GetPlayerManager().FindPlayerByID(playerID)
+        if curPlayer == None or not curPlayer.GetInitOK():
+            return
+        Sync_ChampionshipGuessPriInfo(curPlayer, syncKeyList)
+        Sync_ChampionshipGuessPubInfo(zoneID, curPlayer, syncKeyList)
+        return
+    
+    if exDataType == "ChampionshipGuess":
+        # 竞猜的如果有公共信息需要广播全服玩家,个人信息只同步该竞猜玩家
+        zoneID = exData.get("zoneID", 0)
+        if pubInfo != None:
+            Sync_ChampionshipGuessPubInfo(zoneID, None, syncKeyList)
+        if not playerID:
+            return
+        if not PlayerControl.GetDBPlayerAccIDByID(playerID):
+            # 非本服玩家
+            return
+        msgInfo = [exDataType, exData]
+        curPlayer = CrossRealmPlayer.MapServer_QueryCrossPlayerResult(playerID, "Championship", msgInfo, True)
+        if curPlayer:
+            Sync_ChampionshipGuessPriInfo(curPlayer, syncKeyList)
+        return
+    
+    return
+
+def OnRequestChampionshipVSRoom(playerID, serverGroupID):
+    ## 请求进入排位对战房间
+    
+    stateError = PlayerDBGSEvent.GetDBGSTrig_ByKey(PlayerDBGSEvent.Def_CrossChampionshipStateError)
+    if stateError:
+        GameWorld.ErrLog("跨服排位状态已经异常无法进入! stateError=%s" % stateError, playerID)
+        return
+    
+    state = PlayerDBGSEvent.GetDBGSTrig_ByKey(PlayerDBGSEvent.Def_CrossChampionshipState)
+    if state not in ShareDefine.CrossChampionshipEnterStateInfo:
+        GameWorld.ErrLog("当前状态非跨服排位战斗状态无法进入: state=%s" % state, playerID)
+        return
+    groupMark = ShareDefine.CrossChampionshipEnterStateInfo[state]
+    
+    mapPosList = IpyGameDataPY.GetFuncEvalCfg("CrossChamFB", 2)
+    if not mapPosList:
+        GameWorld.ErrLog("没有配置跨服排位对战地图进入坐标! CrossChamFB 数值2")
+        return
+    
+    roomID = 0
+    vsRoomDict = {}
+    
+    champMgr = GetChampionshipMgr()
+    for zoneID in champMgr.GetChampPKZoneIDList():
+        pkZoneMgr = champMgr.GetChampPKZoneMgr(zoneID)
+        if groupMark not in pkZoneMgr.battleInfo:
+            continue
+        battleDict = pkZoneMgr.battleInfo[groupMark]
+        for battleNum in battleDict.keys():
+            batObj = pkZoneMgr.GetBattle(groupMark, battleNum)
+            if not batObj:
+                continue
+            
+            if playerID == batObj.playerIDA:# or batObj.playerIDA == 496607:
+                factionIndex = 0
+            elif playerID == batObj.playerIDB:# or batObj.playerIDB == 489566:
+                factionIndex = 1
+            else:
+                continue
+            
+            if not batObj.mapID:
+                GameWorld.ErrLog("该跨服排位对战没有分配对战地图,无法进入! groupMark=%s,battleNum=%s" % (groupMark, battleNum), playerID)
+                return
+            roomID = batObj.roomID
+            realMapID = batObj.mapID
+            copyMapID = batObj.copyMapID
+            key = (realMapID, copyMapID)
+            if key not in PyGameData.g_crossDynamicLineCopyMapInfo:
+                GameWorld.ErrLog("该跨服排位对战没有分配对战地图线路,无法进入! groupMark=%s,battleNum=%s,realMapID=%s,copyMapID=%s" 
+                                 % (groupMark, battleNum, realMapID, copyMapID), playerID)
+                return
+            copyMapObj = PyGameData.g_crossDynamicLineCopyMapInfo[key]
+            if copyMapObj.openState != IPY_PlayerDefine.fbosOpen:
+                GameWorld.Log("该跨服排位对战分配的地图线路非开启状态,无法进入! groupMark=%s,battleNum=%s,realMapID=%s,copyMapID=%s,openState=%s" 
+                              % (groupMark, battleNum, realMapID, copyMapID, copyMapObj.openState), playerID)
+                return
+            
+            posX, posY = mapPosList[factionIndex] if len(mapPosList) > factionIndex else mapPosList[0]
+            
+            registerMap = ChConfig.Def_FBMapID_CrossChampionship
+            dataMapID = realMapID
+            
+            vsRoomDict = {roomID:{playerID:{"regMapInfo":[registerMap, realMapID, dataMapID, copyMapID, posX, posY]}}}
+            GameWorld.Log("玩家请求跨服排位对战组: zoneID=%s,groupMark=%s,battleNum=%s,roomID=%s" 
+                          % (zoneID, groupMark, battleNum, roomID), playerID)
+            break
+        
+    if not roomID or not vsRoomDict:
+        GameWorld.ErrLog("找不到玩家跨服排位对战组: state=%s,groupMark=%s" % (state, groupMark), playerID)
+        return
+    PlayerFB.Send_CrossServerMsg_EnterVSRoomRet(vsRoomDict, [serverGroupID])
+    return
+
+def GetChampionshipPKRoomID(zoneID, groupMark, battleNum): return int("%d%03d%02d" % (zoneID, groupMark, battleNum))
+def MapServer_CrossChampionshipPKOver(infoList, tick):
+    ## 收到MapServer副本跨服排位PK结果同步
+    
+    roomID, winnerID, loserID, roundWinnerIDList, overType = infoList
+    zoneID = roomID / 100000
+    groupMark = roomID % 100000 / 100
+    battleNum = roomID % 100
+    GameWorld.Log("=== 收到MapServer_跨服排位PK战斗结果: zoneID=%s,groupMark=%s,battleNum=%s,roomID=%s,winnerID=%s,loserID=%s,roundWinnerIDList=%s,overType=%s" 
+                  % (zoneID, groupMark, battleNum, roomID, winnerID, loserID, roundWinnerIDList, overType), roomID)
+    DoBattleOverLogic(zoneID, groupMark, battleNum, winnerID, loserID, roundWinnerIDList, overType)
+    return
+
+def DoBattleOverLogic(zoneID, groupMark, battleNum, winnerID=0, loserID=0, roundWinnerIDList=None, overType=0):
+    ## 执行对战结算逻辑
+    
+    if not zoneID:
+        return
+    
+    groupMarkList = ShareDefine.CrossChampionshipEnterStateInfo.values()
+    if groupMark not in groupMarkList:
+        GameWorld.ErrLog("跨服排位结算分组异常! groupMark=%s" % groupMark)
+        return
+    
+    champMgr = GetChampionshipMgr()
+    pkZoneMgr = champMgr.GetChampPKZoneMgr(zoneID)
+    battleObj = pkZoneMgr.GetBattle(groupMark, battleNum)
+    if not battleObj:
+        return
+    
+    if roundWinnerIDList == None:
+        roundWinnerIDList = []
+        
+    roomID = battleObj.roomID
+    if battleObj.overTime:
+        GameWorld.ErrLog("跨服排位PK对战已经结算过了,不重复结算! zoneID=%s,groupMark=%s,battleNum=%s,winPlayerID=%s,overTime=%s" 
+                         % (zoneID, groupMark, battleNum, battleObj.winPlayerID, GameWorld.ChangeTimeNumToStr(battleObj.overTime)), roomID)
+        return
+    
+    playerIDA = battleObj.playerIDA
+    playerIDB = battleObj.playerIDB
+    roomPlayerIDList = [playerIDA, playerIDB]
+    GameWorld.Log("结算跨服排位PK战斗结果: zoneID=%s,groupMark=%s,battleNum=%s,playerIDA=%s,playerIDB=%s,roomPlayerIDList=%s" 
+                  % (zoneID, groupMark, battleNum, playerIDA, playerIDB, roomPlayerIDList), roomID)
+    
+    if playerIDA and playerIDB:
+        if not winnerID and not loserID:
+            playerA = pkZoneMgr.GetBatPlayer(playerIDA)
+            playerB = pkZoneMgr.GetBatPlayer(playerIDB)
+            fightPowerA = playerA.fightPower if playerA else 0
+            fightPowerB = playerB.fightPower if playerB else 0
+            if fightPowerA > fightPowerB:
+                winnerID, loserID = playerIDA, playerIDB
+                GameWorld.Log("    跨服排位赛对战地图没有玩家参与或没有胜负玩家,战力高获胜! fightPowerA=%s(%s) > fightPowerB=%s(%s),winnerID=%s,loserID=%s" 
+                              % (fightPowerA, playerIDA, fightPowerB, playerIDB, winnerID, loserID), roomID)
+            elif fightPowerA < fightPowerB:
+                winnerID, loserID = playerIDB, playerIDA
+                GameWorld.Log("    跨服排位赛对战地图没有玩家参与或没有胜负玩家,战力高获胜! fightPowerA=%s(%s) < fightPowerB=%s(%s),winnerID=%s,loserID=%s" 
+                              % (fightPowerA, playerIDA, fightPowerB, playerIDB, winnerID, loserID), roomID)
+            else:
+                random.shuffle(roomPlayerIDList)
+                winnerID, loserID = roomPlayerIDList
+                GameWorld.Log("    跨服排位赛对战地图没有玩家参与或没有胜负玩家,战力相同随机玩家获胜! fightPowerA=%s(%s) = fightPowerB=%s(%s),winnerID=%s,loserID=%s" 
+                              % (fightPowerA, playerIDA, fightPowerB, playerIDB, winnerID, loserID), roomID)
+        elif not loserID:
+            for roomPlayerID in roomPlayerIDList:
+                if roomPlayerID != winnerID:
+                    loserID = roomPlayerID
+                    GameWorld.Log("    跨服排位赛对战地图没有失败玩家,默认对方为失败玩家! loserID=%s" % loserID, roomID)
+                    break
+                
+        if not winnerID or winnerID not in roomPlayerIDList or loserID not in roomPlayerIDList:
+            GameWorld.ErrLog("跨服排位赛PK房间胜负玩家异常,不结算! roomID=%s,winnerID=%s,loserID=%s,roomPlayerIDList=%s" 
+                             % (roomID, winnerID, loserID, roomPlayerIDList), roomID)
+            return
+        
+    elif playerIDA:
+        winnerID = playerIDA
+        loserID = playerIDB
+        GameWorld.Log("    跨服排位赛对战玩家轮空,默认获胜! winner is playerIDA=%s,loserID=%s" % (playerIDA, loserID), roomID)
+    elif playerIDB:
+        winnerID = playerIDB
+        loserID = playerIDA
+        GameWorld.Log("    跨服排位赛对战玩家轮空,默认获胜! winner is playerIDB=%s,loserID=%s" % (playerIDB, loserID), roomID)
+    else:
+        GameWorld.Log("    跨服排位赛PK房间无玩家! roomID=%s,winnerID=%s,loserID=%s,roomPlayerIDList=%s" 
+                             % (roomID, winnerID, loserID, roomPlayerIDList), roomID)
+        
+    # 更新获胜玩家ID、结束时间
+    battleObj.winPlayerID = winnerID
+    battleObj.overTime = int(time.time())
+    
+    winner = pkZoneMgr.GetBatPlayer(winnerID)
+    loser = pkZoneMgr.GetBatPlayer(loserID)
+    
+    winnerName = winner.playerName if winner else str(winnerID)
+    loserName = loser.playerName if loser else str(loserID)
+    
+    # 决赛可获取最终名次
+    playerRankInfo = {}
+    if groupMark == 2:
+        playerRankInfo = GetZoneIDRankInfo(zoneID, [winnerID, loserID])
+        
+    if groupMark == 64:
+        wfAwardItemList = IpyGameDataPY.GetFuncEvalCfg("CrossChamWFAward", 1)
+    elif groupMark == 32:
+        wfAwardItemList = IpyGameDataPY.GetFuncEvalCfg("CrossChamWFAward", 2)
+    elif groupMark == 16:
+        wfAwardItemList = IpyGameDataPY.GetFuncEvalCfg("CrossChamWFAward", 3)
+    else:
+        wfAwardItemList = IpyGameDataPY.GetFuncEvalCfg("CrossChamWFAward", 4)
+        
+    wAwardItemList, fAwardItemList = [], []
+    if wfAwardItemList and len(wfAwardItemList) == 2:
+        wAwardItemList, fAwardItemList = wfAwardItemList
+                
+    timeStr = GameWorld.GetCurrentDataTimeStr()
+    # 结算
+    for playerID in [winnerID, loserID]:
+        if not playerID:
+            continue
+        
+        if playerID == winnerID:
+            addItemList = wAwardItemList
+            mailTypeKey = "CrossChampionshipPKWin%s" % groupMark
+            tagPlayerID, tagPlayerName = loserID, loserName
+        else:
+            addItemList = fAwardItemList
+            mailTypeKey = "CrossChampionshipPKLose%s" % groupMark
+            tagPlayerID, tagPlayerName = winnerID, winnerName
+            
+        rank = playerRankInfo.get(playerID, 0)
+        GameWorld.Log("    结算跨服排位赛玩家奖励: zoneID=%s,roomID=%s,groupMark=%s,battleNum=%s,rank=%s,tagPlayerID=%s" 
+                           % (zoneID, roomID, groupMark, battleNum, rank, tagPlayerID), playerID)
+        if rank:
+            paramList = [rank]
+        else:
+            paramList = []
+        playerIDList = [playerID]
+        PlayerCompensation.SendMailByKey(mailTypeKey, playerIDList, addItemList, paramList, crossMail=True)
+        
+        player = GameWorld.GetPlayerManager().FindPlayerByID(playerID)
+        if player:
+            overPack = ChPyNetSendPack.tagGCCrossChampionshipPKOver()
+            overPack.GroupMark = groupMark
+            overPack.TimeStr = timeStr
+            overPack.OverType = overType
+            overPack.WinnerID = winnerID
+            overPack.LoserID = loserID
+            overPack.RoundWinnerID = roundWinnerIDList
+            overPack.RoundCount = len(overPack.RoundWinnerID)
+            overPack.TagName = tagPlayerName
+            overPack.TagNameLen = len(overPack.TagName)
+            overPack.Rank = rank
+            NetPackCommon.SendFakePack(player, overPack)
+            
+    # 同步子服
+    Send_CrossServerMsg_ChampionshipGroup(battleObj=battleObj)
+    
+    # 记录流向
+    winnerInfo = winner.GetString() if winner else {}
+    loserInfo = loser.GetString() if loser else {}
+    dataDict = {"roundWinnerIDList":roundWinnerIDList, "overType":overType, "winner":winnerInfo, "loser":loserInfo, 
+                "battle":battleObj.GetString(), "playerRankInfo":playerRankInfo}
+    DR_CrossChampionshipPK("PKRoomOver", dataDict)    
+    return
+
+def DoCrossChampionshipFinalOver():
+    ## 执行结算最终结果,所有分区同一时间点处理
+    
+    GameWorld.Log("===================== 执行跨服排位最终结算 ===========================")
+    
+    finalGroupMark = 2  # 决赛分组
+    
+    champMgr = GetChampionshipMgr()
+    champMgr.ClearOfficialZone() # 最终结算重置仙官信息,替换最新仙官
+    
+    pkZoneIDList = champMgr.GetChampPKZoneIDList()
+    GameWorld.Log("pkZoneIDList=%s" % pkZoneIDList)
+    
+    for zoneID in pkZoneIDList:
+        GameWorld.Log("=== 结算排位分区: zoneID=%s ===" % zoneID, zoneID)
+        finalPlayerIDList = []
+        pkZoneMgr = champMgr.GetChampPKZoneMgr(zoneID)
+        battleNumList = pkZoneMgr.battleInfo.get(finalGroupMark, {}).keys()
+        for battleNum in battleNumList:
+            batObj = pkZoneMgr.GetBattle(finalGroupMark, battleNum)
+            if not batObj:
+                continue
+            if not batObj.overTime:
+                GameWorld.ErrLog("最终战斗未结算,执行强制结算! zoneID=%s,finalGroupMark=%s,battleNum=%s,mapID=%s,copyMapID=%s" 
+                                 % (zoneID, finalGroupMark, battleNum, batObj.mapID, batObj.copyMapID), batObj.roomID)
+                DoBattleOverLogic(zoneID, finalGroupMark, battleNum)
+                
+            if batObj.playerIDA and batObj.playerIDA not in finalPlayerIDList:
+                finalPlayerIDList.append(batObj.playerIDA)
+                
+            if batObj.playerIDB and batObj.playerIDB not in finalPlayerIDList:
+                finalPlayerIDList.append(batObj.playerIDB)
+                
+        offZoneMgr = champMgr.GetChampOfficialZoneMgr(zoneID)
+        playerRankInfo = GetZoneIDRankInfo(zoneID, finalPlayerIDList)
+        for playerID, rank in playerRankInfo.items():
+            batPlayer = pkZoneMgr.GetBatPlayer(playerID)
+            accID = "" if not batPlayer else batPlayer.accID
+            fightPower = 0 if not batPlayer else batPlayer.fightPower
+            rankIpyData = IpyGameDataPY.GetIpyGameData("ChampionshipRank", rank)
+            officialID = rankIpyData.GetMainOfficialID() if rankIpyData else 0
+            rankAwardItemList = rankIpyData.GetRankAwardItemList() if rankIpyData else []
+            GameWorld.Log("    最终排名: zoneID=%s,rank=%s,playerID=%s,officialID=%s,rankAwardItemList=%s,accID=%s,fightPower=%s" 
+                          % (zoneID, rank, playerID, officialID, rankAwardItemList, accID, fightPower), zoneID)
+            
+            if officialID:
+                offObj = ChampionshipOfficial()
+                offObj.zoneID = zoneID
+                offObj.officialID = officialID
+                offObj.rank = rank
+                offObj.playerID = playerID
+                
+                offZoneMgr.officialInfo[officialID] = offObj
+                
+            # 名次奖励
+            paramList = [rank]
+            PlayerCompensation.SendMailByKey("CrossChampionshipPKRank", [playerID], rankAwardItemList, paramList, crossMail=True)
+            
+        # 处理4强竞猜发奖励
+        guessType = 4
+        moneyType, _ = IpyGameDataPY.GetFuncEvalCfg("CrossChamGuess", 1)
+        multiPriceDict = IpyGameDataPY.GetFuncEvalCfg("CrossChamGuess", 4, {}) # 猜中奖励倍值字典
+        moneyItemID = ChConfig.MoneyItemIDDict.get(moneyType)
+        GameWorld.Log("竞猜返利货币类型: moneyType=%s,moneyItemID=%s,multiPriceDict=%s" % (moneyType, moneyItemID, multiPriceDict), zoneID)
+        playerGuessDict = pkZoneMgr.guessInfo.get(guessType, {})
+        for guessPlayerID, guessList in playerGuessDict.items():
+            guessCorrectCount = 0 # 猜中人数
+            guessCorrectMoney = 0 # 猜中总投入货币
+            for guessObj in guessList:
+                if guessObj.guessType != guessType or guessObj.guessPlayerID != guessPlayerID:
+                    continue
+                tagPlayerID = guessObj.tagPlayerID
+                guessRank = guessObj.guessRank
+                moneyTotal = guessObj.moneyTotal
+                if not tagPlayerID or tagPlayerID not in playerRankInfo:
+                    continue
+                playerRank = playerRankInfo[tagPlayerID]
+                if playerRank != guessRank:
+                    continue
+                guessCorrectCount += 1
+                guessCorrectMoney += moneyTotal
+                
+            multiPrice = multiPriceDict.get(str(guessCorrectCount), 0)
+            if guessCorrectMoney <= 0 or multiPrice <= 0 or not moneyItemID:
+                continue
+            moneyPriceTotal = guessCorrectMoney * multiPrice # 总收益
+            paramList = [guessCorrectCount, multiPrice]
+            addItemList = [[moneyItemID, moneyPriceTotal, 0]]
+            PlayerCompensation.SendMailByKey("CrossChampionshipGuess4", [guessPlayerID], addItemList, paramList, crossMail=True)
+            
+    exData = {"exDataType":"OfficialReset"}
+    Send_CrossServerMsg_ChampionshipOfficial(exData=exData)
+    
+    serverGroupIDList = [] # 全服统一逻辑
+    PlayerControl.WorldNotifyCross(serverGroupIDList, 0, "ChampionshipOver")
+    GameWorld.Log("===================================================================")
+    return
+
+def GetZoneIDRankInfo(zoneID, playerIDList):
+    ## 获取分区玩家排名
+    
+    champMgr = GetChampionshipMgr()
+    pkZoneMgr = champMgr.GetChampPKZoneMgr(zoneID)
+    
+    # 决赛
+    finalGroupMark = 2
+    finalWinPlayerIDList, finalLosePlayerIDList = [], []
+    battleNumList = pkZoneMgr.battleInfo.get(finalGroupMark, {}).keys()
+    for battleNum in battleNumList:
+        batObj = pkZoneMgr.GetBattle(finalGroupMark, battleNum)
+        if not batObj:
+            continue
+        if not batObj.overTime or not batObj.winPlayerID:
+            continue
+        winPlayerID = batObj.playerIDA if batObj.winPlayerID == batObj.playerIDA else batObj.playerIDB
+        losePlayerID = batObj.playerIDB if batObj.winPlayerID == batObj.playerIDA else batObj.playerIDA
+        finalWinPlayerIDList.append(winPlayerID)
+        finalLosePlayerIDList.append(losePlayerID)
+        
+    # 半决赛
+    semiGroupMark = 4
+    semiWinPlayerIDList, semiLosePlayerIDList = [], []
+    battleNumList = pkZoneMgr.battleInfo.get(semiGroupMark, {}).keys()
+    for battleNum in battleNumList:
+        batObj = pkZoneMgr.GetBattle(semiGroupMark, battleNum)
+        if not batObj:
+            continue
+        if not batObj.overTime or not batObj.winPlayerID:
+            continue
+        winPlayerID = batObj.playerIDA if batObj.winPlayerID == batObj.playerIDA else batObj.playerIDB
+        losePlayerID = batObj.playerIDB if batObj.winPlayerID == batObj.playerIDA else batObj.playerIDA
+        semiWinPlayerIDList.append(winPlayerID)
+        semiLosePlayerIDList.append(losePlayerID)
+        
+    # 1/4决赛
+    wlGroupMark = 8
+    winGroupPlayerIDList, loseGroupPlayerIDList = [], [] # 胜者组、败者组
+    battleNumList = pkZoneMgr.battleInfo.get(wlGroupMark, {}).keys()
+    for battleNum in battleNumList:
+        batObj = pkZoneMgr.GetBattle(wlGroupMark, battleNum)
+        if not batObj:
+            continue
+        if not batObj.overTime or not batObj.winPlayerID:
+            continue
+        winPlayerID = batObj.playerIDA if batObj.winPlayerID == batObj.playerIDA else batObj.playerIDB
+        losePlayerID = batObj.playerIDB if batObj.winPlayerID == batObj.playerIDA else batObj.playerIDA
+        winGroupPlayerIDList.append(winPlayerID)
+        loseGroupPlayerIDList.append(losePlayerID)
+        
+    GameWorld.Log("     8强赛胜负: zoneID=%s,胜者ID=%s,败者ID=%s" % (zoneID, winGroupPlayerIDList, loseGroupPlayerIDList), zoneID)
+    GameWorld.Log("    半决赛胜负: zoneID=%s,胜者ID=%s,败者ID=%s" % (zoneID, semiWinPlayerIDList, semiLosePlayerIDList), zoneID)
+    GameWorld.Log("    总决赛胜负: zoneID=%s,胜者ID=%s,败者ID=%s" % (zoneID, finalWinPlayerIDList, finalLosePlayerIDList), zoneID)
+    
+    playerRankInfo = {}
+    for playerID in playerIDList:
+        if not playerID:
+            continue
+        if playerID in winGroupPlayerIDList:
+            if playerID in semiWinPlayerIDList:
+                if playerID in finalWinPlayerIDList:
+                    playerRankInfo[playerID] = 1
+                elif playerID in finalLosePlayerIDList:
+                    playerRankInfo[playerID] = 2
+            elif playerID in semiLosePlayerIDList:
+                if playerID in finalWinPlayerIDList:
+                    playerRankInfo[playerID] = 3
+                elif playerID in finalLosePlayerIDList:
+                    playerRankInfo[playerID] = 4
+        elif playerID in loseGroupPlayerIDList:
+            if playerID in semiWinPlayerIDList:
+                if playerID in finalWinPlayerIDList:
+                    playerRankInfo[playerID] = 5
+                elif playerID in finalLosePlayerIDList:
+                    playerRankInfo[playerID] = 6
+            elif playerID in semiLosePlayerIDList:
+                if playerID in finalWinPlayerIDList:
+                    playerRankInfo[playerID] = 7
+                elif playerID in finalLosePlayerIDList:
+                    playerRankInfo[playerID] = 8
+                    
+    GameWorld.Log("    zoneID=%s,playerRankInfo=%s" % (zoneID, playerRankInfo), zoneID)
+    return playerRankInfo
+
+def Send_CrossServerMsg_ChampionshipOfficial(syncZonID=None, syncOfficialIDList=None, serverGroupID=0, exData=None):
+    officialList = []
+    champMgr = GetChampionshipMgr()
+    for zoneID in champMgr.GetChampOfficialZoneIDList():
+        if syncZonID != None and zoneID != syncZonID:
+            continue
+        offZoneMgr = champMgr.GetChampOfficialZoneMgr(zoneID)
+        if syncOfficialIDList == None:
+            syncOfficialIDList = offZoneMgr.officialInfo.keys()
+        for officialID in syncOfficialIDList:
+            offObj = offZoneMgr.GetOfficialObj(officialID)
+            if not offObj:
+                continue
+            officialList.append(offObj.GetString())
+            
+    dataMsg = {"exData":exData if exData else {}, "officialList":officialList}
+    serverGroupIDList = [serverGroupID] if serverGroupID else []
+    CrossRealmMsg.SendMsgToClientServer(ShareDefine.CrossServerMsg_ChampionshipOfficial, dataMsg, serverGroupIDList)
+    return
+
+def CrossServerMsg_ChampionshipOfficial(msgData):
+    ## 收到跨服同步的官爵玩家信息
+    
+    exData = msgData["exData"]
+    officialList = msgData["officialList"]
+    
+    if not exData or not isinstance(exData, dict):
+        exData = {}
+    exDataType = exData.get("exDataType", "")
+    
+    champMgr = GetChampionshipMgr()
+    ## 官职重置
+    if exDataType == "OfficialReset":
+        champMgr.ClearOfficialZone()
+        
+    syncZoneOfficialInfo = {}
+    for attrDict in officialList:
+        zoneID = attrDict["zoneID"]
+        officialID = attrDict["officialID"]
+        offZoneMgr = champMgr.GetChampOfficialZoneMgr(zoneID)
+        offObj = offZoneMgr.GetOfficialObj(officialID)
+        if not offObj:
+            offObj = ChampionshipOfficial()
+            offZoneMgr.officialInfo[officialID] = offObj
+        offObj.SetAttr(attrDict)
+        
+        if zoneID not in syncZoneOfficialInfo:
+            syncZoneOfficialInfo[zoneID] = []
+        officialIDList = syncZoneOfficialInfo[zoneID]
+        if officialID not in officialIDList:
+            officialIDList.append(officialID)
+            
+    for zoneID, officialIDList in syncZoneOfficialInfo.items():
+        Sync_ChampionshipOfficialInfo(zoneID, officialIDList)
+    
+    if not exData:
+        return
+    
+    ## 官职申请回应
+    if exDataType == "OfficialApplyReply":
+        mainPlayerName = exData["mainPlayerName"]
+        mainOfficialID = exData["mainOfficialID"]
+        officialID = exData["officialID"]
+        replyDict = exData["replyDict"]
+        for playerID, isOK in replyDict.items():
+            curPlayer = GameWorld.GetPlayerManager().FindPlayerByID(playerID)
+            if curPlayer == None or not curPlayer.GetInitOK():
+                continue
+            clientPack = ChPyNetSendPack.tagGCChampionshipOfficialApplyReplyRet()
+            clientPack.PlayerName = mainPlayerName
+            clientPack.NameLen = len(clientPack.PlayerName)
+            clientPack.MainOfficialID = mainOfficialID
+            clientPack.OfficialID = officialID
+            clientPack.IsOK = 1 if isOK else 0
+            NetPackCommon.SendFakePack(curPlayer, clientPack)
+            
+    ## 官职挑战结果
+    elif exDataType == "OfficialChallenge":
+        playerID = exData["playerID"]
+        tagPlayerName = exData["tagPlayerName"]
+        mainOfficialID = exData["mainOfficialID"]
+        officialID = exData["officialID"]
+        Ret = exData["Ret"]
+        curPlayer = GameWorld.GetPlayerManager().FindPlayerByID(playerID)
+        if curPlayer:
+            clientPack = ChPyNetSendPack.tagGCChampionshipOfficialChallengeRet()
+            clientPack.PlayerName = tagPlayerName
+            clientPack.NameLen = len(clientPack.PlayerName)
+            clientPack.MainOfficialID = mainOfficialID
+            clientPack.OfficialID = officialID
+            clientPack.Ret = Ret
+            NetPackCommon.SendFakePack(curPlayer, clientPack)
+            
+    ## 膜拜
+    elif exDataType == "OfficialWorship":
+        playerID = exData["playerID"]
+        if not playerID:
+            return
+        if not PlayerControl.GetDBPlayerAccIDByID(playerID):
+            # 非本服玩家
+            return
+        msgInfo = [exDataType, exData]
+        CrossRealmPlayer.MapServer_QueryCrossPlayerResult(playerID, "Championship", msgInfo, True)
+        
+    return
+
+def ClientServerMsg_ChampionshipGuess(serverGroupID, msgData):
+    ## 收到子服信息 - 跨服排位竞猜
+    
+    if "exDataType" not in msgData:
+        return
+    exDataType = msgData["exDataType"]
+    
+    # 查询玩家所有参与的竞猜
+    if exDataType == "ChampionshipGuessQuery":
+        zoneID = msgData["zoneID"]
+        playerID = msgData["playerID"]
+        Send_CrossServerMsg_ChampionshipGuess(zoneID, playerID, serverGroupID=serverGroupID, exData=msgData)
+        return
+    
+    if exDataType != "ChampionshipGuess":
+        return
+    
+    zoneID = msgData["zoneID"]
+    playerID = msgData["playerID"]
+    guessType = msgData["guessType"]
+    tagPlayerID = msgData["tagPlayerID"]
+    guessRank = msgData["guessRank"]
+    guessMoney = msgData["guessMoney"]
+    moneyType = msgData["moneyType"]
+    
+    if not tagPlayerID or not guessMoney:
+        return
+    
+    stateError = PlayerDBGSEvent.GetDBGSTrig_ByKey(PlayerDBGSEvent.Def_CrossChampionshipStateError)
+    if stateError:
+        GameWorld.ErrLog("跨服排位状态已经异常无法竞猜! stateError=%s" % stateError, playerID)
+        return
+        
+    guessTypeStateDict = {8:ShareDefine.CrossChampionshipState_Guess8,
+                          4:ShareDefine.CrossChampionshipState_Guess4,
+                          }
+    state = PlayerDBGSEvent.GetDBGSTrig_ByKey(PlayerDBGSEvent.Def_CrossChampionshipState)
+    if guessType not in guessTypeStateDict or state != guessTypeStateDict[guessType]:
+        GameWorld.ErrLog("竞猜类型错误或当前状态无法进行该类型竞猜! guessType=%s,state=%s" % (guessType, state), playerID)
+        return
+    
+    curMoneyType, moneyValue = IpyGameDataPY.GetFuncEvalCfg("CrossChamGuess", 1)
+    guessCountMax = IpyGameDataPY.GetFuncCfg("CrossChamGuess", 2)
+    guessMoneyMax = moneyValue * guessCountMax
+    if moneyType != curMoneyType:
+        GameWorld.ErrLog("竞猜货币类型不一致! moneyType=%s != curMoneyType=%s" % (moneyType, curMoneyType), playerID)
+        return
+    
+    champMgr = GetChampionshipMgr()
+    pkZoneMgr = champMgr.GetChampPKZoneMgr(zoneID)
+    tagBatPlayer = pkZoneMgr.GetBatPlayer(tagPlayerID)
+    if not tagBatPlayer:
+        GameWorld.ErrLog("该分区不存在该参赛玩家,无法排位竞猜! zoneID=%s,tagPlayerID=%s" % (zoneID, tagPlayerID), playerID)
+        return
+        
+    # 4强竞猜
+    if guessType == 4:
+        if not guessRank:
+            return
+        top8PlayerIDList = pkZoneMgr.GetTop8PlayerIDList()
+        if tagPlayerID not in top8PlayerIDList:
+            GameWorld.ErrLog("目前玩家非该分区8强玩家,无法竞猜! zoneID=%s,tagPlayerID=%s not in %s" 
+                             % (zoneID, tagPlayerID, top8PlayerIDList), playerID)
+            return
+        
+    guessObj = None
+    playerGuessList = pkZoneMgr.GetPlayerGuessList(playerID, guessType)
+    for guess in playerGuessList:
+        if guess.tagPlayerID == tagPlayerID:
+            guessObj = guess
+            GameWorld.Log("已经存在该竞猜,玩家进行加注!  guessInfo=%s" % guess.GetString())
+        else:
+            if guessType == 4:
+                if guess.guessRank == guessRank:
+                    GameWorld.ErrLog("该名次已经竞猜了其他玩家,无法重复竞猜同一名次! zoneID=%s,guessType=%s,tagPlayerID=%s,guessRank=%s,已经竞猜过的玩家ID=%s" 
+                         % (zoneID, guessType, tagPlayerID, guessRank, guess.tagPlayerID), playerID)
+                    return
+                
+    guessMoneyAlready = 0 if not guessObj else guessObj.moneyTotal # 已经竞猜的额度
+    if guessMoneyAlready + guessMoney > guessMoneyMax:
+        GameWorld.ErrLog("超出最大可投注份数额度,无法竞猜! zoneID=%s,guessType=%s,tagPlayerID=%s,guessMoneyAlready=%s,guessMoney=%s,guessMoneyMax=%s" 
+                         % (zoneID, guessType, tagPlayerID, guessMoneyAlready, guessMoney, guessMoneyMax), playerID)
+        return
+    
+    syncPub = False # 同步公共信息
+    if not guessObj:
+        guessObj = ChampionshipGuess()
+        guessObj.zoneID = zoneID
+        guessObj.guessType = guessType
+        guessObj.guessRank = guessRank
+        guessObj.guessPlayerID = playerID
+        guessObj.tagPlayerID = tagPlayerID
+        guessObj.moneyTotal = 0 # 投注总货币值
+        playerGuessList.append(guessObj)
+        
+        syncPub = True
+        if guessType not in pkZoneMgr.supportCountInfo:
+            pkZoneMgr.supportCountInfo[guessType] = {}
+        playerSupportCountDict = pkZoneMgr.supportCountInfo[guessType]
+        playerSupportCountDict[tagPlayerID] = playerSupportCountDict.get(tagPlayerID, 0) + 1
+        superPlayerCount = playerSupportCountDict.get(tagPlayerID, 0)
+        GameWorld.Log("更新被竞猜玩家支持人数值! zoneID=%s,guessType=%s,tagPlayerID=%s,superPlayerCount=%s" 
+                      % (zoneID, guessType, tagPlayerID, superPlayerCount), playerID)
+        
+    guessObj.moneyTotal += guessMoney
+    GameWorld.Log("更新竞猜! zoneID=%s,guessType=%s,tagPlayerID=%s,guessRank=%s,moneyTotal=%s" 
+                  % (zoneID, guessType, tagPlayerID, guessRank, guessObj.moneyTotal), playerID)
+    
+    Send_CrossServerMsg_ChampionshipGuess(zoneID, playerID, guessObj, serverGroupID, msgData, syncPub=syncPub)
+    return
+
+def ClientServerMsg_ChampionshipWorship(serverGroupID, msgData):
+    ## 收到子服信息 - 跨服排位膜拜
+        
+    zoneID = msgData["zoneID"]
+    playerID = msgData["playerID"]
+    tagPlayerID = msgData["tagPlayerID"]
+    
+    champMgr = GetChampionshipMgr()
+    offZoneMgr = champMgr.GetChampOfficialZoneMgr(zoneID)
+    officialObj = offZoneMgr.GetPlayerOfficial(tagPlayerID)
+    if not officialObj:
+        GameWorld.ErrLog("该分区目标玩家没有官职,无法膜拜! zoneID=%s,tagPlayerID=%s" % (zoneID, tagPlayerID), playerID)
+        return
+    tagOfficialID = officialObj.officialID
+    mainIpyData = IpyGameDataPY.GetIpyGameData("ChampionshipOfficial", tagOfficialID)
+    if not mainIpyData:
+        return
+    juniorOfficialIDList = mainIpyData.GetJuniorOfficialIDList()
+    if not juniorOfficialIDList:
+        GameWorld.ErrLog("该官职无下级仙官,无法膜拜! zoneID=%s,tagPlayerID=%s,tagOfficialID=%s" % (zoneID, tagPlayerID, tagOfficialID), playerID)
+        return
+    
+    officialObj.worshipCount += 1
+    
+    if officialObj.worshipDouble:
+        msgData["worshipDouble"] = 1
+            
+    syncOfficialIDList = [tagOfficialID]
+    Send_CrossServerMsg_ChampionshipOfficial(zoneID, syncOfficialIDList, exData=msgData)
+    return
+
+def ClientServerMsg_ChampionshipOfficialApply(serverGroupID, msgData):
+    ## 收到子服信息 - 跨服排位仙官申请
+    
+    zoneID = msgData["zoneID"]
+    playerID = msgData["playerID"]
+    mainOfficialID = msgData["mainOfficialID"]
+    officialID = msgData["officialID"]
+    PropData = msgData["PropData"]
+    
+    mainIpyData = IpyGameDataPY.GetIpyGameData("ChampionshipOfficial", mainOfficialID)
+    if not mainIpyData:
+        return
+    juniorOfficialIDList = mainIpyData.GetJuniorOfficialIDList()
+    if officialID not in juniorOfficialIDList:
+        GameWorld.ErrLog("申请官职ID非该界主下级官职,无法申请! mainOfficialID=%s,officialID=%s not in %s" 
+                         % (mainOfficialID, officialID, juniorOfficialIDList), playerID)
+        return
+    
+    ipyData = IpyGameDataPY.GetIpyGameData("ChampionshipOfficial", officialID)
+    if not ipyData:
+        return
+    canBeReplace = ipyData.GetCanBeReplace()
+    if canBeReplace:
+        GameWorld.ErrLog("可被挑战的官职无法申请! mainOfficialID=%s,officialID=%s" % (mainOfficialID, officialID), playerID)
+        return
+    
+    champMgr = GetChampionshipMgr()
+    offZoneMgr = champMgr.GetChampOfficialZoneMgr(zoneID)
+    mainOffObj = offZoneMgr.GetOfficialObj(mainOfficialID)
+    officialObj = offZoneMgr.GetOfficialObj(officialID)
+    if not mainOffObj or not officialObj:
+        return
+    
+    if mainOffObj.playerID:
+        GameWorld.Log("仙官所属界主无玩家,无法申请! zoneID=%s,mainOfficialID=%s,officialID=%s" % (zoneID, mainOfficialID, officialID), playerID)
+        return
+    
+    if officialObj.playerID:
+        GameWorld.Log("仙官已有玩家任职,无法申请! zoneID=%s,mainOfficialID=%s,officialID=%s,offPlayerID=%s" 
+                      % (zoneID, mainOfficialID, officialID, officialObj.playerID), playerID)
+        return
+    
+    if playerID in officialObj.applyPlayerInfo:
+        GameWorld.Log("已经申请过该官职! zoneID=%s,mainOfficialID=%s,officialID=%s" % (zoneID, mainOfficialID, officialID), playerID)
+        return
+    
+    applyPlayerCountMax = IpyGameDataPY.GetFuncCfg("CrossChamOfficial", 1) # 每个官职最大申请玩家数
+    if applyPlayerCountMax and len(officialObj.applyPlayerInfo) >= applyPlayerCountMax:
+        GameWorld.Log("该官职已达到最大申请玩家数! zoneID=%s,mainOfficialID=%s,officialID=%s,applyPlayerIDList=%s,applyPlayerCountMax=%s" 
+                      % (zoneID, mainOfficialID, officialID, officialObj.applyPlayerInfo.keys(), applyPlayerCountMax), playerID)
+        PlayerControl.NotifyCodeCross(serverGroupID, playerID, "ChampionshipOfficialApplyFull")
+        return
+    
+    playerApplyOfficialIDList = []
+    for offID in offZoneMgr.officialInfo.keys():
+        offObj = offZoneMgr.GetOfficialObj(offID)
+        if not offObj:
+            continue
+        if offObj.playerID == playerID:
+            GameWorld.ErrLog("玩家已经有任职官职,无法申请其他官职! zoneID=%s,player officialID=%s" % (zoneID, offID), playerID)
+            PlayerControl.NotifyCodeCross(serverGroupID, playerID, "ChampionshipAlreadyHasOfficial")
+            return
+        if playerID in offObj.applyPlayerInfo:
+            playerApplyOfficialIDList.append(offID)
+            
+    playerApplyCountMax = IpyGameDataPY.GetFuncCfg("CrossChamOfficial", 2) # 每个玩家最大可同时申请官职数
+    if playerApplyCountMax and len(playerApplyOfficialIDList) >= playerApplyCountMax:
+        GameWorld.Log("玩家已达到同时申请官职最大数! zoneID=%s,mainOfficialID=%s,officialID=%s,playerApplyOfficialIDList=%s,playerApplyCountMax=%s" 
+                      % (zoneID, mainOfficialID, officialID, playerApplyOfficialIDList, playerApplyCountMax), playerID)
+        PlayerControl.NotifyCodeCross(serverGroupID, playerID, "ChampionshipOfficialApplyMax")
+        return
+    
+    # 更新没进入跨服的玩家缓存信息
+    PlayerViewCache.FindViewCache(playerID, True, PropData)
+    officialObj.applyPlayerInfo[playerID] = PropData
+    
+    Send_CrossServerMsg_ChampionshipOfficial(zoneID, [officialID])
+    
+    PlayerControl.NotifyCodeCross(serverGroupID, playerID, "ChampionshipOfficialApplyOK")
+    return
+
+#// C0 21 跨服排位仙官申请回应 #tagCGChampionshipOfficialApplyReply
+#
+#struct    tagCGChampionshipOfficialApplyReply
+#{
+#    tagHead        Head;
+#    WORD        MainOfficialID;    //界主官职ID
+#    WORD        OfficialID;    //申请官职ID
+#    DWORD        PlayerID;        //申请的玩家ID
+#    BYTE        IsOK;        //是否同意;1-是;0-否
+#};
+def OnChampionshipOfficialApplyReply(index, clientData, tick):
+    if GameWorld.IsCrossServer():
+        return
+    
+    curPlayer = GameWorld.GetPlayerManager().GetPlayerByIndex(index)
+    playerID = curPlayer.GetPlayerID()
+    
+    mainOfficialID = clientData.MainOfficialID
+    officialID = clientData.OfficialID
+    applyPlayerID = clientData.PlayerID
+    isOK = clientData.IsOK
+    
+    champMgr = GetChampionshipMgr()
+    zoneID = champMgr.GetPlayerOfficialZoneID(playerID)
+    if not zoneID:
+        return
+    
+    sendMsg = {"zoneID":zoneID, "playerID":playerID, "mainOfficialID":mainOfficialID, "officialID":officialID,
+               "applyPlayerID":applyPlayerID, "isOK":isOK}
+    CrossRealmMsg.SendMsgToCrossServer(ShareDefine.ClientServerMsg_ChampionshipOfficialApplyReply, sendMsg)
+    return
+
+def ClientServerMsg_ChampionshipOfficialApplyReply(serverGroupID, msgData):
+    ## 收到子服信息 - 跨服排位仙官申请回应
+    
+    zoneID = msgData["zoneID"]
+    playerID = msgData["playerID"]
+    mainOfficialID = msgData["mainOfficialID"]
+    officialID = msgData["officialID"]
+    applyPlayerID = msgData["applyPlayerID"]
+    isOK = msgData["isOK"]
+    
+    champMgr = GetChampionshipMgr()
+    offZoneMgr = champMgr.GetChampOfficialZoneMgr(zoneID)
+    mainOffObj = offZoneMgr.GetOfficialObj(mainOfficialID)
+    officialObj = offZoneMgr.GetOfficialObj(officialID)
+    if not mainOffObj:
+        return
+    if not officialObj:
+        return
+    
+    if mainOffObj.playerID != playerID:
+        GameWorld.ErrLog("非界主,无法回应仙官申请! zoneID=%s,mainOfficialID=%s,mainOffPlayerID=%s" 
+                         % (zoneID, mainOfficialID, mainOffObj.playerID), playerID)
+        return
+    
+    if applyPlayerID not in officialObj.applyPlayerInfo:
+        GameWorld.Log("玩家没有在该仙官申请列表里,不需要回应! zoneID=%s,mainOfficialID=%s,officialID=%s,applyPlayerID=%s not in applyPlayerIDList=%s" 
+                      % (zoneID, mainOfficialID, officialID, applyPlayerID, officialObj.applyPlayerInfo.keys()), playerID)
+        return
+    
+    replyDict = {applyPlayerID:isOK} # 回应结果 {playerID:isOK, ...}
+    syncOfficialIDList = [officialID]
+    officialObj.applyPlayerInfo.pop(applyPlayerID)
+    
+    # 同意
+    if isOK:
+        applyPlayerOffID = 0
+        # 移除该玩家的其他仙官申请
+        for offID in offZoneMgr.officialInfo.keys():
+            offObj = offZoneMgr.GetOfficialObj(offID)
+            if not offObj:
+                continue
+            
+            if offObj.playerID == applyPlayerID:
+                applyPlayerOffID = offID
+                syncOfficialIDList.append(offID)
+                
+            if applyPlayerID in offObj.applyPlayerInfo:
+                offObj.applyPlayerInfo.pop(applyPlayerID)
+                syncOfficialIDList.append(offID)
+                
+        if applyPlayerOffID:
+            GameWorld.ErrLog("同意玩家官职申请时,申请官职玩家已经任职其他官职,不处理! zoneID=%s,applyPlayerID=%s,applyPlayerOffID=%s" 
+                             % (zoneID, applyPlayerID, applyPlayerOffID), playerID)
+        else:
+            officialObj.playerID = applyPlayerID
+            # 默认拒绝其他申请者
+            for refusePlayerID in officialObj.applyPlayerInfo.keys():
+                replyDict[refusePlayerID] = 0
+            officialObj.applyPlayerInfo = {}
+    else:
+        pass
+    
+    exData = {"exDataType":"OfficialApplyReply", "mainPlayerName":mainOffObj.playerName, "replyDict":replyDict,
+              "mainOfficialID":mainOfficialID, "officialID":officialID}
+    Send_CrossServerMsg_ChampionshipOfficial(zoneID, syncOfficialIDList, exData=exData)
+    return
+
+def ClientServerMsg_ChampionshipOfficialChallenge(serverGroupID, msgData):
+    ## 收到子服信息 - 仙官挑战
+    
+    zoneID = msgData["zoneID"]
+    playerID = msgData["playerID"]
+    mainOfficialID = msgData["mainOfficialID"]
+    officialID = msgData["officialID"]
+    tagPlayerID = msgData["tagPlayerID"]
+    PropData = msgData["PropData"]
+    
+    if playerID == tagPlayerID:
+        GameWorld.ErrLog("挑战仙官不能挑战自己! mainOfficialID=%s,officialID=%s" % (mainOfficialID, officialID), playerID)
+        return
+    
+    mainIpyData = IpyGameDataPY.GetIpyGameData("ChampionshipOfficial", mainOfficialID)
+    if not mainIpyData:
+        return
+    juniorOfficialIDList = mainIpyData.GetJuniorOfficialIDList()
+    if officialID not in juniorOfficialIDList:
+        GameWorld.ErrLog("申请官职ID非该界主下级官职,无法挑战! mainOfficialID=%s,officialID=%s not in %s" 
+                         % (mainOfficialID, officialID, juniorOfficialIDList), playerID)
+        return
+    
+    ipyData = IpyGameDataPY.GetIpyGameData("ChampionshipOfficial", officialID)
+    if not ipyData:
+        return
+    canBeReplace = ipyData.GetCanBeReplace()
+    if not canBeReplace:
+        GameWorld.ErrLog("该仙官无法被挑战替换! mainOfficialID=%s,officialID=%s" % (mainOfficialID, officialID), playerID)
+        return
+    
+    champMgr = GetChampionshipMgr()
+    offZoneMgr = champMgr.GetChampOfficialZoneMgr(zoneID)
+    mainOffObj = offZoneMgr.GetOfficialObj(mainOfficialID)
+    officialObj = offZoneMgr.GetOfficialObj(officialID)
+    if not mainOffObj or not officialObj:
+        return
+    
+    if mainOffObj.playerID:
+        GameWorld.Log("仙官所属界主无玩家,无法挑战! zoneID=%s,mainOfficialID=%s,officialID=%s" % (zoneID, mainOfficialID, officialID), playerID)
+        return
+    
+    for offID in offZoneMgr.officialInfo.keys():
+        offObj = offZoneMgr.GetOfficialObj(offID)
+        if not offObj:
+            continue
+        if offObj.playerID == playerID:
+            GameWorld.ErrLog("玩家已经有任职官职,无法挑战其他官职!  zoneID=%s, player officialID=%s" % (zoneID, offID), playerID)
+            PlayerControl.NotifyCodeCross(serverGroupID, playerID, "ChampionshipAlreadyHasOfficial")
+            return
+        
+    Ret = 0 # 挑战结果;0-失败;1-获胜;2-目标仙官玩家ID已变更,可刷新后重试
+    offPlayerID = officialObj.playerID
+    if not offPlayerID:
+        GameWorld.Log("挑战目标仙官无玩家任职,直接获胜! zoneID=%s,mainOfficialID=%s,officialID=%s" % (zoneID, mainOfficialID, officialID), playerID)
+        Ret = 1
+    elif offPlayerID != tagPlayerID:
+        GameWorld.Log("挑战目标仙官玩家ID已变更,需要刷新后重新挑战! zoneID=%s,mainOfficialID=%s,officialID=%s,offPlayerID(%s) != tagPlayerID(%s)" 
+                      % (zoneID, mainOfficialID, officialID, offPlayerID, tagPlayerID), playerID)
+        Ret = 2
+    else:
+        fightPower = PropData.get("FightPower", 0)
+        tagFightPower = officialObj.fightPower
+        Ret = 1 if fightPower > tagFightPower else 0
+        GameWorld.Log("挑战目标仙官玩家ID结果! zoneID=%s,mainOfficialID=%s,officialID=%s,fightPower=%s,tagFightPower=%s,tagPlayerID=%s,Ret=%s" 
+                      % (zoneID, mainOfficialID, officialID, fightPower, tagFightPower, tagPlayerID, Ret), playerID)
+        
+    playerName = PropData.get("Name", str(playerID))
+    # 暂时只记录挑战胜利的
+    if Ret == 1:
+        officialObj.challengeList.append({"Time":int(time.time()), "Ret":Ret,
+                                          "Name":playerName,
+                                          "AccID":PropData.get("AccID", ""),
+                                          })
+        # 只保留最近5条件记录
+        if len(officialObj.challengeList) > 5:
+            officialObj.challengeList.pop(0)
+            
+        # 更新没进入跨服的玩家缓存信息
+        PlayerViewCache.FindViewCache(playerID, True, PropData)
+        
+        # 更新任职玩家ID
+        officialObj.ResetPlayer()
+        officialObj.playerID = playerID
+        
+        # 邮件通知对方,官职被挑战了
+        if offPlayerID:
+            PlayerCompensation.SendMailByKey("CrossChampionshipOfficialBeChallenge", [offPlayerID], [], [playerName, officialID], crossMail=True)
+            
+    exData = {"exDataType":"OfficialChallenge", "playerID":playerID, "tagPlayerName":officialObj.playerName,
+              "mainOfficialID":mainOfficialID, "officialID":officialID, "Ret":Ret}
+    Send_CrossServerMsg_ChampionshipOfficial(zoneID, [officialID], exData=exData)
+    return
+
+#// C0 23 跨服排位仙官挑战记录查询 #tagCGChampionshipOfficialChallengeQuery
+#
+#struct    tagCGChampionshipOfficialChallengeQuery
+#{
+#    tagHead        Head;
+#    WORD        MainOfficialID;    //界主官职ID
+#    WORD        OfficialID;    //查询官职ID
+#};
+def OnChampionshipOfficialChallengeQuery(index, clientData, tick):
+    if GameWorld.IsCrossServer():
+        return
+    curPlayer = GameWorld.GetPlayerManager().GetPlayerByIndex(index)
+    playerID = curPlayer.GetPlayerID()
+    
+    mainOfficialID = clientData.MainOfficialID
+    officialID = clientData.OfficialID
+    
+    champMgr = GetChampionshipMgr()
+    zoneID = champMgr.GetPlayerOfficialZoneID(playerID)
+    if not zoneID:
+        return
+    
+    offZoneMgr = champMgr.GetChampOfficialZoneMgr(zoneID)
+    officialObj = offZoneMgr.GetOfficialObj(officialID)
+    challengeList = officialObj.challengeList if officialObj else []
+    
+    clientPack = ChPyNetSendPack.tagGCChampionshipOfficialChallengeRecordInfo()
+    clientPack.ZoneID = zoneID
+    clientPack.MainOfficialID = mainOfficialID
+    clientPack.OfficialID = officialID
+    clientPack.RecordList = []
+    for challengeDict in challengeList:
+        recordPack = ChPyNetSendPack.tagGCChampionshipOfficialChallengeRecord()
+        recordPack.PlayerName = challengeDict.get("Name", "")
+        recordPack.NameLen = len(recordPack.PlayerName)
+        recordPack.ChallengeTime = challengeDict.get("Time", 0)
+        recordPack.Ret = challengeDict.get("Ret", 0)
+        clientPack.RecordList.append(recordPack)
+    clientPack.RecordCount = len(clientPack.RecordList)
+    NetPackCommon.SendFakePack(curPlayer, clientPack)
+    return
+
+#// C0 24 跨服排位辞退下级仙官 #tagCGChampionshipOfficialKick
+#
+#struct    tagCGChampionshipOfficialKick
+#{
+#    tagHead        Head;
+#    WORD        MainOfficialID;    //界主官职ID
+#    WORD        OfficialID;    //目标官职ID
+#    DWORD        PlayerID;        //目标玩家ID
+#};
+def OnChampionshipOfficialKick(index, clientData, tick):
+    if GameWorld.IsCrossServer():
+        return
+    curPlayer = GameWorld.GetPlayerManager().GetPlayerByIndex(index)
+    playerID = curPlayer.GetPlayerID()
+    
+    mainOfficialID = clientData.MainOfficialID
+    officialID = clientData.OfficialID
+    tagPlayerID = clientData.PlayerID
+    
+    champMgr = GetChampionshipMgr()
+    zoneID = champMgr.GetPlayerOfficialZoneID(playerID)
+    if not zoneID:
+        return
+    
+    sendMsg = {"zoneID":zoneID, "playerID":playerID, "mainOfficialID":mainOfficialID, "officialID":officialID,
+               "tagPlayerID":tagPlayerID, "playerName":CrossRealmPlayer.GetCrossPlayerName(curPlayer)}
+    CrossRealmMsg.SendMsgToCrossServer(ShareDefine.ClientServerMsg_ChampionshipOfficialKick, sendMsg)
+    return
+
+def ClientServerMsg_ChampionshipOfficialKick(serverGroupID, msgData):
+    ## 收到子服信息 - 跨服排位辞退下级仙官
+    
+    zoneID = msgData["zoneID"]
+    playerID = msgData["playerID"]
+    playerName = msgData["playerName"]
+    mainOfficialID = msgData["mainOfficialID"]
+    officialID = msgData["officialID"]
+    tagPlayerID = msgData["tagPlayerID"]
+    
+    mainIpyData = IpyGameDataPY.GetIpyGameData("ChampionshipOfficial", mainOfficialID)
+    if not mainIpyData:
+        return
+    juniorOfficialIDList = mainIpyData.GetJuniorOfficialIDList()
+    if officialID not in juniorOfficialIDList:
+        GameWorld.ErrLog("官职ID非该界主下级官职,无法辞退! mainOfficialID=%s,officialID=%s not in %s" 
+                         % (mainOfficialID, officialID, juniorOfficialIDList), playerID)
+        return
+    
+    champMgr = GetChampionshipMgr()
+    offZoneMgr = champMgr.GetChampOfficialZoneMgr(zoneID)
+    mainOffObj = offZoneMgr.GetOfficialObj(mainOfficialID)
+    officialObj = offZoneMgr.GetOfficialObj(officialID)
+    if not mainOffObj:
+        return
+    if not officialObj:
+        return
+    
+    if mainOffObj.playerID != playerID:
+        GameWorld.ErrLog("非界主,无法辞退下级仙官! zoneID=%s,mainOfficialID=%s,mainOffPlayerID=%s" 
+                         % (zoneID, mainOfficialID, mainOffObj.playerID), playerID)
+        return
+    
+    if not officialObj.playerID or officialObj.playerID != tagPlayerID:
+        GameWorld.Log("当前仙官玩家ID非目标玩家ID,无法辞退! zoneID=%s,mainOfficialID=%s,officialID=%s,offPlayerID(%s) != tagPlayerID(%s)" 
+                      % (zoneID, mainOfficialID, officialID, officialObj.playerID, tagPlayerID), playerID)
+        return
+    
+    kickCD = IpyGameDataPY.GetFuncCfg("CrossChamOfficial", 4) # 辞退下级仙官公共CD,秒
+    if kickCD:
+        curTime = int(time.time())
+        passSeconds = curTime - mainOffObj.lastDismissJuniorTime
+        if passSeconds < kickCD:
+            GameWorld.ErrLog("界主辞退下级仙官CD中! zoneID=%s,mainOfficialID=%s,passSeconds(%s) < %s" 
+                             % (zoneID, mainOfficialID, passSeconds, kickCD), playerID)
+            return
+        mainOffObj.lastDismissJuniorTime = curTime
+        
+    officialObj.ResetPlayer() # 辞退重置
+    
+    if tagPlayerID:
+        # 邮件通知对方,官职被辞退了
+        PlayerCompensation.SendMailByKey("CrossChampionshipOfficialBeKick", [tagPlayerID], [], [playerName, officialID], crossMail=True)
+        
+    syncOfficialIDList = [mainOfficialID, officialID]
+    Send_CrossServerMsg_ChampionshipOfficial(zoneID, syncOfficialIDList)
+    return
+
+
+#// C0 25 跨服排位主动离任仙官 #tagCGChampionshipOfficialLeave
+#
+#struct    tagCGChampionshipOfficialLeave
+#{
+#    tagHead        Head;
+#    WORD        MainOfficialID;    //界主官职ID
+#    WORD        OfficialID;    //离任官职ID
+#};
+def OnChampionshipOfficialLeave(index, clientData, tick):
+    if GameWorld.IsCrossServer():
+        return
+    curPlayer = GameWorld.GetPlayerManager().GetPlayerByIndex(index)
+    playerID = curPlayer.GetPlayerID()
+    
+    mainOfficialID = clientData.MainOfficialID
+    officialID = clientData.OfficialID
+    
+    champMgr = GetChampionshipMgr()
+    zoneID = champMgr.GetPlayerOfficialZoneID(playerID)
+    if not zoneID:
+        return
+    
+    sendMsg = {"zoneID":zoneID, "playerID":playerID, "mainOfficialID":mainOfficialID, "officialID":officialID}
+    CrossRealmMsg.SendMsgToCrossServer(ShareDefine.ClientServerMsg_ChampionshipOfficialLeave, sendMsg)
+    return
+
+def ClientServerMsg_ChampionshipOfficialLeave(serverGroupID, msgData):
+    ## 收到子服信息 - 跨服排位主动离任仙官
+    
+    zoneID = msgData["zoneID"]
+    playerID = msgData["playerID"]
+    mainOfficialID = msgData["mainOfficialID"]
+    officialID = msgData["officialID"]
+    
+    mainIpyData = IpyGameDataPY.GetIpyGameData("ChampionshipOfficial", mainOfficialID)
+    if not mainIpyData:
+        return
+    juniorOfficialIDList = mainIpyData.GetJuniorOfficialIDList()
+    if officialID not in juniorOfficialIDList:
+        GameWorld.ErrLog("官职ID非该界主下级官职,无法主动离任仙官! mainOfficialID=%s,officialID=%s not in %s" 
+                         % (mainOfficialID, officialID, juniorOfficialIDList), playerID)
+        return
+    
+    champMgr = GetChampionshipMgr()
+    offZoneMgr = champMgr.GetChampOfficialZoneMgr(zoneID)
+    officialObj = offZoneMgr.GetOfficialObj(officialID)
+    if not officialObj:
+        return
+    
+    if not officialObj.playerID or officialObj.playerID != playerID:
+        GameWorld.Log("非本仙官玩家ID,无法主动离任仙官! zoneID=%s,mainOfficialID=%s,officialID=%s,offPlayerID(%s) != playerID(%s)" 
+                      % (zoneID, mainOfficialID, officialID, officialObj.playerID, playerID), playerID)
+        return
+    
+    officialObj.ResetPlayer() # 离任重置
+    
+    syncOfficialIDList = [officialID]
+    Send_CrossServerMsg_ChampionshipOfficial(zoneID, syncOfficialIDList)
+    return
+
+def Sync_ChampionshipPKZoneGroupInfo(zoneID, groupMarkDict=None, curPlayer=None):
+    ## 同步排位分区分组信息
+    # @param groupMarkDict: {groupMark:[battleNum, ...], ...}
+        
+    champMgr = GetChampionshipMgr()
+    if curPlayer:
+        playerZoneID = champMgr.GetPlayerPKZoneID(curPlayer.GetPlayerID())
+        if playerZoneID != zoneID:
+            return
+        
+    pkZoneMgr = champMgr.GetChampPKZoneMgr(zoneID)
+    if groupMarkDict == None:
+        groupMarkDict = {}
+        for groupMark, groupDict in pkZoneMgr.battleInfo.items():
+            groupMarkDict[groupMark] = groupDict.keys()
+        playerIDList = pkZoneMgr.GetBatPlayerIDList()
+    else:
+        playerIDList = []
+        for groupMark, battleNumList in groupMarkDict.items():
+            for battleNum in battleNumList:
+                battleObj = pkZoneMgr.GetBattle(groupMark, battleNum)
+                if not battleObj:
+                    continue
+                playerIDList.append(battleObj.playerIDA)
+                playerIDList.append(battleObj.playerIDB)
+                
+    clientPack = ChPyNetSendPack.tagGCCrossChampionshipPKZoneGroupInfo()
+    clientPack.ActID = PlayerDBGSEvent.GetDBGSTrig_ByKey(PlayerDBGSEvent.Def_CrossChampionshipID)
+    clientPack.StateError = PlayerDBGSEvent.GetDBGSTrig_ByKey(PlayerDBGSEvent.Def_CrossChampionshipStateError)
+    clientPack.ZoneID = zoneID
+    clientPack.GroupList = []
+    for groupMark, battleNumList in groupMarkDict.items():
+        groupPack = ChPyNetSendPack.tagGCCrossChampionshipPKGroup()
+        groupPack.GroupMark = groupMark
+        groupPack.BattleList = []
+        for battleNum in battleNumList:
+            battleObj = pkZoneMgr.GetBattle(groupMark, battleNum)
+            if not battleObj:
+                continue
+            battlePack = ChPyNetSendPack.tagGCCrossChampionshipPKBattle()
+            battlePack.BattleNum = battleNum
+            battlePack.WinPlayerID = battleObj.winPlayerID
+            battlePack.PlayerIDA = battleObj.playerIDA
+            battlePack.PlayerIDB = battleObj.playerIDB
+            groupPack.BattleList.append(battlePack)
+        groupPack.BattleCount = len(groupPack.BattleList)
+        clientPack.GroupList.append(groupPack)
+    clientPack.GroupCount = len(clientPack.GroupList)
+    
+    clientPack.PlayerList = []
+    for playerID in playerIDList:
+        batPlayer = pkZoneMgr.GetBatPlayer(playerID)
+        if not batPlayer:
+            continue
+        playerPack = ChPyNetSendPack.tagGCCrossChampionshipPKPlayer()
+        playerPack.PlayerID = playerID
+        playerPack.PlayerName = batPlayer.playerName
+        playerPack.NameLen = len(playerPack.PlayerName)
+        playerPack.Job = batPlayer.job
+        playerPack.LV = batPlayer.lv
+        playerPack.FightPower = batPlayer.fightPower % ShareDefine.Def_PerPointValue
+        playerPack.FightPowerEx = batPlayer.fightPower / ShareDefine.Def_PerPointValue
+        playerPack.RealmLV = batPlayer.realmLV
+        clientPack.PlayerList.append(playerPack)
+    clientPack.PlayerCount = len(clientPack.PlayerList)
+    
+    if curPlayer != None:
+        NetPackCommon.SendFakePack(curPlayer, clientPack)
+    else:
+        playerManager = GameWorld.GetPlayerManager()
+        for i in xrange(playerManager.GetPlayerCount()):
+            curPlayer = playerManager.GetPlayerByIndex(i)
+            if curPlayer == None or not curPlayer.GetInitOK():
+                continue
+            playerZoneID = champMgr.GetPlayerPKZoneID(curPlayer.GetPlayerID())
+            if playerZoneID != zoneID:
+                continue
+            NetPackCommon.SendFakePack(curPlayer, clientPack)
+            
+    return
+
+def Sync_ChampionshipGuessPriInfo(curPlayer, syncKeyList=None):
+    ## 同步排位分区竞猜个人信息
+    # @param syncKeyList: 指定同步的 [[guessType, tagPlayerID], ...]
+    
+    playerID = curPlayer.GetPlayerID()
+    champMgr = GetChampionshipMgr()
+    playerZoneID = champMgr.GetPlayerPKZoneID(playerID)
+    if not playerZoneID:
+        return
+    
+    pkZoneMgr = champMgr.GetChampPKZoneMgr(playerZoneID)
+    
+    clientPack = ChPyNetSendPack.tagGCChampionshipGuessPriInfo()
+    clientPack.ZoneID = playerZoneID
+    clientPack.GuessList = []
+    
+    for guessType, playerGuessDict in pkZoneMgr.guessInfo.items():
+        priListPack = ChPyNetSendPack.tagGCChampionshipGuessPriList()
+        priListPack.GuessType = guessType
+        priListPack.GuessPlayerList = []
+        playerGuessList = playerGuessDict.get(playerID, [])
+        for guess in playerGuessList:
+            tagPlayerID = guess.tagPlayerID
+            syncKey = [guessType, tagPlayerID]
+            if syncKeyList and syncKey not in syncKeyList:
+                continue
+            priPlayerPack = ChPyNetSendPack.tagGCChampionshipGuessPlayerPri()
+            priPlayerPack.PlayerID = tagPlayerID
+            priPlayerPack.MoneyTotal = guess.moneyTotal
+            priPlayerPack.GuessRank = guess.guessRank
+            priListPack.GuessPlayerList.append(priPlayerPack)
+        priListPack.PlayerCount = len(priListPack.GuessPlayerList)
+        
+        clientPack.GuessList.append(priListPack)
+        
+    clientPack.Count = len(clientPack.GuessList)
+    NetPackCommon.SendFakePack(curPlayer, clientPack)
+    return
+
+def Sync_ChampionshipGuessPubInfo(zoneID, curPlayer=None, syncKeyList=None):
+    ## 同步排位分区竞猜公共信息
+    # @param syncKeyList: 指定同步的 [[guessType, tagPlayerID], ...]
+    
+    champMgr = GetChampionshipMgr()
+    if curPlayer:
+        playerZoneID = champMgr.GetPlayerPKZoneID(curPlayer.GetPlayerID())
+        if playerZoneID != zoneID:
+            return
+        
+    pkZoneMgr = champMgr.GetChampPKZoneMgr(zoneID)
+    
+    # 公共竞猜信息
+    clientPack = ChPyNetSendPack.tagGCChampionshipGuessPubInfo()
+    clientPack.ZoneID = zoneID
+    clientPack.GuessList = []
+    clientPack.Count = len(clientPack.GuessList)
+    
+    for guessType, playerSupportCountDict in pkZoneMgr.supportCountInfo.items():
+        pubListPack = ChPyNetSendPack.tagGCChampionshipGuessPubList()
+        pubListPack.GuessType = guessType
+        pubListPack.GuessPlayerList = []
+        
+        for tagPlayerID, supportCount in playerSupportCountDict.items():
+            syncKey = [guessType, tagPlayerID]
+            if syncKeyList and syncKey not in syncKeyList:
+                continue
+            pubPlayerPack = ChPyNetSendPack.tagGCChampionshipGuessPlayerPub()
+            pubPlayerPack.PlayerID = tagPlayerID
+            pubPlayerPack.SupportCount = supportCount
+            pubListPack.GuessPlayerList.append(pubPlayerPack)
+        pubListPack.PlayerCount = len(pubListPack.GuessPlayerList)
+        
+        clientPack.GuessList.append(pubListPack)
+        
+    if curPlayer != None:
+        NetPackCommon.SendFakePack(curPlayer, clientPack)
+    else:
+        playerManager = GameWorld.GetPlayerManager()
+        for i in xrange(playerManager.GetPlayerCount()):
+            curPlayer = playerManager.GetPlayerByIndex(i)
+            if curPlayer == None or not curPlayer.GetInitOK():
+                continue
+            playerZoneID = champMgr.GetPlayerPKZoneID(curPlayer.GetPlayerID())
+            if playerZoneID != zoneID:
+                continue
+            NetPackCommon.SendFakePack(curPlayer, clientPack)
+    return
+
+def Sync_ChampionshipOfficialInfo(zoneID, officialIDList=None, curPlayer=None):
+    ## 同步排位分区官职信息
+    # @param officialIDList: [officialID, ...]
+    
+    champMgr = GetChampionshipMgr()
+    if curPlayer:
+        playerZoneID = champMgr.GetPlayerOfficialZoneID(curPlayer.GetPlayerID())
+        if playerZoneID != zoneID:
+            return
+        
+    clientPack = ChPyNetSendPack.tagGCChampionshipOfficialInfo()
+    clientPack.ZoneID = zoneID
+    clientPack.OfficialList = []
+    
+    offZoneMgr = champMgr.GetChampOfficialZoneMgr(zoneID)
+    if officialIDList == None:
+        officialIDList = offZoneMgr.officialInfo.keys()
+        
+    for officialID in officialIDList:
+        offObj = offZoneMgr.GetOfficialObj(officialID)
+        if not offObj:
+            continue
+        offPlayer = ChPyNetSendPack.tagGCChampionshipOfficialPlayer()
+        offPlayer.PlayerID = offObj.playerID
+        offPlayer.PlayerName = offObj.playerName
+        offPlayer.NameLen = len(offPlayer.PlayerName)
+        offPlayer.Job = offObj.job
+        offPlayer.LV = offObj.lv
+        offPlayer.FightPower = offObj.fightPower % ShareDefine.Def_PerPointValue
+        offPlayer.FightPowerEx = offObj.fightPower / ShareDefine.Def_PerPointValue
+        offPlayer.RealmLV = offObj.realmLV
+        
+        offPack = ChPyNetSendPack.tagGCChampionshipOfficial()
+        offPack.OfficialID = officialID
+        offPack.LastDismissJuniorTime = offObj.lastDismissJuniorTime
+        offPack.WorshipCount = offObj.worshipCount
+        offPack.WorshipDouble = offObj.worshipDouble
+        offPack.OfficialPlayer = offPlayer
+        offPack.ApplyPlayerList = []
+        for applyPlayerID, playerInfo in offObj.applyPlayerInfo.items():
+            applyPlayer = ChPyNetSendPack.tagGCChampionshipOfficialPlayer()
+            applyPlayer.PlayerID = applyPlayerID
+            applyPlayer.PlayerName = playerInfo.get("Name", "")
+            applyPlayer.NameLen = len(applyPlayer.PlayerName)
+            applyPlayer.Job = playerInfo.get("Job", 1)
+            applyPlayer.LV = playerInfo.get("LV", 1)
+            fightPower = playerInfo.get("FightPower", 0)
+            applyPlayer.FightPower = fightPower % ShareDefine.Def_PerPointValue
+            applyPlayer.FightPowerEx = fightPower / ShareDefine.Def_PerPointValue
+            applyPlayer.RealmLV = playerInfo.get("RealmLV", 1)
+            
+            offPack.ApplyPlayerList.append(applyPlayer)
+        offPack.ApplyPlayerCount = len(offPack.ApplyPlayerList)
+        clientPack.OfficialList.append(offPack)
+        
+    clientPack.OfficialCount = len(clientPack.OfficialList)
+    
+    if curPlayer != None:
+        NetPackCommon.SendFakePack(curPlayer, clientPack)
+    else:
+        playerManager = GameWorld.GetPlayerManager()
+        for i in xrange(playerManager.GetPlayerCount()):
+            curPlayer = playerManager.GetPlayerByIndex(i)
+            if curPlayer == None or not curPlayer.GetInitOK():
+                continue
+            playerZoneID = champMgr.GetPlayerOfficialZoneID(curPlayer.GetPlayerID())
+            if playerZoneID != zoneID:
+                continue
+            NetPackCommon.SendFakePack(curPlayer, clientPack)
+            
+    return
+
+def DR_CrossChampionshipPK(eventName, dataDict={}):
+    drDataDict = {}
+    drDataDict.update(dataDict)
+    DataRecordPack.SendEventPack("CrossChampionship_%s" % eventName, drDataDict)
+    return
+
diff --git a/ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/CrossRealmMsg.py b/ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/CrossRealmMsg.py
index 46088ec..a6fc4a8 100644
--- a/ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/CrossRealmMsg.py
+++ b/ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/CrossRealmMsg.py
@@ -24,6 +24,7 @@
 import CrossRealmPlayer
 import PlayerCompensation
 import CrossActionControl
+import CrossChampionship
 import CrossBattlefield
 import CrossBillboard
 import GameWorldBoss
@@ -137,6 +138,27 @@
         elif msgType == ShareDefine.ClientServerMsg_BattlefieldCallChange:
             CrossBattlefield.ClientServerMsg_BattlefieldCallChange(serverGroupID, msgData)
             
+        elif msgType == ShareDefine.ClientServerMsg_ChampionshipOfficialApply:
+            CrossChampionship.ClientServerMsg_ChampionshipOfficialApply(serverGroupID, msgData)
+            
+        elif msgType == ShareDefine.ClientServerMsg_ChampionshipOfficialApplyReply:
+            CrossChampionship.ClientServerMsg_ChampionshipOfficialApplyReply(serverGroupID, msgData)
+            
+        elif msgType == ShareDefine.ClientServerMsg_ChampionshipOfficialKick:
+            CrossChampionship.ClientServerMsg_ChampionshipOfficialKick(serverGroupID, msgData)
+            
+        elif msgType == ShareDefine.ClientServerMsg_ChampionshipOfficialLeave:
+            CrossChampionship.ClientServerMsg_ChampionshipOfficialLeave(serverGroupID, msgData)
+            
+        elif msgType == ShareDefine.ClientServerMsg_ChampionshipOfficialChallenge:
+            CrossChampionship.ClientServerMsg_ChampionshipOfficialChallenge(serverGroupID, msgData)
+            
+        elif msgType == ShareDefine.ClientServerMsg_ChampionshipGuess:
+            CrossChampionship.ClientServerMsg_ChampionshipGuess(serverGroupID, msgData)
+            
+        elif msgType == ShareDefine.ClientServerMsg_ChampionshipWorship:
+            CrossChampionship.ClientServerMsg_ChampionshipWorship(serverGroupID, msgData)
+            
         # 需要发送到地图服务器处理的
         elif msgType in [ShareDefine.ClientServerMsg_Reborn, ShareDefine.ClientServerMsg_CollectNPC]:
             MapServer_CrossServerReceiveMsg(msgType, msgData, serverGroupID)
@@ -166,6 +188,7 @@
     '''
     CrossRealmPlayer.Sync_CrossCommInitDataToClientServer(serverGroupID)
     CrossRealmPK.Sync_CrossPKInitDataToClientServer(tick, serverGroupID)
+    CrossChampionship.Sync_CrossChampionshipDataToClientServer(serverGroupID)
     CrossBattlefield.Sync_CrossBattlefieldDataToClientServer(serverGroupID)
     CrossBoss.Sync_CrossBossInitDataToClientServer(serverGroupID)
     CrossActionControl.Sync_CrossActInfoToClientServer(serverGroupID)
@@ -318,6 +341,24 @@
         elif msgType == ShareDefine.CrossServerMsg_BattlefieldOver:
             CrossBattlefield.CrossServerMsg_BattlefieldOver(msgData)
             
+        elif msgType == ShareDefine.CrossServerMsg_ChampionshipState:
+            CrossChampionship.CrossServerMsg_ChampionshipState(msgData)
+            
+        elif msgType == ShareDefine.CrossServerMsg_ChampionshipPlayer:
+            CrossChampionship.CrossServerMsg_ChampionshipPlayer(msgData)
+            
+        elif msgType == ShareDefine.CrossServerMsg_ChampionshipGroup:
+            CrossChampionship.CrossServerMsg_ChampionshipGroup(msgData)
+            
+        elif msgType == ShareDefine.CrossServerMsg_ChampionshipGuess:
+            CrossChampionship.CrossServerMsg_ChampionshipGuess(msgData, tick)
+            
+        elif msgType == ShareDefine.CrossServerMsg_ChampionshipOfficial:
+            CrossChampionship.CrossServerMsg_ChampionshipOfficial(msgData)
+            
+        elif msgType == ShareDefine.CrossServerMsg_ChampionshipDailyOfficial:
+            CrossChampionship.CrossServerMsg_ChampionshipDailyOfficial(msgData)
+            
         elif msgType == ShareDefine.CrossServerMsg_SyncBillboard:
             CrossBillboard.CrossServerMsg_SyncBillboard(msgData, tick)
             
@@ -348,6 +389,9 @@
         elif msgType == ShareDefine.CrossServerMsg_EnterFBRet:
             PlayerFB.CrossServerMsg_EnterFBRet(msgData, tick)
             
+        elif msgType == ShareDefine.CrossServerMsg_EnterVSRoomRet:
+            PlayerFB.CrossServerMsg_EnterVSRoomRet(msgData, tick)
+            
         elif msgType == ShareDefine.CrossServerMsg_SendMail:
             PlayerCompensation.CrossServerMsg_SendMail(msgData)
             
diff --git a/ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/GameWorldProcess.py b/ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/GameWorldProcess.py
index e09fe8c..aa92dea 100644
--- a/ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/GameWorldProcess.py
+++ b/ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/GameWorldProcess.py
@@ -110,6 +110,7 @@
 import PyDataManager
 import GameWorldOpenServerCampaign
 import CrossBillboard
+import CrossChampionship
 #---------------------------------------------------------------------
 
 #---------------------------------------------------------------------
@@ -368,6 +369,8 @@
     GameWorldActionControl.Dispose_FBStateTime()
     #跨服PK
     CrossRealmPK.OnMinuteProcess()
+    #跨服排位
+    CrossChampionship.OnMinuteProcess()
     CrossBattlefield.OnMinuteProcess()
     #处理重开服务器后, 活动继续开启逻辑根据天数
     #GameWorldActionControl.Dispose_Action_GoOn_ByDay(tick)
@@ -1267,6 +1270,8 @@
     GameWorldArena.OnServerStart()
     #跨服PK
     CrossRealmPK.OnGameServerInitOK()
+    #跨服排位
+    CrossChampionship.OnServerStart()
     #跨服战场
     CrossBattlefield.OnServerStart()
     #红包
@@ -1981,6 +1986,7 @@
     ChPlayer.SavePlayerLVData()
     PlayerFBHelpBattle.OnServerClose()
     CrossActionControl.OnServerClose()
+    CrossChampionship.OnServerClose()
     CrossBattlefield.OnServerClose()
     PlayerFamilyRedPacket.OnServerClose()
     CrossLuckyCloudBuy.OnServerClose()
diff --git a/ServerPython/CoreServerGroup/GameServer/Script/IpyGameDataPY.py b/ServerPython/CoreServerGroup/GameServer/Script/IpyGameDataPY.py
index 76e2ec6..27cfd99 100644
--- a/ServerPython/CoreServerGroup/GameServer/Script/IpyGameDataPY.py
+++ b/ServerPython/CoreServerGroup/GameServer/Script/IpyGameDataPY.py
@@ -627,10 +627,35 @@
                         ("list", "ServerGroupIDList", 0),
                         ),
 
+                "ChampionshipTime":(
+                        ("DWORD", "ID", 1),
+                        ("BYTE", "StartDay", 0),
+                        ("BYTE", "StartHour", 0),
+                        ("BYTE", "StartMinute", 0),
+                        ("BYTE", "EndDay", 0),
+                        ("BYTE", "EndHour", 0),
+                        ("BYTE", "EndMinute", 0),
+                        ("WORD", "StateValue", 0),
+                        ("dict", "NotifyInfo", 0),
+                        ),
+
+                "ChampionshipRank":(
+                        ("BYTE", "Rank", 1),
+                        ("list", "RankAwardItemList", 0),
+                        ("WORD", "MainOfficialID", 0),
+                        ),
+
+                "ChampionshipOfficial":(
+                        ("WORD", "OfficialID", 1),
+                        ("list", "JuniorOfficialIDList", 0),
+                        ("list", "DailyAwardItemList", 0),
+                        ("BYTE", "CanBeReplace", 0),
+                        ),
+
                 "CrossRealmPKSeason":(
                         ("char", "CrossZoneName", 1),
                         ("BYTE", "ZoneID", 1),
-                        ("BYTE", "SeasonID", 0),
+                        ("WORD", "SeasonID", 0),
                         ("char", "StartDate", 0),
                         ("char", "EndDate", 0),
                         ("char", "EndTime", 0),
@@ -2070,6 +2095,59 @@
     def GetZoneName(self): return self.ZoneName # 赛区名字
     def GetServerGroupIDList(self): return self.ServerGroupIDList # 赛区服务器组ID列表
 
+# 跨服排位赛流程表
+class IPY_ChampionshipTime():
+    
+    def __init__(self):
+        self.ID = 0
+        self.StartDay = 0
+        self.StartHour = 0
+        self.StartMinute = 0
+        self.EndDay = 0
+        self.EndHour = 0
+        self.EndMinute = 0
+        self.StateValue = 0
+        self.NotifyInfo = {}
+        return
+        
+    def GetID(self): return self.ID
+    def GetStartDay(self): return self.StartDay # 开始天
+    def GetStartHour(self): return self.StartHour # 开始时
+    def GetStartMinute(self): return self.StartMinute # 开始分
+    def GetEndDay(self): return self.EndDay # 结束天
+    def GetEndHour(self): return self.EndHour # 结束时
+    def GetEndMinute(self): return self.EndMinute # 结束分
+    def GetStateValue(self): return self.StateValue # 状态值
+    def GetNotifyInfo(self): return self.NotifyInfo # 广播提示信息
+
+# 跨服排位奖励表
+class IPY_ChampionshipRank():
+    
+    def __init__(self):
+        self.Rank = 0
+        self.RankAwardItemList = []
+        self.MainOfficialID = 0
+        return
+        
+    def GetRank(self): return self.Rank #  名次
+    def GetRankAwardItemList(self): return self.RankAwardItemList # 名次奖励物品列表
+    def GetMainOfficialID(self): return self.MainOfficialID # 主官职ID
+
+# 跨服排位官职表
+class IPY_ChampionshipOfficial():
+    
+    def __init__(self):
+        self.OfficialID = 0
+        self.JuniorOfficialIDList = []
+        self.DailyAwardItemList = []
+        self.CanBeReplace = 0
+        return
+        
+    def GetOfficialID(self): return self.OfficialID #  官职ID
+    def GetJuniorOfficialIDList(self): return self.JuniorOfficialIDList # 下级官职ID列表
+    def GetDailyAwardItemList(self): return self.DailyAwardItemList # 官职每日邮件奖励物品列表
+    def GetCanBeReplace(self): return self.CanBeReplace # 是否可被挑战替换
+
 # 跨服竞技场赛季表
 class IPY_CrossRealmPKSeason():
     
@@ -2616,6 +2694,12 @@
         self.ipyCrossZoneCommLen = len(self.ipyCrossZoneCommCache)
         self.ipyCrossZonePKCache = self.__LoadFileData("CrossZonePK", IPY_CrossZonePK)
         self.ipyCrossZonePKLen = len(self.ipyCrossZonePKCache)
+        self.ipyChampionshipTimeCache = self.__LoadFileData("ChampionshipTime", IPY_ChampionshipTime)
+        self.ipyChampionshipTimeLen = len(self.ipyChampionshipTimeCache)
+        self.ipyChampionshipRankCache = self.__LoadFileData("ChampionshipRank", IPY_ChampionshipRank)
+        self.ipyChampionshipRankLen = len(self.ipyChampionshipRankCache)
+        self.ipyChampionshipOfficialCache = self.__LoadFileData("ChampionshipOfficial", IPY_ChampionshipOfficial)
+        self.ipyChampionshipOfficialLen = len(self.ipyChampionshipOfficialCache)
         self.ipyCrossRealmPKSeasonCache = self.__LoadFileData("CrossRealmPKSeason", IPY_CrossRealmPKSeason)
         self.ipyCrossRealmPKSeasonLen = len(self.ipyCrossRealmPKSeasonCache)
         self.ipyCrossRealmPKDanCache = self.__LoadFileData("CrossRealmPKDan", IPY_CrossRealmPKDan)
@@ -2932,6 +3016,12 @@
     def GetCrossZoneCommByIndex(self, index): return self.ipyCrossZoneCommCache[index]
     def GetCrossZonePKCount(self): return self.ipyCrossZonePKLen
     def GetCrossZonePKByIndex(self, index): return self.ipyCrossZonePKCache[index]
+    def GetChampionshipTimeCount(self): return self.ipyChampionshipTimeLen
+    def GetChampionshipTimeByIndex(self, index): return self.ipyChampionshipTimeCache[index]
+    def GetChampionshipRankCount(self): return self.ipyChampionshipRankLen
+    def GetChampionshipRankByIndex(self, index): return self.ipyChampionshipRankCache[index]
+    def GetChampionshipOfficialCount(self): return self.ipyChampionshipOfficialLen
+    def GetChampionshipOfficialByIndex(self, index): return self.ipyChampionshipOfficialCache[index]
     def GetCrossRealmPKSeasonCount(self): return self.ipyCrossRealmPKSeasonLen
     def GetCrossRealmPKSeasonByIndex(self, index): return self.ipyCrossRealmPKSeasonCache[index]
     def GetCrossRealmPKDanCount(self): return self.ipyCrossRealmPKDanLen
diff --git a/ServerPython/CoreServerGroup/GameServer/Script/Player/ChPlayer.py b/ServerPython/CoreServerGroup/GameServer/Script/Player/ChPlayer.py
index 8e9b5fe..691de98 100644
--- a/ServerPython/CoreServerGroup/GameServer/Script/Player/ChPlayer.py
+++ b/ServerPython/CoreServerGroup/GameServer/Script/Player/ChPlayer.py
@@ -64,6 +64,7 @@
 import GameWorldArena
 import CrossLuckyCloudBuy
 import CrossRealmPK
+import CrossChampionship
 import AuctionHouse
 import PlayerAssist
 import PlayerFB
@@ -192,6 +193,8 @@
         GameWorldArena.OnPlayerLogin(curPlayer)
         #跨服PK
         CrossRealmPK.OnPlayerLogin(curPlayer)
+        #跨服排位
+        CrossChampionship.OnPlayerLogin(curPlayer, tick)
         #幸运云购
         CrossLuckyCloudBuy.OnPlayerLogin(curPlayer)
         #诛仙BOSS
diff --git a/ServerPython/CoreServerGroup/GameServer/Script/Player/CrossRealmPlayer.py b/ServerPython/CoreServerGroup/GameServer/Script/Player/CrossRealmPlayer.py
index d25d85e..a4815ec 100644
--- a/ServerPython/CoreServerGroup/GameServer/Script/Player/CrossRealmPlayer.py
+++ b/ServerPython/CoreServerGroup/GameServer/Script/Player/CrossRealmPlayer.py
@@ -441,9 +441,10 @@
     ## 同步地图跨服玩家处理信息,玩家可能不在线,缓存后等玩家上线处理,暂不考虑存档问题,服务器维护后未处理的命令将失效
     
     curPlayer = GameWorld.GetPlayerManager().FindPlayerByID(playerID)
-    if curPlayer:
+    if curPlayer and curPlayer.GetInitOK():
         msgInfo = str(msgInfo)
         curPlayer.MapServer_QueryPlayerResult(0, 0, callName, msgInfo, len(msgInfo))
+        return curPlayer
     else:
         # 缓存起来,等上线后处理
         if playerID not in PyGameData.g_unNotifyPlayerCrossMsgDict:
diff --git a/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerDBGSEvent.py b/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerDBGSEvent.py
index bd006c6..b07ca94 100644
--- a/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerDBGSEvent.py
+++ b/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerDBGSEvent.py
@@ -166,6 +166,12 @@
 Def_ArenaOSSeasonState = "ArenaOSSeasonState"
 #竞技场当前赛季开始时的世界等级
 Def_ArenaWorldLV = "ArenaWorldLV"
+#跨服排位争霸赛活动ID
+Def_CrossChampionshipID = "CrossChampionshipID"
+#跨服排位争霸赛活动状态
+Def_CrossChampionshipState = "CrossChampionshipState"
+#跨服排位争霸赛活动状态是否已经异常 - 该活动只能按状态顺序执行,不能跳状态,否则视为活动异常
+Def_CrossChampionshipStateError = "CrossChampionshipStateError"
 
 def SetInitOpenServerTime(initTime):
     openDatetime = GameWorld.ChangeTimeNumToDatetime(initTime)
diff --git a/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerEventCounter.py b/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerEventCounter.py
index c03779b..241ec57 100644
--- a/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerEventCounter.py
+++ b/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerEventCounter.py
@@ -33,6 +33,7 @@
 import PlayerDuJie
 import PlayerCharm
 import CrossBattlefield
+import CrossChampionship
 #---------------------------------------------------------------------
 
 #---------------------------------------------------------------------
@@ -63,6 +64,8 @@
     PlayerCharm.DoOnDay()
     #家族更新
     PlayerFamily.FamilyOnDay(tick)
+    #跨服排位
+    CrossChampionship.DoOnDay()
     
     playerManager = GameWorld.GetPlayerManager()
     for i in xrange(playerManager.GetPlayerCount()):
@@ -90,6 +93,8 @@
     GameWorldArena.OnDayEx()
     #跨服战场
     CrossBattlefield.DoOnDayEx()
+    #跨服排位
+    CrossChampionship.DoOnDayEx()
     playerManager = GameWorld.GetPlayerManager()
     for i in xrange(playerManager.GetPlayerCount()):
         curPlayer = playerManager.GetPlayerByIndex(i)
diff --git a/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerFB.py b/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerFB.py
index 7f38e29..86ba160 100644
--- a/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerFB.py
+++ b/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerFB.py
@@ -33,6 +33,7 @@
 import IPY_PlayerDefine
 import CrossBattlefield
 import CrossRealmPlayer
+import CrossChampionship
 import DataRecordPack
 import CrossRealmMsg
 import ShareDefine
@@ -147,6 +148,10 @@
     mapID = msgData["MapID"]
     funcLineID = msgData["FuncLineID"]
     playerLV = msgData["LV"]
+    
+    if mapID == ChConfig.Def_FBMapID_CrossChampionship:
+        CrossChampionship.OnRequestChampionshipVSRoom(playerID, serverGroupID)
+        return
     
     zoneIpyData = CrossRealmPlayer.GetCrossZoneIpyDataByServerGroupID(mapID, serverGroupID)
     if not zoneIpyData:
@@ -469,6 +474,15 @@
     GameWorld.GetPlayerManager().MapServer_QueryPlayer(0, 0, 0, realMapID, "OpenFB", msgInfo, len(msgInfo))
     return copyMapObj
 
+def SendMapOpenFBEx(realMapID, copyPropertyList):
+    ## 通知地图开启副本线路
+    # @param realMapID: 地图ID
+    # @param copyPropertyList: [[copyMapID, propertyID], ...]
+    msgInfo = str(copyPropertyList)
+    GameWorld.GetPlayerManager().MapServer_QueryPlayer(0, 0, 0, realMapID, "OpenFBEx", msgInfo, len(msgInfo))
+    GameWorld.Log("SendMapOpenFBEx: realMapID=%s,msgInfo=%s" % (realMapID, msgInfo))
+    return
+
 def OpenCrossDynamicLineBySys(zoneID, mapID, funcLineIDList, checkExist):
     ## 系统开启跨服动态线路
     
@@ -714,6 +728,7 @@
 #  @param sendCMD: 请求的命令 根据请求类型和请求命令来决定最终操作
 #  @return None
 def EnterFBLine(curPlayer, queryCallName, sendCMD, tick):
+    playerID = curPlayer.GetPlayerID()
     GameWorld.Log("EnterFBLine()...queryCallName=%s,sendCMD=%s" % (queryCallName, sendCMD), curPlayer.GetPlayerID())
     playerManager = GameWorld.GetPlayerManager()
     try:
@@ -787,3 +802,49 @@
     playerManager.MapServer_QueryPlayer(curPlayer.GetPlayerID(), ChConfig.queryType_EnterFB, 0, tagMapID,
                 queryCallName, sendCMD, len(sendCMD), curPlayer.GetRouteServerIndex())
     return
+
+def Send_CrossServerMsg_EnterVSRoomRet(vsRoomDict, serverGroupIDList=None):
+    ## 发送子服跨服对战房间请求进入结果
+    # @param vsRoomDict: {roomID:{playerID:playerInfo, ...}, }
+    #      playerInfo key
+    #            serverGroupID    所属服务器分组ID
+    #            regMapInfo        传送跨服注册信息 [registerMap, mapID, dataMapID, copyMapID, posX, posY]
+    CrossRealmMsg.SendMsgToClientServer(ShareDefine.CrossServerMsg_EnterVSRoomRet, vsRoomDict, serverGroupIDList)
+    return
+
+def CrossServerMsg_EnterVSRoomRet(msgData, tick):
+    ## 跨服对战房间请求进入结果
+    
+    curServerGroupID = GameWorld.GetServerGroupID()
+    GameWorld.DebugLog("=== 跨服PK对战房间请求进入结果  === curServerGroupID=%s" % curServerGroupID)
+    vsRoomDict = msgData
+    for roomID, playerDict in vsRoomDict.items():
+        GameWorld.DebugLog("    roomID=%s,playerDict=%s" % (roomID, playerDict))
+        for playerID, playerInfo in playerDict.items():
+            if "serverGroupID" in playerInfo:
+                serverGroupID = playerInfo["serverGroupID"]
+                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
+            
+            if "regMapInfo" not in playerInfo:
+                continue
+            regMapInfo = playerInfo["regMapInfo"]
+            if len(regMapInfo) != 6:
+                continue
+            registerMap, mapID, dataMapID, copyMapID, posX, posY = regMapInfo
+            
+            PlayerControl.SetVsRoomId(player, roomID, True)
+            # 通知地图玩家匹配成功, 上传数据, 准备进入跨服服务器
+            CrossRealmPlayer.SendCrossRealmReg(player, registerMap, mapID, dataMapID, copyMapID, posX, posY)
+            
+    return
+
diff --git a/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerQuery.py b/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerQuery.py
index 4d45f72..4d97414 100644
--- a/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerQuery.py
+++ b/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerQuery.py
@@ -70,6 +70,7 @@
 import CrossRealmPlayer
 import CrossRealmMsg
 import CrossRealmPK
+import CrossChampionship
 import CrossBattlefield
 import ChPyNetSendPack
 import NetPackCommon
@@ -619,6 +620,11 @@
         GameDataRecord.ChangeCoinCnt(eval(resultName))
         return
     
+    #跨服排位PK战斗结算
+    if callName == "CrossChampionshipPKOver":
+        CrossChampionship.MapServer_CrossChampionshipPKOver(eval(resultName), tick)
+        return
+    
     #跨服匹配PK战斗结算
     if callName == "CrossPKOver":
         CrossRealmPK.MapServer_CrossPKOver(eval(resultName), tick)
diff --git a/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerViewCache.py b/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerViewCache.py
index 322b1a8..b857004 100644
--- a/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerViewCache.py
+++ b/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerViewCache.py
@@ -24,6 +24,7 @@
 import GameWorldArena
 import ChPyNetSendPack
 import PlayerFBHelpBattle
+import CrossChampionship
 import CrossBattlefield
 import PyGameDataStruct
 import IpyGameDataPY
@@ -48,6 +49,9 @@
     if CrossBattlefield.IsBattlefieldCallPlayer(playerID):
         return True
     
+    if CrossChampionship.IsChampionshipPlayer(playerID):
+        return True
+    
     SaveDBLimitLV = IpyGameDataPY.GetFuncCfg("PlayerViewCache", 1)
     #校验玩家等级
     if playerLV < SaveDBLimitLV:
@@ -65,6 +69,9 @@
         return True
     
     if CrossBattlefield.IsBattlefieldCallPlayer(playerID):
+        return True
+    
+    if CrossChampionship.IsChampionshipPlayer(playerID):
         return True
     
     NeedCheckBillBoardType = IpyGameDataPY.GetFuncEvalCfg("PlayerViewCache", 2)
@@ -106,8 +113,9 @@
     GameWorld.DebugLog("删除查看缓存!", playerID)
     return
 
-def FindViewCache(playerID, isAddNew=False):
+def FindViewCache(playerID, isAddNew=False, newPropData={}):
     ## 查找玩家缓存
+    # @param newPropData: 新数据初始PropData {}, key: LV,RealmLV,Job,VIPLV,Name,FamilyID,FamilyName,FightPower
     curCache = None
     pyViewCacheMgr = PyDataManager.GetPlayerViewCachePyManager()
     playerViewCachePyDict = pyViewCacheMgr.playerViewCachePyDict
@@ -116,6 +124,9 @@
     elif isAddNew:
         curCache = PyGameDataStruct.tagPlayerViewCachePy()
         curCache.PlayerID = playerID
+        if newPropData:
+            curCache.PropData = json.dumps(newPropData, ensure_ascii=False).replace(" ", "")
+            curCache.PropDataSize = len(curCache.PropData)
         playerViewCachePyDict[playerID] = curCache
     return curCache
 
diff --git a/ServerPython/CoreServerGroup/GameServer/Script/PyGameData.py b/ServerPython/CoreServerGroup/GameServer/Script/PyGameData.py
index 2338f7c..1790f5f 100644
--- a/ServerPython/CoreServerGroup/GameServer/Script/PyGameData.py
+++ b/ServerPython/CoreServerGroup/GameServer/Script/PyGameData.py
@@ -145,6 +145,8 @@
 g_openDateTime = None # 本场次开启的时间
 g_overPlayerIDList = [] # 本场次已经结算的玩家ID列表
 
+g_championshipMgr = None # 跨服排位争霸赛管理
+
 g_familyTalkCache = {} #{familyID:[[time,content,extras],..]}
 g_worldTalkCache = [] #[[time,name, playerID, content,extras],..]
 
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/PyNetPack.ini b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/PyNetPack.ini
index d4769e7..b868ea6 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/PyNetPack.ini
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/PyNetPack.ini
@@ -618,6 +618,30 @@
 PacketSubCMD_5=0x13
 PacketCallFunc_5=OnUnlockRuneHole
 
+;跨服排位
+[PlayerCrossChampionship]
+ScriptName = Player\PlayerCrossChampionship.py
+Writer = hxp
+Releaser = hxp
+RegType = 0
+RegisterPackCount = 4
+
+PacketCMD_1=0xC1
+PacketSubCMD_1=0x20
+PacketCallFunc_1=OnChampionshipOfficialApply
+
+PacketCMD_2=0xC1
+PacketSubCMD_2=0x21
+PacketCallFunc_2=OnChampionshipOfficialChallenge
+
+PacketCMD_3=0xC1
+PacketSubCMD_3=0x22
+PacketCallFunc_3=OnChampionshipGuess
+
+PacketCMD_4=0xC1
+PacketSubCMD_4=0x23
+PacketCallFunc_4=OnChampionshipWorship
+
 ;跨服PK竞技场
 [PlayerCrossRealmPK]
 ScriptName = Player\PlayerCrossRealmPK.py
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetPack.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetPack.py
index 0482b74..f894f03 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetPack.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetPack.py
@@ -3987,6 +3987,242 @@
 
 
 #------------------------------------------------------
+# C0 21 跨服排位仙官申请回应 #tagCGChampionshipOfficialApplyReply
+
+class  tagCGChampionshipOfficialApplyReply(Structure):
+    _pack_ = 1
+    _fields_ = [
+                  ("Cmd", c_ubyte),
+                  ("SubCmd", c_ubyte),
+                  ("MainOfficialID", c_ushort),    #界主官职ID
+                  ("OfficialID", c_ushort),    #申请官职ID
+                  ("PlayerID", c_int),    #申请的玩家ID
+                  ("IsOK", c_ubyte),    #是否同意;1-是;0-否
+                  ]
+
+    def __init__(self):
+        self.Clear()
+        self.Cmd = 0xC0
+        self.SubCmd = 0x21
+        return
+
+    def ReadData(self, stringData, _pos=0, _len=0):
+        self.Clear()
+        memmove(addressof(self), stringData[_pos:], self.GetLength())
+        return _pos + self.GetLength()
+
+    def Clear(self):
+        self.Cmd = 0xC0
+        self.SubCmd = 0x21
+        self.MainOfficialID = 0
+        self.OfficialID = 0
+        self.PlayerID = 0
+        self.IsOK = 0
+        return
+
+    def GetLength(self):
+        return sizeof(tagCGChampionshipOfficialApplyReply)
+
+    def GetBuffer(self):
+        return string_at(addressof(self), self.GetLength())
+
+    def OutputString(self):
+        DumpString = '''// C0 21 跨服排位仙官申请回应 //tagCGChampionshipOfficialApplyReply:
+                                Cmd:%s,
+                                SubCmd:%s,
+                                MainOfficialID:%d,
+                                OfficialID:%d,
+                                PlayerID:%d,
+                                IsOK:%d
+                                '''\
+                                %(
+                                self.Cmd,
+                                self.SubCmd,
+                                self.MainOfficialID,
+                                self.OfficialID,
+                                self.PlayerID,
+                                self.IsOK
+                                )
+        return DumpString
+
+
+m_NAtagCGChampionshipOfficialApplyReply=tagCGChampionshipOfficialApplyReply()
+ChNetPackDict[eval("0x%02x%02x"%(m_NAtagCGChampionshipOfficialApplyReply.Cmd,m_NAtagCGChampionshipOfficialApplyReply.SubCmd))] = m_NAtagCGChampionshipOfficialApplyReply
+
+
+#------------------------------------------------------
+# C0 23 跨服排位仙官挑战记录查询 #tagCGChampionshipOfficialChallengeQuery
+
+class  tagCGChampionshipOfficialChallengeQuery(Structure):
+    _pack_ = 1
+    _fields_ = [
+                  ("Cmd", c_ubyte),
+                  ("SubCmd", c_ubyte),
+                  ("MainOfficialID", c_ushort),    #界主官职ID
+                  ("OfficialID", c_ushort),    #查询官职ID
+                  ]
+
+    def __init__(self):
+        self.Clear()
+        self.Cmd = 0xC0
+        self.SubCmd = 0x23
+        return
+
+    def ReadData(self, stringData, _pos=0, _len=0):
+        self.Clear()
+        memmove(addressof(self), stringData[_pos:], self.GetLength())
+        return _pos + self.GetLength()
+
+    def Clear(self):
+        self.Cmd = 0xC0
+        self.SubCmd = 0x23
+        self.MainOfficialID = 0
+        self.OfficialID = 0
+        return
+
+    def GetLength(self):
+        return sizeof(tagCGChampionshipOfficialChallengeQuery)
+
+    def GetBuffer(self):
+        return string_at(addressof(self), self.GetLength())
+
+    def OutputString(self):
+        DumpString = '''// C0 23 跨服排位仙官挑战记录查询 //tagCGChampionshipOfficialChallengeQuery:
+                                Cmd:%s,
+                                SubCmd:%s,
+                                MainOfficialID:%d,
+                                OfficialID:%d
+                                '''\
+                                %(
+                                self.Cmd,
+                                self.SubCmd,
+                                self.MainOfficialID,
+                                self.OfficialID
+                                )
+        return DumpString
+
+
+m_NAtagCGChampionshipOfficialChallengeQuery=tagCGChampionshipOfficialChallengeQuery()
+ChNetPackDict[eval("0x%02x%02x"%(m_NAtagCGChampionshipOfficialChallengeQuery.Cmd,m_NAtagCGChampionshipOfficialChallengeQuery.SubCmd))] = m_NAtagCGChampionshipOfficialChallengeQuery
+
+
+#------------------------------------------------------
+# C0 24 跨服排位辞退下级仙官 #tagCGChampionshipOfficialKick
+
+class  tagCGChampionshipOfficialKick(Structure):
+    _pack_ = 1
+    _fields_ = [
+                  ("Cmd", c_ubyte),
+                  ("SubCmd", c_ubyte),
+                  ("MainOfficialID", c_ushort),    #界主官职ID
+                  ("OfficialID", c_ushort),    #目标官职ID
+                  ("PlayerID", c_int),    #目标玩家ID
+                  ]
+
+    def __init__(self):
+        self.Clear()
+        self.Cmd = 0xC0
+        self.SubCmd = 0x24
+        return
+
+    def ReadData(self, stringData, _pos=0, _len=0):
+        self.Clear()
+        memmove(addressof(self), stringData[_pos:], self.GetLength())
+        return _pos + self.GetLength()
+
+    def Clear(self):
+        self.Cmd = 0xC0
+        self.SubCmd = 0x24
+        self.MainOfficialID = 0
+        self.OfficialID = 0
+        self.PlayerID = 0
+        return
+
+    def GetLength(self):
+        return sizeof(tagCGChampionshipOfficialKick)
+
+    def GetBuffer(self):
+        return string_at(addressof(self), self.GetLength())
+
+    def OutputString(self):
+        DumpString = '''// C0 24 跨服排位辞退下级仙官 //tagCGChampionshipOfficialKick:
+                                Cmd:%s,
+                                SubCmd:%s,
+                                MainOfficialID:%d,
+                                OfficialID:%d,
+                                PlayerID:%d
+                                '''\
+                                %(
+                                self.Cmd,
+                                self.SubCmd,
+                                self.MainOfficialID,
+                                self.OfficialID,
+                                self.PlayerID
+                                )
+        return DumpString
+
+
+m_NAtagCGChampionshipOfficialKick=tagCGChampionshipOfficialKick()
+ChNetPackDict[eval("0x%02x%02x"%(m_NAtagCGChampionshipOfficialKick.Cmd,m_NAtagCGChampionshipOfficialKick.SubCmd))] = m_NAtagCGChampionshipOfficialKick
+
+
+#------------------------------------------------------
+# C0 25 跨服排位主动离任仙官 #tagCGChampionshipOfficialLeave
+
+class  tagCGChampionshipOfficialLeave(Structure):
+    _pack_ = 1
+    _fields_ = [
+                  ("Cmd", c_ubyte),
+                  ("SubCmd", c_ubyte),
+                  ("MainOfficialID", c_ushort),    #界主官职ID
+                  ("OfficialID", c_ushort),    #离任官职ID
+                  ]
+
+    def __init__(self):
+        self.Clear()
+        self.Cmd = 0xC0
+        self.SubCmd = 0x25
+        return
+
+    def ReadData(self, stringData, _pos=0, _len=0):
+        self.Clear()
+        memmove(addressof(self), stringData[_pos:], self.GetLength())
+        return _pos + self.GetLength()
+
+    def Clear(self):
+        self.Cmd = 0xC0
+        self.SubCmd = 0x25
+        self.MainOfficialID = 0
+        self.OfficialID = 0
+        return
+
+    def GetLength(self):
+        return sizeof(tagCGChampionshipOfficialLeave)
+
+    def GetBuffer(self):
+        return string_at(addressof(self), self.GetLength())
+
+    def OutputString(self):
+        DumpString = '''// C0 25 跨服排位主动离任仙官 //tagCGChampionshipOfficialLeave:
+                                Cmd:%s,
+                                SubCmd:%s,
+                                MainOfficialID:%d,
+                                OfficialID:%d
+                                '''\
+                                %(
+                                self.Cmd,
+                                self.SubCmd,
+                                self.MainOfficialID,
+                                self.OfficialID
+                                )
+        return DumpString
+
+
+m_NAtagCGChampionshipOfficialLeave=tagCGChampionshipOfficialLeave()
+ChNetPackDict[eval("0x%02x%02x"%(m_NAtagCGChampionshipOfficialLeave.Cmd,m_NAtagCGChampionshipOfficialLeave.SubCmd))] = m_NAtagCGChampionshipOfficialLeave
+
+
+#------------------------------------------------------
 # C0 09 跨服战场召集场次修改 #tagCGCrossBattlefieldCallChange
 
 class  tagCGCrossBattlefieldCallChange(Structure):
@@ -19225,6 +19461,254 @@
 
 
 #------------------------------------------------------
+# C1 22 跨服排位竞猜 #tagCMChampionshipGuess
+
+class  tagCMChampionshipGuess(Structure):
+    _pack_ = 1
+    _fields_ = [
+                  ("Cmd", c_ubyte),
+                  ("SubCmd", c_ubyte),
+                  ("ZoneID", c_ubyte),    #排位数据分区ID
+                  ("GuessType", c_ubyte),    #竞猜类型 8-8强;4-4强排位
+                  ("PlayerID", c_int),    #目标玩家ID
+                  ("GuessCount", c_ubyte),    #投注/追加份数
+                  ("GuessRank", c_ubyte),    # 竞猜名次,没有名次的竞猜默认0;1-代表第一名
+                  ]
+
+    def __init__(self):
+        self.Clear()
+        self.Cmd = 0xC1
+        self.SubCmd = 0x22
+        return
+
+    def ReadData(self, stringData, _pos=0, _len=0):
+        self.Clear()
+        memmove(addressof(self), stringData[_pos:], self.GetLength())
+        return _pos + self.GetLength()
+
+    def Clear(self):
+        self.Cmd = 0xC1
+        self.SubCmd = 0x22
+        self.ZoneID = 0
+        self.GuessType = 0
+        self.PlayerID = 0
+        self.GuessCount = 0
+        self.GuessRank = 0
+        return
+
+    def GetLength(self):
+        return sizeof(tagCMChampionshipGuess)
+
+    def GetBuffer(self):
+        return string_at(addressof(self), self.GetLength())
+
+    def OutputString(self):
+        DumpString = '''// C1 22 跨服排位竞猜 //tagCMChampionshipGuess:
+                                Cmd:%s,
+                                SubCmd:%s,
+                                ZoneID:%d,
+                                GuessType:%d,
+                                PlayerID:%d,
+                                GuessCount:%d,
+                                GuessRank:%d
+                                '''\
+                                %(
+                                self.Cmd,
+                                self.SubCmd,
+                                self.ZoneID,
+                                self.GuessType,
+                                self.PlayerID,
+                                self.GuessCount,
+                                self.GuessRank
+                                )
+        return DumpString
+
+
+m_NAtagCMChampionshipGuess=tagCMChampionshipGuess()
+ChNetPackDict[eval("0x%02x%02x"%(m_NAtagCMChampionshipGuess.Cmd,m_NAtagCMChampionshipGuess.SubCmd))] = m_NAtagCMChampionshipGuess
+
+
+#------------------------------------------------------
+# C1 20 跨服排位仙官申请 #tagCMChampionshipOfficialApply
+
+class  tagCMChampionshipOfficialApply(Structure):
+    _pack_ = 1
+    _fields_ = [
+                  ("Cmd", c_ubyte),
+                  ("SubCmd", c_ubyte),
+                  ("ZoneID", c_ubyte),    #仙官数据分区ID
+                  ("MainOfficialID", c_ushort),    #界主官职ID
+                  ("OfficialID", c_ushort),    #申请官职ID
+                  ]
+
+    def __init__(self):
+        self.Clear()
+        self.Cmd = 0xC1
+        self.SubCmd = 0x20
+        return
+
+    def ReadData(self, stringData, _pos=0, _len=0):
+        self.Clear()
+        memmove(addressof(self), stringData[_pos:], self.GetLength())
+        return _pos + self.GetLength()
+
+    def Clear(self):
+        self.Cmd = 0xC1
+        self.SubCmd = 0x20
+        self.ZoneID = 0
+        self.MainOfficialID = 0
+        self.OfficialID = 0
+        return
+
+    def GetLength(self):
+        return sizeof(tagCMChampionshipOfficialApply)
+
+    def GetBuffer(self):
+        return string_at(addressof(self), self.GetLength())
+
+    def OutputString(self):
+        DumpString = '''// C1 20 跨服排位仙官申请 //tagCMChampionshipOfficialApply:
+                                Cmd:%s,
+                                SubCmd:%s,
+                                ZoneID:%d,
+                                MainOfficialID:%d,
+                                OfficialID:%d
+                                '''\
+                                %(
+                                self.Cmd,
+                                self.SubCmd,
+                                self.ZoneID,
+                                self.MainOfficialID,
+                                self.OfficialID
+                                )
+        return DumpString
+
+
+m_NAtagCMChampionshipOfficialApply=tagCMChampionshipOfficialApply()
+ChNetPackDict[eval("0x%02x%02x"%(m_NAtagCMChampionshipOfficialApply.Cmd,m_NAtagCMChampionshipOfficialApply.SubCmd))] = m_NAtagCMChampionshipOfficialApply
+
+
+#------------------------------------------------------
+# C1 21 跨服排位仙官挑战 #tagCMChampionshipOfficialChallenge
+
+class  tagCMChampionshipOfficialChallenge(Structure):
+    _pack_ = 1
+    _fields_ = [
+                  ("Cmd", c_ubyte),
+                  ("SubCmd", c_ubyte),
+                  ("ZoneID", c_ubyte),    #仙官数据分区ID
+                  ("MainOfficialID", c_ushort),    #界主官职ID
+                  ("OfficialID", c_ushort),    #挑战的目标官职ID
+                  ("PlayerID", c_int),    #挑战时的目标玩家ID
+                  ]
+
+    def __init__(self):
+        self.Clear()
+        self.Cmd = 0xC1
+        self.SubCmd = 0x21
+        return
+
+    def ReadData(self, stringData, _pos=0, _len=0):
+        self.Clear()
+        memmove(addressof(self), stringData[_pos:], self.GetLength())
+        return _pos + self.GetLength()
+
+    def Clear(self):
+        self.Cmd = 0xC1
+        self.SubCmd = 0x21
+        self.ZoneID = 0
+        self.MainOfficialID = 0
+        self.OfficialID = 0
+        self.PlayerID = 0
+        return
+
+    def GetLength(self):
+        return sizeof(tagCMChampionshipOfficialChallenge)
+
+    def GetBuffer(self):
+        return string_at(addressof(self), self.GetLength())
+
+    def OutputString(self):
+        DumpString = '''// C1 21 跨服排位仙官挑战 //tagCMChampionshipOfficialChallenge:
+                                Cmd:%s,
+                                SubCmd:%s,
+                                ZoneID:%d,
+                                MainOfficialID:%d,
+                                OfficialID:%d,
+                                PlayerID:%d
+                                '''\
+                                %(
+                                self.Cmd,
+                                self.SubCmd,
+                                self.ZoneID,
+                                self.MainOfficialID,
+                                self.OfficialID,
+                                self.PlayerID
+                                )
+        return DumpString
+
+
+m_NAtagCMChampionshipOfficialChallenge=tagCMChampionshipOfficialChallenge()
+ChNetPackDict[eval("0x%02x%02x"%(m_NAtagCMChampionshipOfficialChallenge.Cmd,m_NAtagCMChampionshipOfficialChallenge.SubCmd))] = m_NAtagCMChampionshipOfficialChallenge
+
+
+#------------------------------------------------------
+# C1 23 跨服排位膜拜 #tagCMChampionshipWorship
+
+class  tagCMChampionshipWorship(Structure):
+    _pack_ = 1
+    _fields_ = [
+                  ("Cmd", c_ubyte),
+                  ("SubCmd", c_ubyte),
+                  ("ZoneID", c_ubyte),    #仙官数据分区ID
+                  ("PlayerID", c_int),    #目标玩家ID
+                  ]
+
+    def __init__(self):
+        self.Clear()
+        self.Cmd = 0xC1
+        self.SubCmd = 0x23
+        return
+
+    def ReadData(self, stringData, _pos=0, _len=0):
+        self.Clear()
+        memmove(addressof(self), stringData[_pos:], self.GetLength())
+        return _pos + self.GetLength()
+
+    def Clear(self):
+        self.Cmd = 0xC1
+        self.SubCmd = 0x23
+        self.ZoneID = 0
+        self.PlayerID = 0
+        return
+
+    def GetLength(self):
+        return sizeof(tagCMChampionshipWorship)
+
+    def GetBuffer(self):
+        return string_at(addressof(self), self.GetLength())
+
+    def OutputString(self):
+        DumpString = '''// C1 23 跨服排位膜拜 //tagCMChampionshipWorship:
+                                Cmd:%s,
+                                SubCmd:%s,
+                                ZoneID:%d,
+                                PlayerID:%d
+                                '''\
+                                %(
+                                self.Cmd,
+                                self.SubCmd,
+                                self.ZoneID,
+                                self.PlayerID
+                                )
+        return DumpString
+
+
+m_NAtagCMChampionshipWorship=tagCMChampionshipWorship()
+ChNetPackDict[eval("0x%02x%02x"%(m_NAtagCMChampionshipWorship.Cmd,m_NAtagCMChampionshipWorship.SubCmd))] = m_NAtagCMChampionshipWorship
+
+
+#------------------------------------------------------
 # C1 09 跨服战场购买开启场次 #tagCMCrossBattlefieldBuyOpen
 
 class  tagCMCrossBattlefieldBuyOpen(Structure):
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetSendPack.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetSendPack.py
index 14ebe55..934c504 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetSendPack.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetSendPack.py
@@ -12288,6 +12288,922 @@
 
 
 #------------------------------------------------------
+# C0 23 跨服排位竞猜个人信息 #tagGCChampionshipGuessPriInfo
+
+class  tagGCChampionshipGuessPlayerPri(Structure):
+    _pack_ = 1
+    _fields_ = [
+                  ("PlayerID", c_int),    # 目标玩家ID
+                  ("MoneyTotal", c_int),    # 已投注该玩家货币总数
+                  ("GuessRank", c_ubyte),    # 竞猜名次,没有名次的竞猜默认0;1-代表第一名
+                  ]
+
+    def __init__(self):
+        self.Clear()
+        return
+
+    def ReadData(self, stringData, _pos=0, _len=0):
+        self.Clear()
+        memmove(addressof(self), stringData[_pos:], self.GetLength())
+        return _pos + self.GetLength()
+
+    def Clear(self):
+        self.PlayerID = 0
+        self.MoneyTotal = 0
+        self.GuessRank = 0
+        return
+
+    def GetLength(self):
+        return sizeof(tagGCChampionshipGuessPlayerPri)
+
+    def GetBuffer(self):
+        return string_at(addressof(self), self.GetLength())
+
+    def OutputString(self):
+        DumpString = '''// C0 23 跨服排位竞猜个人信息 //tagGCChampionshipGuessPriInfo:
+                                PlayerID:%d,
+                                MoneyTotal:%d,
+                                GuessRank:%d
+                                '''\
+                                %(
+                                self.PlayerID,
+                                self.MoneyTotal,
+                                self.GuessRank
+                                )
+        return DumpString
+
+
+class  tagGCChampionshipGuessPriList(Structure):
+    GuessType = 0    #(BYTE GuessType)//竞猜类型 8-8强;4-4强排位
+    PlayerCount = 0    #(BYTE PlayerCount)
+    GuessPlayerList = list()    #(vector<tagGCChampionshipGuessPlayerPri> GuessPlayerList)// 被竞猜玩家列表
+    data = None
+
+    def __init__(self):
+        self.Clear()
+        return
+
+    def ReadData(self, _lpData, _pos=0, _Len=0):
+        self.Clear()
+        self.GuessType,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        self.PlayerCount,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        for i in range(self.PlayerCount):
+            temGuessPlayerList = tagGCChampionshipGuessPlayerPri()
+            _pos = temGuessPlayerList.ReadData(_lpData, _pos)
+            self.GuessPlayerList.append(temGuessPlayerList)
+        return _pos
+
+    def Clear(self):
+        self.GuessType = 0
+        self.PlayerCount = 0
+        self.GuessPlayerList = list()
+        return
+
+    def GetLength(self):
+        length = 0
+        length += 1
+        length += 1
+        for i in range(self.PlayerCount):
+            length += self.GuessPlayerList[i].GetLength()
+
+        return length
+
+    def GetBuffer(self):
+        data = ''
+        data = CommFunc.WriteBYTE(data, self.GuessType)
+        data = CommFunc.WriteBYTE(data, self.PlayerCount)
+        for i in range(self.PlayerCount):
+            data = CommFunc.WriteString(data, self.GuessPlayerList[i].GetLength(), self.GuessPlayerList[i].GetBuffer())
+        return data
+
+    def OutputString(self):
+        DumpString = '''
+                                GuessType:%d,
+                                PlayerCount:%d,
+                                GuessPlayerList:%s
+                                '''\
+                                %(
+                                self.GuessType,
+                                self.PlayerCount,
+                                "..."
+                                )
+        return DumpString
+
+
+class  tagGCChampionshipGuessPriInfo(Structure):
+    Head = tagHead()
+    ZoneID = 0    #(BYTE ZoneID)// 排位数据分区ID
+    Count = 0    #(BYTE Count)
+    GuessList = list()    #(vector<tagGCChampionshipGuessPriList> GuessList)
+    data = None
+
+    def __init__(self):
+        self.Clear()
+        self.Head.Cmd = 0xC0
+        self.Head.SubCmd = 0x23
+        return
+
+    def ReadData(self, _lpData, _pos=0, _Len=0):
+        self.Clear()
+        _pos = self.Head.ReadData(_lpData, _pos)
+        self.ZoneID,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        self.Count,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        for i in range(self.Count):
+            temGuessList = tagGCChampionshipGuessPriList()
+            _pos = temGuessList.ReadData(_lpData, _pos)
+            self.GuessList.append(temGuessList)
+        return _pos
+
+    def Clear(self):
+        self.Head = tagHead()
+        self.Head.Clear()
+        self.Head.Cmd = 0xC0
+        self.Head.SubCmd = 0x23
+        self.ZoneID = 0
+        self.Count = 0
+        self.GuessList = list()
+        return
+
+    def GetLength(self):
+        length = 0
+        length += self.Head.GetLength()
+        length += 1
+        length += 1
+        for i in range(self.Count):
+            length += self.GuessList[i].GetLength()
+
+        return length
+
+    def GetBuffer(self):
+        data = ''
+        data = CommFunc.WriteString(data, self.Head.GetLength(), self.Head.GetBuffer())
+        data = CommFunc.WriteBYTE(data, self.ZoneID)
+        data = CommFunc.WriteBYTE(data, self.Count)
+        for i in range(self.Count):
+            data = CommFunc.WriteString(data, self.GuessList[i].GetLength(), self.GuessList[i].GetBuffer())
+        return data
+
+    def OutputString(self):
+        DumpString = '''
+                                Head:%s,
+                                ZoneID:%d,
+                                Count:%d,
+                                GuessList:%s
+                                '''\
+                                %(
+                                self.Head.OutputString(),
+                                self.ZoneID,
+                                self.Count,
+                                "..."
+                                )
+        return DumpString
+
+
+m_NAtagGCChampionshipGuessPriInfo=tagGCChampionshipGuessPriInfo()
+ChNetPackDict[eval("0x%02x%02x"%(m_NAtagGCChampionshipGuessPriInfo.Head.Cmd,m_NAtagGCChampionshipGuessPriInfo.Head.SubCmd))] = m_NAtagGCChampionshipGuessPriInfo
+
+
+#------------------------------------------------------
+# C0 22 跨服排位竞猜公共信息 #tagGCChampionshipGuessPubInfo
+
+class  tagGCChampionshipGuessPlayerPub(Structure):
+    _pack_ = 1
+    _fields_ = [
+                  ("PlayerID", c_int),    # 目标玩家ID
+                  ("SupportCount", c_int),    # 支持人数
+                  ]
+
+    def __init__(self):
+        self.Clear()
+        return
+
+    def ReadData(self, stringData, _pos=0, _len=0):
+        self.Clear()
+        memmove(addressof(self), stringData[_pos:], self.GetLength())
+        return _pos + self.GetLength()
+
+    def Clear(self):
+        self.PlayerID = 0
+        self.SupportCount = 0
+        return
+
+    def GetLength(self):
+        return sizeof(tagGCChampionshipGuessPlayerPub)
+
+    def GetBuffer(self):
+        return string_at(addressof(self), self.GetLength())
+
+    def OutputString(self):
+        DumpString = '''// C0 22 跨服排位竞猜公共信息 //tagGCChampionshipGuessPubInfo:
+                                PlayerID:%d,
+                                SupportCount:%d
+                                '''\
+                                %(
+                                self.PlayerID,
+                                self.SupportCount
+                                )
+        return DumpString
+
+
+class  tagGCChampionshipGuessPubList(Structure):
+    GuessType = 0    #(BYTE GuessType)//竞猜类型 8-8强;4-4强排位
+    PlayerCount = 0    #(BYTE PlayerCount)
+    GuessPlayerList = list()    #(vector<tagGCChampionshipGuessPlayerPub> GuessPlayerList)// 被竞猜玩家列表
+    data = None
+
+    def __init__(self):
+        self.Clear()
+        return
+
+    def ReadData(self, _lpData, _pos=0, _Len=0):
+        self.Clear()
+        self.GuessType,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        self.PlayerCount,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        for i in range(self.PlayerCount):
+            temGuessPlayerList = tagGCChampionshipGuessPlayerPub()
+            _pos = temGuessPlayerList.ReadData(_lpData, _pos)
+            self.GuessPlayerList.append(temGuessPlayerList)
+        return _pos
+
+    def Clear(self):
+        self.GuessType = 0
+        self.PlayerCount = 0
+        self.GuessPlayerList = list()
+        return
+
+    def GetLength(self):
+        length = 0
+        length += 1
+        length += 1
+        for i in range(self.PlayerCount):
+            length += self.GuessPlayerList[i].GetLength()
+
+        return length
+
+    def GetBuffer(self):
+        data = ''
+        data = CommFunc.WriteBYTE(data, self.GuessType)
+        data = CommFunc.WriteBYTE(data, self.PlayerCount)
+        for i in range(self.PlayerCount):
+            data = CommFunc.WriteString(data, self.GuessPlayerList[i].GetLength(), self.GuessPlayerList[i].GetBuffer())
+        return data
+
+    def OutputString(self):
+        DumpString = '''
+                                GuessType:%d,
+                                PlayerCount:%d,
+                                GuessPlayerList:%s
+                                '''\
+                                %(
+                                self.GuessType,
+                                self.PlayerCount,
+                                "..."
+                                )
+        return DumpString
+
+
+class  tagGCChampionshipGuessPubInfo(Structure):
+    Head = tagHead()
+    ZoneID = 0    #(BYTE ZoneID)// 排位数据分区ID
+    Count = 0    #(BYTE Count)
+    GuessList = list()    #(vector<tagGCChampionshipGuessPubList> GuessList)
+    data = None
+
+    def __init__(self):
+        self.Clear()
+        self.Head.Cmd = 0xC0
+        self.Head.SubCmd = 0x22
+        return
+
+    def ReadData(self, _lpData, _pos=0, _Len=0):
+        self.Clear()
+        _pos = self.Head.ReadData(_lpData, _pos)
+        self.ZoneID,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        self.Count,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        for i in range(self.Count):
+            temGuessList = tagGCChampionshipGuessPubList()
+            _pos = temGuessList.ReadData(_lpData, _pos)
+            self.GuessList.append(temGuessList)
+        return _pos
+
+    def Clear(self):
+        self.Head = tagHead()
+        self.Head.Clear()
+        self.Head.Cmd = 0xC0
+        self.Head.SubCmd = 0x22
+        self.ZoneID = 0
+        self.Count = 0
+        self.GuessList = list()
+        return
+
+    def GetLength(self):
+        length = 0
+        length += self.Head.GetLength()
+        length += 1
+        length += 1
+        for i in range(self.Count):
+            length += self.GuessList[i].GetLength()
+
+        return length
+
+    def GetBuffer(self):
+        data = ''
+        data = CommFunc.WriteString(data, self.Head.GetLength(), self.Head.GetBuffer())
+        data = CommFunc.WriteBYTE(data, self.ZoneID)
+        data = CommFunc.WriteBYTE(data, self.Count)
+        for i in range(self.Count):
+            data = CommFunc.WriteString(data, self.GuessList[i].GetLength(), self.GuessList[i].GetBuffer())
+        return data
+
+    def OutputString(self):
+        DumpString = '''
+                                Head:%s,
+                                ZoneID:%d,
+                                Count:%d,
+                                GuessList:%s
+                                '''\
+                                %(
+                                self.Head.OutputString(),
+                                self.ZoneID,
+                                self.Count,
+                                "..."
+                                )
+        return DumpString
+
+
+m_NAtagGCChampionshipGuessPubInfo=tagGCChampionshipGuessPubInfo()
+ChNetPackDict[eval("0x%02x%02x"%(m_NAtagGCChampionshipGuessPubInfo.Head.Cmd,m_NAtagGCChampionshipGuessPubInfo.Head.SubCmd))] = m_NAtagGCChampionshipGuessPubInfo
+
+
+#------------------------------------------------------
+# C0 19 跨服排位仙官申请回应结果 #tagGCChampionshipOfficialApplyReplyRet
+
+class  tagGCChampionshipOfficialApplyReplyRet(Structure):
+    Head = tagHead()
+    NameLen = 0    #(BYTE NameLen)
+    PlayerName = ""    #(String PlayerName)// 界主玩家名
+    MainOfficialID = 0    #(WORD MainOfficialID)//界主官职ID
+    OfficialID = 0    #(WORD OfficialID)//申请官职ID
+    IsOK = 0    #(BYTE IsOK)//是否同意;1-是;0-否
+    data = None
+
+    def __init__(self):
+        self.Clear()
+        self.Head.Cmd = 0xC0
+        self.Head.SubCmd = 0x19
+        return
+
+    def ReadData(self, _lpData, _pos=0, _Len=0):
+        self.Clear()
+        _pos = self.Head.ReadData(_lpData, _pos)
+        self.NameLen,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        self.PlayerName,_pos = CommFunc.ReadString(_lpData, _pos,self.NameLen)
+        self.MainOfficialID,_pos = CommFunc.ReadWORD(_lpData, _pos)
+        self.OfficialID,_pos = CommFunc.ReadWORD(_lpData, _pos)
+        self.IsOK,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        return _pos
+
+    def Clear(self):
+        self.Head = tagHead()
+        self.Head.Clear()
+        self.Head.Cmd = 0xC0
+        self.Head.SubCmd = 0x19
+        self.NameLen = 0
+        self.PlayerName = ""
+        self.MainOfficialID = 0
+        self.OfficialID = 0
+        self.IsOK = 0
+        return
+
+    def GetLength(self):
+        length = 0
+        length += self.Head.GetLength()
+        length += 1
+        length += len(self.PlayerName)
+        length += 2
+        length += 2
+        length += 1
+
+        return length
+
+    def GetBuffer(self):
+        data = ''
+        data = CommFunc.WriteString(data, self.Head.GetLength(), self.Head.GetBuffer())
+        data = CommFunc.WriteBYTE(data, self.NameLen)
+        data = CommFunc.WriteString(data, self.NameLen, self.PlayerName)
+        data = CommFunc.WriteWORD(data, self.MainOfficialID)
+        data = CommFunc.WriteWORD(data, self.OfficialID)
+        data = CommFunc.WriteBYTE(data, self.IsOK)
+        return data
+
+    def OutputString(self):
+        DumpString = '''
+                                Head:%s,
+                                NameLen:%d,
+                                PlayerName:%s,
+                                MainOfficialID:%d,
+                                OfficialID:%d,
+                                IsOK:%d
+                                '''\
+                                %(
+                                self.Head.OutputString(),
+                                self.NameLen,
+                                self.PlayerName,
+                                self.MainOfficialID,
+                                self.OfficialID,
+                                self.IsOK
+                                )
+        return DumpString
+
+
+m_NAtagGCChampionshipOfficialApplyReplyRet=tagGCChampionshipOfficialApplyReplyRet()
+ChNetPackDict[eval("0x%02x%02x"%(m_NAtagGCChampionshipOfficialApplyReplyRet.Head.Cmd,m_NAtagGCChampionshipOfficialApplyReplyRet.Head.SubCmd))] = m_NAtagGCChampionshipOfficialApplyReplyRet
+
+
+#------------------------------------------------------
+# C0 21 跨服排位仙官挑战记录 #tagGCChampionshipOfficialChallengeRecordInfo
+
+class  tagGCChampionshipOfficialChallengeRecord(Structure):
+    NameLen = 0    #(BYTE NameLen)
+    PlayerName = ""    #(String PlayerName)
+    ChallengeTime = 0    #(DWORD ChallengeTime)//挑战时间戳
+    Ret = 0    #(BYTE Ret)//挑战结果;0-失败;1-获胜;
+    data = None
+
+    def __init__(self):
+        self.Clear()
+        return
+
+    def ReadData(self, _lpData, _pos=0, _Len=0):
+        self.Clear()
+        self.NameLen,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        self.PlayerName,_pos = CommFunc.ReadString(_lpData, _pos,self.NameLen)
+        self.ChallengeTime,_pos = CommFunc.ReadDWORD(_lpData, _pos)
+        self.Ret,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        return _pos
+
+    def Clear(self):
+        self.NameLen = 0
+        self.PlayerName = ""
+        self.ChallengeTime = 0
+        self.Ret = 0
+        return
+
+    def GetLength(self):
+        length = 0
+        length += 1
+        length += len(self.PlayerName)
+        length += 4
+        length += 1
+
+        return length
+
+    def GetBuffer(self):
+        data = ''
+        data = CommFunc.WriteBYTE(data, self.NameLen)
+        data = CommFunc.WriteString(data, self.NameLen, self.PlayerName)
+        data = CommFunc.WriteDWORD(data, self.ChallengeTime)
+        data = CommFunc.WriteBYTE(data, self.Ret)
+        return data
+
+    def OutputString(self):
+        DumpString = '''
+                                NameLen:%d,
+                                PlayerName:%s,
+                                ChallengeTime:%d,
+                                Ret:%d
+                                '''\
+                                %(
+                                self.NameLen,
+                                self.PlayerName,
+                                self.ChallengeTime,
+                                self.Ret
+                                )
+        return DumpString
+
+
+class  tagGCChampionshipOfficialChallengeRecordInfo(Structure):
+    Head = tagHead()
+    ZoneID = 0    #(BYTE ZoneID)// 分区ID
+    MainOfficialID = 0    #(WORD MainOfficialID)// 界主官职ID
+    OfficialID = 0    #(WORD OfficialID)// 记录的官职ID
+    RecordCount = 0    #(BYTE RecordCount)// 挑战记录数
+    RecordList = list()    #(vector<tagGCChampionshipOfficialChallengeRecord> RecordList)
+    data = None
+
+    def __init__(self):
+        self.Clear()
+        self.Head.Cmd = 0xC0
+        self.Head.SubCmd = 0x21
+        return
+
+    def ReadData(self, _lpData, _pos=0, _Len=0):
+        self.Clear()
+        _pos = self.Head.ReadData(_lpData, _pos)
+        self.ZoneID,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        self.MainOfficialID,_pos = CommFunc.ReadWORD(_lpData, _pos)
+        self.OfficialID,_pos = CommFunc.ReadWORD(_lpData, _pos)
+        self.RecordCount,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        for i in range(self.RecordCount):
+            temRecordList = tagGCChampionshipOfficialChallengeRecord()
+            _pos = temRecordList.ReadData(_lpData, _pos)
+            self.RecordList.append(temRecordList)
+        return _pos
+
+    def Clear(self):
+        self.Head = tagHead()
+        self.Head.Clear()
+        self.Head.Cmd = 0xC0
+        self.Head.SubCmd = 0x21
+        self.ZoneID = 0
+        self.MainOfficialID = 0
+        self.OfficialID = 0
+        self.RecordCount = 0
+        self.RecordList = list()
+        return
+
+    def GetLength(self):
+        length = 0
+        length += self.Head.GetLength()
+        length += 1
+        length += 2
+        length += 2
+        length += 1
+        for i in range(self.RecordCount):
+            length += self.RecordList[i].GetLength()
+
+        return length
+
+    def GetBuffer(self):
+        data = ''
+        data = CommFunc.WriteString(data, self.Head.GetLength(), self.Head.GetBuffer())
+        data = CommFunc.WriteBYTE(data, self.ZoneID)
+        data = CommFunc.WriteWORD(data, self.MainOfficialID)
+        data = CommFunc.WriteWORD(data, self.OfficialID)
+        data = CommFunc.WriteBYTE(data, self.RecordCount)
+        for i in range(self.RecordCount):
+            data = CommFunc.WriteString(data, self.RecordList[i].GetLength(), self.RecordList[i].GetBuffer())
+        return data
+
+    def OutputString(self):
+        DumpString = '''
+                                Head:%s,
+                                ZoneID:%d,
+                                MainOfficialID:%d,
+                                OfficialID:%d,
+                                RecordCount:%d,
+                                RecordList:%s
+                                '''\
+                                %(
+                                self.Head.OutputString(),
+                                self.ZoneID,
+                                self.MainOfficialID,
+                                self.OfficialID,
+                                self.RecordCount,
+                                "..."
+                                )
+        return DumpString
+
+
+m_NAtagGCChampionshipOfficialChallengeRecordInfo=tagGCChampionshipOfficialChallengeRecordInfo()
+ChNetPackDict[eval("0x%02x%02x"%(m_NAtagGCChampionshipOfficialChallengeRecordInfo.Head.Cmd,m_NAtagGCChampionshipOfficialChallengeRecordInfo.Head.SubCmd))] = m_NAtagGCChampionshipOfficialChallengeRecordInfo
+
+
+#------------------------------------------------------
+# C0 20 跨服排位仙官挑战结果 #tagGCChampionshipOfficialChallengeRet
+
+class  tagGCChampionshipOfficialChallengeRet(Structure):
+    Head = tagHead()
+    NameLen = 0    #(BYTE NameLen)
+    PlayerName = ""    #(String PlayerName)// 原仙官玩家名,可能为空,代表本来无玩家
+    MainOfficialID = 0    #(WORD MainOfficialID)//界主官职ID
+    OfficialID = 0    #(WORD OfficialID)//挑战的官职ID
+    Ret = 0    #(BYTE Ret)//挑战结果;0-失败;1-获胜;2-目标仙官玩家ID已变更,可刷新后重试
+    data = None
+
+    def __init__(self):
+        self.Clear()
+        self.Head.Cmd = 0xC0
+        self.Head.SubCmd = 0x20
+        return
+
+    def ReadData(self, _lpData, _pos=0, _Len=0):
+        self.Clear()
+        _pos = self.Head.ReadData(_lpData, _pos)
+        self.NameLen,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        self.PlayerName,_pos = CommFunc.ReadString(_lpData, _pos,self.NameLen)
+        self.MainOfficialID,_pos = CommFunc.ReadWORD(_lpData, _pos)
+        self.OfficialID,_pos = CommFunc.ReadWORD(_lpData, _pos)
+        self.Ret,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        return _pos
+
+    def Clear(self):
+        self.Head = tagHead()
+        self.Head.Clear()
+        self.Head.Cmd = 0xC0
+        self.Head.SubCmd = 0x20
+        self.NameLen = 0
+        self.PlayerName = ""
+        self.MainOfficialID = 0
+        self.OfficialID = 0
+        self.Ret = 0
+        return
+
+    def GetLength(self):
+        length = 0
+        length += self.Head.GetLength()
+        length += 1
+        length += len(self.PlayerName)
+        length += 2
+        length += 2
+        length += 1
+
+        return length
+
+    def GetBuffer(self):
+        data = ''
+        data = CommFunc.WriteString(data, self.Head.GetLength(), self.Head.GetBuffer())
+        data = CommFunc.WriteBYTE(data, self.NameLen)
+        data = CommFunc.WriteString(data, self.NameLen, self.PlayerName)
+        data = CommFunc.WriteWORD(data, self.MainOfficialID)
+        data = CommFunc.WriteWORD(data, self.OfficialID)
+        data = CommFunc.WriteBYTE(data, self.Ret)
+        return data
+
+    def OutputString(self):
+        DumpString = '''
+                                Head:%s,
+                                NameLen:%d,
+                                PlayerName:%s,
+                                MainOfficialID:%d,
+                                OfficialID:%d,
+                                Ret:%d
+                                '''\
+                                %(
+                                self.Head.OutputString(),
+                                self.NameLen,
+                                self.PlayerName,
+                                self.MainOfficialID,
+                                self.OfficialID,
+                                self.Ret
+                                )
+        return DumpString
+
+
+m_NAtagGCChampionshipOfficialChallengeRet=tagGCChampionshipOfficialChallengeRet()
+ChNetPackDict[eval("0x%02x%02x"%(m_NAtagGCChampionshipOfficialChallengeRet.Head.Cmd,m_NAtagGCChampionshipOfficialChallengeRet.Head.SubCmd))] = m_NAtagGCChampionshipOfficialChallengeRet
+
+
+#------------------------------------------------------
+# C0 18 跨服排位官职信息 #tagGCChampionshipOfficialInfo
+
+class  tagGCChampionshipOfficialPlayer(Structure):
+    PlayerID = 0    #(DWORD PlayerID)// 玩家ID
+    NameLen = 0    #(BYTE NameLen)
+    PlayerName = ""    #(String PlayerName)
+    Job = 0    #(BYTE Job)
+    LV = 0    #(WORD LV)
+    FightPower = 0    #(DWORD FightPower)// 战力求余亿部分
+    FightPowerEx = 0    #(DWORD FightPowerEx)// 战力整除亿部分
+    RealmLV = 0    #(WORD RealmLV)
+    data = None
+
+    def __init__(self):
+        self.Clear()
+        return
+
+    def ReadData(self, _lpData, _pos=0, _Len=0):
+        self.Clear()
+        self.PlayerID,_pos = CommFunc.ReadDWORD(_lpData, _pos)
+        self.NameLen,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        self.PlayerName,_pos = CommFunc.ReadString(_lpData, _pos,self.NameLen)
+        self.Job,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        self.LV,_pos = CommFunc.ReadWORD(_lpData, _pos)
+        self.FightPower,_pos = CommFunc.ReadDWORD(_lpData, _pos)
+        self.FightPowerEx,_pos = CommFunc.ReadDWORD(_lpData, _pos)
+        self.RealmLV,_pos = CommFunc.ReadWORD(_lpData, _pos)
+        return _pos
+
+    def Clear(self):
+        self.PlayerID = 0
+        self.NameLen = 0
+        self.PlayerName = ""
+        self.Job = 0
+        self.LV = 0
+        self.FightPower = 0
+        self.FightPowerEx = 0
+        self.RealmLV = 0
+        return
+
+    def GetLength(self):
+        length = 0
+        length += 4
+        length += 1
+        length += len(self.PlayerName)
+        length += 1
+        length += 2
+        length += 4
+        length += 4
+        length += 2
+
+        return length
+
+    def GetBuffer(self):
+        data = ''
+        data = CommFunc.WriteDWORD(data, self.PlayerID)
+        data = CommFunc.WriteBYTE(data, self.NameLen)
+        data = CommFunc.WriteString(data, self.NameLen, self.PlayerName)
+        data = CommFunc.WriteBYTE(data, self.Job)
+        data = CommFunc.WriteWORD(data, self.LV)
+        data = CommFunc.WriteDWORD(data, self.FightPower)
+        data = CommFunc.WriteDWORD(data, self.FightPowerEx)
+        data = CommFunc.WriteWORD(data, self.RealmLV)
+        return data
+
+    def OutputString(self):
+        DumpString = '''
+                                PlayerID:%d,
+                                NameLen:%d,
+                                PlayerName:%s,
+                                Job:%d,
+                                LV:%d,
+                                FightPower:%d,
+                                FightPowerEx:%d,
+                                RealmLV:%d
+                                '''\
+                                %(
+                                self.PlayerID,
+                                self.NameLen,
+                                self.PlayerName,
+                                self.Job,
+                                self.LV,
+                                self.FightPower,
+                                self.FightPowerEx,
+                                self.RealmLV
+                                )
+        return DumpString
+
+
+class  tagGCChampionshipOfficial(Structure):
+    OfficialID = 0    #(DWORD OfficialID)// 官职ID
+    LastDismissJuniorTime = 0    #(DWORD LastDismissJuniorTime)// 上次辞退下级仙官时间戳,跨服时间,如果自己是本界主时,用于计算辞退CD
+    WorshipCount = 0    #(DWORD WorshipCount)// 被膜拜次数
+    WorshipDouble = 0    #(BYTE WorshipDouble)// 今日是否双倍膜拜,仅在规定时间点内有用
+    OfficialPlayer=tagGCChampionshipOfficialPlayer()    #(tagGCChampionshipOfficialPlayer OfficialPlayer)// 任职玩家信息,可能没有
+    ApplyPlayerCount = 0    #(BYTE ApplyPlayerCount)// 申请该仙官玩家数
+    ApplyPlayerList = list()    #(vector<tagGCChampionshipOfficialPlayer> ApplyPlayerList)// 申请该仙官玩家列表
+    data = None
+
+    def __init__(self):
+        self.Clear()
+        return
+
+    def ReadData(self, _lpData, _pos=0, _Len=0):
+        self.Clear()
+        self.OfficialID,_pos = CommFunc.ReadDWORD(_lpData, _pos)
+        self.LastDismissJuniorTime,_pos = CommFunc.ReadDWORD(_lpData, _pos)
+        self.WorshipCount,_pos = CommFunc.ReadDWORD(_lpData, _pos)
+        self.WorshipDouble,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        _pos = self.OfficialPlayer.ReadData(_lpData,_pos)
+        self.ApplyPlayerCount,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        for i in range(self.ApplyPlayerCount):
+            temApplyPlayerList = tagGCChampionshipOfficialPlayer()
+            _pos = temApplyPlayerList.ReadData(_lpData, _pos)
+            self.ApplyPlayerList.append(temApplyPlayerList)
+        return _pos
+
+    def Clear(self):
+        self.OfficialID = 0
+        self.LastDismissJuniorTime = 0
+        self.WorshipCount = 0
+        self.WorshipDouble = 0
+        self.OfficialPlayer=tagGCChampionshipOfficialPlayer()
+        self.OfficialPlayer.Clear()
+        self.ApplyPlayerCount = 0
+        self.ApplyPlayerList = list()
+        return
+
+    def GetLength(self):
+        length = 0
+        length += 4
+        length += 4
+        length += 4
+        length += 1
+        length += self.OfficialPlayer.GetLength()
+        length += 1
+        for i in range(self.ApplyPlayerCount):
+            length += self.ApplyPlayerList[i].GetLength()
+
+        return length
+
+    def GetBuffer(self):
+        data = ''
+        data = CommFunc.WriteDWORD(data, self.OfficialID)
+        data = CommFunc.WriteDWORD(data, self.LastDismissJuniorTime)
+        data = CommFunc.WriteDWORD(data, self.WorshipCount)
+        data = CommFunc.WriteBYTE(data, self.WorshipDouble)
+        data = CommFunc.WriteString(data,self.OfficialPlayer.GetLength(),self.OfficialPlayer.GetBuffer())
+        data = CommFunc.WriteBYTE(data, self.ApplyPlayerCount)
+        for i in range(self.ApplyPlayerCount):
+            data = CommFunc.WriteString(data, self.ApplyPlayerList[i].GetLength(), self.ApplyPlayerList[i].GetBuffer())
+        return data
+
+    def OutputString(self):
+        DumpString = '''
+                                OfficialID:%d,
+                                LastDismissJuniorTime:%d,
+                                WorshipCount:%d,
+                                WorshipDouble:%d,
+                                OfficialPlayer:%s,
+                                ApplyPlayerCount:%d,
+                                ApplyPlayerList:%s
+                                '''\
+                                %(
+                                self.OfficialID,
+                                self.LastDismissJuniorTime,
+                                self.WorshipCount,
+                                self.WorshipDouble,
+                                self.OfficialPlayer.OutputString(),
+                                self.ApplyPlayerCount,
+                                "..."
+                                )
+        return DumpString
+
+
+class  tagGCChampionshipOfficialInfo(Structure):
+    Head = tagHead()
+    ZoneID = 0    #(BYTE ZoneID)// 官职数据分区ID
+    OfficialCount = 0    #(BYTE OfficialCount)// 官职数,包含界主及所有仙官
+    OfficialList = list()    #(vector<tagGCChampionshipOfficial> OfficialList)
+    data = None
+
+    def __init__(self):
+        self.Clear()
+        self.Head.Cmd = 0xC0
+        self.Head.SubCmd = 0x18
+        return
+
+    def ReadData(self, _lpData, _pos=0, _Len=0):
+        self.Clear()
+        _pos = self.Head.ReadData(_lpData, _pos)
+        self.ZoneID,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        self.OfficialCount,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        for i in range(self.OfficialCount):
+            temOfficialList = tagGCChampionshipOfficial()
+            _pos = temOfficialList.ReadData(_lpData, _pos)
+            self.OfficialList.append(temOfficialList)
+        return _pos
+
+    def Clear(self):
+        self.Head = tagHead()
+        self.Head.Clear()
+        self.Head.Cmd = 0xC0
+        self.Head.SubCmd = 0x18
+        self.ZoneID = 0
+        self.OfficialCount = 0
+        self.OfficialList = list()
+        return
+
+    def GetLength(self):
+        length = 0
+        length += self.Head.GetLength()
+        length += 1
+        length += 1
+        for i in range(self.OfficialCount):
+            length += self.OfficialList[i].GetLength()
+
+        return length
+
+    def GetBuffer(self):
+        data = ''
+        data = CommFunc.WriteString(data, self.Head.GetLength(), self.Head.GetBuffer())
+        data = CommFunc.WriteBYTE(data, self.ZoneID)
+        data = CommFunc.WriteBYTE(data, self.OfficialCount)
+        for i in range(self.OfficialCount):
+            data = CommFunc.WriteString(data, self.OfficialList[i].GetLength(), self.OfficialList[i].GetBuffer())
+        return data
+
+    def OutputString(self):
+        DumpString = '''
+                                Head:%s,
+                                ZoneID:%d,
+                                OfficialCount:%d,
+                                OfficialList:%s
+                                '''\
+                                %(
+                                self.Head.OutputString(),
+                                self.ZoneID,
+                                self.OfficialCount,
+                                "..."
+                                )
+        return DumpString
+
+
+m_NAtagGCChampionshipOfficialInfo=tagGCChampionshipOfficialInfo()
+ChNetPackDict[eval("0x%02x%02x"%(m_NAtagGCChampionshipOfficialInfo.Head.Cmd,m_NAtagGCChampionshipOfficialInfo.Head.SubCmd))] = m_NAtagGCChampionshipOfficialInfo
+
+
+#------------------------------------------------------
 # C0 09 跨服战场玩家购买战场信息 #tagGCCrossBattlefieldBuyInfo
 
 class  tagGCCrossBattlefieldPlayer(Structure):
@@ -12753,6 +13669,429 @@
 
 m_NAtagGCCrossBillboardInfo=tagGCCrossBillboardInfo()
 ChNetPackDict[eval("0x%02x%02x"%(m_NAtagGCCrossBillboardInfo.Head.Cmd,m_NAtagGCCrossBillboardInfo.Head.SubCmd))] = m_NAtagGCCrossBillboardInfo
+
+
+#------------------------------------------------------
+# C0 16 跨服排位战斗结果 #tagGCCrossChampionshipPKOver
+
+class  tagGCCrossChampionshipPKOver(Structure):
+    Head = tagHead()
+    GroupMark = 0    #(DWORD GroupMark)// 分组标识:64、32、16、8 - 64、32、16、8强赛;4 - 半决赛; 2 - 决赛
+    TimeStr = ""    #(char TimeStr[19])// 结算时间,格式 yyyy-MM-dd HH:mm:ss
+    OverType = 0    #(BYTE OverType)// 0-正常,1-有人离线
+    WinnerID = 0    #(DWORD WinnerID)// 胜方ID
+    LoserID = 0    #(DWORD LoserID)// 败方ID
+    RoundCount = 0    #(BYTE RoundCount)// PK回合数
+    RoundWinnerID = list()    #(vector<DWORD> RoundWinnerID)// 回合获胜ID列表
+    TagNameLen = 0    #(BYTE TagNameLen)
+    TagName = ""    #(String TagName)
+    Rank = 0    #(BYTE Rank)// 最终名次,决赛才有
+    data = None
+
+    def __init__(self):
+        self.Clear()
+        self.Head.Cmd = 0xC0
+        self.Head.SubCmd = 0x16
+        return
+
+    def ReadData(self, _lpData, _pos=0, _Len=0):
+        self.Clear()
+        _pos = self.Head.ReadData(_lpData, _pos)
+        self.GroupMark,_pos = CommFunc.ReadDWORD(_lpData, _pos)
+        self.TimeStr,_pos = CommFunc.ReadString(_lpData, _pos,19)
+        self.OverType,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        self.WinnerID,_pos = CommFunc.ReadDWORD(_lpData, _pos)
+        self.LoserID,_pos = CommFunc.ReadDWORD(_lpData, _pos)
+        self.RoundCount,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        for i in range(self.RoundCount):
+            value,_pos=CommFunc.ReadDWORD(_lpData,_pos)
+            self.RoundWinnerID.append(value)
+        self.TagNameLen,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        self.TagName,_pos = CommFunc.ReadString(_lpData, _pos,self.TagNameLen)
+        self.Rank,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        return _pos
+
+    def Clear(self):
+        self.Head = tagHead()
+        self.Head.Clear()
+        self.Head.Cmd = 0xC0
+        self.Head.SubCmd = 0x16
+        self.GroupMark = 0
+        self.TimeStr = ""
+        self.OverType = 0
+        self.WinnerID = 0
+        self.LoserID = 0
+        self.RoundCount = 0
+        self.RoundWinnerID = list()
+        self.TagNameLen = 0
+        self.TagName = ""
+        self.Rank = 0
+        return
+
+    def GetLength(self):
+        length = 0
+        length += self.Head.GetLength()
+        length += 4
+        length += 19
+        length += 1
+        length += 4
+        length += 4
+        length += 1
+        length += 4 * self.RoundCount
+        length += 1
+        length += len(self.TagName)
+        length += 1
+
+        return length
+
+    def GetBuffer(self):
+        data = ''
+        data = CommFunc.WriteString(data, self.Head.GetLength(), self.Head.GetBuffer())
+        data = CommFunc.WriteDWORD(data, self.GroupMark)
+        data = CommFunc.WriteString(data, 19, self.TimeStr)
+        data = CommFunc.WriteBYTE(data, self.OverType)
+        data = CommFunc.WriteDWORD(data, self.WinnerID)
+        data = CommFunc.WriteDWORD(data, self.LoserID)
+        data = CommFunc.WriteBYTE(data, self.RoundCount)
+        for i in range(self.RoundCount):
+            data = CommFunc.WriteDWORD(data, self.RoundWinnerID[i])
+        data = CommFunc.WriteBYTE(data, self.TagNameLen)
+        data = CommFunc.WriteString(data, self.TagNameLen, self.TagName)
+        data = CommFunc.WriteBYTE(data, self.Rank)
+        return data
+
+    def OutputString(self):
+        DumpString = '''
+                                Head:%s,
+                                GroupMark:%d,
+                                TimeStr:%s,
+                                OverType:%d,
+                                WinnerID:%d,
+                                LoserID:%d,
+                                RoundCount:%d,
+                                RoundWinnerID:%s,
+                                TagNameLen:%d,
+                                TagName:%s,
+                                Rank:%d
+                                '''\
+                                %(
+                                self.Head.OutputString(),
+                                self.GroupMark,
+                                self.TimeStr,
+                                self.OverType,
+                                self.WinnerID,
+                                self.LoserID,
+                                self.RoundCount,
+                                "...",
+                                self.TagNameLen,
+                                self.TagName,
+                                self.Rank
+                                )
+        return DumpString
+
+
+m_NAtagGCCrossChampionshipPKOver=tagGCCrossChampionshipPKOver()
+ChNetPackDict[eval("0x%02x%02x"%(m_NAtagGCCrossChampionshipPKOver.Head.Cmd,m_NAtagGCCrossChampionshipPKOver.Head.SubCmd))] = m_NAtagGCCrossChampionshipPKOver
+
+
+#------------------------------------------------------
+# C0 15 跨服排位分区分组信息 #tagGCCrossChampionshipPKZoneGroupInfo
+
+class  tagGCCrossChampionshipPKBattle(Structure):
+    _pack_ = 1
+    _fields_ = [
+                  ("BattleNum", c_ubyte),    # 对战组编号 1~n
+                  ("WinPlayerID", c_int),    # 获胜玩家ID
+                  ("PlayerIDA", c_int),    # 玩家IDA
+                  ("PlayerIDB", c_int),    # 玩家IDB
+                  ]
+
+    def __init__(self):
+        self.Clear()
+        return
+
+    def ReadData(self, stringData, _pos=0, _len=0):
+        self.Clear()
+        memmove(addressof(self), stringData[_pos:], self.GetLength())
+        return _pos + self.GetLength()
+
+    def Clear(self):
+        self.BattleNum = 0
+        self.WinPlayerID = 0
+        self.PlayerIDA = 0
+        self.PlayerIDB = 0
+        return
+
+    def GetLength(self):
+        return sizeof(tagGCCrossChampionshipPKBattle)
+
+    def GetBuffer(self):
+        return string_at(addressof(self), self.GetLength())
+
+    def OutputString(self):
+        DumpString = '''// C0 15 跨服排位分区分组信息 //tagGCCrossChampionshipPKZoneGroupInfo:
+                                BattleNum:%d,
+                                WinPlayerID:%d,
+                                PlayerIDA:%d,
+                                PlayerIDB:%d
+                                '''\
+                                %(
+                                self.BattleNum,
+                                self.WinPlayerID,
+                                self.PlayerIDA,
+                                self.PlayerIDB
+                                )
+        return DumpString
+
+
+class  tagGCCrossChampionshipPKGroup(Structure):
+    GroupMark = 0    #(DWORD GroupMark)// 战斗分区mark, 如 64、32、16、8、4-半决赛、2-决赛;
+    BattleCount = 0    #(BYTE BattleCount)// 对战组数
+    BattleList = list()    #(vector<tagGCCrossChampionshipPKBattle> BattleList)// 对战组列表
+    data = None
+
+    def __init__(self):
+        self.Clear()
+        return
+
+    def ReadData(self, _lpData, _pos=0, _Len=0):
+        self.Clear()
+        self.GroupMark,_pos = CommFunc.ReadDWORD(_lpData, _pos)
+        self.BattleCount,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        for i in range(self.BattleCount):
+            temBattleList = tagGCCrossChampionshipPKBattle()
+            _pos = temBattleList.ReadData(_lpData, _pos)
+            self.BattleList.append(temBattleList)
+        return _pos
+
+    def Clear(self):
+        self.GroupMark = 0
+        self.BattleCount = 0
+        self.BattleList = list()
+        return
+
+    def GetLength(self):
+        length = 0
+        length += 4
+        length += 1
+        for i in range(self.BattleCount):
+            length += self.BattleList[i].GetLength()
+
+        return length
+
+    def GetBuffer(self):
+        data = ''
+        data = CommFunc.WriteDWORD(data, self.GroupMark)
+        data = CommFunc.WriteBYTE(data, self.BattleCount)
+        for i in range(self.BattleCount):
+            data = CommFunc.WriteString(data, self.BattleList[i].GetLength(), self.BattleList[i].GetBuffer())
+        return data
+
+    def OutputString(self):
+        DumpString = '''
+                                GroupMark:%d,
+                                BattleCount:%d,
+                                BattleList:%s
+                                '''\
+                                %(
+                                self.GroupMark,
+                                self.BattleCount,
+                                "..."
+                                )
+        return DumpString
+
+
+class  tagGCCrossChampionshipPKPlayer(Structure):
+    PlayerID = 0    #(DWORD PlayerID)// 玩家ID
+    NameLen = 0    #(BYTE NameLen)
+    PlayerName = ""    #(String PlayerName)
+    Job = 0    #(BYTE Job)
+    LV = 0    #(WORD LV)
+    FightPower = 0    #(DWORD FightPower)// 战力求余亿部分
+    FightPowerEx = 0    #(DWORD FightPowerEx)// 战力整除亿部分
+    RealmLV = 0    #(WORD RealmLV)
+    data = None
+
+    def __init__(self):
+        self.Clear()
+        return
+
+    def ReadData(self, _lpData, _pos=0, _Len=0):
+        self.Clear()
+        self.PlayerID,_pos = CommFunc.ReadDWORD(_lpData, _pos)
+        self.NameLen,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        self.PlayerName,_pos = CommFunc.ReadString(_lpData, _pos,self.NameLen)
+        self.Job,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        self.LV,_pos = CommFunc.ReadWORD(_lpData, _pos)
+        self.FightPower,_pos = CommFunc.ReadDWORD(_lpData, _pos)
+        self.FightPowerEx,_pos = CommFunc.ReadDWORD(_lpData, _pos)
+        self.RealmLV,_pos = CommFunc.ReadWORD(_lpData, _pos)
+        return _pos
+
+    def Clear(self):
+        self.PlayerID = 0
+        self.NameLen = 0
+        self.PlayerName = ""
+        self.Job = 0
+        self.LV = 0
+        self.FightPower = 0
+        self.FightPowerEx = 0
+        self.RealmLV = 0
+        return
+
+    def GetLength(self):
+        length = 0
+        length += 4
+        length += 1
+        length += len(self.PlayerName)
+        length += 1
+        length += 2
+        length += 4
+        length += 4
+        length += 2
+
+        return length
+
+    def GetBuffer(self):
+        data = ''
+        data = CommFunc.WriteDWORD(data, self.PlayerID)
+        data = CommFunc.WriteBYTE(data, self.NameLen)
+        data = CommFunc.WriteString(data, self.NameLen, self.PlayerName)
+        data = CommFunc.WriteBYTE(data, self.Job)
+        data = CommFunc.WriteWORD(data, self.LV)
+        data = CommFunc.WriteDWORD(data, self.FightPower)
+        data = CommFunc.WriteDWORD(data, self.FightPowerEx)
+        data = CommFunc.WriteWORD(data, self.RealmLV)
+        return data
+
+    def OutputString(self):
+        DumpString = '''
+                                PlayerID:%d,
+                                NameLen:%d,
+                                PlayerName:%s,
+                                Job:%d,
+                                LV:%d,
+                                FightPower:%d,
+                                FightPowerEx:%d,
+                                RealmLV:%d
+                                '''\
+                                %(
+                                self.PlayerID,
+                                self.NameLen,
+                                self.PlayerName,
+                                self.Job,
+                                self.LV,
+                                self.FightPower,
+                                self.FightPowerEx,
+                                self.RealmLV
+                                )
+        return DumpString
+
+
+class  tagGCCrossChampionshipPKZoneGroupInfo(Structure):
+    Head = tagHead()
+    ActID = 0    #(DWORD ActID)// 活动ID,活动ID不同则可重置前端排位赛相关缓存数据
+    StateError = 0    #(BYTE StateError)// 本次活动是否已经出现流程状态异常;如服务器异常或维护服务器导致跳过步骤,则会废弃该次比赛,直到下次新活动;
+    ZoneID = 0    #(BYTE ZoneID)// 排位分区ID
+    PlayerCount = 0    #(BYTE PlayerCount)// 参赛玩家数
+    PlayerList = list()    #(vector<tagGCCrossChampionshipPKPlayer> PlayerList)
+    GroupCount = 0    #(WORD GroupCount)
+    GroupList = list()    #(vector<tagGCCrossChampionshipPKGroup> GroupList)
+    data = None
+
+    def __init__(self):
+        self.Clear()
+        self.Head.Cmd = 0xC0
+        self.Head.SubCmd = 0x15
+        return
+
+    def ReadData(self, _lpData, _pos=0, _Len=0):
+        self.Clear()
+        _pos = self.Head.ReadData(_lpData, _pos)
+        self.ActID,_pos = CommFunc.ReadDWORD(_lpData, _pos)
+        self.StateError,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        self.ZoneID,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        self.PlayerCount,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        for i in range(self.PlayerCount):
+            temPlayerList = tagGCCrossChampionshipPKPlayer()
+            _pos = temPlayerList.ReadData(_lpData, _pos)
+            self.PlayerList.append(temPlayerList)
+        self.GroupCount,_pos = CommFunc.ReadWORD(_lpData, _pos)
+        for i in range(self.GroupCount):
+            temGroupList = tagGCCrossChampionshipPKGroup()
+            _pos = temGroupList.ReadData(_lpData, _pos)
+            self.GroupList.append(temGroupList)
+        return _pos
+
+    def Clear(self):
+        self.Head = tagHead()
+        self.Head.Clear()
+        self.Head.Cmd = 0xC0
+        self.Head.SubCmd = 0x15
+        self.ActID = 0
+        self.StateError = 0
+        self.ZoneID = 0
+        self.PlayerCount = 0
+        self.PlayerList = list()
+        self.GroupCount = 0
+        self.GroupList = list()
+        return
+
+    def GetLength(self):
+        length = 0
+        length += self.Head.GetLength()
+        length += 4
+        length += 1
+        length += 1
+        length += 1
+        for i in range(self.PlayerCount):
+            length += self.PlayerList[i].GetLength()
+        length += 2
+        for i in range(self.GroupCount):
+            length += self.GroupList[i].GetLength()
+
+        return length
+
+    def GetBuffer(self):
+        data = ''
+        data = CommFunc.WriteString(data, self.Head.GetLength(), self.Head.GetBuffer())
+        data = CommFunc.WriteDWORD(data, self.ActID)
+        data = CommFunc.WriteBYTE(data, self.StateError)
+        data = CommFunc.WriteBYTE(data, self.ZoneID)
+        data = CommFunc.WriteBYTE(data, self.PlayerCount)
+        for i in range(self.PlayerCount):
+            data = CommFunc.WriteString(data, self.PlayerList[i].GetLength(), self.PlayerList[i].GetBuffer())
+        data = CommFunc.WriteWORD(data, self.GroupCount)
+        for i in range(self.GroupCount):
+            data = CommFunc.WriteString(data, self.GroupList[i].GetLength(), self.GroupList[i].GetBuffer())
+        return data
+
+    def OutputString(self):
+        DumpString = '''
+                                Head:%s,
+                                ActID:%d,
+                                StateError:%d,
+                                ZoneID:%d,
+                                PlayerCount:%d,
+                                PlayerList:%s,
+                                GroupCount:%d,
+                                GroupList:%s
+                                '''\
+                                %(
+                                self.Head.OutputString(),
+                                self.ActID,
+                                self.StateError,
+                                self.ZoneID,
+                                self.PlayerCount,
+                                "...",
+                                self.GroupCount,
+                                "..."
+                                )
+        return DumpString
+
+
+m_NAtagGCCrossChampionshipPKZoneGroupInfo=tagGCCrossChampionshipPKZoneGroupInfo()
+ChNetPackDict[eval("0x%02x%02x"%(m_NAtagGCCrossChampionshipPKZoneGroupInfo.Head.Cmd,m_NAtagGCCrossChampionshipPKZoneGroupInfo.Head.SubCmd))] = m_NAtagGCCrossChampionshipPKZoneGroupInfo
 
 
 #------------------------------------------------------
@@ -41311,6 +42650,58 @@
 
 
 #------------------------------------------------------
+# C1 09 跨服排位玩家信息 #tagMCChampionshipPlayerInfo
+
+class  tagMCChampionshipPlayerInfo(Structure):
+    _pack_ = 1
+    _fields_ = [
+                  ("Cmd", c_ubyte),
+                  ("SubCmd", c_ubyte),
+                  ("WorshipCount", c_ubyte),    # 今日已膜拜次数
+                  ]
+
+    def __init__(self):
+        self.Clear()
+        self.Cmd = 0xC1
+        self.SubCmd = 0x09
+        return
+
+    def ReadData(self, stringData, _pos=0, _len=0):
+        self.Clear()
+        memmove(addressof(self), stringData[_pos:], self.GetLength())
+        return _pos + self.GetLength()
+
+    def Clear(self):
+        self.Cmd = 0xC1
+        self.SubCmd = 0x09
+        self.WorshipCount = 0
+        return
+
+    def GetLength(self):
+        return sizeof(tagMCChampionshipPlayerInfo)
+
+    def GetBuffer(self):
+        return string_at(addressof(self), self.GetLength())
+
+    def OutputString(self):
+        DumpString = '''// C1 09 跨服排位玩家信息 //tagMCChampionshipPlayerInfo:
+                                Cmd:%s,
+                                SubCmd:%s,
+                                WorshipCount:%d
+                                '''\
+                                %(
+                                self.Cmd,
+                                self.SubCmd,
+                                self.WorshipCount
+                                )
+        return DumpString
+
+
+m_NAtagMCChampionshipPlayerInfo=tagMCChampionshipPlayerInfo()
+ChNetPackDict[eval("0x%02x%02x"%(m_NAtagMCChampionshipPlayerInfo.Cmd,m_NAtagMCChampionshipPlayerInfo.SubCmd))] = m_NAtagMCChampionshipPlayerInfo
+
+
+#------------------------------------------------------
 # C1 07 跨服战场玩家信息 #tagMCCrossBattlefieldPlayerInfo
 
 class  tagMCCrossBattlefieldPlayerInfo(Structure):
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GM/Commands/SetMoney.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GM/Commands/SetMoney.py
index 0d933d9..b7666c4 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GM/Commands/SetMoney.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GM/Commands/SetMoney.py
@@ -28,7 +28,7 @@
 moneyNameDict = {
                  1:"仙玉", 2:"绑玉", 3:"铜钱", 6:"战盟贡献度", 10:"战盟仓库积分", 13:"境界修行点", 14:"符印融合石", 15:"仙盟活跃令", 
                  16:"助战积分", 18:"荣誉", 19:"Boss积分", 23:"符印精华", 24:"符印碎片", 25:"寻宝积分", 26:"集市额度", 27:"丹精", 28:"魂尘", 
-                 29:"聚魂碎片", 30:"核心环", 31:"功能特权令", 32:"环保值", 33:"GM令", 34:"古神币"
+                 29:"聚魂碎片", 30:"核心环", 31:"功能特权令", 32:"环保值", 33:"GM令", 34:"古神币", 35:"功德点"
                  }
 
 ## GM命令执行入口
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 e04dbeb..ab5c956 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorldLogic/FBLogic.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorldLogic/FBLogic.py
@@ -518,7 +518,8 @@
             fbFuncLineID = FBCommon.GetCrossDynamicLineMapFuncLineID()
             playerZoneID = curPlayer.NomalDictGetProperty(ChConfig.Def_Player_Dict_ReqCrossFBZoneID)
             playerFuncLineID = curPlayer.NomalDictGetProperty(ChConfig.Def_Player_Dict_ReqCrossFBFuncLine)
-            if fbZoneID != playerZoneID or fbFuncLineID != playerFuncLineID:
+            # 跨服排位分区与玩家分区可能不一样
+            if (fbZoneID != playerZoneID or fbFuncLineID != playerFuncLineID) and mapID not in [ChConfig.Def_FBMapID_CrossChampionship]:
                 GameWorld.ErrLog("DoEnterFB 玩家与当前副本线路所属分区或功能分线不同,踢出玩家!fbZoneID=%s,playerZoneID=%s,fbFuncLineID=%s,playerFuncLineID=%s" 
                                  % (fbZoneID, playerZoneID, fbFuncLineID, playerFuncLineID), curPlayerID)
                 CrossRealmPlayer.PlayerExitCrossServer(curPlayer)
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorldLogic/FBProcess/GameLogic_CrossChampionship.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorldLogic/FBProcess/GameLogic_CrossChampionship.py
new file mode 100644
index 0000000..2871188
--- /dev/null
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorldLogic/FBProcess/GameLogic_CrossChampionship.py
@@ -0,0 +1,581 @@
+#!/usr/bin/python
+# -*- coding: GBK -*-
+#-------------------------------------------------------------------------------
+#
+##@package GameWorldLogic.FBProcess.GameLogic_CrossChampionship
+#
+# @todo:跨服排位争霸赛
+# @author hxp
+# @date 2022-09-21
+# @version 1.0
+#
+# 详细描述: 跨服排位争霸赛
+#
+#-------------------------------------------------------------------------------
+#"""Version = 2022-09-21 21:30"""
+#-------------------------------------------------------------------------------
+
+import ChPlayer
+import GameWorld
+import IPY_GameWorld
+import PlayerControl
+import GameWorldProcess
+import IpyGameDataPY
+import SkillCommon
+import FBCommon
+import ChConfig
+import GameObj
+
+(
+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 OnOpenFB(tick):
+    # 开启副本直接进入等待阶段
+    FBCommon.SetFBStep(FB_State_Waiting, tick)
+    return
+
+## 是否能够通过活动查询进入
+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)
+    
+    if gameFB.GetGameFBDictByKey(GameFBDict_PlayerLeaveTick % playerID):
+        GameWorld.Log("    玩家离线保护时间内上线!", playerID)
+        gameFB.SetGameFBDict(GameFBDict_PlayerLeaveTick % playerID, 0)
+        playerManager = GameWorld.GetMapCopyPlayerManager()
+        for index in xrange(playerManager.GetPlayerCount()):
+            player = playerManager.GetPlayerByIndex(index)
+            if player and player.GetPlayerID() != curPlayer.GetPlayerID():
+                player.Sync_TimeTick(ChConfig.tttPlayerLeave, 0, 0, True)
+                
+    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
+    PlayerControl.SetSight(curPlayer, ChConfig.Def_PlayerSight_Default * 3)
+    
+    # 非战斗阶段,通知动态障碍点
+    if fbStep < FB_State_Fight:
+        FBCommon.SyncDynamicBarrierState(IpyGameDataPY.GetFuncEvalCfg("CrossChamPKFB", 2), 1, curPlayer) # 准备期间有动态障碍点
+        
+    fbTimeList = IpyGameDataPY.GetFuncEvalCfg("CrossChamPKFB", 1)
+    
+    if fbStep == FB_State_Open:
+        pass
+    
+    elif fbStep == FB_State_Waiting:
+        playerIDA = gameFB.GetGameFBDictByKey(GameFBDict_FBPlayerID % 1)
+        playerIDB = gameFB.GetGameFBDictByKey(GameFBDict_FBPlayerID % 2)
+        if not playerIDA and not playerIDB:
+            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)
+            GameWorld.Log("    第一个进入,阵营1,roomID=%s" % (roomID), playerID)
+            __ResetPlayerState(gameFB, curPlayer, playerID)
+            
+        elif 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("    第二个进入,阵营2,roomID=%s" % (roomID), playerID)
+            __ResetPlayerState(gameFB, curPlayer, playerID)
+            
+        playerIDA = gameFB.GetGameFBDictByKey(GameFBDict_FBPlayerID % 1)
+        playerIDB = gameFB.GetGameFBDictByKey(GameFBDict_FBPlayerID % 2)
+        if GameWorld.GetMapCopyPlayerManager().GetPlayerCount() == 2 and playerIDA and playerIDB:
+            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:
+            notify_tick = fbTimeList[Def_Time_MaxWait] * 1000 - (tick - GameWorld.GetGameFB().GetFBStepTick())
+            curPlayer.Sync_TimeTick(ChConfig.tttWaitPlayer, 0, max(notify_tick, 0), True)
+            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())
+    PlayerControl.DelLimitSuperBuff(curPlayer, tick)
+    PlayerControl.PlayerControl(curPlayer).RefreshPlayerAttrState()
+    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))
+    
+    ## 通知对方,对手掉线
+    playerManager = GameWorld.GetMapCopyPlayerManager()
+    for index in xrange(playerManager.GetPlayerCount()):
+        player = playerManager.GetPlayerByIndex(index)
+        if player and player.GetPlayerID() != curPlayer.GetPlayerID():
+            fbTimeList = IpyGameDataPY.GetFuncEvalCfg("CrossChamPKFB", 1)
+            player.Sync_TimeTick(ChConfig.tttPlayerLeave, 0, max(fbTimeList[Def_Time_Protect] * 1000, 0), True)
+            
+    return
+
+##玩家主动离开副本.
+def DoPlayerLeaveFB(curPlayer, tick):
+    gameFB = GameWorld.GetGameFB()
+    fbStep = gameFB.GetFBStep()
+    
+    if fbStep <= FB_State_Waiting or fbStep >= FB_State_Leave:
+        return
+    
+    leavePlayerID = curPlayer.GetPlayerID()
+    roomID = GameWorld.GetGameWorld().GetPropertyID()
+    playerIDA = gameFB.GetGameFBDictByKey(GameFBDict_FBPlayerID % 1)
+    playerIDB = gameFB.GetGameFBDictByKey(GameFBDict_FBPlayerID % 2)
+    
+    loser, loserID = curPlayer, leavePlayerID
+    winnerID = playerIDA if playerIDB == loserID else playerIDB
+    winner = GameWorld.GetMapCopyPlayerManager().FindPlayerByID(winnerID)
+    GameWorld.Log("玩家主动退出,直接算输! roomID=%s,leavePlayerID=%s,loserID=%s,winnerID=%s" % (roomID, leavePlayerID, loserID, winnerID))
+    __DoFBPKAllOver(winner, winnerID, loser, loserID, Def_OverType_PlayerExit, tick)
+    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("CrossChamPKFB", 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("CrossChamPKFB", 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
+    roomID = GameWorld.GetGameWorld().GetPropertyID()
+    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
+        
+        GameWorld.Log("两个人都在线,根据超时规则判断胜负玩家! roomID=%s" % (roomID))
+        playerInfoList = []
+        for playerID in [playerIDA, playerIDB]:
+            player = copyMapPlayerManager.FindPlayerByID(playerID)
+            # 还是离线时间的,走掉线逻辑,越晚掉线的赢;需要加这个逻辑主要是因为当玩家没有触发完整登录流程导致玩家在线但是没有触发DoEnter
+            playerLeaveTick = gameFB.GetGameFBDictByKey(GameFBDict_PlayerLeaveTick % playerID)
+            if playerLeaveTick:
+                pvpDamage, sortTick, curHP, curMaxHP = 0, 0, 0, 0
+                playerInfoList.append([pvpDamage, sortTick, curHP, curMaxHP, playerLeaveTick, playerID, player])
+                GameWorld.Log("PK超时: playerLeaveTick=%s" % (playerLeaveTick), playerID)
+                continue
+            pvpDamage = gameFB.GetPlayerGameFBDictByKey(playerID, FBPDict_PVPDamage)
+            pvpDamTick = gameFB.GetPlayerGameFBDictByKey(playerID, FBPDict_PVPDamUpdTick)
+            sortTick = tick - pvpDamTick
+            curHP = 0 if not player else GameObj.GetHP(player)
+            curMaxHP = 0 if not player else GameObj.GetMaxHP(player)
+            playerInfoList.append([pvpDamage, sortTick, curHP, curMaxHP, playerLeaveTick, playerID, player])
+            GameWorld.Log("PK超时: pvpDamge=%s,pvpDamTick=%s,tick=%s,sortTick=%s,HP=%s/%s,playerLeaveTick=%s" 
+                          % (pvpDamage, pvpDamTick, tick, sortTick, curHP, curMaxHP, playerLeaveTick), 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
+        playerID = player.GetPlayerID()
+        if playerID not in [playerIDA, playerIDB]:
+            GameWorld.ErrLog("副本中玩家不在进入的玩家ID里,不处理! roomID=%s,playerID=%s" % (roomID, playerID))
+            continue
+        winner = player
+        winnerID = player.GetPlayerID()
+        GameWorld.Log("超时结算,玩家在线,直接获胜: roomID=%s,winnerID=%s" % (roomID, winnerID))
+        break
+    
+    if not winner:
+        playerLeaveTickA = gameFB.GetGameFBDictByKey(GameFBDict_PlayerLeaveTick % playerIDA)
+        playerLeaveTickB = gameFB.GetGameFBDictByKey(GameFBDict_PlayerLeaveTick % playerIDB)
+        GameWorld.Log("超时结算,没有玩家在线,后离线的获胜: playerLeaveTickA=%s,playerLeaveTickB=%s" % (playerLeaveTickA, playerLeaveTickB))
+        # 离线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("CrossChamPKFB", 1)
+    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("CrossChamPKFB", 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("CrossChamPKFB", 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("CrossChamPKFB", 1)
+    prepareTime = fbTimeList[Def_Time_MapPrepare] * 1000
+    helpDict["prepareTime"] = prepareTime
+    
+    roundNum = gameFB.GetGameFBDictByKey(FB_RoundNum)
+    winnerID = gameFB.GetGameFBDictByKey(FB_RoundWinPlayerID % roundNum)
+    
+    nextRoundNum = gameFB.GetGameFBDictByKey(FB_RoundNum) + 1
+    gameFB.SetGameFBDict(FB_RoundNum, nextRoundNum)
+    
+    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 GameObj.GetHP(player) <= 0:
+            GameWorld.DebugLog("复活玩家...", player.GetPlayerID())
+            ChPlayer.PlayerRebornByType(player, ChConfig.rebornType_System, tick, isAddSuperBuff=False)
+            __ResetPlayerState(gameFB, player, playerID)
+        elif winnerID and playerID != winnerID:
+            GameWorld.DebugLog("平局,输的玩家回满血!", playerID)
+            __ResetPlayerState(gameFB, player, playerID)         
+        else:
+            __ResetPlayerState(gameFB, player, playerID, False)
+                
+        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("CrossChamPKFB", 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("CrossChamPKFB", 3))
+    if not isOver:
+        if winner:
+            clearDeBuff = False
+            # 胜利者马上清除负面buff,防止死亡导致回合表现异常,如中毒
+            for buffType in [IPY_GameWorld.bfDeBuff, IPY_GameWorld.bfProcessDeBuff, IPY_GameWorld.bfActionBuff]:
+                buffTuple = SkillCommon.GetBuffManagerByBuffType(winner, buffType)
+                if buffTuple:
+                    buffState = buffTuple[0]
+                    buffCount = buffState.GetBuffCount()
+                    if buffCount:
+                        clearDeBuff = True
+                        buffState.Clear()
+                        GameWorld.DebugLog("胜者马上清除 buffType=%s,buffCount=%s" % (buffType, buffCount), winner.GetPlayerID())
+                        
+            if clearDeBuff:
+                PlayerControl.PlayerControl(winner).RefreshAllState()
+                
+        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, resetAttr=True):
+    posX = gameFB.GetPlayerGameFBDictByKey(playerID, FBPDict_ResetPosX)
+    posY = gameFB.GetPlayerGameFBDictByKey(playerID, FBPDict_ResetPosY)
+    player.ResetPos(posX, posY)
+    
+    if not resetAttr:
+        return
+    
+    if GameObj.GetHP(player) != GameObj.GetMaxHP(player):
+        GameObj.SetHP(player, GameObj.GetMaxHP(player))
+        
+    if PlayerControl.GetProDef(player) != PlayerControl.GetMaxProDef(player):
+        PlayerControl.SetProDef(player, PlayerControl.GetMaxProDef(player))
+        
+    SkillCommon.ResetAllSkillCD(player)
+    return
+
+## 跨服PK结束处理,注意 winner、loser 参数可能为None
+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("CrossChamPKFB", 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, "CrossChampionshipPKOver", 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/Player/ChPlayer.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/ChPlayer.py
index 966f1c9..77ed195 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/ChPlayer.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/ChPlayer.py
@@ -73,6 +73,7 @@
 import PlayerGatherSoul
 import PlayerFairyDomain
 import PlayerCrossRealmPK
+import PlayerCrossChampionship
 import PlayerCrossBattlefield
 import GameFuncComm
 import PlayerMagicWeapon
@@ -719,6 +720,7 @@
     
     # 跨服PK
     PlayerCrossRealmPK.DoPlayerLogin(curPlayer)
+    PlayerCrossChampionship.DoPlayerLogin(curPlayer)
     PlayerCrossBattlefield.DoPlayerLogin(curPlayer)
     
     # 幸运云购
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/CrossRealmPlayer.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/CrossRealmPlayer.py
index 532dbf8..04d3991 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/CrossRealmPlayer.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/CrossRealmPlayer.py
@@ -27,6 +27,17 @@
 import FBLogic
 import PlayerAssist
 
+def GetPlayerCrossPropDataShort(curPlayer):
+    ## 获取跨服玩家属性简短信息
+    PropData = {}
+    PropData["AccID"] = curPlayer.GetAccID()
+    PropData["LV"] = curPlayer.GetLV()
+    PropData["RealmLV"] = curPlayer.GetOfficialRank()
+    PropData["Job"] = curPlayer.GetJob()
+    PropData["Name"] = GetCrossPlayerName(curPlayer)
+    PropData["FightPower"] = PlayerControl.GetFightPower(curPlayer)
+    return PropData
+
 # 获取玩家跨服服务器上的名字
 def GetCrossPlayerName(curPlayer):
     # 通过游戏账号中的平台标志获取名称,目前为spid
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerCrossChampionship.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerCrossChampionship.py
new file mode 100644
index 0000000..186191b
--- /dev/null
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerCrossChampionship.py
@@ -0,0 +1,240 @@
+#!/usr/bin/python
+# -*- coding: GBK -*-
+#-------------------------------------------------------------------------------
+#
+##@package Player.PlayerCrossChampionship
+#
+# @todo:跨服排位争霸赛
+# @author hxp
+# @date 2022-09-21
+# @version 1.0
+#
+# 详细描述: 跨服排位争霸赛
+#
+#-------------------------------------------------------------------------------
+#"""Version = 2022-09-21 21:30"""
+#-------------------------------------------------------------------------------
+
+import GameWorld
+import ShareDefine
+import PlayerControl
+import CrossRealmPlayer
+import ChPyNetSendPack
+import NetPackCommon
+import IpyGameDataPY
+import ChConfig
+
+import random
+import time
+
+
+def DoPlayerLogin(curPlayer):
+    if curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_Championship_WorshipCount):
+        Sync_ChampionshipPlayerInfo(curPlayer)
+    return
+
+def DoPlayerOnDay(curPlayer):
+    if curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_Championship_WorshipCount):
+        PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_Championship_WorshipCount, 0)
+        Sync_ChampionshipPlayerInfo(curPlayer)        
+    return
+
+#// C1 20 跨服排位仙官申请 #tagCMChampionshipOfficialApply
+#
+#struct    tagCMChampionshipOfficialApply
+#{
+#    tagHead        Head;
+#    BYTE        ZoneID;        //仙官数据分区ID
+#    WORD        MainOfficialID;    //界主官职ID
+#    WORD        OfficialID;    //申请官职ID
+#};
+def OnChampionshipOfficialApply(index, clientData, tick):
+    if GameWorld.IsCrossServer():
+        return
+    
+    curPlayer = GameWorld.GetPlayerManager().GetPlayerByIndex(index)
+    playerID = curPlayer.GetPlayerID()
+    
+    zoneID = clientData.ZoneID
+    mainOfficialID = clientData.MainOfficialID
+    officialID = clientData.OfficialID
+    
+    realmLV = curPlayer.GetOfficialRank()
+    needRealmLV = IpyGameDataPY.GetFuncCfg("CrossChamOfficial", 3)
+    if realmLV < needRealmLV:
+        GameWorld.DebugLog("所需境界不足,无法申请仙官! realmLV(%s) < %s" % (realmLV, needRealmLV), playerID)
+        return
+    
+    # 发送跨服服务器
+    dataMsg = {"zoneID":zoneID, "mainOfficialID":mainOfficialID, "officialID":officialID,
+               "playerID":playerID, "PropData":CrossRealmPlayer.GetPlayerCrossPropDataShort(curPlayer)}
+    GameWorld.SendMsgToCrossServer(ShareDefine.ClientServerMsg_ChampionshipOfficialApply, dataMsg)
+    return
+
+
+#// C1 21 跨服排位仙官挑战 #tagCMChampionshipOfficialChallenge
+#
+#struct    tagCMChampionshipOfficialChallenge
+#{
+#    tagHead        Head;
+#    BYTE        ZoneID;        //仙官数据分区ID
+#    WORD        MainOfficialID;    //界主官职ID
+#    WORD        OfficialID;    //挑战的目标官职ID
+#    DWORD        PlayerID;        //挑战时的目标玩家ID
+#};
+def OnChampionshipOfficialChallenge(index, clientData, tick):
+    if GameWorld.IsCrossServer():
+        return
+    
+    curPlayer = GameWorld.GetPlayerManager().GetPlayerByIndex(index)
+    playerID = curPlayer.GetPlayerID()
+    
+    zoneID = clientData.ZoneID
+    mainOfficialID = clientData.MainOfficialID
+    officialID = clientData.OfficialID
+    tagPlayerID = clientData.PlayerID
+    
+    realmLV = curPlayer.GetOfficialRank()
+    needRealmLV = IpyGameDataPY.GetFuncCfg("CrossChamOfficial", 3)
+    if realmLV < needRealmLV:
+        GameWorld.DebugLog("所需境界不足,无法挑战仙官! realmLV(%s) < %s" % (realmLV, needRealmLV), playerID)
+        return
+    
+    # 发送跨服服务器
+    dataMsg = {"zoneID":zoneID, "mainOfficialID":mainOfficialID, "officialID":officialID,
+               "playerID":playerID, "tagPlayerID":tagPlayerID, "PropData":CrossRealmPlayer.GetPlayerCrossPropDataShort(curPlayer)}
+    GameWorld.SendMsgToCrossServer(ShareDefine.ClientServerMsg_ChampionshipOfficialChallenge, dataMsg)
+    return
+
+
+#// C1 22 跨服排位竞猜 #tagCMChampionshipGuess
+#
+#struct    tagCMChampionshipGuess
+#{
+#    tagHead        Head;
+#    BYTE        ZoneID;        //排位数据分区ID
+#    BYTE        GuessType;    //竞猜类型 8-8强;4-4强排位
+#    DWORD        PlayerID;        //目标玩家ID
+#    BYTE        GuessCount;    //投注/追加份数
+#    BYTE        GuessRank;    // 竞猜名次,没有名次的竞猜默认0;1-代表第一名
+#};
+def OnChampionshipGuess(index, clientData, tick):
+    if GameWorld.IsCrossServer():
+        return
+    
+    curPlayer = GameWorld.GetPlayerManager().GetPlayerByIndex(index)
+    playerID = curPlayer.GetPlayerID()
+    zoneID = clientData.ZoneID
+    guessType = clientData.GuessType
+    tagPlayerID = clientData.PlayerID
+    guessCount = clientData.GuessCount
+    guessRank = clientData.GuessRank
+    
+    moneyType, moneyValue = IpyGameDataPY.GetFuncEvalCfg("CrossChamGuess", 1)
+    guessMoney = moneyValue * guessCount
+    if guessMoney <= 0:
+        return
+    
+    if not PlayerControl.HaveMoney(curPlayer, moneyType, guessMoney):
+        return
+    
+    if not GameWorld.SetPlayerTickTime(curPlayer, ChConfig.TYPE_Player_Tick_Championship, tick):
+        PlayerControl.NotifyCode(curPlayer, "RequestLater")
+        return
+    
+    # 发送跨服服务器
+    dataMsg = {"zoneID":zoneID, "guessType":guessType, "playerID":playerID, "tagPlayerID":tagPlayerID,
+               "guessRank":guessRank, "guessMoney":guessMoney, "moneyType":moneyType, "exDataType":"ChampionshipGuess"}
+    GameWorld.SendMsgToCrossServer(ShareDefine.ClientServerMsg_ChampionshipGuess, dataMsg)
+    return
+
+
+#// C1 23 跨服排位膜拜 #tagCMChampionshipWorship
+#
+#struct    tagCMChampionshipWorship
+#{
+#    tagHead        Head;
+#    BYTE        ZoneID;        //仙官数据分区ID
+#    DWORD        PlayerID;        //目标玩家ID
+#};
+def OnChampionshipWorship(index, clientData, tick):
+    if GameWorld.IsCrossServer():
+        return
+    
+    curPlayer = GameWorld.GetPlayerManager().GetPlayerByIndex(index)
+    playerID = curPlayer.GetPlayerID()
+    zoneID = clientData.ZoneID
+    tagPlayerID = clientData.PlayerID
+    
+    worshipCountMax = IpyGameDataPY.GetFuncCfg("CrossChamWorship", 1)
+    if worshipCountMax:
+        worshipCountToday = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_Championship_WorshipCount)
+        if worshipCountToday >= worshipCountMax:
+            GameWorld.DebugLog("膜拜次数不足! worshipCountToday=%s >= %s" % (worshipCountToday, worshipCountMax), curPlayer.GetPlayerID())
+            return False
+        
+    if not GameWorld.SetPlayerTickTime(curPlayer, ChConfig.TYPE_Player_Tick_Championship, tick):
+        PlayerControl.NotifyCode(curPlayer, "RequestLater")
+        return
+    
+    # 发送跨服服务器
+    dataMsg = {"zoneID":zoneID, "playerID":playerID, "tagPlayerID":tagPlayerID, "exDataType":"OfficialWorship", "WorshipTime":int(time.time())}
+    GameWorld.SendMsgToCrossServer(ShareDefine.ClientServerMsg_ChampionshipWorship, dataMsg)
+    return
+
+def GameServer_Championship(curPlayer, msgData):
+    
+    playerID = curPlayer.GetPlayerID()
+    
+    msgType = msgData[0]
+    if msgType == "ChampionshipGuess":
+        dataMsg = msgData[1]
+        if not isinstance(dataMsg, dict) or "moneyType" not in dataMsg:
+            return
+        moneyType = dataMsg["moneyType"]
+        guessMoney = dataMsg["guessMoney"]
+        infoDict = dataMsg
+        PlayerControl.PayMoney(curPlayer, moneyType, guessMoney, msgType, infoDict)
+        
+    elif msgType == "OfficialWorship":
+        dataMsg = msgData[1]
+        worshipTime = dataMsg["WorshipTime"]
+        worshipDouble = dataMsg.get("worshipDouble", 0)
+        if GameWorld.CheckTimeIsSameServerDayEx(worshipTime):
+            worshipCountToday = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_Championship_WorshipCount) + 1
+            PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_Championship_WorshipCount, worshipCountToday)
+            GameWorld.DebugLog("更新膜拜次数! worshipCountToday=%s" % worshipCountToday, playerID)
+            Sync_ChampionshipPlayerInfo(curPlayer)
+            
+        gongdePointRange = IpyGameDataPY.GetFuncEvalCfg("CrossChamWorship", 2) # 随机奖励功德点范围
+        if len(gongdePointRange) != 2:
+            return
+        gongdePoint = random.randint(gongdePointRange[0], gongdePointRange[1])
+        GameWorld.DebugLog("膜拜随机功德点: gongdePoint=%s" % gongdePoint, playerID)
+        doubleHMList = IpyGameDataPY.GetFuncEvalCfg("CrossChamWorship", 3) # 双倍膜拜时间范围
+        if worshipDouble and len(doubleHMList) == 2:
+            fromHour, fromMinute = doubleHMList[0]
+            toHour, toMinute = doubleHMList[1]
+            serverTime = GameWorld.GetCurrentTime()
+            curHour, curMinute = serverTime.hour, serverTime.minute
+            fromValue = fromHour * 100 + fromMinute
+            toValue = toHour * 100 + toMinute
+            curValue = curHour * 100 + curMinute
+            if fromValue <= curValue <= toValue:
+                gongdePoint *= 2
+                GameWorld.DebugLog("膜拜双倍功德点: gongdePoint=%s" % gongdePoint, playerID)
+            else:
+                GameWorld.DebugLog("非双倍膜拜期间: doubleHM(%s~%s), curHM=%s" % (fromValue, toValue, curValue), playerID)
+        
+        if gongdePoint:
+            PlayerControl.GiveMoney(curPlayer, ShareDefine.TYPE_Price_GuShenMoney, gongdePoint, "OfficialWorship")
+            
+    return
+
+def Sync_ChampionshipPlayerInfo(curPlayer):
+    clientPack = ChPyNetSendPack.tagMCChampionshipPlayerInfo()
+    clientPack.WorshipCount = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_Championship_WorshipCount)
+    NetPackCommon.SendFakePack(curPlayer, clientPack)
+    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 60852d6..1254f42 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerEventCounter.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerEventCounter.py
@@ -61,6 +61,7 @@
 import PlayerGoldInvest
 import PlayerNewGuyCard
 import PlayerCrossRealmPK
+import PlayerCrossChampionship
 import PlayerCrossBattlefield
 import PlayerPet
 import BossHurtMng
@@ -577,6 +578,8 @@
         FBHelpBattle.DoPlayerOnDay(curPlayer)
         #跨服竞技场
         PlayerCrossRealmPK.DoPlayerOnDay(curPlayer)
+        #跨服排位
+        PlayerCrossChampionship.DoPlayerOnDay(curPlayer)
         #跨服战场
         PlayerCrossBattlefield.DoPlayerOnDay(curPlayer)
         #缥缈仙域
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/RemoteQuery/GY_Query_Championship.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/RemoteQuery/GY_Query_Championship.py
new file mode 100644
index 0000000..85d3dfc
--- /dev/null
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/RemoteQuery/GY_Query_Championship.py
@@ -0,0 +1,51 @@
+#!/usr/bin/python
+# -*- coding: GBK -*-
+#-------------------------------------------------------------------------------
+#
+##@package Player.RemoteQuery.GY_Query_Championship
+#
+# @todo:跨服排位
+# @author hxp
+# @date 2022-09-21
+# @version 1.0
+#
+# 详细描述: 跨服排位
+#
+#-------------------------------------------------------------------------------
+#"""Version = 2022-09-21 21:30"""
+#-------------------------------------------------------------------------------
+
+import GameWorld
+import PlayerCrossChampionship
+import ChConfig
+
+#------------------------------------------------------------------------------ 
+## 跨服赛报名调用接口
+#  @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):
+    curPlayer.SetTickByType(ChConfig.TYPE_Player_Tick_Championship, 0)
+    msgData = eval(funResult)
+    playerID = curPlayer.GetPlayerID()
+    GameWorld.Log("GY_Query_Championship msgData=%s" % (msgData), playerID)
+    PlayerCrossChampionship.GameServer_Championship(curPlayer, msgData)
+    return
+    
+    
+    
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/RemoteQuery/GY_Query_OpenFBEx.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/RemoteQuery/GY_Query_OpenFBEx.py
new file mode 100644
index 0000000..b330dbe
--- /dev/null
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/RemoteQuery/GY_Query_OpenFBEx.py
@@ -0,0 +1,71 @@
+#!/usr/bin/python
+# -*- coding: GBK -*-
+#-------------------------------------------------------------------------------
+#
+##@package Player.RemoteQuery.GY_Query_OpenFBEx
+#
+# @todo:开启副本线路
+# @author hxp
+# @date 2022-09-21
+# @version 1.0
+#
+# 详细描述: 开启副本线路
+#
+#-------------------------------------------------------------------------------
+#"""Version = 2022-09-21 21:30"""
+#-------------------------------------------------------------------------------
+
+import GameWorld
+import IPY_GameWorld
+
+#逻辑实现
+## 请求逻辑
+#  @param query_Type 请求类型
+#  @param query_ID 请求的玩家ID
+#  @param paramList 发包命令
+#  @param tick 当前时间
+#  @return "True" or "False" or ""
+#  @remarks 函数详细说明.
+def DoLogic(query_Type, query_ID, paramList, tick):
+    
+    gameWorldManager = GameWorld.GetGameWorld()
+    maxCopyCount = gameWorldManager.GetGameWorldCount()
+    GameWorld.Log("GY_Query_OpenFBEx! maxCopyCount=%s, paramList=%s" % (maxCopyCount, paramList))
+    
+    for copyMapID, propertyID in paramList:
+        if copyMapID >= maxCopyCount:
+            GameWorld.ErrLog("GY_Query_OpenFBEx 虚拟分线不存在! copyMapID=%s, propertyID=%s, maxCopyCount=%s" 
+                             % (copyMapID, propertyID, maxCopyCount))
+            continue
+        
+        tagGameWorld = IPY_GameWorld.IPY_GameWorld(copyMapID)
+        if tagGameWorld.GetOpenState() != IPY_GameWorld.fbosClosed:
+            GameWorld.ErrLog("GY_Query_OpenFBEx 虚拟分线已经是开启状态! copyMapID=%s, propertyID=%s, GetPropertyID=%s" 
+                             % (copyMapID, propertyID, tagGameWorld.GetPropertyID()))
+            continue
+        
+        if tagGameWorld.GetFBFirstOpen():
+            GameWorld.ErrLog("GY_Query_OpenFBEx 虚拟分线已经在开启中! copyMapID=%s, propertyID=%s, GetPropertyID=%s" 
+                             % (copyMapID, propertyID, tagGameWorld.GetPropertyID()))
+            continue
+        
+        GameWorld.Log("GY_Query_OpenFBEx copyMapID=%s, propertyID=%s" % (copyMapID, propertyID))
+        tagGameWorld.SetFBFirstOpen(1) # 开启副本
+        tagGameWorld.SetPropertyID(propertyID)
+        
+    return ''
+
+                
+#---------------------------------------------------------------------
+#执行结果
+## 执行结果
+#  @param curPlayer 发出请求的玩家
+#  @param callFunName 功能名称
+#  @param funResult 查询的结果
+#  @param tick 当前时间
+#  @return None
+#  @remarks 函数详细说明.
+def DoResult(curPlayer, callFunName, funResult, tick):
+    return
+
+

--
Gitblit v1.8.0