From 84ede803777ff10b5cbe93b1ec0168af08f55d5e Mon Sep 17 00:00:00 2001
From: hxp <ale99527@vip.qq.com>
Date: 星期三, 13 一月 2021 18:11:26 +0800
Subject: [PATCH] 8677 【BT】【后端】跨服冲榜活动; 新增跨服活动时间管理模块、跨服榜单;跨服邮件;跨服广播优化;相关GM命令、后台工具;

---
 ServerPython/CoreServerGroup/GameServer/Script/IpyGameDataPY.py                                    |   73 +
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/CrossActCTGBillboard.py |  288 ++++
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetPack.py                 |   60 
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetSendPack.py             |  669 +++++++++
 ServerPython/CoreServerGroup/GameServer/Script/GM/GMShell.py                                       |   25 
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerBillboard.py      |   34 
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/PyGameData.py                  |    3 
 ServerPython/CoreServerGroup/GameServer/Script/ChPyNetPack.py                                      |   60 
 ServerPython/CoreServerGroup/GameServer/Script/ChPyNetSendPack.py                                  |  669 +++++++++
 ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerDBGSEvent.py                           |    2 
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/IpyGameDataPY.py               |   55 
 ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/CrossActionControl.py                |  523 +++++++
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/ChPlayer.py             |    6 
 PySysDB/PySysDBPY.h                                                                                |   21 
 ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/CrossActCTGBillboard.py              |  100 +
 ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerCompensation.py                        |  232 +++
 ServerPython/CoreServerGroup/GameServer/PyNetPack.ini                                              |   11 
 ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerControl.py                             |   37 
 ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/GameWorldActionControl.py            |    3 
 ServerPython/CoreServerGroup/GameServer/Script/PyGameDataStruct.py                                 |  251 +++
 ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerQuery.py                               |    5 
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/CrossRealmPlayer.py     |   37 
 ServerPython/CoreServerGroup/GameServer/Script/GM/Commands/BillboardDataCross.py                   |  107 +
 ServerPython/CoreServerGroup/GameServer/Script/PyDataManager.py                                    |   18 
 ServerPython/CoreServerGroup/GameServer/Script/GM/Commands/GMT_CrossActServerIDChange.py           |  170 ++
 ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/CrossRealmMsg.py                     |   27 
 ServerPython/CoreServerGroup/GameServer/Script/GM/Commands/GMT_QueryBillboardCross.py              |   88 +
 ServerPython/CoreServerGroup/GameServer/Script/PyGameData.py                                       |    4 
 ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/CrossBillboard.py                    |  552 +++++++
 PySysDB/PySysDBG.h                                                                                 |   27 
 30 files changed, 4,131 insertions(+), 26 deletions(-)

diff --git a/PySysDB/PySysDBG.h b/PySysDB/PySysDBG.h
index 2192bf8..66f15ab 100644
--- a/PySysDB/PySysDBG.h
+++ b/PySysDB/PySysDBG.h
@@ -757,6 +757,33 @@
 	WORD		LVLimit;	//限制等级
 };
 
+//跨服充值排行活动时间表
+
+struct tagCrossActCTGBillboard
+{
+	DWORD		_CfgID;	//配置ID
+	char		ActGroupName;	//活动组名(同组活动的名字需相同)
+	list		ServerIDRangeList;	//活动的账号服务器ID范围列表 [[serverIDA, serverIDB], ...]
+	char		StartDate;	//开启日期
+	char		EndDate;	//结束日期
+	dict		NotifyInfoStart;	//全服提示信息 - 相对开始时间
+	dict		NotifyInfoEnd;	//全服提示信息 - 相对结束时间
+	list		NotifyInfoLoop;	//全服提示信息 - 循环广播[循环分钟, 广播key, [广播参数列表可选]]
+	BYTE		IsDayReset;	//是否每天重置
+	list		TemplateIDList;	//模板ID列表
+};
+
+//跨服充值排行模板名次奖励表
+
+struct tagCrossActCTGBillboardOrder
+{
+	DWORD		_TemplateID;	//模板ID
+	WORD		OrderA;	//名次A
+	WORD		OrderB;	//至名次B
+	DWORD		CTGAtleast;	//至少充值RMB
+	list		AwardItemList;	//奖励物品列表[[物品ID,个数,是否拍品], ...]
+};
+
 //装备升星表
 
 struct tagEquipStarUp
diff --git a/PySysDB/PySysDBPY.h b/PySysDB/PySysDBPY.h
index d2b8d44..41ecc05 100644
--- a/PySysDB/PySysDBPY.h
+++ b/PySysDB/PySysDBPY.h
@@ -1930,6 +1930,27 @@
 	DWORD		Weight;	//权重
 };
 
+//跨服充值排行模板达标奖励表
+
+struct tagCrossActCTGBillboardDabiao
+{
+	DWORD		_TemplateID;	//模板ID
+	DWORD		CTGNeed;	//需充值RMB
+	BYTE		AwardIndex;	//奖励记录索引,从0开始,同个模板不可重复,不可变更
+	list		AwardItemList;	//奖励物品列表[[物品ID,个数,是否拍品], ...]
+};
+
+//跨服充值排行模板名次奖励表
+
+struct tagCrossActCTGBillboardOrder
+{
+	DWORD		_TemplateID;	//模板ID
+	WORD		OrderA;	//名次A
+	WORD		OrderB;	//至名次B
+	DWORD		CTGAtleast;	//至少充值RMB
+	list		AwardItemList;	//奖励物品列表[[物品ID,个数,是否拍品], ...]
+};
+
 //神秘商店表
 
 struct tagMysteryShop
diff --git a/ServerPython/CoreServerGroup/GameServer/PyNetPack.ini b/ServerPython/CoreServerGroup/GameServer/PyNetPack.ini
index 9fa7b62..f1fae7f 100644
--- a/ServerPython/CoreServerGroup/GameServer/PyNetPack.ini
+++ b/ServerPython/CoreServerGroup/GameServer/PyNetPack.ini
@@ -386,6 +386,17 @@
 PacketSubCMD_2=0x03
 PacketCallFunc_2=OnForceQuitCrossState
 
+[CrossBillboard]
+ScriptName = GameWorldLogic\CrossBillboard.py
+Writer = hxp
+Releaser = hxp
+RegType = 0
+RegisterPackCount = 1
+
+PacketCMD_1=0xC0
+PacketSubCMD_1=0x04
+PacketCallFunc_1=OnViewCrossBillboard
+
 [PlayerXMZZ]
 ScriptName = Player\PlayerXMZZ.py
 Writer = xdh
diff --git a/ServerPython/CoreServerGroup/GameServer/Script/ChPyNetPack.py b/ServerPython/CoreServerGroup/GameServer/Script/ChPyNetPack.py
index 734ef0f..1282455 100644
--- a/ServerPython/CoreServerGroup/GameServer/Script/ChPyNetPack.py
+++ b/ServerPython/CoreServerGroup/GameServer/Script/ChPyNetPack.py
@@ -3767,6 +3767,66 @@
 
 
 #------------------------------------------------------
+# C0 04 查看跨服排行榜 #tagCGViewCrossBillboard
+
+class  tagCGViewCrossBillboard(Structure):
+    _pack_ = 1
+    _fields_ = [
+                  ("Cmd", c_ubyte),
+                  ("SubCmd", c_ubyte),
+                  ("Type", c_ubyte),    #榜单类型
+                  ("GroupValue1", c_ubyte),    # 分组值1
+                  ("GroupValue2", c_ubyte),    # 分组值2,与分组值1组合归为同组榜单数据
+                  ]
+
+    def __init__(self):
+        self.Clear()
+        self.Cmd = 0xC0
+        self.SubCmd = 0x04
+        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 = 0x04
+        self.Type = 0
+        self.GroupValue1 = 0
+        self.GroupValue2 = 0
+        return
+
+    def GetLength(self):
+        return sizeof(tagCGViewCrossBillboard)
+
+    def GetBuffer(self):
+        return string_at(addressof(self), self.GetLength())
+
+    def OutputString(self):
+        DumpString = '''// C0 04 查看跨服排行榜 //tagCGViewCrossBillboard:
+                                Cmd:%s,
+                                SubCmd:%s,
+                                Type:%d,
+                                GroupValue1:%d,
+                                GroupValue2:%d
+                                '''\
+                                %(
+                                self.Cmd,
+                                self.SubCmd,
+                                self.Type,
+                                self.GroupValue1,
+                                self.GroupValue2
+                                )
+        return DumpString
+
+
+m_NAtagCGViewCrossBillboard=tagCGViewCrossBillboard()
+ChNetPackDict[eval("0x%02x%02x"%(m_NAtagCGViewCrossBillboard.Cmd,m_NAtagCGViewCrossBillboard.SubCmd))] = m_NAtagCGViewCrossBillboard
+
+
+#------------------------------------------------------
 # C0 01 查看跨服竞技场赛季排行榜 #tagCGViewCrossPKBillboard
 
 class  tagCGViewCrossPKBillboard(Structure):
diff --git a/ServerPython/CoreServerGroup/GameServer/Script/ChPyNetSendPack.py b/ServerPython/CoreServerGroup/GameServer/Script/ChPyNetSendPack.py
index 054a382..f873f17 100644
--- a/ServerPython/CoreServerGroup/GameServer/Script/ChPyNetSendPack.py
+++ b/ServerPython/CoreServerGroup/GameServer/Script/ChPyNetSendPack.py
@@ -5067,6 +5067,70 @@
 
 
 #------------------------------------------------------
+# AC 12 跨服运营活动结束 # tagGCCrossActEnd
+
+class  tagGCCrossActEnd(Structure):
+    Head = tagHead()
+    ActNameLen = 0    #(BYTE ActNameLen)
+    ActName = ""    #(String ActName)
+    data = None
+
+    def __init__(self):
+        self.Clear()
+        self.Head.Cmd = 0xAC
+        self.Head.SubCmd = 0x12
+        return
+
+    def ReadData(self, _lpData, _pos=0, _Len=0):
+        self.Clear()
+        _pos = self.Head.ReadData(_lpData, _pos)
+        self.ActNameLen,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        self.ActName,_pos = CommFunc.ReadString(_lpData, _pos,self.ActNameLen)
+        return _pos
+
+    def Clear(self):
+        self.Head = tagHead()
+        self.Head.Clear()
+        self.Head.Cmd = 0xAC
+        self.Head.SubCmd = 0x12
+        self.ActNameLen = 0
+        self.ActName = ""
+        return
+
+    def GetLength(self):
+        length = 0
+        length += self.Head.GetLength()
+        length += 1
+        length += len(self.ActName)
+
+        return length
+
+    def GetBuffer(self):
+        data = ''
+        data = CommFunc.WriteString(data, self.Head.GetLength(), self.Head.GetBuffer())
+        data = CommFunc.WriteBYTE(data, self.ActNameLen)
+        data = CommFunc.WriteString(data, self.ActNameLen, self.ActName)
+        return data
+
+    def OutputString(self):
+        DumpString = '''
+                                Head:%s,
+                                ActNameLen:%d,
+                                ActName:%s
+                                '''\
+                                %(
+                                self.Head.OutputString(),
+                                self.ActNameLen,
+                                self.ActName
+                                )
+        return DumpString
+
+
+m_NAtagGCCrossActEnd=tagGCCrossActEnd()
+ChNetPackDict[eval("0x%02x%02x"%(m_NAtagGCCrossActEnd.Head.Cmd,m_NAtagGCCrossActEnd.Head.SubCmd))] = m_NAtagGCCrossActEnd
+
+
+#------------------------------------------------------
 # AC 09 仙界盛典活动信息 #tagGCFairyCeremonyInfo
 
 class  tagGCFairyCeremonyInfo(Structure):
@@ -11037,6 +11101,190 @@
 
 m_NAtagGCTeamMemFuncDataList=tagGCTeamMemFuncDataList()
 ChNetPackDict[eval("0x%02x%02x"%(m_NAtagGCTeamMemFuncDataList.Head.Cmd,m_NAtagGCTeamMemFuncDataList.Head.SubCmd))] = m_NAtagGCTeamMemFuncDataList
+
+
+#------------------------------------------------------
+# C0 07 跨服排行榜信息 #tagGCCrossBillboardInfo
+
+class  tagGCCrossBillboardData(Structure):
+    ID = 0    #(DWORD ID)
+    Name1 = ""    #(char Name1[33])//名字1,用来显示排序对象名字 
+    Name2 = ""    #(char Name2[33])//名字2
+    Type2 = 0    #(BYTE Type2)//附加类型,用来表示排序对象的类型,比如,玩家所属职业门派,宠物类型等
+    Value1 = 0    #(DWORD Value1)//自定义值1
+    Value2 = 0    #(DWORD Value2)//自定义值2
+    CmpValue = 0    #(DWORD CmpValue)// 比较权值
+    CmpValue2 = 0    #(DWORD CmpValue2)// 比较权值
+    CmpValue3 = 0    #(DWORD CmpValue3)// 比较权值
+    data = None
+
+    def __init__(self):
+        self.Clear()
+        return
+
+    def ReadData(self, _lpData, _pos=0, _Len=0):
+        self.Clear()
+        self.ID,_pos = CommFunc.ReadDWORD(_lpData, _pos)
+        self.Name1,_pos = CommFunc.ReadString(_lpData, _pos,33)
+        self.Name2,_pos = CommFunc.ReadString(_lpData, _pos,33)
+        self.Type2,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        self.Value1,_pos = CommFunc.ReadDWORD(_lpData, _pos)
+        self.Value2,_pos = CommFunc.ReadDWORD(_lpData, _pos)
+        self.CmpValue,_pos = CommFunc.ReadDWORD(_lpData, _pos)
+        self.CmpValue2,_pos = CommFunc.ReadDWORD(_lpData, _pos)
+        self.CmpValue3,_pos = CommFunc.ReadDWORD(_lpData, _pos)
+        return _pos
+
+    def Clear(self):
+        self.ID = 0
+        self.Name1 = ""
+        self.Name2 = ""
+        self.Type2 = 0
+        self.Value1 = 0
+        self.Value2 = 0
+        self.CmpValue = 0
+        self.CmpValue2 = 0
+        self.CmpValue3 = 0
+        return
+
+    def GetLength(self):
+        length = 0
+        length += 4
+        length += 33
+        length += 33
+        length += 1
+        length += 4
+        length += 4
+        length += 4
+        length += 4
+        length += 4
+
+        return length
+
+    def GetBuffer(self):
+        data = ''
+        data = CommFunc.WriteDWORD(data, self.ID)
+        data = CommFunc.WriteString(data, 33, self.Name1)
+        data = CommFunc.WriteString(data, 33, self.Name2)
+        data = CommFunc.WriteBYTE(data, self.Type2)
+        data = CommFunc.WriteDWORD(data, self.Value1)
+        data = CommFunc.WriteDWORD(data, self.Value2)
+        data = CommFunc.WriteDWORD(data, self.CmpValue)
+        data = CommFunc.WriteDWORD(data, self.CmpValue2)
+        data = CommFunc.WriteDWORD(data, self.CmpValue3)
+        return data
+
+    def OutputString(self):
+        DumpString = '''
+                                ID:%d,
+                                Name1:%s,
+                                Name2:%s,
+                                Type2:%d,
+                                Value1:%d,
+                                Value2:%d,
+                                CmpValue:%d,
+                                CmpValue2:%d,
+                                CmpValue3:%d
+                                '''\
+                                %(
+                                self.ID,
+                                self.Name1,
+                                self.Name2,
+                                self.Type2,
+                                self.Value1,
+                                self.Value2,
+                                self.CmpValue,
+                                self.CmpValue2,
+                                self.CmpValue3
+                                )
+        return DumpString
+
+
+class  tagGCCrossBillboardInfo(Structure):
+    Head = tagHead()
+    Type = 0    #(BYTE Type)//榜单类型
+    GroupValue1 = 0    #(BYTE GroupValue1)// 分组值1
+    GroupValue2 = 0    #(BYTE GroupValue2)// 分组值2,与分组值1组合归为同组榜单数据
+    BillboardCount = 0    #(BYTE BillboardCount)
+    CrossBillboardDataList = list()    #(vector<tagGCCrossBillboardData> CrossBillboardDataList)
+    data = None
+
+    def __init__(self):
+        self.Clear()
+        self.Head.Cmd = 0xC0
+        self.Head.SubCmd = 0x07
+        return
+
+    def ReadData(self, _lpData, _pos=0, _Len=0):
+        self.Clear()
+        _pos = self.Head.ReadData(_lpData, _pos)
+        self.Type,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        self.GroupValue1,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        self.GroupValue2,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        self.BillboardCount,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        for i in range(self.BillboardCount):
+            temCrossBillboardDataList = tagGCCrossBillboardData()
+            _pos = temCrossBillboardDataList.ReadData(_lpData, _pos)
+            self.CrossBillboardDataList.append(temCrossBillboardDataList)
+        return _pos
+
+    def Clear(self):
+        self.Head = tagHead()
+        self.Head.Clear()
+        self.Head.Cmd = 0xC0
+        self.Head.SubCmd = 0x07
+        self.Type = 0
+        self.GroupValue1 = 0
+        self.GroupValue2 = 0
+        self.BillboardCount = 0
+        self.CrossBillboardDataList = list()
+        return
+
+    def GetLength(self):
+        length = 0
+        length += self.Head.GetLength()
+        length += 1
+        length += 1
+        length += 1
+        length += 1
+        for i in range(self.BillboardCount):
+            length += self.CrossBillboardDataList[i].GetLength()
+
+        return length
+
+    def GetBuffer(self):
+        data = ''
+        data = CommFunc.WriteString(data, self.Head.GetLength(), self.Head.GetBuffer())
+        data = CommFunc.WriteBYTE(data, self.Type)
+        data = CommFunc.WriteBYTE(data, self.GroupValue1)
+        data = CommFunc.WriteBYTE(data, self.GroupValue2)
+        data = CommFunc.WriteBYTE(data, self.BillboardCount)
+        for i in range(self.BillboardCount):
+            data = CommFunc.WriteString(data, self.CrossBillboardDataList[i].GetLength(), self.CrossBillboardDataList[i].GetBuffer())
+        return data
+
+    def OutputString(self):
+        DumpString = '''
+                                Head:%s,
+                                Type:%d,
+                                GroupValue1:%d,
+                                GroupValue2:%d,
+                                BillboardCount:%d,
+                                CrossBillboardDataList:%s
+                                '''\
+                                %(
+                                self.Head.OutputString(),
+                                self.Type,
+                                self.GroupValue1,
+                                self.GroupValue2,
+                                self.BillboardCount,
+                                "..."
+                                )
+        return DumpString
+
+
+m_NAtagGCCrossBillboardInfo=tagGCCrossBillboardInfo()
+ChNetPackDict[eval("0x%02x%02x"%(m_NAtagGCCrossBillboardInfo.Head.Cmd,m_NAtagGCCrossBillboardInfo.Head.SubCmd))] = m_NAtagGCCrossBillboardInfo
 
 
 #------------------------------------------------------
@@ -25809,6 +26057,427 @@
 
 
 #------------------------------------------------------
+# AA 32 跨服充值排行活动信息 #tagMCCACTGBillboardInfo
+
+class  tagMCCACTGBillboardAwardItem(Structure):
+    _pack_ = 1
+    _fields_ = [
+                  ("ItemID", c_int),    
+                  ("ItemCount", c_ushort),    
+                  ("IsBind", c_ubyte),    # 是否拍品
+                  ]
+
+    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.ItemID = 0
+        self.ItemCount = 0
+        self.IsBind = 0
+        return
+
+    def GetLength(self):
+        return sizeof(tagMCCACTGBillboardAwardItem)
+
+    def GetBuffer(self):
+        return string_at(addressof(self), self.GetLength())
+
+    def OutputString(self):
+        DumpString = '''// AA 32 跨服充值排行活动信息 //tagMCCACTGBillboardInfo:
+                                ItemID:%d,
+                                ItemCount:%d,
+                                IsBind:%d
+                                '''\
+                                %(
+                                self.ItemID,
+                                self.ItemCount,
+                                self.IsBind
+                                )
+        return DumpString
+
+
+class  tagMCCACTGBillboardDabiao(Structure):
+    AwardIndex = 0    #(BYTE AwardIndex)// 奖励索引 0~31
+    NeedRMB = 0    #(DWORD NeedRMB)// 所需充值RMB
+    AwardItemCount = 0    #(BYTE AwardItemCount)// 奖励物品数
+    AwardItemList = list()    #(vector<tagMCCACTGBillboardAwardItem> AwardItemList)// 奖励物品信息
+    data = None
+
+    def __init__(self):
+        self.Clear()
+        return
+
+    def ReadData(self, _lpData, _pos=0, _Len=0):
+        self.Clear()
+        self.AwardIndex,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        self.NeedRMB,_pos = CommFunc.ReadDWORD(_lpData, _pos)
+        self.AwardItemCount,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        for i in range(self.AwardItemCount):
+            temAwardItemList = tagMCCACTGBillboardAwardItem()
+            _pos = temAwardItemList.ReadData(_lpData, _pos)
+            self.AwardItemList.append(temAwardItemList)
+        return _pos
+
+    def Clear(self):
+        self.AwardIndex = 0
+        self.NeedRMB = 0
+        self.AwardItemCount = 0
+        self.AwardItemList = list()
+        return
+
+    def GetLength(self):
+        length = 0
+        length += 1
+        length += 4
+        length += 1
+        for i in range(self.AwardItemCount):
+            length += self.AwardItemList[i].GetLength()
+
+        return length
+
+    def GetBuffer(self):
+        data = ''
+        data = CommFunc.WriteBYTE(data, self.AwardIndex)
+        data = CommFunc.WriteDWORD(data, self.NeedRMB)
+        data = CommFunc.WriteBYTE(data, self.AwardItemCount)
+        for i in range(self.AwardItemCount):
+            data = CommFunc.WriteString(data, self.AwardItemList[i].GetLength(), self.AwardItemList[i].GetBuffer())
+        return data
+
+    def OutputString(self):
+        DumpString = '''
+                                AwardIndex:%d,
+                                NeedRMB:%d,
+                                AwardItemCount:%d,
+                                AwardItemList:%s
+                                '''\
+                                %(
+                                self.AwardIndex,
+                                self.NeedRMB,
+                                self.AwardItemCount,
+                                "..."
+                                )
+        return DumpString
+
+
+class  tagMCCACTGBillboardOrder(Structure):
+    OrderA = 0    #(BYTE OrderA)// 名次A
+    OrderB = 0    #(BYTE OrderB)// 至名次B
+    NeedRMB = 0    #(DWORD NeedRMB)// 所需充值RMB,未达标的该名次空,排名后面的玩家向下顺延
+    AwardItemCount = 0    #(BYTE AwardItemCount)// 奖励物品数
+    AwardItemList = list()    #(vector<tagMCCACTGBillboardAwardItem> AwardItemList)// 奖励物品信息
+    data = None
+
+    def __init__(self):
+        self.Clear()
+        return
+
+    def ReadData(self, _lpData, _pos=0, _Len=0):
+        self.Clear()
+        self.OrderA,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        self.OrderB,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        self.NeedRMB,_pos = CommFunc.ReadDWORD(_lpData, _pos)
+        self.AwardItemCount,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        for i in range(self.AwardItemCount):
+            temAwardItemList = tagMCCACTGBillboardAwardItem()
+            _pos = temAwardItemList.ReadData(_lpData, _pos)
+            self.AwardItemList.append(temAwardItemList)
+        return _pos
+
+    def Clear(self):
+        self.OrderA = 0
+        self.OrderB = 0
+        self.NeedRMB = 0
+        self.AwardItemCount = 0
+        self.AwardItemList = list()
+        return
+
+    def GetLength(self):
+        length = 0
+        length += 1
+        length += 1
+        length += 4
+        length += 1
+        for i in range(self.AwardItemCount):
+            length += self.AwardItemList[i].GetLength()
+
+        return length
+
+    def GetBuffer(self):
+        data = ''
+        data = CommFunc.WriteBYTE(data, self.OrderA)
+        data = CommFunc.WriteBYTE(data, self.OrderB)
+        data = CommFunc.WriteDWORD(data, self.NeedRMB)
+        data = CommFunc.WriteBYTE(data, self.AwardItemCount)
+        for i in range(self.AwardItemCount):
+            data = CommFunc.WriteString(data, self.AwardItemList[i].GetLength(), self.AwardItemList[i].GetBuffer())
+        return data
+
+    def OutputString(self):
+        DumpString = '''
+                                OrderA:%d,
+                                OrderB:%d,
+                                NeedRMB:%d,
+                                AwardItemCount:%d,
+                                AwardItemList:%s
+                                '''\
+                                %(
+                                self.OrderA,
+                                self.OrderB,
+                                self.NeedRMB,
+                                self.AwardItemCount,
+                                "..."
+                                )
+        return DumpString
+
+
+class  tagMCCACTGBillboardTempInfo(Structure):
+    TemplateID = 0    #(BYTE TemplateID)// 活动模板ID
+    DabiaoAwardCount = 0    #(BYTE DabiaoAwardCount)// 达标奖励档数
+    DabiaoAwardInfo = list()    #(vector<tagMCCACTGBillboardDabiao> DabiaoAwardInfo)// 达标奖励信息
+    OrderAwardCount = 0    #(BYTE OrderAwardCount)// 排行奖励档数
+    OrderAwardInfo = list()    #(vector<tagMCCACTGBillboardOrder> OrderAwardInfo)// 排行奖励信息
+    data = None
+
+    def __init__(self):
+        self.Clear()
+        return
+
+    def ReadData(self, _lpData, _pos=0, _Len=0):
+        self.Clear()
+        self.TemplateID,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        self.DabiaoAwardCount,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        for i in range(self.DabiaoAwardCount):
+            temDabiaoAwardInfo = tagMCCACTGBillboardDabiao()
+            _pos = temDabiaoAwardInfo.ReadData(_lpData, _pos)
+            self.DabiaoAwardInfo.append(temDabiaoAwardInfo)
+        self.OrderAwardCount,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        for i in range(self.OrderAwardCount):
+            temOrderAwardInfo = tagMCCACTGBillboardOrder()
+            _pos = temOrderAwardInfo.ReadData(_lpData, _pos)
+            self.OrderAwardInfo.append(temOrderAwardInfo)
+        return _pos
+
+    def Clear(self):
+        self.TemplateID = 0
+        self.DabiaoAwardCount = 0
+        self.DabiaoAwardInfo = list()
+        self.OrderAwardCount = 0
+        self.OrderAwardInfo = list()
+        return
+
+    def GetLength(self):
+        length = 0
+        length += 1
+        length += 1
+        for i in range(self.DabiaoAwardCount):
+            length += self.DabiaoAwardInfo[i].GetLength()
+        length += 1
+        for i in range(self.OrderAwardCount):
+            length += self.OrderAwardInfo[i].GetLength()
+
+        return length
+
+    def GetBuffer(self):
+        data = ''
+        data = CommFunc.WriteBYTE(data, self.TemplateID)
+        data = CommFunc.WriteBYTE(data, self.DabiaoAwardCount)
+        for i in range(self.DabiaoAwardCount):
+            data = CommFunc.WriteString(data, self.DabiaoAwardInfo[i].GetLength(), self.DabiaoAwardInfo[i].GetBuffer())
+        data = CommFunc.WriteBYTE(data, self.OrderAwardCount)
+        for i in range(self.OrderAwardCount):
+            data = CommFunc.WriteString(data, self.OrderAwardInfo[i].GetLength(), self.OrderAwardInfo[i].GetBuffer())
+        return data
+
+    def OutputString(self):
+        DumpString = '''
+                                TemplateID:%d,
+                                DabiaoAwardCount:%d,
+                                DabiaoAwardInfo:%s,
+                                OrderAwardCount:%d,
+                                OrderAwardInfo:%s
+                                '''\
+                                %(
+                                self.TemplateID,
+                                self.DabiaoAwardCount,
+                                "...",
+                                self.OrderAwardCount,
+                                "..."
+                                )
+        return DumpString
+
+
+class  tagMCCACTGBillboardInfo(Structure):
+    Head = tagHead()
+    ServerInfoLen = 0    #(BYTE ServerInfoLen)
+    ServerIDRangeInfo = ""    #(String ServerIDRangeInfo)//开放该活动的服务器ID范围列表,json格式 [[IDA, IDB], ...], [] 为全服
+    GroupValue1 = 0    #(BYTE GroupValue1)// 活动榜单分组值1,用于查询对应榜单
+    StartDate = ""    #(char StartDate[10])// 开始日期 y-m-d
+    EndtDate = ""    #(char EndtDate[10])// 结束日期 y-m-d
+    TemplateID = 0    #(BYTE TemplateID)// 当前活动模板ID
+    TemplateCount = 0    #(BYTE TemplateCount)
+    TempInfo = list()    #(vector<tagMCCACTGBillboardTempInfo> TempInfo)// 模板信息
+    data = None
+
+    def __init__(self):
+        self.Clear()
+        self.Head.Cmd = 0xAA
+        self.Head.SubCmd = 0x32
+        return
+
+    def ReadData(self, _lpData, _pos=0, _Len=0):
+        self.Clear()
+        _pos = self.Head.ReadData(_lpData, _pos)
+        self.ServerInfoLen,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        self.ServerIDRangeInfo,_pos = CommFunc.ReadString(_lpData, _pos,self.ServerInfoLen)
+        self.GroupValue1,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        self.StartDate,_pos = CommFunc.ReadString(_lpData, _pos,10)
+        self.EndtDate,_pos = CommFunc.ReadString(_lpData, _pos,10)
+        self.TemplateID,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        self.TemplateCount,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        for i in range(self.TemplateCount):
+            temTempInfo = tagMCCACTGBillboardTempInfo()
+            _pos = temTempInfo.ReadData(_lpData, _pos)
+            self.TempInfo.append(temTempInfo)
+        return _pos
+
+    def Clear(self):
+        self.Head = tagHead()
+        self.Head.Clear()
+        self.Head.Cmd = 0xAA
+        self.Head.SubCmd = 0x32
+        self.ServerInfoLen = 0
+        self.ServerIDRangeInfo = ""
+        self.GroupValue1 = 0
+        self.StartDate = ""
+        self.EndtDate = ""
+        self.TemplateID = 0
+        self.TemplateCount = 0
+        self.TempInfo = list()
+        return
+
+    def GetLength(self):
+        length = 0
+        length += self.Head.GetLength()
+        length += 1
+        length += len(self.ServerIDRangeInfo)
+        length += 1
+        length += 10
+        length += 10
+        length += 1
+        length += 1
+        for i in range(self.TemplateCount):
+            length += self.TempInfo[i].GetLength()
+
+        return length
+
+    def GetBuffer(self):
+        data = ''
+        data = CommFunc.WriteString(data, self.Head.GetLength(), self.Head.GetBuffer())
+        data = CommFunc.WriteBYTE(data, self.ServerInfoLen)
+        data = CommFunc.WriteString(data, self.ServerInfoLen, self.ServerIDRangeInfo)
+        data = CommFunc.WriteBYTE(data, self.GroupValue1)
+        data = CommFunc.WriteString(data, 10, self.StartDate)
+        data = CommFunc.WriteString(data, 10, self.EndtDate)
+        data = CommFunc.WriteBYTE(data, self.TemplateID)
+        data = CommFunc.WriteBYTE(data, self.TemplateCount)
+        for i in range(self.TemplateCount):
+            data = CommFunc.WriteString(data, self.TempInfo[i].GetLength(), self.TempInfo[i].GetBuffer())
+        return data
+
+    def OutputString(self):
+        DumpString = '''
+                                Head:%s,
+                                ServerInfoLen:%d,
+                                ServerIDRangeInfo:%s,
+                                GroupValue1:%d,
+                                StartDate:%s,
+                                EndtDate:%s,
+                                TemplateID:%d,
+                                TemplateCount:%d,
+                                TempInfo:%s
+                                '''\
+                                %(
+                                self.Head.OutputString(),
+                                self.ServerInfoLen,
+                                self.ServerIDRangeInfo,
+                                self.GroupValue1,
+                                self.StartDate,
+                                self.EndtDate,
+                                self.TemplateID,
+                                self.TemplateCount,
+                                "..."
+                                )
+        return DumpString
+
+
+m_NAtagMCCACTGBillboardInfo=tagMCCACTGBillboardInfo()
+ChNetPackDict[eval("0x%02x%02x"%(m_NAtagMCCACTGBillboardInfo.Head.Cmd,m_NAtagMCCACTGBillboardInfo.Head.SubCmd))] = m_NAtagMCCACTGBillboardInfo
+
+
+#------------------------------------------------------
+# AA 33 跨服充值排行活动玩家信息 #tagMCCACTGBillboardPlayerInfo
+
+class  tagMCCACTGBillboardPlayerInfo(Structure):
+    _pack_ = 1
+    _fields_ = [
+                  ("Cmd", c_ubyte),
+                  ("SubCmd", c_ubyte),
+                  ("CTGRMBTotal", c_int),    # 活动已累计充值RMB
+                  ("DabiaoAwardRecord", c_int),    # 达标奖励记录,与达标奖励索引位或运算判断是否已领取
+                  ]
+
+    def __init__(self):
+        self.Clear()
+        self.Cmd = 0xAA
+        self.SubCmd = 0x33
+        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 = 0xAA
+        self.SubCmd = 0x33
+        self.CTGRMBTotal = 0
+        self.DabiaoAwardRecord = 0
+        return
+
+    def GetLength(self):
+        return sizeof(tagMCCACTGBillboardPlayerInfo)
+
+    def GetBuffer(self):
+        return string_at(addressof(self), self.GetLength())
+
+    def OutputString(self):
+        DumpString = '''// AA 33 跨服充值排行活动玩家信息 //tagMCCACTGBillboardPlayerInfo:
+                                Cmd:%s,
+                                SubCmd:%s,
+                                CTGRMBTotal:%d,
+                                DabiaoAwardRecord:%d
+                                '''\
+                                %(
+                                self.Cmd,
+                                self.SubCmd,
+                                self.CTGRMBTotal,
+                                self.DabiaoAwardRecord
+                                )
+        return DumpString
+
+
+m_NAtagMCCACTGBillboardPlayerInfo=tagMCCACTGBillboardPlayerInfo()
+ChNetPackDict[eval("0x%02x%02x"%(m_NAtagMCCACTGBillboardPlayerInfo.Cmd,m_NAtagMCCACTGBillboardPlayerInfo.SubCmd))] = m_NAtagMCCACTGBillboardPlayerInfo
+
+
+#------------------------------------------------------
 # AA 09 消费返利活动信息 #tagMCCostRebateInfo
 
 class  tagMCCostRebateAwardItem(Structure):
diff --git a/ServerPython/CoreServerGroup/GameServer/Script/GM/Commands/BillboardDataCross.py b/ServerPython/CoreServerGroup/GameServer/Script/GM/Commands/BillboardDataCross.py
new file mode 100644
index 0000000..c8d0327
--- /dev/null
+++ b/ServerPython/CoreServerGroup/GameServer/Script/GM/Commands/BillboardDataCross.py
@@ -0,0 +1,107 @@
+#!/usr/bin/python
+# -*- coding: GBK -*-
+#-------------------------------------------------------------------------------
+#
+##@package GM.Commands.BillboardDataCross
+#
+# @todo:跨服榜单数据
+# @author hxp
+# @date 2021-01-13
+# @version 1.0
+#
+# 详细描述: 跨服榜单数据
+#
+#-------------------------------------------------------------------------------
+#"""Version = 2021-01-13 17:00"""
+#-------------------------------------------------------------------------------
+
+import GameWorld
+import ShareDefine
+import PyDataManager
+import CrossBillboard
+
+def __Help(curPlayer, errInfo=""):
+    GameWorld.DebugAnswer(curPlayer, "---------- %s" % GameWorld.GetCurrentDataTimeStr())
+    if errInfo:
+        GameWorld.DebugAnswer(curPlayer, errInfo)
+    GameWorld.DebugAnswer(curPlayer, "新增跨服榜单假数据: BillboardDataCross 类型  分组值1 分组值2 条数 比较值1 可选参数(比较值2 常规值1 常规值2)")
+    GameWorld.DebugAnswer(curPlayer, "删除跨服榜单假数据: BillboardDataCross 类型 分组值1 分组值2")
+    GameWorld.DebugAnswer(curPlayer, "跨服运营活动榜类型:150-充值")
+    return
+
+## 执行逻辑
+#  @param curPlayer 当前玩家
+#  @param gmList []
+#  @return None
+def OnExec(curPlayer, gmList):
+    
+    paramLen = len(gmList)
+    if paramLen < 3:
+        __Help(curPlayer)
+        return
+    
+    billboardType = gmList[0]
+    if billboardType not in ShareDefine.CrossBillboardTypeList:
+        __Help(curPlayer, "榜单类型不存在!")
+        return
+    
+    GameWorld.DebugAnswer(curPlayer, "发送完毕,执行结果查看跨服服务器!")
+    return
+
+def OnGetMergeParam(curPlayer):
+    ## 跨服命令额外参数
+    return []
+
+def OnMergeServerExec(gmList, tick):
+    ## 跨服执行命令
+    
+    paramLen = len(gmList)
+    if paramLen < 3:
+        return
+    
+    billboardType = gmList[0]
+    groupValue1 = gmList[1]
+    groupValue2 = gmList[2]
+    
+    billboardMgr = PyDataManager.GetCrossBillboardManager()
+    billboardObj = billboardMgr.GetCrossBillboard(billboardType, groupValue1, groupValue2)
+    
+    curDataCount = billboardObj.GetCount()
+    maxDataCount = billboardObj.GetMaxCount()
+    
+    # 清除榜单假数据
+    if paramLen == 3:
+        billboardObj.ClearData()
+        GameWorld.Log("删除跨服榜单(%s-%s-%s): %s 条" % (billboardType, groupValue1, groupValue2, curDataCount))
+        return
+    
+    count = gmList[3] if len(gmList) > 3 else 0
+    cmpValue1 = gmList[4] if len(gmList) > 4 else 0
+    cmpValue2 = gmList[5] if len(gmList) > 5 else 0
+    value1 = gmList[6] if len(gmList) > 6 else 0
+    value2 = gmList[7] if len(gmList) > 7 else 0
+    
+    id2 = 0
+    type2 = 0
+    name2 = ""
+    cmpValue3 = 0
+    
+    count = min(count, maxDataCount - curDataCount)
+    FakeName = "假名字".decode(ShareDefine.Def_Game_Character_Encoding).encode(GameWorld.GetCharacterEncoding())
+    
+    for i in xrange(count):
+        dataPlayerID = curDataCount + 1 + i
+        dataPlayerName = "%s%s" % (FakeName, i)
+        dataCmpValue1 = max(0, cmpValue1 - i)
+        dataCmpValue2 = max(0, cmpValue2 - i)
+        
+        dataID = dataPlayerID
+        name1 = dataPlayerName
+        cmpValue = dataCmpValue1
+        cmpValue2 = dataCmpValue2
+        CrossBillboard.UpdCrossBillboard(billboardType, groupValue1, dataID, name1, name2, type2, value1, value2, cmpValue, cmpValue2, cmpValue3, groupValue2, id2)
+        
+    GameWorld.Log("插入虚假榜单(%s-%s-%s): %s 条" % (billboardType, groupValue1, groupValue2, count))
+    return
+
+
diff --git a/ServerPython/CoreServerGroup/GameServer/Script/GM/Commands/GMT_CrossActServerIDChange.py b/ServerPython/CoreServerGroup/GameServer/Script/GM/Commands/GMT_CrossActServerIDChange.py
new file mode 100644
index 0000000..7cb503f
--- /dev/null
+++ b/ServerPython/CoreServerGroup/GameServer/Script/GM/Commands/GMT_CrossActServerIDChange.py
@@ -0,0 +1,170 @@
+#!/usr/bin/python
+# -*- coding: GBK -*-
+#-------------------------------------------------------------------------------
+#
+##@package GM.Commands.GMT_CrossActServerIDChange
+#
+# @todo:跨服活动区服ID修改
+# @author hxp
+# @date 2021-01-13
+# @version 1.0
+#
+# 详细描述: 跨服活动区服ID修改
+#
+#-------------------------------------------------------------------------------
+#"""Version = 2021-01-13 17:00"""
+#-------------------------------------------------------------------------------
+
+import GameWorld
+import DataRecordPack
+import CrossActionControl
+import CrossRealmMsg
+import ShareDefine
+import GMCommon
+
+#---------------------------------------------------------------------
+
+## 执行逻辑
+#  @param curPlayer 当前玩家
+#  @param gmCmdDict: 命令字典
+#  @return None
+#  @remarks 函数详细说明.
+def OnExec(orderId, gmCmdDict):
+    
+    GameWorld.Log("GMT_CrossActServerIDChange gmCmdDict=%s" % str(gmCmdDict))
+    
+    if not GameWorld.IsCrossServer():
+        GMCommon.GMCommandResult(orderId, gmCmdDict, GMCommon.Def_IsNotCrossServer)
+        return
+    
+    errInfo = ""
+    doChange = gmCmdDict.get("doChange")
+    if doChange:
+        errInfo = __DoChangeCrossActServerIDRangeList(gmCmdDict)
+        
+    crossActInfoDict = CrossActionControl.GetCrossActInfoDict()
+    backMsg = {"crossActInfoDict":crossActInfoDict}
+    if errInfo:
+        backMsg["ErrorInfo"] = errInfo
+        GMCommon.GMCommandResult(orderId, gmCmdDict, GMCommon.Def_ParamErr, backMsg)
+        return
+    
+    # 记录流向
+    DataRecordPack.DR_ToolGMOperate(0, '', '', 'GMT_CrossActServerIDChange', str(gmCmdDict))
+    # 回复
+    GMCommon.GMCommandResult(orderId, gmCmdDict, GMCommon.Def_Success, backMsg)
+    return
+    
+def __DoChangeCrossActServerIDRangeList(gmCmdDict):
+    
+    crossActInfoDict = CrossActionControl.GetCrossActInfoDict()
+    changeInfoDict = {} # {actName:{cfgID:ServerIDList, ...}, ...}
+    for k, v in gmCmdDict.items():
+        if not k.endswith("_ServerIDRangeList"):
+            continue
+        kspList = k.split("_")
+        if len(kspList) != 3:
+            continue
+        actName, cfgID, _ = kspList
+        try:
+            cfgID = int(cfgID)
+            changeServerIDList = eval(v)
+            # 检查修改格式是否正确
+            for changeList in changeServerIDList:
+                if not (isinstance(changeList, list) 
+                        and len(changeList) == 2 
+                        and isinstance(changeList[0], int) 
+                        and isinstance(changeList[1], int)
+                        ):
+                    errInfo = "%s CfgID(%s) error serverIDList(%s)" % (actName, cfgID, changeList)
+                    return errInfo
+        except:
+            errInfo = "%s CfgID(%s) error %s" % (actName, cfgID, v)
+            return errInfo
+        
+        if actName not in changeInfoDict:
+            changeInfoDict[actName] = {}
+        changeInfoDict[actName][cfgID] = changeServerIDList
+        
+    GameWorld.Log("    crossActInfoDict=%s" % crossActInfoDict)
+    GameWorld.Log("    changeInfoDict=%s" % changeInfoDict)
+    if not changeInfoDict:
+        errInfo = "no change info!"
+        return errInfo
+    
+    # 检查修改后是否有交叉
+    checkGroupInfo = {} # {actName:{actGroupName:[cfgID, ...], ...}} # 先分组
+    for actName, actInfoDict in crossActInfoDict.items():
+        if actName not in changeInfoDict:
+            # 没有修改的活动不需要检查
+            continue
+        if actName not in checkGroupInfo:
+            checkGroupInfo[actName] = {}
+        actGroupListDict = checkGroupInfo[actName]
+        for cfgID, actInfo in actInfoDict.items():
+            actGroupName = actInfo[ShareDefine.ActKey_IpyDataInfo]["ActGroupName"]
+            if actGroupName not in actGroupListDict:
+                actGroupListDict[actGroupName] = []
+            cfgIDList = actGroupListDict[actGroupName]
+            cfgIDList.append(cfgID)
+            
+    GameWorld.Log("    checkGroupInfo: %s" % checkGroupInfo)
+    
+    for actName, actGroupListDict in checkGroupInfo.items():
+        actInfoDict = crossActInfoDict[actName]
+        changeInfo = changeInfoDict.get(actName, {})
+        for actGroupName, cfgIDList in actGroupListDict.items():
+            allServerIDRangeList = []
+            for cfgID in cfgIDList:
+                befActInfo = actInfoDict[cfgID]
+                if cfgID in changeInfo:
+                    allServerIDRangeList.extend(changeInfo[cfgID])
+                else:
+                    befServerIDList = befActInfo[ShareDefine.ActKey_ServerIDRangeList]
+                    allServerIDRangeList.extend(befServerIDList)
+                    
+            GameWorld.Log("    actName=%s,actGroupName=%s,cfgIDList=%s" % (actName, actGroupName, cfgIDList))
+            GameWorld.Log("        allServerIDRangeList=%s" % (allServerIDRangeList))
+            errorServerIDList = []
+            for i in xrange(len(allServerIDRangeList)):
+                checkIDA, checkIDB = allServerIDRangeList[i]
+                for j in xrange(i):
+                    serverIDA, serverIDB = allServerIDRangeList[j]
+                    if serverIDA <= checkIDA <= serverIDB:
+                        errorServerIDList.append(checkIDA)
+                        
+                    if serverIDA <= checkIDB <= serverIDB:
+                        errorServerIDList.append(checkIDB)
+                        
+            GameWorld.Log("        errorServerIDList=%s" % (errorServerIDList))
+            if errorServerIDList:
+                return "%s exist errorServerIDList=%s in actGroupName(%s)" % (actName, errorServerIDList, actGroupName)
+            
+    # 检查通过后进行修改
+    sysnCrossActInfoDict = {}
+    GameWorld.Log("    do change...")
+    for actName, changInfo in changeInfoDict.items():
+        for cfgID, changeServerIDRangeList in changInfo.items():
+            if actName not in crossActInfoDict:
+                continue
+            if cfgID not in crossActInfoDict[actName]:
+                continue
+            actInfoDict = crossActInfoDict[actName][cfgID]
+            beforeServerIDRangeList = actInfoDict[ShareDefine.ActKey_ServerIDRangeList]
+            # 直接覆盖替换
+            actInfoDict[ShareDefine.ActKey_ServerIDRangeList] = changeServerIDRangeList
+                        
+            GameWorld.Log("        actName=%s,cfgID=%s,beforeServerIDRangeList=%s -> %s" 
+                          % (actName, cfgID, beforeServerIDRangeList, changeServerIDRangeList))
+            
+            if actName not in sysnCrossActInfoDict:
+                sysnCrossActInfoDict[actName] = {}
+            sysnCrossActInfoDict[actName][cfgID] = actInfoDict
+            
+    GameWorld.Log("    changeOK! crossActInfoDict=%s" % crossActInfoDict)
+    
+    # 同步子服务器
+    serverGroupIDList = []
+    CrossRealmMsg.SendMsgToClientServer(ShareDefine.CrossServerMsg_CrossActInfo, sysnCrossActInfoDict, serverGroupIDList)
+    return ""
+
diff --git a/ServerPython/CoreServerGroup/GameServer/Script/GM/Commands/GMT_QueryBillboardCross.py b/ServerPython/CoreServerGroup/GameServer/Script/GM/Commands/GMT_QueryBillboardCross.py
new file mode 100644
index 0000000..16a067f
--- /dev/null
+++ b/ServerPython/CoreServerGroup/GameServer/Script/GM/Commands/GMT_QueryBillboardCross.py
@@ -0,0 +1,88 @@
+#!/usr/bin/python
+# -*- coding: GBK -*-
+#-------------------------------------------------------------------------------
+#
+##@package GM.Commands.GMT_QueryBillboardCross
+#
+# @todo:查询跨服排行榜
+# @author hxp
+# @date 2021-01-13
+# @version 1.0
+#
+# 详细描述: 查询跨服排行榜
+#
+#-------------------------------------------------------------------------------
+#"""Version = 2021-01-13 17:00"""
+#-------------------------------------------------------------------------------
+
+#导入
+import GMCommon
+import ShareDefine
+import PyDataManager
+import GameWorld
+
+
+#逻辑实现(这里curPlayer = None)
+## 执行逻辑
+#  @param curPlayer 当前玩家
+#  @param gmList [cmdIndex gmAccID forbidAcc]
+#  @return None
+#  @remarks 函数详细说明.
+def OnExec(orderId, gmCmdDict):
+    
+    if not GameWorld.IsCrossServer():
+        GMCommon.GMCommandResult(orderId, gmCmdDict, GMCommon.Def_IsNotCrossServer)
+        return
+    
+    billboardType = GameWorld.ToIntDef(gmCmdDict.get('billboardType', ''), None)
+    billType = GameWorld.ToIntDef(gmCmdDict.get('billType', ''), None) # 其他指定类型
+    if billType != None:
+        billboardType = billType
+        
+    if billboardType == None or billboardType not in ShareDefine.CrossBillboardTypeList:
+        GMCommon.GMCommandResult(orderId, gmCmdDict, GMCommon.Def_TypeNumErr)
+        return
+    
+    groupValue1 = GameWorld.ToIntDef(gmCmdDict.get('groupValue1', ''), None)
+    groupValue2 = GameWorld.ToIntDef(gmCmdDict.get('groupValue2', ''), None)
+    
+    billboardMgr = PyDataManager.GetCrossBillboardManager()
+    groupList = billboardMgr.GetBillboardGroupList(billboardType)
+    
+    backMsg = {"billboardType":billboardType, "groupList":groupList}
+    
+    if groupValue1 != None and groupValue2 != None:
+        billboardObj = billboardMgr.GetCrossBillboard(billboardType, groupValue1, groupValue2)
+        
+        billboardInfo = []
+        for i in xrange(billboardObj.GetCount()):
+            billboardData = billboardObj.At(i)
+            if not billboardData:
+                continue
+            billboardDict = {
+                             "ID":billboardData.ID,
+                             "ID2":billboardData.ID2,
+                             "Name1":billboardData.Name1,
+                             "Name2":billboardData.Name2,
+                             "Type2":billboardData.Type2,
+                             "Value1":billboardData.Value1,
+                             "Value2":billboardData.Value2,
+                             "CmpValue":billboardData.CmpValue,
+                             "CmpValue2":billboardData.CmpValue2,
+                             "CmpValue3":billboardData.CmpValue3,
+                             }
+            
+            for k, v in billboardDict.items():
+                if not v:
+                    billboardDict.pop(k)
+                    
+            billboardInfo.append(billboardDict)
+            
+        backMsg.update({"billboardInfo":billboardInfo, "groupValue1":groupValue1, "groupValue2":groupValue2})
+        
+    #执行成功
+    GMCommon.GMCommandResult(orderId, gmCmdDict, GMCommon.Def_Success, backMsg)
+    return
+
+    
+    
diff --git a/ServerPython/CoreServerGroup/GameServer/Script/GM/GMShell.py b/ServerPython/CoreServerGroup/GameServer/Script/GM/GMShell.py
index 6f97c43..7a34771 100644
--- a/ServerPython/CoreServerGroup/GameServer/Script/GM/GMShell.py
+++ b/ServerPython/CoreServerGroup/GameServer/Script/GM/GMShell.py
@@ -87,13 +87,22 @@
             GameWorld.Log("###使用GM命令 = %s错误,玩家不是GM"%(callFunName), curPlayer.GetPlayerID())
             return
         
+        #把剩余参数转换为整型
+        for i in range(0, len(alist)):
+            if i == 0:
+                continue
+            value = GameWorld.ToIntDef(alist[i], None)
+            if value == None:
+                #GameWorld.DebugAnswer(curPlayer, "参数错误, 参数%s必须为纯数字!" % (i + 1))
+                continue
+            alist[i] = value
+            
         #非跨服服务器下使用跨服GM命令,则发送到跨服
         if not GameWorld.IsCrossServer():
             callFunc = GameWorld.GetExecFunc(Commands, "%s.%s"%(callFunName, "OnGetMergeParam"))
             if callFunc != None:
                 extendParamList = callFunc(curPlayer)
-                alist.extend(extendParamList)
-                CrossRealmMsg.SendMsgToCrossServer(ShareDefine.ClientServerMsg_GMCMD, alist)
+                CrossRealmMsg.SendMsgToCrossServer(ShareDefine.ClientServerMsg_GMCMD, alist + extendParamList)
                 
         callFunc = GameWorld.GetExecFunc(Commands, "%s.%s"%(callFunName, "OnExec"))
         if callFunc == None:
@@ -102,17 +111,7 @@
             GameWorld.DebugAnswer(curPlayer, 'no cmd !!!')
             return
         
-        #删除命令,只将参数传入
-        del alist[0]
-        #把剩余参数转换为整型
-        for i in range(0, len(alist)):
-            value = GameWorld.ToIntDef(alist[i], None)
-            if value == None:
-                #GameWorld.DebugAnswer(curPlayer, "参数错误, 参数%s必须为纯数字!" % (i + 1))
-                continue
-            alist[i] = value
-            
-        callFunc(curPlayer,alist)
+        callFunc(curPlayer, alist[1:])
         
     except BaseException:
         GameWorld.DebugAnswer(curPlayer, "执行GM命令错误, 请查看GameServer日志!")
diff --git a/ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/CrossActCTGBillboard.py b/ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/CrossActCTGBillboard.py
new file mode 100644
index 0000000..b7970fa
--- /dev/null
+++ b/ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/CrossActCTGBillboard.py
@@ -0,0 +1,100 @@
+#!/usr/bin/python
+# -*- coding: GBK -*-
+#-------------------------------------------------------------------------------
+#
+##@package CrossActCTGBillboard
+#
+# @todo:跨服运营活动 - 充值排行
+# @author hxp
+# @date 2021-01-13
+# @version 1.0
+#
+# 详细描述: 跨服运营活动 - 充值排行
+#
+#-------------------------------------------------------------------------------
+#"""Version = 2021-01-13 17:00"""
+#-------------------------------------------------------------------------------
+
+import ShareDefine
+import PyDataManager
+import PlayerCompensation
+import IpyGameDataPY
+import GameWorld
+
+def OnActIDChange(cfgID, dbTemplateID, state):
+    ## 活动ID变更
+    
+    # 先结算上期活动
+    __GiveBillboardOrderAward(cfgID, dbTemplateID)
+    
+    # 如果有新活动,处理新活动
+    if not state:
+        return
+    
+    groupValue1 = cfgID
+    billboardType = ShareDefine.Def_CBT_ActCTG
+    
+    billboardMgr = PyDataManager.GetCrossBillboardManager()
+    billboardObj = billboardMgr.GetCrossBillboard(billboardType, groupValue1)
+    billboardObj.ClearData() # 新活动重置榜单数据
+    
+    return
+
+def __GiveBillboardOrderAward(cfgID, dbTemplateID):
+    ## 结算榜单排名奖励
+    
+    groupValue1 = cfgID
+    billboardType = ShareDefine.Def_CBT_ActCTG
+    
+    # 先结算上期活动
+    billboardMgr = PyDataManager.GetCrossBillboardManager()
+    billboardObj = billboardMgr.GetCrossBillboard(billboardType, groupValue1)
+    billboardDataCount = billboardObj.GetCount()
+    if not billboardDataCount:
+        GameWorld.Log("跨服充值排行数据为空! billboardType=%s,cfgID=%s" % (billboardType, cfgID))
+        return
+    
+    # 结算时排序并保存榜单数据流向
+    billboardObj.SortData()
+    billboardObj.SaveDRData()
+    
+    GameWorld.Log("结算跨服充值排行奖励: billboardType=%s,cfgID=%s,dbTemplateID=%s,billboardDataCount=%s" 
+                  % (billboardType, cfgID, dbTemplateID, billboardDataCount))
+    
+    orderIpyDataList = IpyGameDataPY.GetIpyGameDataList("CrossActCTGBillboardOrder", dbTemplateID)
+    if not orderIpyDataList:
+        return
+    
+    billboardIndex = 0
+    for ipyData in orderIpyDataList:
+        orderA = ipyData.GetOrderA()
+        orderB = ipyData.GetOrderB()
+        ctgAtleast = ipyData.GetCTGAtleast()
+        awardItemList = ipyData.GetAwardItemList()
+        orderCountTotal = orderB - orderA + 1 # 奖励名次数量
+        orderCount = 0
+        
+        for index in xrange(billboardIndex, billboardDataCount):
+            if orderCount >= orderCountTotal:
+                break
+            
+            billboardData = billboardObj.At(index)
+            playerID = billboardData.ID
+            ctgRMB = billboardData.CmpValue
+            if ctgRMB < ctgAtleast:
+                break
+            
+            realOrder = orderA + orderCount
+            paramList = [realOrder]
+            PlayerCompensation.SendMailByKey("CABillboardCTGOrder", [playerID], awardItemList, paramList, crossMail=True)
+            GameWorld.Log("    playerID=%s,榜单名次=%s,实际名次=%s,充值总RMB=%s" % (playerID, index + 1, realOrder, ctgRMB))
+            
+            orderCount += 1
+            billboardIndex += 1
+            
+    # 结算完清除榜单数据
+    billboardObj.ClearData()
+    return
+
+
+
diff --git a/ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/CrossActionControl.py b/ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/CrossActionControl.py
new file mode 100644
index 0000000..15bcc39
--- /dev/null
+++ b/ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/CrossActionControl.py
@@ -0,0 +1,523 @@
+#!/usr/bin/python
+# -*- coding: GBK -*-
+#-------------------------------------------------------------------------------
+#
+##@package CrossActionControl
+#
+# @todo:跨服活动总开关逻辑
+# @author hxp
+# @date 2020-01-13
+# @version 1.0
+#
+# 详细描述: 跨服活动总开关逻辑
+#          跨服活动的时间以跨服服务器为准,所有的状态控制由跨服服务器控制并广播子服务器
+#          子服仅做具体活动逻辑
+#
+#-------------------------------------------------------------------------------
+#"""Version = 2020-01-13 17:00"""
+#-------------------------------------------------------------------------------
+
+import GameWorld
+import ShareDefine
+import PlayerControl
+import IpyGameDataPY
+import CrossActCTGBillboard
+import CrossRealmMsg
+import PyGameData
+import ChConfig
+
+import datetime
+import time
+
+(
+CrossAct_ReloadSign, # 信息重载标记
+CrossAct_TodayInfo, # 当日的活动信息
+) = range(2)
+
+def OnPlayerLogin(curPlayer):
+    return
+
+def OnServerClose():
+    if not GameWorld.IsCrossServer():
+        return
+        
+    GameWorld.GetUniversalRecMgr().Delete(ShareDefine.Def_UniversalGameRecType_CrossActInfo)
+    
+    if not PyGameData.g_crossActInfoDict:
+        return
+    GameWorld.Log("保存跨服运营活动信息通用记录: ")
+    
+    # 保存活动中的
+    recDataList = GameWorld.GetUniversalRecMgr().GetTypeList(ShareDefine.Def_UniversalGameRecType_CrossActInfo)
+    for actName, actInfoDict in PyGameData.g_crossActInfoDict.items():
+        for cfgID, actInfo in actInfoDict.items():
+            if not actInfo.get(ShareDefine.ActKey_State):
+                # 非活动中的,已经结算过了,不需要存储
+                continue
+            state = actInfo.get(ShareDefine.ActKey_State, 0)
+            actID = actInfo.get(ShareDefine.ActKey_ID, 0)
+            templateID = actInfo.get(ShareDefine.ActKey_TemplateID, 0)
+            serverIDRangeList = actInfo.get(ShareDefine.ActKey_ServerIDRangeList, "")
+            recData = recDataList.AddRec()
+            recData.SetStrValue1(actName)
+            recData.SetStrValue3(str(serverIDRangeList))
+            recData.SetValue1(cfgID)
+            recData.SetValue2(state)
+            recData.SetValue3(actID)
+            recData.SetValue4(templateID)
+            GameWorld.Log("    actName=%s,cfgID=%s,state=%s,actID=%s,templateID=%s,serverIDRangeList=%s" 
+                          % (actName, cfgID, state, actID, templateID, serverIDRangeList))
+            
+    return
+
+def GetCrossActInfoDict():
+    if PyGameData.g_crossActInfoDict == None:
+        PyGameData.g_crossActInfoDict = {}
+        
+        # 先加载通用记录存储中的活动信息
+        recDataList = GameWorld.GetUniversalRecMgr().GetTypeList(ShareDefine.Def_UniversalGameRecType_CrossActInfo)
+        GameWorld.Log("加载通用记录中的跨服运营活动信息: %s" % recDataList.Count())
+        for index in xrange(recDataList.Count()):
+            recData = recDataList.At(index)
+            actName = recData.GetStrValue1()
+            strValue3 = recData.GetStrValue3()
+            serverIDRangeList = eval(strValue3) if strValue3 else []
+            cfgID = recData.GetValue1()
+            state = recData.GetValue2()
+            actID = recData.GetValue3()
+            templateID = recData.GetValue4()
+            if not state:
+                continue
+            if actName not in PyGameData.g_crossActInfoDict:
+                PyGameData.g_crossActInfoDict[actName] = {}
+            actInfoDict = PyGameData.g_crossActInfoDict[actName]
+            dbInfo = {ShareDefine.ActKey_ID:actID, ShareDefine.ActKey_State:state, ShareDefine.ActKey_TemplateID:templateID} # 活动ID、状态、模板信息单独存储,重置活动判断用
+            actInfo = {ShareDefine.ActKey_CfgID:cfgID, ShareDefine.ActKey_ServerIDRangeList:serverIDRangeList}
+            actInfo.update(dbInfo)
+            actInfo[ShareDefine.ActKey_DBInfo] = dbInfo
+            actInfoDict[cfgID] = actInfo
+            
+            GameWorld.Log("    actName=%s,cfgID=%s, %s" % (actName, cfgID, actInfoDict))
+            
+    return PyGameData.g_crossActInfoDict
+
+def __GetParseIpyDataList(ipyDataMgr, actName, actInfoDict):
+    ## 获取需要处理的合法分组活动配置列表,已经在活动中的必须要处理
+    
+    groupInfo = {}
+    actCfgCount = getattr(ipyDataMgr, "Get%sCount" % actName)()
+    for cfgIndex in xrange(actCfgCount):
+        ipyData = getattr(ipyDataMgr, "Get%sByIndex" % actName)(cfgIndex)
+        actGroupName = ipyData.GetActGroupName()
+        if actGroupName not in groupInfo:
+            groupInfo[actGroupName] = []
+        groupIpyDataList = groupInfo[actGroupName]
+        groupIpyDataList.append(ipyData)
+        
+    parseIpyDataList = []
+    for actGroupName, groupIpyDataList in groupInfo.items():
+        allOpen = False
+        cfgIDList = []
+        allServerIDRangeList = []
+        for ipyData in groupIpyDataList:
+            cfgID = ipyData.GetCfgID()
+            cfgIDList.append(cfgID)
+            serverIDRangeList = ipyData.GetServerIDRangeList()
+            
+            if cfgID in actInfoDict and actInfoDict[cfgID]:
+                actInfo = actInfoDict[cfgID]
+                # 已经在活动中的记录必须要处理
+                parseIpyDataList.append(ipyData)
+                serverIDRangeList = actInfo[ShareDefine.ActKey_ServerIDRangeList]
+                GameWorld.Log("    使用已经在活动中的记录的区服分组: cfgID=%s,serverIDRangeList=%s" 
+                              % (cfgID, serverIDRangeList))
+                
+            # 没配置的全服开放
+            if not serverIDRangeList:
+                allOpen = True
+            else:
+                allServerIDRangeList.extend(serverIDRangeList)
+                
+        if allOpen and len(groupIpyDataList) > 1:
+            GameWorld.ErrLog("    同组活动服务器ID配置异常,有全服开放的,只能配置1条,不处理! actGroupName=%s,cfgIDList=%s" % (actGroupName, cfgIDList))
+            continue
+        
+        errorServerIDList = []
+        for i in xrange(len(allServerIDRangeList)):
+            checkIDA, checkIDB = allServerIDRangeList[i]
+            for j in xrange(i):
+                serverIDA, serverIDB = allServerIDRangeList[j]
+                if serverIDA <= checkIDA <= serverIDB:
+                    errorServerIDList.append(checkIDA)
+                    
+                if serverIDA <= checkIDB <= serverIDB:
+                    errorServerIDList.append(checkIDB)
+                    
+        if errorServerIDList:
+            GameWorld.ErrLog("    同组活动服务器ID配置异常,有交叉,不处理! actGroupName=%s,cfgIDList=%s,errorServerIDList=%s" 
+                             % (actGroupName, cfgIDList, errorServerIDList))
+            continue
+        
+        for ipyData in groupIpyDataList:
+            cfgID = ipyData.GetCfgID()
+            if cfgID in actInfoDict and actInfoDict[cfgID]:
+                continue
+            parseIpyDataList.append(ipyData)
+            
+    return parseIpyDataList
+
+def __GetCrossActInfo(isRefreshState=True):
+    # @return: isReload, CrossActInfo
+    
+    key = "CrossActInfo"
+    CrossActInfo = IpyGameDataPY.GetConfigEx(key)
+    serverTime = GameWorld.GetServerTime()
+    curDateStr = "%d-%d-%d" % (serverTime.year, serverTime.month, serverTime.day)
+    curHour = serverTime.hour
+    reloadSignHour = 0 if curHour < 5 else 5
+    reloadSign = "%s %s" % (curDateStr, reloadSignHour)
+    if CrossActInfo and CrossActInfo[CrossAct_ReloadSign] == reloadSign:
+        #GameWorld.DebugLog("已经加载过本日跨服运营活动处理信息!reloadSign=%s" % reloadSign)
+        return False, CrossActInfo
+    
+    # 因为后面的时间判断都是精确到分的,而处理此逻辑的时候可能不是0秒,所以这里的datetime取当前时间精确到分的
+    curDateTimeStr = "%s %02d:%02d:00" % (curDateStr, serverTime.hour, serverTime.minute)
+    curDateTime = datetime.datetime.strptime(curDateTimeStr, ChConfig.TYPE_Time_Format)
+    
+    actTimeInfoDict = {}
+    ipyDataMgr = IpyGameDataPY.IPY_Data()
+    
+    GameWorld.Log("=============================================================")
+    GameWorld.Log("加载本日跨服运营活动信息: %s, reloadSign=%s =====" % (curDateTime, reloadSign))
+    crossActInfoDict = GetCrossActInfoDict()
+    GameWorld.Log("    crossActInfoDict=%s" % crossActInfoDict)
+    
+    for actName in ShareDefine.CrossActNameList:
+        
+        # 取出本活动所属本服ID的所有配置
+        GameWorld.Log("加载跨服运营活动: actName=%s" % (actName))
+        
+        if not hasattr(ipyDataMgr, "Get%sCount" % actName):
+            GameWorld.ErrLog("    没有该跨服运营活动类型对应活动时间表! actName=%s" % actName)
+            continue
+        
+        curActInfoDict = crossActInfoDict.get(actName, {})
+        
+        # 验证服务器ID不重复的配置
+        parseIpyDataList = __GetParseIpyDataList(ipyDataMgr, actName, curActInfoDict)
+        for ipyData in parseIpyDataList:
+            cfgID = ipyData.GetCfgID()
+            startDateStr = ipyData.GetStartDate()
+            endDateStr = ipyData.GetEndDate()
+            GameWorld.Log("    cfgID=%s,startDateStr=%s,endDateStr=%s,curDateTime=%s" % (cfgID, startDateStr, endDateStr, curDateTime))
+            if not startDateStr:
+                startDateStr = curDateStr
+                GameWorld.Log("        开始日期为空,默认每天,今日为: startDateStr=%s" % startDateStr)
+            if not endDateStr:
+                endDateStr = curDateStr
+                GameWorld.Log("        结束日期为空,默认每天,今日为: endDateStr=%s" % endDateStr)
+                
+            if hasattr(ipyData, "GetStartTimeList") and hasattr(ipyData, "GetEndTimeList"):
+                startHMStrList = ipyData.GetStartTimeList()
+                endHMStrList = ipyData.GetEndTimeList()
+            else:
+                startHMStrList = []
+                endHMStrList = []
+                
+            notifyInfoDictStart = ipyData.GetNotifyInfoStart() if hasattr(ipyData, "GetNotifyInfoStart") else {}
+            notifyInfoDictEnd = ipyData.GetNotifyInfoEnd() if hasattr(ipyData, "GetNotifyInfoEnd") else {}
+            notifyInfoLoopInfo = ipyData.GetNotifyInfoLoop() if hasattr(ipyData, "GetNotifyInfoLoop") else [] # [循环分钟, 广播key, [广播参数列表可选]]
+            
+            if len(startHMStrList) != len(endHMStrList):
+                GameWorld.ErrLog("        活动配置开始及结束时间个数不匹配! actName=%s,cfgID=%s,startHMStrList=%s,endHMStrList=%s" 
+                                 % (actName, cfgID, startHMStrList, endHMStrList))
+                
+            resetType = 0 if not hasattr(ipyData, "GetResetType") else ipyData.GetResetType() # 重置类型,0-0点重置;1-5点重置
+            if resetType == 1:
+                startDayDate = datetime.datetime.strptime("%s 05:00:00" % (startDateStr), ChConfig.TYPE_Time_Format)
+                endDayDate = datetime.datetime.strptime("%s 05:00:00" % (endDateStr), ChConfig.TYPE_Time_Format) # 结束日期5点
+            elif resetType == 2:
+                startDayDate = datetime.datetime.strptime("%s 05:00:00" % (startDateStr), ChConfig.TYPE_Time_Format)
+                endDayDate = datetime.datetime.strptime("%s 00:00:00" % (endDateStr), ChConfig.TYPE_Time_Format) + datetime.timedelta(days=1) # 结束日期隔天0点
+            else:
+                startDayDate = datetime.datetime.strptime("%s 00:00:00" % (startDateStr), ChConfig.TYPE_Time_Format)
+                endDayDate = datetime.datetime.strptime("%s 00:00:00" % (endDateStr), ChConfig.TYPE_Time_Format) + datetime.timedelta(days=1) # 结束日期隔天0点
+                
+            GameWorld.Log("        resetType=%s,startDayDate=%s,endDayDate=%s,startHMStrList=%s,endHMStrList=%s" 
+                          % (resetType, startDayDate, endDayDate, startHMStrList, endHMStrList))
+            
+            if curDateTime < startDayDate or curDateTime >= endDayDate:
+                isActTime = False
+                if cfgID not in curActInfoDict or not curActInfoDict[cfgID]:
+                    GameWorld.Log("        非活动时间!不处理!")
+                    continue
+            else:
+                isActTime = True
+                
+            GameWorld.Log("        需要处理的跨服运营活动信息: cfgID=%s,isActTime=%s" % (cfgID, isActTime))
+            
+            startList = [] # [startDateTime, ...]
+            endList = [] # [endDateTime, ...]
+            startNotifyDict = {} # {notifyDateTime:notifyInfo, ...}
+            endNotifyDict = {} # {notifyDateTime:notifyInfo, ...}
+            loopNotifyDict = {} # {notifyDateTime:notifyInfo, ...}
+            notifyDict = {}
+            
+            # 没配置时分的代表全天
+            if not startHMStrList:
+                startDateTime = startDayDate
+                endDateTime = endDayDate
+                
+                startList.append(startDateTime)
+                endList.append(endDateTime)
+                
+            # 每天按时段开启的,支持多时段
+            else:
+                for hmIndex, startHMStr in enumerate(startHMStrList):
+                    if hmIndex >= len(endHMStrList):
+                        break
+                    endHMStr = endHMStrList[hmIndex]
+                    # 每天开的, 实际开关时间只取今天的日期; 这里有个问题,全服广播的时间不是今天的, 暂不做支持,之后真有这种需求再说
+                    startTimeStr = "%d-%d-%d %s:00" % (curDateTime.year, curDateTime.month, curDateTime.day, startHMStr)
+                    endTimeStr = "%d-%d-%d %s:00" % (curDateTime.year, curDateTime.month, curDateTime.day, endHMStr)
+                    startDateTime = datetime.datetime.strptime(startTimeStr, ChConfig.TYPE_Time_Format)
+                    endDateTime = datetime.datetime.strptime(endTimeStr, ChConfig.TYPE_Time_Format)
+                    
+                    startList.append(startDateTime)
+                    endList.append(endDateTime)
+                    
+            GameWorld.Log("        startList=%s" % (startList))
+            GameWorld.Log("        end  List=%s" % (endList))
+            
+            for dtIndex, startDateTime in enumerate(startList):
+                endDateTime = endList[dtIndex]
+                # 广播 - 相对实际开始时间
+                for notifyMinute, notifyInfo in notifyInfoDictStart.items():
+                    notifyDateTime = startDateTime + datetime.timedelta(minutes=notifyMinute)
+                    if notifyDateTime.year == curDateTime.year and notifyDateTime.month == curDateTime.month and notifyDateTime.day == curDateTime.day:
+                        startNotifyDict[notifyDateTime] = notifyInfo
+                        
+                # 广播 - 相对实际结束时间
+                for notifyMinute, notifyInfo in notifyInfoDictEnd.items():
+                    notifyDateTime = endDateTime + datetime.timedelta(minutes=notifyMinute)
+                    if notifyDateTime.year == curDateTime.year and notifyDateTime.month == curDateTime.month and notifyDateTime.day == curDateTime.day:
+                        endNotifyDict[notifyDateTime] = notifyInfo
+                        
+                # 广播 - 循环广播
+                if notifyInfoLoopInfo and len(notifyInfoLoopInfo) >= 2:
+                    loopMinutes, loopNotifyKey = notifyInfoLoopInfo[:2]
+                    loopNotifyParamList = notifyInfoLoopInfo[2] if len(notifyInfoLoopInfo) > 2 else []
+                    notifyInfo = [loopNotifyKey, loopNotifyParamList] # 循环广播的默认无参数
+                    loopCount, loopMaxCount = 0, 100
+                    while loopMinutes and loopNotifyKey and loopCount < loopMaxCount:
+                        loopCount += 1
+                        notifyDateTime = curDateTime + datetime.timedelta(minutes=loopMinutes * loopCount)
+                        if notifyDateTime >= endDateTime:
+                            break
+                        if notifyDateTime.year == curDateTime.year and notifyDateTime.month == curDateTime.month and notifyDateTime.day == curDateTime.day:
+                            loopNotifyDict[notifyDateTime] = notifyInfo
+                            
+            if startNotifyDict or endNotifyDict or loopNotifyDict:
+                GameWorld.Log("        startNotifyDict: %s, %s" % (len(startNotifyDict.keys()), sorted(startNotifyDict.keys())))
+                GameWorld.Log("        end  NotifyDict: %s, %s" % (len(endNotifyDict.keys()), sorted(endNotifyDict.keys())))
+                GameWorld.Log("        loop NotifyDict: %s, %s" % (len(loopNotifyDict.keys()), sorted(loopNotifyDict.keys())))
+                notifyDict.update(startNotifyDict)
+                notifyDict.update(endNotifyDict)
+                notifyDict.update(loopNotifyDict)
+                
+            if actName not in actTimeInfoDict:
+                actTimeInfoDict[actName] = {}
+            actTimeInfoDict[actName][cfgID] = [ipyData, startList, endList, notifyDict]
+            
+            if actName not in crossActInfoDict:
+                crossActInfoDict[actName] = {}
+            curActInfoDict = crossActInfoDict[actName]
+            if cfgID not in curActInfoDict:
+                curActInfoDict[cfgID] = {}
+            curCfgActInfoDict = curActInfoDict[cfgID]
+            
+            # ipyData 活动时间表信息由跨服服务器同步子服,活动内容取子服自己的
+            ipyDataDict = {}
+            for k, v in ipyData.__dict__.items():
+                if k in ["NotifyInfoStart", "NotifyInfoEnd", "NotifyInfoLoop", "ServerIDRangeList"]:
+                    continue
+                ipyDataDict[k] = v
+            ipyDataDict.update({"StartDate":startDateStr, "EndDate":endDateStr})
+            GameWorld.Log("        ipyDataDict=%s" % ipyDataDict)
+            
+            curCfgActInfoDict.update({ShareDefine.ActKey_CfgID:cfgID, ShareDefine.ActKey_IpyDataInfo:ipyDataDict})
+            if ShareDefine.ActKey_ServerIDRangeList not in curCfgActInfoDict:
+                # 没有的话则使用配置中的,防止配置修改导致服务器ID分区变动引起的活动数据异常,除非后台工具强制修改
+                curCfgActInfoDict[ShareDefine.ActKey_ServerIDRangeList] = ipyData.GetServerIDRangeList()
+                
+            actID, dayIndex, templateID = 0, 0, 0
+            if isActTime:
+                dayIndex = (curDateTime - startDayDate).days
+                actIDDateTime = startDayDate
+                isDayReset = 0 if not hasattr(ipyData, "GetIsDayReset") else ipyData.GetIsDayReset()
+                # 按时段开的默认每天重置
+                if isDayReset or (startHMStrList and endHMStrList):
+                    actIDDateTime += datetime.timedelta(days=dayIndex)
+                actID = int(time.mktime(actIDDateTime.timetuple())) # 默认取开始时间点的time值作为活动ID
+                GameWorld.Log("        isDayReset=%s,actIDDateTime=%s,actID=%s" % (isDayReset, actIDDateTime, actID))
+                
+                # 模板ID
+                if hasattr(ipyData, "TemplateIDList"):
+                    templateIDList = ipyData.GetTemplateIDList()
+                    templateID = templateIDList[-1] if dayIndex >= len(templateIDList) else templateIDList[dayIndex]
+                    
+                    # 其他特殊模板ID获取处理,有需要的单独处理即可,根据活动规则自行扩展...  
+                    
+                    
+            curCfgActInfoDict.update({ShareDefine.ActKey_ID:actID, ShareDefine.ActKey_TemplateID:templateID, 
+                                      ShareDefine.ActKey_DayIndex:dayIndex})
+            
+    CrossActInfo = IpyGameDataPY.SetConfigEx(key, [reloadSign, actTimeInfoDict])
+    
+    GameWorld.Log("本日跨服运营活动信息加载完毕!reloadSign=%s,isRefreshState=%s" % (reloadSign, isRefreshState))
+    GameWorld.Log("    actTimeInfoDict=%s" % actTimeInfoDict)
+    GameWorld.Log("    crossActInfoDict=%s" % crossActInfoDict)
+    GameWorld.Log("=============================================================")
+    if isRefreshState:
+        Dispose_CrossActState(True)
+        
+    return True, CrossActInfo
+
+def Dispose_CrossActState(reloadRefresh=False):
+    
+    isReload, CrossActInfo = __GetCrossActInfo(False) # 这里必须传False
+    isReload = isReload or reloadRefresh
+    actTimeInfoDict = CrossActInfo[CrossAct_TodayInfo]
+    
+    crossActInfoDict = GetCrossActInfoDict()
+    
+    # 这里时间需精确到分钟,不然后面的比较会匹配不到
+    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)
+    
+    sysnCrossActInfoDict = {}
+    for actName in ShareDefine.CrossActNameList:
+        if actName not in actTimeInfoDict or actName not in crossActInfoDict:
+            continue
+        
+        for ipyData, startList, endList, notifyDict in actTimeInfoDict[actName].values():
+            
+            state = 0 # 默认关闭
+            cfgID = ipyData.GetCfgID()
+            
+            if cfgID not in crossActInfoDict[actName]:
+                crossActInfoDict[actName][cfgID] = {}
+            actInfoDict = crossActInfoDict[actName][cfgID]
+            
+            # 状态
+            for dIndex, startDateTime in enumerate(startList):
+                endDateTime = endList[dIndex]
+                if startDateTime <= curDateTime < endDateTime:
+                    state = dIndex + 1 # 也是代表第几个时间段
+                    break
+                
+            # 全服广播提示信息
+            if curDateTime in notifyDict:
+                serverIDRangeList = actInfoDict.get(ShareDefine.ActKey_ServerIDRangeList)
+                if serverIDRangeList != None:
+                    notifyKey, paramList = notifyDict[curDateTime]
+                    country = 0
+                    serverGroupIDList = []
+                    crossNotifyList = []
+                    crossNotifyList.append([ShareDefine.CrossNotify_CrossAct, [country, notifyKey, paramList], serverIDRangeList])
+                    PlayerControl.CrossNotifyEx(serverGroupIDList, crossNotifyList)
+                
+            dbInfo = actInfoDict.get(ShareDefine.ActKey_DBInfo, {})
+            dbState = dbInfo.get(ShareDefine.ActKey_State, 0)
+            dbActID = dbInfo.get(ShareDefine.ActKey_ID, 0)
+            dbTemplateID = dbInfo.get(ShareDefine.ActKey_TemplateID, 0)
+            
+            actID = actInfoDict.get(ShareDefine.ActKey_ID, 0)
+            templateID = actInfoDict.get(ShareDefine.ActKey_TemplateID, 0)
+            if not isReload and dbState == state and dbActID == actID:
+                #已经是这个状态了
+                continue
+            GameWorld.Log("跨服运营活动变更: actName=%s,cfgID=%s,dbState=%s -> state=%s, dbActID=%s -> actID=%s" 
+                          % (actName, cfgID, dbState, state, dbActID, actID))
+            
+            if dbActID != actID:
+                GameWorld.Log("    活动ID变更: actName=%s,cfgID=%s,dbActID=%s -> actID=%s,dbTemplateID=%s" 
+                              % (actName, cfgID, dbActID, actID, dbTemplateID))
+                
+                if actName == ShareDefine.CrossActName_CTGBillboard:
+                    CrossActCTGBillboard.OnActIDChange(cfgID, dbTemplateID, state)
+                    
+            if dbState != state:
+                pass
+                          
+            # 更新状态
+            actInfoDict[ShareDefine.ActKey_State] = state
+            actInfoDict[ShareDefine.ActKey_DBInfo] = {ShareDefine.ActKey_ID:actID, ShareDefine.ActKey_State:state, ShareDefine.ActKey_TemplateID:templateID}
+            GameWorld.Log("    活动状态同步信息: actName=%s,cfgID=%s,actInfoDict=%s" % (actName, cfgID, actInfoDict))
+            if actName not in sysnCrossActInfoDict:
+                sysnCrossActInfoDict[actName] = {}
+            sysnCrossActInfoDict[actName][cfgID] = actInfoDict
+            
+            # 非活动中的处理完关闭后,最后删除
+            if not state:
+                del crossActInfoDict[actName][cfgID]
+                if not crossActInfoDict[actName]:
+                    del crossActInfoDict[actName]
+                GameWorld.DebugLog("    删除结束的活动: actName=%s,cfgID=%s,crossActInfoDict=%s" % (actName, cfgID, crossActInfoDict))
+                
+    # 同步子服务器
+    serverGroupIDList = []
+    CrossRealmMsg.SendMsgToClientServer(ShareDefine.CrossServerMsg_CrossActInfo, sysnCrossActInfoDict, serverGroupIDList)
+    return
+
+def Sync_CrossActInfoToClientServer(serverGroupID=0):
+    ''' 同步跨服运营活动信息到子服务器
+    @param serverGroupID: 为0时同步所有子服
+    '''
+    
+    isReload, _ = __GetCrossActInfo()
+    if isReload:
+        # 如果是重读的,则在内层已经同步了,此处不重复同步
+        return
+    
+    # 同步子服务器
+    sysnCrossActInfoDict = GetCrossActInfoDict()
+    serverGroupIDList = [serverGroupID] if serverGroupID else []
+    CrossRealmMsg.SendMsgToClientServer(ShareDefine.CrossServerMsg_CrossActInfo, sysnCrossActInfoDict, serverGroupIDList)
+    return
+
+## ================================================================================================
+
+def CrossServerMsg_CrossActInfo(sysnCrossActInfoDict):
+    ## 收到跨服服务器同步的跨服运营活动状态
+    
+    GameWorld.Log("===== 收到跨服服务器同步的跨服运营活动状态: %s" % sysnCrossActInfoDict)
+    if PyGameData.g_crossActInfoDict == None:
+        PyGameData.g_crossActInfoDict = {}
+    PyGameData.g_crossActInfoDict.update(sysnCrossActInfoDict)
+    
+    for actName, actInfoDict in sysnCrossActInfoDict.items():
+        GameWorld.SendMapServerMsgEx(ShareDefine.Def_Notify_WorldKey_CrossActInfo % actName, actInfoDict)
+        
+    # 删除非活动中的
+    for actName, actInfoDict in PyGameData.g_crossActInfoDict.items():
+        for cfgID, actInfo in actInfoDict.items():
+            if not actInfo.get(ShareDefine.ActKey_State, 0):
+                del PyGameData.g_crossActInfoDict[actName][cfgID]
+                
+    return
+
+def SendMapServerCrossActionState():
+    # 地图启动成功时通知跨服活动相关状态  - 本服地图,跨服地图不需要通知
+    
+    if PyGameData.g_crossActInfoDict == None:
+        return
+    
+    sysnCrossActInfoDict = PyGameData.g_crossActInfoDict
+    for actName in ShareDefine.CrossActNameList:
+        actInfoDict = sysnCrossActInfoDict.get(actName, {})
+        GameWorld.SendMapServerMsgEx(ShareDefine.Def_Notify_WorldKey_CrossActInfo % actName, actInfoDict)
+        
+    return
+
diff --git a/ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/CrossBillboard.py b/ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/CrossBillboard.py
new file mode 100644
index 0000000..b7926c8
--- /dev/null
+++ b/ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/CrossBillboard.py
@@ -0,0 +1,552 @@
+#!/usr/bin/python
+# -*- coding: GBK -*-
+#-------------------------------------------------------------------------------
+#
+##@package CrossBillboard
+#
+# @todo:跨服排行榜
+# @author hxp
+# @date 2020-01-13
+# @version 1.0
+#
+# 详细描述: 跨服排行榜
+#
+#-------------------------------------------------------------------------------
+#"""Version = 2020-01-13 17:00"""
+#-------------------------------------------------------------------------------
+
+import CommFunc
+import ShareDefine
+import CrossRealmMsg
+import PyGameDataStruct
+import ChPyNetSendPack
+import DataRecordPack
+import NetPackCommon
+import PyDataManager
+import GameWorld
+
+import operator
+import time
+
+Def_CrossBillboard_MaxDataCount = 100 # 跨服榜单数据最大条数暂固定最大为100条,如有需要调整需针对实际情况进行评估(如数据同步、同步封包等)
+    
+class CrossBillboardManager(object):
+    ## 跨服排行榜管理,注意该类只处理数据逻辑,功能相关逻辑不要写在该类,不然重读脚本不会生效
+    
+    def __init__(self):
+        self.__billboardDict = {} # 排行榜字典 {(billboardType, groupValue1, groupValue2):CrossBillboard, ...}
+        return
+    
+    def GetBillboardGroupList(self, bType):
+        ## 根据榜单类型获取该类型所有分组榜单信息
+        ## @return: [(billboardType, groupValue1, groupValue2), ...]
+        groupList = []
+        for billboardType, groupValue1, groupValue2 in self.__billboardDict.keys():
+            if bType == billboardType:
+                groupList.append((billboardType, groupValue1, groupValue2))
+        return groupList
+    
+    def GetCrossBillboard(self, billboardType, groupValue1, groupValue2=0):
+        ''' 获取跨服排行榜
+        @param billboardType: 排行榜类型
+        @param groupValue1: 分组值1
+        @param groupValue2: 分组值2,与分组值1组合归为同组榜单数据
+        @return: CrossBillboard
+        '''
+        key = (billboardType, groupValue1, groupValue2)
+        if key in self.__billboardDict:
+            billboardObj = self.__billboardDict[key]
+        else:
+            billboardObj = CrossBillboard(billboardType, groupValue1, groupValue2)
+            self.__billboardDict[key] = billboardObj
+        return billboardObj
+    
+    # 保存数据 存数据库和realtimebackup
+    def GetSaveData(self):
+        savaData = ""
+        cntData = ""
+        cnt = 0
+        for billboardType, groupValue1, groupValue2 in self.__billboardDict.keys():
+            billboardObj = self.GetCrossBillboard(billboardType, groupValue1, groupValue2)
+            for i in xrange(billboardObj.GetCount()):
+                billboardData = billboardObj.At(i)
+                cnt += 1
+                savaData += billboardData.getBuffer()
+                
+        GameWorld.Log("Save DBCrossBillboard cnt :%s" % cnt)
+        return CommFunc.WriteDWORD(cntData, cnt) + savaData
+    
+    # 从数据库载入数据
+    def LoadPyGameData(self, datas, pos, dataslen):
+        cnt, pos = CommFunc.ReadDWORD(datas, pos)
+        GameWorld.Log("Load DBCrossBillboard cnt :%s" % cnt)
+        
+        for _ in xrange(cnt):
+            billboardData = PyGameDataStruct.tagDBCrossBillboard()
+            billboardData.clear()
+            pos += billboardData.readData(datas, pos, dataslen)
+            
+            billboardType, groupValue1, groupValue2 = billboardData.BillboardType, billboardData.GroupValue1, billboardData.GroupValue2
+            billboardObj = self.GetCrossBillboard(billboardType, groupValue1, groupValue2)
+            billboardObj.AddBillboardData(billboardData)
+            
+        # 排序
+        for billboardType, groupValue1, groupValue2 in self.__billboardDict.keys():
+            billboardObj = self.GetCrossBillboard(billboardType, groupValue1, groupValue2)
+            billboardObj.SortData()
+            
+        return pos
+    
+class CrossBillboard(object):
+    ''' 对应具体类型排行榜逻辑类
+    '''
+    
+    def __init__(self, billboardType, groupValue1=0, groupValue2=0):
+        self.__billboardType = billboardType
+        self.__groupValue1 = groupValue1
+        self.__groupValue2 = groupValue2
+        self.__crossServerDataVer = 0 # 主服榜单数据版本
+        self.__clientServerDataVer = 0 # 子服榜单数据版本
+        self.__billboardList = [] # [tagDBCrossBillboard, ...] 
+        self.__idOrderDict = {} # {id:名次, ...}
+        return
+    
+    def GetBillboardType(self): return self.__billboardType
+    def GetGroupValue1(self): return self.__groupValue1
+    def GetGroupValue2(self): return self.__groupValue2
+    
+    def ClearData(self):
+        GameWorld.Log("CrossBillboard ClearData billboardType=%s,groupValue1=%s,groupValue2=%s" 
+                      % (self.__billboardType, self.__groupValue1, self.__groupValue2))
+        self.__billboardList = [] # [tagDBCrossBillboard, ...] 
+        self.__idOrderDict = {} # {id:名次, ...}
+        
+        self.UpdCrossServerDataVer(0)
+        return
+    
+    def SortData(self):
+        self.__billboardList.sort(key=operator.attrgetter("CmpValue", "CmpValue2", "CmpValue3"), reverse=True)
+        self.__idOrderDict = {} # 排序后重置,下次查询时更新并缓存
+        self.UpdCrossServerDataVer()
+        return
+    
+    def AddBillboardData(self, billboardData):
+        ## 添加榜单数据到该榜
+        # @param billboardData: PyGameDataStruct.tagDBCrossBillboard()
+        # @return: 是否成功
+        if self.IsFull():
+            return False
+        self.__billboardList.append(billboardData)
+        return True
+    
+    def FindByID(self, findID):
+        ''' 根据ID查询榜单数据
+        @param findID: 查找的ID
+        @return: None or PyGameDataStruct.tagDBCrossBillboard()
+        '''
+        idOrderDict = self.GetIDOrderDict()
+        if findID not in idOrderDict:
+            return None
+        order = idOrderDict[findID]
+        return self.__billboardList[order - 1]
+    
+    def SaveDRData(self):
+        ## 记录流向数据
+        eventTypeName = "CrossBillboard_%s" % (self.__billboardType)
+        drDict = {"BillboardType":self.__billboardType, "GroupValue1":self.__groupValue1, "GroupValue2":self.__groupValue2, 
+                  "DataCount":len(self.__billboardList)}
+        DataRecordPack.SendEventPack(eventTypeName, drDict)
+        for billboardData in self.__billboardList:
+            dataDict = {"BillboardType":billboardData.BillboardType, "GroupValue1":billboardData.GroupValue1, 
+                        "GroupValue2":billboardData.GroupValue2, "Type2":billboardData.Type2,
+                        "ID":billboardData.ID, "ID2":billboardData.ID2,
+                        "Name1":billboardData.Name1, "Name2":billboardData.Name2,
+                        "Value1":billboardData.Value1, "Value2":billboardData.Value2,
+                        "CmpValue":billboardData.CmpValue, "CmpValue2":billboardData.CmpValue2, 
+                        "CmpValue3":billboardData.CmpValue3}
+            DataRecordPack.SendEventPack(eventTypeName, dataDict)
+        return
+    
+    def GetBillboardDataList(self): return self.__billboardList
+    def GetIDOrderDict(self):
+        ## 获取ID对应名次字典
+        # @return: {ID:名次, ...}  名次从1开始
+        if not self.__idOrderDict:
+            for order, billboardData in enumerate(self.__billboardList, 1):
+                self.__idOrderDict[billboardData.ID] = order
+        return self.__idOrderDict
+    
+    def GetCount(self): return len(self.__billboardList)
+    def GetMaxCount(self): return Def_CrossBillboard_MaxDataCount
+    
+    def At(self, i): return self.__billboardList[i]
+    def IsFull(self): return len(self.__billboardList) >= Def_CrossBillboard_MaxDataCount
+    
+    def UpdCrossServerDataVer(self, version=None):
+        ## 更新跨服榜单数据版本号,用于跨服主服、子服验证数据版本,同步榜单数据用
+        if not GameWorld.IsCrossServer():
+            return
+        if version == None:
+            version = int(time.time())
+        self.__crossServerDataVer = version
+        SyncCrossBillboardToClientServer(self.__billboardType, self.__groupValue1, self.__groupValue2)
+        return
+    def GetCrossServerDataVer(self): return self.__crossServerDataVer
+    
+    def CheckClientServerDataVer(self):
+        ## 检查子服榜单数据版本是否需要同步
+        # @return: 是否需要向跨服主服同步最新数据
+        return self.__clientServerDataVer == 0 or self.__clientServerDataVer != self.__crossServerDataVer
+    
+    def UpdClientServerBillboard(self, crossServerDataVer, syncBillboardList=None):
+        ## 更新本服的跨服榜单数据
+        
+        # 更新跨服数据版本
+        self.__crossServerDataVer = crossServerDataVer
+        # 特殊版本0代表清除数据
+        if crossServerDataVer == 0:
+            self.ClearData()
+            
+        # 更新数据
+        if syncBillboardList != None:
+            self.__billboardList = self.__billboardList[:len(syncBillboardList)] # 直接用本服以后的排行数据实例clear后覆盖更新,不足的创建新实例
+            self.__idOrderDict = {}
+            for i, syncData in enumerate(syncBillboardList):
+                ID, ID2, Name1, Name2, Type2, Value1, Value2, CmpValue, CmpValue2, CmpValue3 = syncData
+                if i < len(self.__billboardList):
+                    billboardData = self.__billboardList[i]
+                    billboardData.clear()
+                else:
+                    billboardData = PyGameDataStruct.tagDBCrossBillboard()
+                    self.__billboardList.append(billboardData)
+                    
+                billboardData.GroupValue1 = self.__groupValue1
+                billboardData.GroupValue2 = self.__groupValue2
+                billboardData.BillboardType = self.__billboardType
+                billboardData.ID = ID
+                billboardData.ID2 = ID2
+                billboardData.Name1 = Name1
+                billboardData.Name2 = Name2
+                billboardData.Type2 = Type2
+                billboardData.Value1 = Value1
+                billboardData.Value2 = Value2
+                billboardData.CmpValue = CmpValue
+                billboardData.CmpValue2 = CmpValue2
+                billboardData.CmpValue3 = CmpValue3
+                
+                self.__idOrderDict[ID] = i + 1
+                
+            self.__clientServerDataVer = crossServerDataVer
+            
+        return
+
+#// C0 04 查看跨服排行榜 #tagCGViewCrossBillboard
+#
+#struct    tagCGViewCrossBillboard
+#{
+#    tagHead        Head;
+#    BYTE        Type;        //榜单类型
+#    BYTE        GroupValue1;    // 分组值1
+#    BYTE        GroupValue2;    // 分组值2,与分组值1组合归为同组榜单数据
+#};
+def OnViewCrossBillboard(index, clientData, tick):
+    curPlayer = GameWorld.GetPlayerManager().GetPlayerByIndex(index)
+    if GameWorld.IsCrossServer():
+        return
+    playerID = curPlayer.GetPlayerID()
+    billboardType, groupValue1, groupValue2 = clientData.Type, clientData.GroupValue1, clientData.GroupValue2
+    
+    if billboardType not in ShareDefine.CrossBillboardTypeList:
+        return
+    
+    billboardMgr = PyDataManager.GetCrossBillboardManager()
+    billboardObj = billboardMgr.GetCrossBillboard(billboardType, groupValue1, groupValue2)
+    
+    GameWorld.DebugLog("玩家请求查看跨服排行榜: billboardType=%s,groupValue1=%s,groupValue2=%s" % (billboardType, groupValue1, groupValue2))
+    if not billboardObj.CheckClientServerDataVer():
+        SyncCrossBillboardToPlayer(curPlayer, billboardType, groupValue1, groupValue2, billboardObj.GetBillboardDataList())
+        return
+    
+    # 请求查询跨服服务器
+    dataMsg = {"BillboardType":billboardType, "GroupValue1":groupValue1, "GroupValue2":groupValue2,
+               "QueryData":{"EventName":"View", "PlayerID":playerID}}
+    CrossRealmMsg.SendMsgToCrossServer(ShareDefine.ClientServerMsg_QueryBillboard, dataMsg)
+    return
+
+def ClientServerMsg_QueryBillboard(serverGroupID, msgData):
+    ## 收到子服请求查询排行榜信息
+    billboardType = msgData["BillboardType"]
+    groupValue1 = msgData["GroupValue1"]
+    groupValue2 = msgData["GroupValue2"]
+    queryData = msgData.get("QueryData", {}) # 原数据返回子服
+    SyncCrossBillboardToClientServer(billboardType, groupValue1, groupValue2, [serverGroupID], queryData)
+    return
+
+def SyncCrossBillboardToClientServer(billboardType, groupValue1, groupValue2, serverGroupIDList=[], queryData={}):
+    ## 同步跨服榜单到子服
+    if not GameWorld.IsCrossServer():
+        return
+    billboardMgr = PyDataManager.GetCrossBillboardManager()
+    billboardObj = billboardMgr.GetCrossBillboard(billboardType, groupValue1, groupValue2)
+    crossServerDataVer = billboardObj.GetCrossServerDataVer()
+    msgData = {"BillboardType":billboardType, "GroupValue1":groupValue1, "GroupValue2":groupValue2,
+               "QueryData":queryData, "CrossServerDataVer":crossServerDataVer}
+    
+    # 有查询数据时才同步榜单数据列表,否则只同步数据版本号
+    if queryData:
+        syncBillboardList = []
+        billboardList = billboardObj.GetBillboardDataList()
+        for billboardData in billboardList:
+            ID = billboardData.ID
+            ID2 = billboardData.ID2
+            Name1 = billboardData.Name1
+            Name2 = billboardData.Name2
+            Type2 = billboardData.Type2
+            Value1 = billboardData.Value1
+            Value2 = billboardData.Value2
+            CmpValue = billboardData.CmpValue
+            CmpValue2 = billboardData.CmpValue2
+            CmpValue3 = billboardData.CmpValue3
+            syncBillboardList.append([ID, ID2, Name1, Name2, Type2, Value1, Value2, CmpValue, CmpValue2, CmpValue3])
+        msgData["BillboardDataList"] = syncBillboardList
+        
+    CrossRealmMsg.SendMsgToClientServer(ShareDefine.CrossServerMsg_SyncBillboard, msgData, serverGroupIDList)
+    return
+
+def CrossServerMsg_SyncBillboard(msgData, tick):
+    ## 收到跨服服务器同步的排行榜信息
+    billboardType = msgData["BillboardType"]
+    groupValue1 = msgData["GroupValue1"]
+    groupValue2 = msgData["GroupValue2"]
+    crossServerDataVer = msgData["CrossServerDataVer"]
+    syncBillboardList = msgData.get("BillboardDataList")
+    GameWorld.DebugLog("收到跨服服务器同步的排行榜信息: billboardType=%s,groupValue1=%s,groupValue2=%s,crossServerDataVer=%s" 
+                       % (billboardType, groupValue1, groupValue2, crossServerDataVer))
+    
+    billboardMgr = PyDataManager.GetCrossBillboardManager()
+    billboardObj = billboardMgr.GetCrossBillboard(billboardType, groupValue1, groupValue2)
+    billboardObj.UpdClientServerBillboard(crossServerDataVer, syncBillboardList)
+    
+    queryData = msgData.get("QueryData")
+    if not queryData:
+        return
+    
+    eventName = queryData.get("EventName")
+    eventData = queryData.get("EventData")
+    queryPlayerID = queryData.get("PlayerID", 0)
+    if not eventName or not queryPlayerID:
+        return
+    
+    queryPlayer = GameWorld.GetPlayerManager().FindPlayerByID(queryPlayerID)
+    if not queryPlayer:
+        return
+    
+    if eventName == "View":        
+        SyncCrossBillboardToPlayer(queryPlayer, billboardType, groupValue1, groupValue2, billboardObj.GetBillboardDataList())
+    else:
+        idOrderDict = billboardObj.GetIDOrderDict()
+        order = idOrderDict.get(queryPlayerID, 0)
+        sysMsg = str([billboardType, groupValue1, groupValue2, eventName, eventData, order])
+        queryPlayer.MapServer_QueryPlayerResult(0, 0, "CrossBillboardOrder", sysMsg, len(sysMsg))
+        
+    return
+
+def SyncCrossBillboardToPlayer(curPlayer, billboardType, groupValue1, groupValue2, billboardList):
+    ## 同步给玩家跨服榜单
+    billboardInfo = ChPyNetSendPack.tagGCCrossBillboardInfo()
+    billboardInfo.Type = billboardType
+    billboardInfo.GroupValue1 = groupValue1
+    billboardInfo.GroupValue2 = groupValue2
+    billboardInfo.CrossBillboardDataList = []
+    for billboardData in billboardList:
+        billboardInfoData = ChPyNetSendPack.tagGCCrossBillboardData()
+        billboardInfoData.ID = billboardData.ID
+        billboardInfoData.Name1 = billboardData.Name1
+        billboardInfoData.Name2 = billboardData.Name2
+        billboardInfoData.Type2 = billboardData.Type2
+        billboardInfoData.Value1 = billboardData.Value1
+        billboardInfoData.Value2 = billboardData.Value2
+        billboardInfoData.CmpValue = billboardData.CmpValue
+        billboardInfoData.CmpValue2 = billboardData.CmpValue2
+        billboardInfoData.CmpValue3 = billboardData.CmpValue3
+        billboardInfo.CrossBillboardDataList.append(billboardInfoData)
+    billboardInfo.BillboardCount = len(billboardInfo.CrossBillboardDataList)
+    NetPackCommon.SendFakePack(curPlayer, billboardInfo)
+    return
+
+def MapServer_UpdateCrossBillboard(billInfoDict):
+    '''地图更新跨服排行榜, 通用
+    {"Type":bType, "GroupValue1":groupValue1, "Type2":type2, "ID":dataID, "ID2":id2, "Name1":name1, "Name2":name2,
+    "Value1":value1, "Value2":value2, "CmpValue":cmpValue, "CmpValue2":cmpValue2, "CmpValue3":cmpValue3,
+    "GroupValue2":groupValue2}
+    '''
+    
+    if GameWorld.IsCrossServer():
+        # 只有子服务器能调用
+        return
+    GameWorld.DebugLog("子服地图更新跨服榜单数据! %s" % billInfoDict)
+    
+    billboardType = billInfoDict["Type"]
+    if billboardType not in ShareDefine.CrossBillboardTypeList:
+        return
+    groupValue1 = billInfoDict["GroupValue1"]
+    groupValue2 = billInfoDict["GroupValue2"]
+    dataID = billInfoDict["ID"]
+    if not groupValue1 or not dataID:
+        return
+    
+    type2 = billInfoDict["Type2"]
+    id2 = billInfoDict["ID2"]
+    name1 = billInfoDict["Name1"]
+    name2 = billInfoDict["Name2"]
+    value1 = billInfoDict["Value1"]
+    value2 = billInfoDict["Value2"]
+    cmpValue = billInfoDict["CmpValue"]
+    cmpValue2 = billInfoDict["CmpValue2"]
+    cmpValue3 = billInfoDict["CmpValue3"]
+    
+    billboardMgr = PyDataManager.GetCrossBillboardManager()
+    billboardObj = billboardMgr.GetCrossBillboard(billboardType, groupValue1, groupValue2)
+    billboardData = billboardObj.FindByID(dataID)
+    if billboardData:
+        if cmpValue == billboardData.CmpValue and cmpValue2 == billboardData.CmpValue2 \
+            and (not cmpValue3 or cmpValue3 == billboardData.CmpValue3) \
+            and value1 == billboardData.Value1 and value2 == billboardData.Value2 \
+            and name1 == billboardData.Name1 and name2 == billboardData.Name2 \
+            and type2 == billboardData.Type2 and id2 == billboardData.ID2:
+            GameWorld.DebugLog("    榜单值相同,不同步跨服服务器! ")
+            return
+        
+    elif billboardObj.IsFull():
+        lastBillBoardData = __CmpLastBillboardData(cmpValue, cmpValue2, cmpValue3, billboardObj)
+        if not lastBillBoardData:
+            GameWorld.DebugLog("    榜单值不超过最后一名,不同步跨服服务器! ")
+            return
+        
+    else:
+        GameWorld.DebugLog("    本服没有在榜上!")
+        
+    # 同步跨服服务器
+    CrossRealmMsg.SendMsgToCrossServer(ShareDefine.ClientServerMsg_UpdateBillboard, billInfoDict)
+    return
+
+def ClientServerMsg_UpdateBillboard(serverGroupID, billInfoDict):
+    GameWorld.Log("收到子服更新跨服榜单数据! serverGroupID=%s, %s" % (serverGroupID, billInfoDict))
+    
+    billboardType = billInfoDict["Type"]
+    if billboardType not in ShareDefine.CrossBillboardTypeList:
+        return
+    groupValue1 = billInfoDict["GroupValue1"]
+    groupValue2 = billInfoDict["GroupValue2"]
+    
+    type2 = billInfoDict["Type2"]
+    dataID = billInfoDict["ID"]
+    id2 = billInfoDict["ID2"]
+    name1 = billInfoDict["Name1"]
+    name2 = billInfoDict["Name2"]
+    value1 = billInfoDict["Value1"]
+    value2 = billInfoDict["Value2"]
+    cmpValue = billInfoDict["CmpValue"]
+    cmpValue2 = billInfoDict["CmpValue2"]
+    cmpValue3 = billInfoDict["CmpValue3"]
+    
+    UpdCrossBillboard(billboardType, groupValue1, dataID, name1, name2, type2, value1, value2,
+                      cmpValue, cmpValue2, cmpValue3, groupValue2, id2)
+    return
+
+def UpdCrossBillboard(billboardType, groupValue1, dataID, name1, name2, type2, value1, value2, cmpValue,
+                      cmpValue2=0, cmpValue3=0, groupValue2=0, id2=0, autoSort=True):
+    ''' 更新跨服排行榜
+    @param billboardType: 排行榜索引类型,同个榜单类型可以有多个分组榜单数据,独立排序
+    @param groupValue1: 榜单分组1
+    @param dataID: 榜单唯一数据ID,如玩家ID等
+    @param name1: 显示名称1,不影响排序
+    @param name2: 显示名称2,不影响排序
+    @param type2: 榜单数据类型2,自定义,一般为职业等二级分类,不影响排序
+    @param value1: 显示值1,不影响排序
+    @param value2: 显示值2,不影响排序
+    @param cmpValue: 比较值1
+    @param cmpValue2: 比较值2
+    @param cmpValue3: 比较值3,没设定的话默认为时间戳比较值
+    @param groupValue1: 榜单分组2
+    @param id2: 扩展数据ID2
+    @param autoSort: 是否排序,默认True
+    @return: 是否上榜更新榜单
+    '''
+    if not GameWorld.IsCrossServer():
+        # 只有跨服服务器能调用
+        return
+    if not groupValue1 or not dataID:
+        return
+    billboardMgr = PyDataManager.GetCrossBillboardManager()
+    billboardObj = billboardMgr.GetCrossBillboard(billboardType, groupValue1, groupValue2)
+    billboardData = billboardObj.FindByID(dataID)
+    isNewData = False
+    if not billboardData:
+        isNewData = True
+        if billboardObj.IsFull():
+            # 与最后一名对比
+            lastBillBoardData = __CmpLastBillboardData(cmpValue, cmpValue2, cmpValue3, billboardObj)
+            if not lastBillBoardData:
+                GameWorld.DebugLog("    榜单值不超过最后一名,不上榜! ")
+                return
+            billboardData = lastBillBoardData
+            billboardData.clear()
+        else:
+            billboardData = PyGameDataStruct.tagDBCrossBillboard()
+            if not billboardObj.AddBillboardData(billboardData):
+                return
+            
+    # 没设置值默认为时间time,先上榜的排前面
+    if cmpValue3 == 0:
+        # 时间权值仅在比较值变更的情况下才更新, 防止其他附属值更新时导致比较值相同的玩家名次间会变动的问题
+        if isNewData or billboardData.CmpValue != cmpValue or billboardData.CmpValue2 != cmpValue2:
+            calcTime = GameWorld.ChangeTimeStrToNum("2090-01-01 00:00:00")
+            cmpValue3 = max(0, calcTime - int(time.time())) # 比较值3如果没指定值则默认存当前更新的time
+        else:
+            cmpValue3 = billboardData.CmpValue3
+            
+    cmpValueChange = billboardData.CmpValue != cmpValue or billboardData.CmpValue2 != cmpValue2 or billboardData.CmpValue3 != cmpValue3
+    
+    # 更新所有值
+    billboardData.GroupValue1 = groupValue1
+    billboardData.GroupValue2 = groupValue2
+    billboardData.BillboardType = billboardType
+    billboardData.ID = dataID
+    billboardData.ID2 = id2
+    billboardData.Name1 = name1
+    billboardData.Name2 = name2
+    billboardData.Type2 = type2
+    billboardData.Value1 = value1
+    billboardData.Value2 = value2
+    billboardData.CmpValue = cmpValue
+    billboardData.CmpValue2 = cmpValue2
+    billboardData.CmpValue3 = cmpValue3
+    
+    GameWorld.DebugLog("更新跨服排行榜值: billboardType=%s,groupValue1=%s,groupValue2=%s,dataID=%s,isNewData=%s,cmpValueChange=%s,type2=%s,value1=%s,value2=%s,cmpValue=%s,cmpValue2=%s,cmpValue3=%s" 
+                       % (billboardType, groupValue1, groupValue2, dataID, isNewData, cmpValueChange,
+                          type2, value1, value2, cmpValue, cmpValue2, cmpValue3), dataID)
+    
+    if autoSort and cmpValueChange:
+        billboardObj.SortData()
+    else:
+        billboardObj.UpdCrossServerDataVer()
+    return True
+
+def __CmpLastBillboardData(cmpValue, cmpValue2, cmpValue3, billboardObj):
+    ## 比较是否超过最后一名
+    # @return: 超过则返回最后一名数据实例,否则返回None
+    if not billboardObj.GetCount():
+        return
+    lastBillBoardData = billboardObj.At(billboardObj.GetCount() - 1)
+    if cmpValue < lastBillBoardData.CmpValue:
+        #无法上榜
+        return
+    elif cmpValue == lastBillBoardData.CmpValue: 
+        if cmpValue2 < lastBillBoardData.CmpValue2:
+            return
+        elif cmpValue2 == lastBillBoardData.CmpValue2:
+            if cmpValue3 <= lastBillBoardData.CmpValue3:
+                return
+    return lastBillBoardData
+
diff --git a/ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/CrossRealmMsg.py b/ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/CrossRealmMsg.py
index d660881..05939f6 100644
--- a/ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/CrossRealmMsg.py
+++ b/ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/CrossRealmMsg.py
@@ -21,6 +21,8 @@
 import IPY_GameServer
 import CrossRealmPlayer
 import PlayerCompensation
+import CrossActionControl
+import CrossBillboard
 import GameWorldBoss
 import CrossRealmPK
 import PlayerQuery
@@ -79,7 +81,16 @@
             
         elif msgType == ShareDefine.ClientServerMsg_PKBillboard:
             CrossRealmPK.ClientServerMsg_PKBillboard(serverGroupID, msgData)
-                        
+            
+        elif msgType == ShareDefine.ClientServerMsg_QueryBillboard:
+            CrossBillboard.ClientServerMsg_QueryBillboard(serverGroupID, msgData)
+            
+        elif msgType == ShareDefine.ClientServerMsg_UpdateBillboard:
+            CrossBillboard.ClientServerMsg_UpdateBillboard(serverGroupID, msgData)
+            
+        elif msgType == ShareDefine.ClientServerMsg_MailContent:
+            PlayerCompensation.ClientServerMsg_MailContent(serverGroupID, msgData, tick)
+            
         elif msgType == ShareDefine.ClientServerMsg_ChatCrossWorld:
             PlayerTalk.ClientServerMsg_ChatCrossWorld(serverGroupID, msgData, tick)
                         
@@ -136,6 +147,8 @@
     CrossRealmPlayer.Sync_CrossCommInitDataToClientServer(serverGroupID)
     CrossRealmPK.Sync_CrossPKInitDataToClientServer(tick, serverGroupID)
     CrossBoss.Sync_CrossBossInitDataToClientServer(serverGroupID)
+    CrossActionControl.Sync_CrossActInfoToClientServer(serverGroupID)
+    PlayerCompensation.Sync_CrossMailPlayerIDToClientServer(serverGroupID)
     return
 
 def MapServer_CrossServerReceiveMsg(msgType, msgData, serverGroupID):
@@ -253,11 +266,17 @@
         elif msgType == ShareDefine.CrossServerMsg_PKSyncBillboard:
             CrossRealmPK.CrossServerMsg_PKSyncBillboard(msgData)
             
+        elif msgType == ShareDefine.CrossServerMsg_SyncBillboard:
+            CrossBillboard.CrossServerMsg_SyncBillboard(msgData, tick)
+            
         elif msgType == ShareDefine.CrossServerMsg_CrossBossInfo:
             CrossBoss.CrossServerMsg_CrossBossInfo(msgData)
             
         elif msgType == ShareDefine.CrossServerMsg_CrossBossState:
             CrossBoss.CrossServerMsg_CrossBossState(msgData)
+            
+        elif msgType == ShareDefine.CrossServerMsg_CrossActInfo:
+            CrossActionControl.CrossServerMsg_CrossActInfo(msgData)
             
         elif msgType == ShareDefine.CrossServerMsg_PutInItem:
             CrossRealmPlayer.CrossServerMsg_PutInItem(msgData)
@@ -277,6 +296,12 @@
         elif msgType == ShareDefine.CrossServerMsg_SendMail:
             PlayerCompensation.CrossServerMsg_SendMail(msgData)
             
+        elif msgType == ShareDefine.CrossServerMsg_MailPlayerIDList:
+            PlayerCompensation.CrossServerMsg_MailPlayerIDList(msgData)
+            
+        elif msgType == ShareDefine.CrossServerMsg_MailContent:
+            PlayerCompensation.CrossServerMsg_MailContent(msgData)
+            
         elif msgType == ShareDefine.CrossServerMsg_FBPlayerCount:
             PlayerFB.CrossServerMsg_FBPlayerCount(msgData)
             
diff --git a/ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/GameWorldActionControl.py b/ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/GameWorldActionControl.py
index e75d064..0ef4888 100644
--- a/ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/GameWorldActionControl.py
+++ b/ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/GameWorldActionControl.py
@@ -37,6 +37,7 @@
 import GameWorldAverageLv
 import PlayerFamilyBoss
 import PlayerHorsePetBoss
+import CrossActionControl
 import GameWorldProcess
 import ChPyNetSendPack
 import NetPackCommon
@@ -106,6 +107,7 @@
     if GameWorld.IsCrossServer():
         # 跨服不处理运营活动
         return
+    CrossActionControl.SendMapServerCrossActionState()
     
     isReload, OperationActionInfo = __GetOperationActionInfo()
     mapServerInfoDict = OperationActionInfo[OperationAction_MapServerInfo]
@@ -506,6 +508,7 @@
     
     if GameWorld.IsCrossServer():
         # 跨服不处理运营活动
+        CrossActionControl.Dispose_CrossActState(reloadRefresh)
         return
     
     isReload, OperationActionInfo = __GetOperationActionInfo(False) # 这里必须传False
diff --git a/ServerPython/CoreServerGroup/GameServer/Script/IpyGameDataPY.py b/ServerPython/CoreServerGroup/GameServer/Script/IpyGameDataPY.py
index 1ea80b1..0516bb5 100644
--- a/ServerPython/CoreServerGroup/GameServer/Script/IpyGameDataPY.py
+++ b/ServerPython/CoreServerGroup/GameServer/Script/IpyGameDataPY.py
@@ -624,6 +624,27 @@
                         ("WORD", "LVLimit", 0),
                         ),
 
+                "CrossActCTGBillboard":(
+                        ("DWORD", "CfgID", 1),
+                        ("char", "ActGroupName", 0),
+                        ("list", "ServerIDRangeList", 0),
+                        ("char", "StartDate", 0),
+                        ("char", "EndDate", 0),
+                        ("dict", "NotifyInfoStart", 0),
+                        ("dict", "NotifyInfoEnd", 0),
+                        ("list", "NotifyInfoLoop", 0),
+                        ("BYTE", "IsDayReset", 0),
+                        ("list", "TemplateIDList", 0),
+                        ),
+
+                "CrossActCTGBillboardOrder":(
+                        ("DWORD", "TemplateID", 1),
+                        ("WORD", "OrderA", 0),
+                        ("WORD", "OrderB", 0),
+                        ("DWORD", "CTGAtleast", 0),
+                        ("list", "AwardItemList", 0),
+                        ),
+
                 "EquipStarUp":(
                         ("BYTE", "ClassLV", 1),
                         ("BYTE", "EquipPlace", 1),
@@ -1892,6 +1913,50 @@
     def GetNotifyInfoLoop(self): return self.NotifyInfoLoop # 全服提示信息 - 循环广播[间隔分钟, 广播key]
     def GetLVLimit(self): return self.LVLimit # 限制等级
 
+# 跨服充值排行活动时间表
+class IPY_CrossActCTGBillboard():
+    
+    def __init__(self):
+        self.CfgID = 0
+        self.ActGroupName = ""
+        self.ServerIDRangeList = []
+        self.StartDate = ""
+        self.EndDate = ""
+        self.NotifyInfoStart = {}
+        self.NotifyInfoEnd = {}
+        self.NotifyInfoLoop = []
+        self.IsDayReset = 0
+        self.TemplateIDList = []
+        return
+        
+    def GetCfgID(self): return self.CfgID # 配置ID
+    def GetActGroupName(self): return self.ActGroupName # 活动组名(同组活动的名字需相同)
+    def GetServerIDRangeList(self): return self.ServerIDRangeList # 活动的账号服务器ID范围列表 [[serverIDA, serverIDB], ...]
+    def GetStartDate(self): return self.StartDate # 开启日期
+    def GetEndDate(self): return self.EndDate # 结束日期
+    def GetNotifyInfoStart(self): return self.NotifyInfoStart # 全服提示信息 - 相对开始时间
+    def GetNotifyInfoEnd(self): return self.NotifyInfoEnd # 全服提示信息 - 相对结束时间
+    def GetNotifyInfoLoop(self): return self.NotifyInfoLoop # 全服提示信息 - 循环广播[循环分钟, 广播key, [广播参数列表可选]]
+    def GetIsDayReset(self): return self.IsDayReset # 是否每天重置
+    def GetTemplateIDList(self): return self.TemplateIDList # 模板ID列表
+
+# 跨服充值排行模板名次奖励表
+class IPY_CrossActCTGBillboardOrder():
+    
+    def __init__(self):
+        self.TemplateID = 0
+        self.OrderA = 0
+        self.OrderB = 0
+        self.CTGAtleast = 0
+        self.AwardItemList = []
+        return
+        
+    def GetTemplateID(self): return self.TemplateID # 模板ID
+    def GetOrderA(self): return self.OrderA # 名次A
+    def GetOrderB(self): return self.OrderB # 至名次B
+    def GetCTGAtleast(self): return self.CTGAtleast # 至少充值RMB
+    def GetAwardItemList(self): return self.AwardItemList # 奖励物品列表[[物品ID,个数,是否拍品], ...]
+
 # 装备升星表
 class IPY_EquipStarUp():
     
@@ -2084,6 +2149,10 @@
         self.ipyNewUniquenessArriveLen = len(self.ipyNewUniquenessArriveCache)
         self.ipyActLuckyTreasureCache = self.__LoadFileData("ActLuckyTreasure", IPY_ActLuckyTreasure)
         self.ipyActLuckyTreasureLen = len(self.ipyActLuckyTreasureCache)
+        self.ipyCrossActCTGBillboardCache = self.__LoadFileData("CrossActCTGBillboard", IPY_CrossActCTGBillboard)
+        self.ipyCrossActCTGBillboardLen = len(self.ipyCrossActCTGBillboardCache)
+        self.ipyCrossActCTGBillboardOrderCache = self.__LoadFileData("CrossActCTGBillboardOrder", IPY_CrossActCTGBillboardOrder)
+        self.ipyCrossActCTGBillboardOrderLen = len(self.ipyCrossActCTGBillboardOrderCache)
         self.ipyEquipStarUpCache = self.__LoadFileData("EquipStarUp", IPY_EquipStarUp)
         self.ipyEquipStarUpLen = len(self.ipyEquipStarUpCache)
         self.ipyFamilyWarRankAwardCache = self.__LoadFileData("FamilyWarRankAward", IPY_FamilyWarRankAward)
@@ -2368,6 +2437,10 @@
     def GetNewUniquenessArriveByIndex(self, index): return self.ipyNewUniquenessArriveCache[index]
     def GetActLuckyTreasureCount(self): return self.ipyActLuckyTreasureLen
     def GetActLuckyTreasureByIndex(self, index): return self.ipyActLuckyTreasureCache[index]
+    def GetCrossActCTGBillboardCount(self): return self.ipyCrossActCTGBillboardLen
+    def GetCrossActCTGBillboardByIndex(self, index): return self.ipyCrossActCTGBillboardCache[index]
+    def GetCrossActCTGBillboardOrderCount(self): return self.ipyCrossActCTGBillboardOrderLen
+    def GetCrossActCTGBillboardOrderByIndex(self, index): return self.ipyCrossActCTGBillboardOrderCache[index]
     def GetEquipStarUpCount(self): return self.ipyEquipStarUpLen
     def GetEquipStarUpByIndex(self, index): return self.ipyEquipStarUpCache[index]
     def GetFamilyWarRankAwardCount(self): return self.ipyFamilyWarRankAwardLen
diff --git a/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerCompensation.py b/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerCompensation.py
index 876684c..84c3f33 100644
--- a/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerCompensation.py
+++ b/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerCompensation.py
@@ -28,12 +28,16 @@
 import NetPackCommon
 import CommFunc
 import ChPyNetSendPack
+import PyGameDataStruct
+import CrossRealmMsg
 import DataRecordPack
 import ReadChConfig
 import PlayerDBOper
 import EventReport
 import IpyGameDataPY
 import PlayerControl
+import PyDataManager
+import PyGameData
 import datetime
 import uuid
 import math
@@ -68,6 +72,216 @@
 
 Def_RequestState = "CompensationRequestState"
 
+#==================================================================================================
+class CrossPersonalCompensationManager(object):
+    ## 跨服邮件管理,注意该类只处理数据逻辑,功能相关逻辑不要写在该类,不然重读脚本不会生效
+    
+    def __init__(self):
+        self.playerMailDict = {} # 玩家补偿列表 {playerID:{GUID:tagDBCrossPersonalCompensation, ...}, ...}
+        return
+    
+    # 保存数据 存数据库和realtimebackup
+    def GetSaveData(self):
+        savaData = ""
+        cntData = ""
+        cnt = 0
+        for mailDict in self.playerMailDict.values():
+            for mailObj in mailDict.values():
+                cnt += 1
+                savaData += mailObj.getBuffer()
+                
+        GameWorld.Log("Save DBCrossPersonalCompensation cnt :%s" % cnt)
+        return CommFunc.WriteDWORD(cntData, cnt) + savaData
+    
+    # 从数据库载入数据
+    def LoadPyGameData(self, datas, pos, dataslen):
+        cnt, pos = CommFunc.ReadDWORD(datas, pos)
+        GameWorld.Log("Load DBCrossPersonalCompensation cnt :%s" % cnt)
+        
+        for _ in xrange(cnt):
+            mailObj = PyGameDataStruct.tagDBCrossPersonalCompensation()
+            mailObj.clear()
+            pos += mailObj.readData(datas, pos, dataslen)
+            
+            playerID = mailObj.PlayerID
+            guid = mailObj.GUID
+            if playerID not in self.playerMailDict:
+                self.playerMailDict[playerID] = {}
+            mailDict = self.playerMailDict[playerID]
+            mailDict[guid] = mailObj
+            
+        return pos
+    
+def Sync_CrossMailPlayerIDToClientServer(serverGroupID=0):
+    ''' 同步有跨服邮件的玩家ID到子服
+    @param serverGroupID: 为0时同步所有子服
+    '''
+    crossMailMgr = PyDataManager.GetCrossPersonalCompensationManager()
+    addMailPlayerIDList = crossMailMgr.playerMailDict.keys()
+    if not addMailPlayerIDList:
+        return
+    # 同步子服务器
+    serverGroupIDList = [serverGroupID] if serverGroupID else []
+    dataMsg = {"IDType":"Add", "PlayerIDList":addMailPlayerIDList}
+    CrossRealmMsg.SendMsgToClientServer(ShareDefine.CrossServerMsg_MailPlayerIDList, dataMsg, serverGroupIDList)
+    return
+
+def CrossServerMsg_MailPlayerIDList(dataMsg):
+    ## 收到跨服服务器同步有跨服邮件的玩家ID列表
+    idType = dataMsg["IDType"]
+    playerIDList = dataMsg["PlayerIDList"]
+    for playerID in playerIDList:
+        if idType == "Del":
+            if playerID in PyGameData.g_crossMailPlayerDict:
+                PyGameData.g_crossMailPlayerDict.pop(playerID)
+            continue
+        
+        if idType == "Add":
+            if playerID in PyGameData.g_crossMailPlayerDict:
+                continue
+            PyGameData.g_crossMailPlayerDict[playerID] = 0
+            
+            player = GameWorld.GetPlayerManager().FindPlayerByID(playerID)
+            if not player or not player.GetInitOK():
+                continue
+            RequestToGetCrossMail(player)
+            
+    return
+
+def RequestToGetCrossMail(curPlayer):
+    ## 请求同步跨服邮件内容
+    playerID = curPlayer.GetPlayerID()
+    if playerID not in PyGameData.g_crossMailPlayerDict:
+        return
+    lastTick = PyGameData.g_crossMailPlayerDict[playerID]
+    tick = GameWorld.GetGameWorld().GetTick()
+    if tick - lastTick <= 30000:
+        return
+    PyGameData.g_crossMailPlayerDict[playerID] = tick
+    dataMsg = {"CMD":"Get", "PlayerID":playerID}
+    CrossRealmMsg.SendMsgToCrossServer(ShareDefine.ClientServerMsg_MailContent, dataMsg)
+    return
+
+def ClientServerMsg_MailContent(serverGroupID, msgData, tick):
+    ## 收到子服玩家请求同步跨服邮件
+    
+    GameWorld.Log("收到子服玩家同步个人邮件命令: serverGroupID=%s, %s" % (serverGroupID, msgData))
+    
+    reqCMD = msgData["CMD"]
+    playerID = msgData["PlayerID"]
+    guidList = msgData.get("GuidList", [])
+    crossMailMgr = PyDataManager.GetCrossPersonalCompensationManager()
+    if playerID not in crossMailMgr.playerMailDict:
+        return
+    playerMailDict = crossMailMgr.playerMailDict[playerID]
+    
+    if reqCMD == "Get":
+        SyncTickAttrKey = "SyncTick"
+        getMailList = []
+        for guid, mailObj in playerMailDict.items():
+            if hasattr(mailObj, SyncTickAttrKey):
+                getTick = getattr(mailObj, SyncTickAttrKey)
+                if tick - getTick <= 30000:
+                    GameWorld.DebugLog("短时间内重复请求领取的邮件不同步,防止重复发放! GUID=%s" % guid)
+                    continue
+            setattr(mailObj, SyncTickAttrKey, tick)
+            crossMailDict = {"PlayerID":mailObj.PlayerID, "GUID":mailObj.GUID, "LimitTime":mailObj.LimitTime,
+                             "Text":mailObj.Text, "ItemInfo":mailObj.ItemInfo, "Detail":mailObj.Detail,
+                             "Gold":mailObj.Gold, "GoldPaper":mailObj.GoldPaper, "Silver":mailObj.Silver,
+                             "MoneySource":mailObj.MoneySource
+                             }
+            getMailList.append(crossMailDict)
+            
+        if getMailList:
+            CrossRealmMsg.SendMsgToClientServer(ShareDefine.CrossServerMsg_MailContent, getMailList, [serverGroupID])
+            
+    elif reqCMD == "GetOK":
+        
+        for guid in guidList:
+            playerMailDict.pop(guid, None)
+            DataRecordPack.DR_GiveCompensationSuccess(playerID, guid)
+            
+        if not playerMailDict:
+            crossMailMgr.playerMailDict.pop(playerID, None)
+            dataMsg = {"IDType":"Del", "PlayerIDList":[playerID]}
+            CrossRealmMsg.SendMsgToClientServer(ShareDefine.CrossServerMsg_MailPlayerIDList, dataMsg, [serverGroupID])
+            
+    return
+
+def CrossServerMsg_MailContent(getMailList):
+    ## 收到跨服服务器同步的待发送邮件内容
+    
+    playerGetGUIDInfo = {}
+    for mailDict in getMailList:
+        GUID = mailDict.get("GUID", "")
+        playerID = mailDict.get("PlayerID", 0)
+        if not GUID or not playerID:
+            continue
+        
+        GameWorld.Log("收到跨服个人邮件内容:%s" % mailDict, playerID)
+        
+        addItemDictList = eval(mailDict.get("ItemInfo", "[]"))
+        LimitTime = mailDict.get("LimitTime", "")
+        Text = mailDict.get("Text", "")
+        gold = GameWorld.ToIntDef(mailDict.get("Gold"))
+        goldPaper = GameWorld.ToIntDef(mailDict.get("GoldPaper"))
+        silver = GameWorld.ToIntDef(mailDict.get("Silver"))
+        moneySource = GameWorld.ToIntDef(mailDict.get("MoneySource"), ChConfig.Def_GiveMoney_Mail)
+        detail = mailDict.get("Detail", "")
+        
+        AddPersonalItem(GUID, addItemDictList, [playerID], LimitTime, Text, gold, goldPaper, silver, detail, moneySource)
+        
+        if playerID not in playerGetGUIDInfo:
+            playerGetGUIDInfo[playerID] = []
+        guidList = playerGetGUIDInfo[playerID]
+        guidList.append(GUID)
+        
+    for playerID, guidList in playerGetGUIDInfo.items():
+        dataMsg = {"CMD":"GetOK", "PlayerID":playerID, "GuidList":guidList}
+        CrossRealmMsg.SendMsgToCrossServer(ShareDefine.ClientServerMsg_MailContent, dataMsg)
+        
+    return
+
+def __AddPlayerCrossMail(addItemDictList, PlayerIDList, LimitTime, Text, gold, goldPaper, silver, detail, moneySource):
+    ## 添加跨服玩家个人补偿邮件
+    
+    addMailPlayerIDList = []
+    crossMailMgr = PyDataManager.GetCrossPersonalCompensationManager()
+    for playerID in PlayerIDList:
+        GUID = str(uuid.uuid1()) # 由于跨服邮件由每个玩家独自同步个人邮件,所以插入时每个人的邮件单独GUID,防止批量发送同内容邮件时重复插入奖励物品
+        mailObj = PyGameDataStruct.tagDBCrossPersonalCompensation()
+        mailObj.PlayerID = playerID
+        mailObj.GUID = GUID
+        mailObj.LimitTime = LimitTime
+        mailObj.Text = Text
+        mailObj.TextLen = len(mailObj.Text)
+        mailObj.Gold = gold
+        mailObj.GoldPaper = goldPaper
+        mailObj.Silver = silver
+        mailObj.ItemInfo = json.dumps(addItemDictList, ensure_ascii=False)
+        mailObj.ItemLen = len(mailObj.ItemInfo)
+        mailObj.Detail = detail
+        mailObj.DetailLen = len(mailObj.Detail)
+        mailObj.MoneySource = moneySource
+        
+        if playerID not in crossMailMgr.playerMailDict:
+            crossMailMgr.playerMailDict[playerID] = {}
+            addMailPlayerIDList.append(playerID)
+        playerMailDict = crossMailMgr.playerMailDict[playerID]
+        playerMailDict[GUID] = mailObj
+        
+        #添加流向
+        addDict = {"LimitTime":LimitTime, "Text":Text, "Gold":gold, "GoldPaper":goldPaper, "Silver":silver, 
+                   "ItemListLen":len(addItemDictList), "Detail":detail, "MoneySource":moneySource, "CrossMail":True}
+        DataRecordPack.DR_AddPersonalCompensation(PlayerIDList, GUID, addItemDictList, addDict)
+    
+    if addMailPlayerIDList:
+        dataMsg = {"IDType":"Add", "PlayerIDList":addMailPlayerIDList}
+        CrossRealmMsg.SendMsgToClientServer(ShareDefine.CrossServerMsg_MailPlayerIDList, dataMsg)
+        
+    return
+
+#==================================================================================================
 ## 根据物品信息字典,生成补偿物品实例,用于GM工具添加补偿
 #  @param curItemDict 
 #  @return IpyCompensationItem
@@ -86,10 +300,10 @@
 #  @param addItemList [(itemID, itemCnt, 是否拍品), {或物品信息字典}, ...]
 #  @return GUID
 def SendPersonalItemMailEx(title, content, getDays, playerIDList, addItemList, gold = 0, goldPaper = 0, silver = 0, 
-                           detail="", moneySource=ChConfig.Def_GiveMoney_Mail):
+                           detail="", moneySource=ChConfig.Def_GiveMoney_Mail, crossMail=False):
     limitTime = str(GameWorld.GetDatetimeByDiffDays(getDays))
     limitTime = limitTime.split(".")[0]
-    return SendPersonalItemMail(title, content, limitTime, playerIDList, addItemList, gold, goldPaper, silver, detail, moneySource)
+    return SendPersonalItemMail(title, content, limitTime, playerIDList, addItemList, gold, goldPaper, silver, detail, moneySource, crossMail)
     
 def SendPersonalItemMailBatch(batchMailInfoList):
     ## 批量发送邮件
@@ -123,14 +337,14 @@
     return
 
 def SendMailByKey(mailTypeKey, playerIDList, addItemList, paramList=[], gold=0, goldPaper=0, silver=0, 
-                  detail="", moneySource=ChConfig.Def_GiveMoney_Mail):
+                  detail="", moneySource=ChConfig.Def_GiveMoney_Mail, crossMail=False):
     if not mailTypeKey:
         mailTypeKey = ShareDefine.DefaultLackSpaceMailType
     GameWorld.DebugLog("SendMailByKey %s, playerIDList=%s, addItemList=%s, paramList=%s, gold=%s, goldPaper=%s, silver=%s, moneySource=%s" 
                        % (mailTypeKey, playerIDList, addItemList, paramList, gold, goldPaper, silver, moneySource))
     title = ""
     content = "<MailTemplate>%s</MailTemplate>%s" % (mailTypeKey, json.dumps(paramList, ensure_ascii=False))
-    return SendPersonalItemMailEx(title, content, 30, playerIDList, addItemList, gold, goldPaper, silver, detail, moneySource)
+    return SendPersonalItemMailEx(title, content, 30, playerIDList, addItemList, gold, goldPaper, silver, detail, moneySource, crossMail)
 
 def CrossServerMsg_SendMail(msgData):
     ## 收到跨服服务器同步的发送邮件
@@ -147,7 +361,7 @@
 #  @return GUID
 #  @remarks addItemList支持append字典
 def SendPersonalItemMail(title, content, limitTime, playerIDList, addItemList, gold = 0, goldPaper = 0, silver = 0, 
-                         detail="", moneySource=ChConfig.Def_GiveMoney_Mail):
+                         detail="", moneySource=ChConfig.Def_GiveMoney_Mail, crossMail=False):
     if not playerIDList:
         return ""
     
@@ -185,7 +399,7 @@
         GUID = str(uuid.uuid1())
         AddPersonalItem(GUID, addItemDictList[startIndex:startIndex + perMailItemCnt], playerIDList, 
                                            limitTime, "%s<$_$>%s<$_$>%s" % (ChConfig.Def_Mail_SenderSys, title, content),
-                                           gold, goldPaper, silver, detail, moneySource)
+                                           gold, goldPaper, silver, detail, moneySource, crossMail)
     return GUID
 
 ## 发送纯文字个人补偿
@@ -514,8 +728,11 @@
 ## 添加个人补偿
 #  @param addItemDict, PlayerIDList, LimitTime, Text 
 #  @return None
-def AddPersonalItem(GUID, addItemDictList, PlayerIDList, LimitTime, Text, gold = 0, goldPaper = 0, silver = 0, detail="", moneySource=ChConfig.Def_GiveMoney_Mail):
+def AddPersonalItem(GUID, addItemDictList, PlayerIDList, LimitTime, Text, gold = 0, goldPaper = 0, silver = 0, 
+                    detail="", moneySource=ChConfig.Def_GiveMoney_Mail, crossMail=False):
     if GameWorld.IsCrossServer():
+        if crossMail:
+            __AddPlayerCrossMail(addItemDictList, PlayerIDList, LimitTime, Text, gold, goldPaper, silver, detail, moneySource)
         return
     GameWorld.DebugLog("Compensation### AddPersonalItem GUID:%s ItemDict:\n%s "%(GUID, addItemDictList))
     
@@ -633,6 +850,7 @@
 
 # 提取接收邮件下发
 def NotifyPlayerCompensation(curPlayer):
+    RequestToGetCrossMail(curPlayer)
     notifyList = SeekPlayerCompensation(curPlayer)
     SyncQueryCompensationResult(curPlayer, notifyList)
     return
diff --git a/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerControl.py b/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerControl.py
index fc99fab..992828b 100644
--- a/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerControl.py
+++ b/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerControl.py
@@ -71,16 +71,47 @@
     CrossRealmMsg.SendMsgToClientServer(ShareDefine.CrossServerMsg_Notify, crossNotifyList, serverGroupIDList)
     return
 
+def CrossNotifyEx(serverGroupIDList, crossNotifyList):
+    ''' 跨服广播信息提示,支持同步多条,同时也建议多条一起同步
+    @param serverGroupIDList: 需要同步到的目标服务器组ID列表
+    @param crossNotifyList: 信息提示列表,[[notifyType, paramsList, 自定义扩展信息], ...]  notifyType 如 ShareDefine.CrossNotify_CrossAct
+    '''
+    CrossRealmMsg.SendMsgToClientServer(ShareDefine.CrossServerMsg_Notify, crossNotifyList, serverGroupIDList)
+    return
+
 def CrossServerMsg_Notify(crossNotifyList):
     GameWorld.DebugLog("收到跨服同步的广播提示内容: count=%s" % len(crossNotifyList))
     for notifyInfo in crossNotifyList:
-        if "Type" not in notifyInfo or "Params" not in notifyInfo:
+        if isinstance(notifyInfo, dict):
+            if "Type" not in notifyInfo or "Params" not in notifyInfo:
+                continue
+            notifyType = notifyInfo["Type"]
+            params = notifyInfo["Params"]
+        elif isinstance(notifyInfo, list) and len(notifyInfo) >= 2:
+            notifyType, params = notifyInfo[:2]
+        else:
             continue
-        notifyType = notifyInfo["Type"]
-        params = notifyInfo["Params"]
+        
         if notifyType == ShareDefine.CrossNotify_World:
             country, msgMark, msgParamList = params
             WorldNotify(country, msgMark, msgParamList)
+        elif notifyType == ShareDefine.CrossNotify_CrossAct:
+            country, msgMark, msgParamList = params
+            serverIDRangeList = notifyInfo[2]
+            playerManager = GameWorld.GetPlayerManager()
+            for i in xrange(playerManager.GetPlayerCount()):
+                curPlayer = playerManager.GetPlayerByIndex(i)
+                if curPlayer == None or not curPlayer.GetInitOK() or GetIsTJG(curPlayer):
+                    continue
+                if not serverIDRangeList:
+                    NotifyCode(curPlayer, msgMark, msgParamList)
+                    return
+                playerServerID = GameWorld.GetPlayerServerID(curPlayer)
+                for serverIDA, serverIDB in serverIDRangeList:
+                    if serverIDA <= playerServerID <= serverIDB:
+                        NotifyCode(curPlayer, msgMark, msgParamList)
+                        break
+                    
         elif notifyType == ShareDefine.CrossNotify_Family:
             familyID, msgMark, msgParamList = params
             FamilyNotify(familyID, msgMark, msgParamList)
diff --git a/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerDBGSEvent.py b/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerDBGSEvent.py
index 1f74503..90f94aa 100644
--- a/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerDBGSEvent.py
+++ b/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerDBGSEvent.py
@@ -139,6 +139,8 @@
 # 服务器建盟次数
 Def_ServerCreatFamilyTimes = "CreatFamilyTimes"
 
+#设置跨服运营活动ID的标记
+Def_CrossActID = 'CAID_%s_%s' #参数为(运营活动名, 活动表配置cfgID)
 #设置运营活动ID的标记
 Def_OperationActID = 'OperationActID_%s' #参数为运营活动名
 #运营活动开启时世界等级,参数为运营活动名
diff --git a/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerQuery.py b/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerQuery.py
index 42df784..e684816 100644
--- a/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerQuery.py
+++ b/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerQuery.py
@@ -34,6 +34,7 @@
 import ChConfig
 import GMCommon
 import DirtyList
+import CrossBillboard
 import PlayerBillboard
 import PlayerExam
 import PlayerControl
@@ -549,6 +550,10 @@
     if callName == "UpdateBillboard":     #地图服务器更新排行榜
         PlayerBillboard.MapServer_UpdateBillboard(eval(resultName), tick)
         return
+
+    if callName == "UpdateCrossBillboard":     #地图服务器更新跨服排行榜
+        CrossBillboard.MapServer_UpdateCrossBillboard(eval(resultName))
+        return
     
     if callName == 'PyAddFamilyInfoValue':     #地图服务器增加战盟信息值
         curPlayer = GameWorld.GetPlayerManager().FindPlayerByID(srcPlayerID)
diff --git a/ServerPython/CoreServerGroup/GameServer/Script/PyDataManager.py b/ServerPython/CoreServerGroup/GameServer/Script/PyDataManager.py
index 5e225a8..7599174 100644
--- a/ServerPython/CoreServerGroup/GameServer/Script/PyDataManager.py
+++ b/ServerPython/CoreServerGroup/GameServer/Script/PyDataManager.py
@@ -14,7 +14,9 @@
 
 import GameWorld
 import PlayerSocial
+import CrossBillboard
 import PlayerFamilyStore
+import PlayerCompensation
 import PlayerBourse
 import GameWorldBoss
 import PlayerSealDemon
@@ -295,6 +297,8 @@
 
 class PyGameDataManager(object):
     def __init__(self):
+        self.CrossPersonalCompensationManager = PlayerCompensation.CrossPersonalCompensationManager()
+        self.CrossBillboardManager = CrossBillboard.CrossBillboardManager()
         self.PlayerAssistThanksPyManager = PlayerAssistThanksPyManager()
         self.PlayerAssistPyManager = PlayerAssistPyManager()
         self.PlayerViewCachePyManager = PlayerViewCachePyManager()
@@ -318,6 +322,8 @@
 
     def GetSaveData(self):
         buff = ""
+        buff += self.CrossPersonalCompensationManager.GetSaveData()
+        buff += self.CrossBillboardManager.GetSaveData()
         buff += self.PlayerAssistThanksPyManager.GetSaveData()
         buff += self.PlayerAssistPyManager.GetSaveData()
         buff += self.PlayerViewCachePyManager.GetSaveData()
@@ -340,6 +346,8 @@
         return buff
     
     def LoadGameData(self, gameBuffer, pos):
+        pos = self.CrossPersonalCompensationManager.LoadPyGameData(gameBuffer, pos, len(gameBuffer))
+        pos = self.CrossBillboardManager.LoadPyGameData(gameBuffer, pos, len(gameBuffer))
         pos = self.PlayerAssistThanksPyManager.LoadPyGameData(gameBuffer, pos, len(gameBuffer))
         pos = self.PlayerAssistPyManager.LoadPyGameData(gameBuffer, pos, len(gameBuffer))
         pos = self.PlayerViewCachePyManager.LoadPyGameData(gameBuffer, pos, len(gameBuffer))
@@ -369,6 +377,16 @@
         PyGameData.g_pyGameDataManager = pyGameDataMgr
     return pyGameDataMgr
 
+def GetCrossPersonalCompensationManager():
+    # 跨服个人补偿邮件管理
+    pyGameDataMgr = GetPyGameDataManager()
+    return pyGameDataMgr.CrossPersonalCompensationManager
+
+def GetCrossBillboardManager():
+    # 跨服排行榜管理
+    pyGameDataMgr = GetPyGameDataManager()
+    return pyGameDataMgr.CrossBillboardManager
+
 def GetPlayerAssistThanksPyManager():
     # 协助感谢表
     pyGameDataMgr = GetPyGameDataManager()
diff --git a/ServerPython/CoreServerGroup/GameServer/Script/PyGameData.py b/ServerPython/CoreServerGroup/GameServer/Script/PyGameData.py
index 3d93548..5e6afa0 100644
--- a/ServerPython/CoreServerGroup/GameServer/Script/PyGameData.py
+++ b/ServerPython/CoreServerGroup/GameServer/Script/PyGameData.py
@@ -91,6 +91,10 @@
 
 g_crossZoneName = "" # 跨服分区名
 
+g_crossActInfoDict = None # 跨服运营活动信息 {actName:{actInfoDict}, ...}
+
+g_crossMailPlayerDict = {} # 有跨服邮件的玩家ID信息 {playerID:tick, ...}
+
 g_crossPlayerViewCache = {} # 查看跨服玩家信息 {playerID:[cacheInfo, updTick], ...}
 
 g_crossPKPlayerDict = {} # 跨服PK玩家字典  {playerID:PKPlayer, ...}
diff --git a/ServerPython/CoreServerGroup/GameServer/Script/PyGameDataStruct.py b/ServerPython/CoreServerGroup/GameServer/Script/PyGameDataStruct.py
index e5a824c..bcb5cc3 100644
--- a/ServerPython/CoreServerGroup/GameServer/Script/PyGameDataStruct.py
+++ b/ServerPython/CoreServerGroup/GameServer/Script/PyGameDataStruct.py
@@ -15,6 +15,257 @@
 from ctypes import (Structure, memset, memmove, sizeof, addressof, create_string_buffer, string_at)
 import CommFunc
 
+# 跨服补偿个人领取表 #tagDBCrossPersonalCompensation
+class tagDBCrossPersonalCompensation(Structure):
+    _pack_ = 1
+    _fields_ = [
+        ('PlayerID', ctypes.c_ulong),
+        ('GUID', ctypes.c_char * 40),
+        ('LimitTime', ctypes.c_char * 30),
+        ('TextLen', ctypes.c_ulong),
+        ('Text', ctypes.c_char_p),
+        ('Gold', ctypes.c_ulong),
+        ('GoldPaper', ctypes.c_ulong),
+        ('Silver', ctypes.c_ulong),
+        ('ItemLen', ctypes.c_ushort),
+        ('ItemInfo', ctypes.c_char_p),
+        ('DetailLen', ctypes.c_ushort),
+        ('Detail', ctypes.c_char_p),
+        ('MoneySource', ctypes.c_ushort),
+        ('ADOResult', ctypes.c_ulong),
+    ]
+
+    def __init__(self):
+        Structure.__init__(self)
+        self.clear()
+
+    def clear(self):
+        self.PlayerID = 0
+        self.GUID = ''
+        self.LimitTime = ''
+        self.TextLen = 0
+        self.Text = ''
+        self.Gold = 0
+        self.GoldPaper = 0
+        self.Silver = 0
+        self.ItemLen = 0
+        self.ItemInfo = ''
+        self.DetailLen = 0
+        self.Detail = ''
+        self.MoneySource = 0
+
+    def readData(self, buf, pos = 0, length = 0):
+        if not pos <= length:
+            return -1
+        if len(buf) < pos + self.getLength():
+            return -1
+        self.clear()
+        self.PlayerID, pos = CommFunc.ReadDWORD(buf, pos)
+        self.GUID, pos = CommFunc.ReadString(buf, pos, 40)
+        self.LimitTime, pos = CommFunc.ReadString(buf, pos, 30)
+        self.TextLen, pos = CommFunc.ReadDWORD(buf, pos)
+        tmp, pos = CommFunc.ReadString(buf, pos, self.TextLen)
+        self.Text = ctypes.c_char_p(tmp)
+        self.Gold, pos = CommFunc.ReadDWORD(buf, pos)
+        self.GoldPaper, pos = CommFunc.ReadDWORD(buf, pos)
+        self.Silver, pos = CommFunc.ReadDWORD(buf, pos)
+        self.ItemLen, pos = CommFunc.ReadWORD(buf, pos)
+        tmp, pos = CommFunc.ReadString(buf, pos, self.ItemLen)
+        self.ItemInfo = ctypes.c_char_p(tmp)
+        self.DetailLen, pos = CommFunc.ReadWORD(buf, pos)
+        tmp, pos = CommFunc.ReadString(buf, pos, self.DetailLen)
+        self.Detail = ctypes.c_char_p(tmp)
+        self.MoneySource, pos = CommFunc.ReadWORD(buf, pos)
+        return self.getLength()
+
+    def getBuffer(self):
+        buf = ''
+        buf = CommFunc.WriteDWORD(buf, self.PlayerID)
+        buf = CommFunc.WriteString(buf, sizeof(ctypes.c_char) * 40, self.GUID)
+        buf = CommFunc.WriteString(buf, sizeof(ctypes.c_char) * 30, self.LimitTime)
+        buf = CommFunc.WriteDWORD(buf, self.TextLen)
+        buf = CommFunc.WriteString(buf, self.TextLen, self.Text)
+        buf = CommFunc.WriteDWORD(buf, self.Gold)
+        buf = CommFunc.WriteDWORD(buf, self.GoldPaper)
+        buf = CommFunc.WriteDWORD(buf, self.Silver)
+        buf = CommFunc.WriteWORD(buf, self.ItemLen)
+        buf = CommFunc.WriteString(buf, self.ItemLen, self.ItemInfo)
+        buf = CommFunc.WriteWORD(buf, self.DetailLen)
+        buf = CommFunc.WriteString(buf, self.DetailLen, self.Detail)
+        buf = CommFunc.WriteWORD(buf, self.MoneySource)
+        return buf
+
+    def getLength(self):
+        length = 0
+        length += sizeof(ctypes.c_ulong)
+        length += sizeof(ctypes.c_char) * 40
+        length += sizeof(ctypes.c_char) * 30
+        length += sizeof(ctypes.c_ulong)
+        length += self.TextLen
+        length += sizeof(ctypes.c_ulong)
+        length += sizeof(ctypes.c_ulong)
+        length += sizeof(ctypes.c_ulong)
+        length += sizeof(ctypes.c_ushort)
+        length += self.ItemLen
+        length += sizeof(ctypes.c_ushort)
+        length += self.DetailLen
+        length += sizeof(ctypes.c_ushort)
+        return length
+
+    def outputString(self):
+        output = '''// 跨服补偿个人领取表 #tagDBCrossPersonalCompensation:
+            PlayerID = %s,
+            GUID = %s,
+            LimitTime = %s,
+            TextLen = %s,
+            Text = %s,
+            Gold = %s,
+            GoldPaper = %s,
+            Silver = %s,
+            ItemLen = %s,
+            ItemInfo = %s,
+            DetailLen = %s,
+            Detail = %s,
+            MoneySource = %s,
+            ADOResult = %s,
+            '''%(
+                self.PlayerID,
+                self.GUID,
+                self.LimitTime,
+                self.TextLen,
+                self.Text,
+                self.Gold,
+                self.GoldPaper,
+                self.Silver,
+                self.ItemLen,
+                self.ItemInfo,
+                self.DetailLen,
+                self.Detail,
+                self.MoneySource,
+                self.ADOResult,
+            )
+        return output
+
+    #Char数组类型Set接口,使用该接口对此类型数据赋值,防止赋值的数据过长报错
+    def SetGUID(self,Str):
+        if len(Str)<=40:
+            self.GUID = Str
+        else:
+            self.GUID = Str[:40]
+            
+    def SetLimitTime(self,Str):
+        if len(Str)<=30:
+            self.LimitTime = Str
+        else:
+            self.LimitTime = Str[:30]
+            
+
+# 跨服排行榜 #tagDBCrossBillboard
+class tagDBCrossBillboard(Structure):
+    _pack_ = 1
+    _fields_ = [
+        ('GroupValue1', ctypes.c_ubyte),
+        ('GroupValue2', ctypes.c_ubyte),
+        ('BillboardType', ctypes.c_ubyte),
+        ('ID', ctypes.c_ulong),
+        ('ID2', ctypes.c_ulong),
+        ('Name1', ctypes.c_char * 33),
+        ('Name2', ctypes.c_char * 33),
+        ('Type2', ctypes.c_ubyte),
+        ('Value1', ctypes.c_ulong),
+        ('Value2', ctypes.c_ulong),
+        ('CmpValue', ctypes.c_ulong),
+        ('CmpValue2', ctypes.c_ulong),
+        ('CmpValue3', ctypes.c_ulong),
+        ('ADOResult', ctypes.c_ulong),
+    ]
+
+    def __init__(self):
+        Structure.__init__(self)
+        self.clear()
+
+
+    def clear(self):
+        memset(addressof(self), 0, self.getLength())
+
+    def readData(self, buf, pos = 0, length = 0):
+        if not pos <= length:
+            return -1
+        if len(buf) < pos + self.getLength():
+            return -1
+        self.clear()
+        self.GroupValue1, pos = CommFunc.ReadBYTE(buf, pos)
+        self.GroupValue2, pos = CommFunc.ReadBYTE(buf, pos)
+        self.BillboardType, pos = CommFunc.ReadBYTE(buf, pos)
+        self.ID, pos = CommFunc.ReadDWORD(buf, pos)
+        self.ID2, pos = CommFunc.ReadDWORD(buf, pos)
+        self.Name1, pos = CommFunc.ReadString(buf, pos, 33)
+        self.Name2, pos = CommFunc.ReadString(buf, pos, 33)
+        self.Type2, pos = CommFunc.ReadBYTE(buf, pos)
+        self.Value1, pos = CommFunc.ReadDWORD(buf, pos)
+        self.Value2, pos = CommFunc.ReadDWORD(buf, pos)
+        self.CmpValue, pos = CommFunc.ReadDWORD(buf, pos)
+        self.CmpValue2, pos = CommFunc.ReadDWORD(buf, pos)
+        self.CmpValue3, pos = CommFunc.ReadDWORD(buf, pos)
+        return self.getLength()
+
+
+    def getBuffer(self):
+        buf = create_string_buffer(self.getLength())
+        memmove(addressof(buf), addressof(self), self.getLength())
+        return string_at(addressof(buf), self.getLength())
+
+    def getLength(self):
+        return sizeof(tagDBCrossBillboard)
+
+    def outputString(self):
+        output = '''// 跨服排行榜 #tagDBCrossBillboard:
+            GroupValue1 = %s,
+            GroupValue2 = %s,
+            BillboardType = %s,
+            ID = %s,
+            ID2 = %s,
+            Name1 = %s,
+            Name2 = %s,
+            Type2 = %s,
+            Value1 = %s,
+            Value2 = %s,
+            CmpValue = %s,
+            CmpValue2 = %s,
+            CmpValue3 = %s,
+            ADOResult = %s,
+            '''%(
+                self.GroupValue1,
+                self.GroupValue2,
+                self.BillboardType,
+                self.ID,
+                self.ID2,
+                self.Name1,
+                self.Name2,
+                self.Type2,
+                self.Value1,
+                self.Value2,
+                self.CmpValue,
+                self.CmpValue2,
+                self.CmpValue3,
+                self.ADOResult,
+            )
+        return output
+
+    #Char数组类型Set接口,使用该接口对此类型数据赋值,防止赋值的数据过长报错
+    def SetName1(self,Str):
+        if len(Str)<=33:
+            self.Name1 = Str
+        else:
+            self.Name1 = Str[:33]
+            
+    def SetName2(self,Str):
+        if len(Str)<=33:
+            self.Name2 = Str
+        else:
+            self.Name2 = Str[:33]
+            
+
 # 协助感谢表 #tagDBAssistThanks
 class tagDBAssistThanks(Structure):
     _pack_ = 1
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetPack.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetPack.py
index 734ef0f..1282455 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetPack.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetPack.py
@@ -3767,6 +3767,66 @@
 
 
 #------------------------------------------------------
+# C0 04 查看跨服排行榜 #tagCGViewCrossBillboard
+
+class  tagCGViewCrossBillboard(Structure):
+    _pack_ = 1
+    _fields_ = [
+                  ("Cmd", c_ubyte),
+                  ("SubCmd", c_ubyte),
+                  ("Type", c_ubyte),    #榜单类型
+                  ("GroupValue1", c_ubyte),    # 分组值1
+                  ("GroupValue2", c_ubyte),    # 分组值2,与分组值1组合归为同组榜单数据
+                  ]
+
+    def __init__(self):
+        self.Clear()
+        self.Cmd = 0xC0
+        self.SubCmd = 0x04
+        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 = 0x04
+        self.Type = 0
+        self.GroupValue1 = 0
+        self.GroupValue2 = 0
+        return
+
+    def GetLength(self):
+        return sizeof(tagCGViewCrossBillboard)
+
+    def GetBuffer(self):
+        return string_at(addressof(self), self.GetLength())
+
+    def OutputString(self):
+        DumpString = '''// C0 04 查看跨服排行榜 //tagCGViewCrossBillboard:
+                                Cmd:%s,
+                                SubCmd:%s,
+                                Type:%d,
+                                GroupValue1:%d,
+                                GroupValue2:%d
+                                '''\
+                                %(
+                                self.Cmd,
+                                self.SubCmd,
+                                self.Type,
+                                self.GroupValue1,
+                                self.GroupValue2
+                                )
+        return DumpString
+
+
+m_NAtagCGViewCrossBillboard=tagCGViewCrossBillboard()
+ChNetPackDict[eval("0x%02x%02x"%(m_NAtagCGViewCrossBillboard.Cmd,m_NAtagCGViewCrossBillboard.SubCmd))] = m_NAtagCGViewCrossBillboard
+
+
+#------------------------------------------------------
 # C0 01 查看跨服竞技场赛季排行榜 #tagCGViewCrossPKBillboard
 
 class  tagCGViewCrossPKBillboard(Structure):
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetSendPack.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetSendPack.py
index 054a382..f873f17 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetSendPack.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetSendPack.py
@@ -5067,6 +5067,70 @@
 
 
 #------------------------------------------------------
+# AC 12 跨服运营活动结束 # tagGCCrossActEnd
+
+class  tagGCCrossActEnd(Structure):
+    Head = tagHead()
+    ActNameLen = 0    #(BYTE ActNameLen)
+    ActName = ""    #(String ActName)
+    data = None
+
+    def __init__(self):
+        self.Clear()
+        self.Head.Cmd = 0xAC
+        self.Head.SubCmd = 0x12
+        return
+
+    def ReadData(self, _lpData, _pos=0, _Len=0):
+        self.Clear()
+        _pos = self.Head.ReadData(_lpData, _pos)
+        self.ActNameLen,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        self.ActName,_pos = CommFunc.ReadString(_lpData, _pos,self.ActNameLen)
+        return _pos
+
+    def Clear(self):
+        self.Head = tagHead()
+        self.Head.Clear()
+        self.Head.Cmd = 0xAC
+        self.Head.SubCmd = 0x12
+        self.ActNameLen = 0
+        self.ActName = ""
+        return
+
+    def GetLength(self):
+        length = 0
+        length += self.Head.GetLength()
+        length += 1
+        length += len(self.ActName)
+
+        return length
+
+    def GetBuffer(self):
+        data = ''
+        data = CommFunc.WriteString(data, self.Head.GetLength(), self.Head.GetBuffer())
+        data = CommFunc.WriteBYTE(data, self.ActNameLen)
+        data = CommFunc.WriteString(data, self.ActNameLen, self.ActName)
+        return data
+
+    def OutputString(self):
+        DumpString = '''
+                                Head:%s,
+                                ActNameLen:%d,
+                                ActName:%s
+                                '''\
+                                %(
+                                self.Head.OutputString(),
+                                self.ActNameLen,
+                                self.ActName
+                                )
+        return DumpString
+
+
+m_NAtagGCCrossActEnd=tagGCCrossActEnd()
+ChNetPackDict[eval("0x%02x%02x"%(m_NAtagGCCrossActEnd.Head.Cmd,m_NAtagGCCrossActEnd.Head.SubCmd))] = m_NAtagGCCrossActEnd
+
+
+#------------------------------------------------------
 # AC 09 仙界盛典活动信息 #tagGCFairyCeremonyInfo
 
 class  tagGCFairyCeremonyInfo(Structure):
@@ -11037,6 +11101,190 @@
 
 m_NAtagGCTeamMemFuncDataList=tagGCTeamMemFuncDataList()
 ChNetPackDict[eval("0x%02x%02x"%(m_NAtagGCTeamMemFuncDataList.Head.Cmd,m_NAtagGCTeamMemFuncDataList.Head.SubCmd))] = m_NAtagGCTeamMemFuncDataList
+
+
+#------------------------------------------------------
+# C0 07 跨服排行榜信息 #tagGCCrossBillboardInfo
+
+class  tagGCCrossBillboardData(Structure):
+    ID = 0    #(DWORD ID)
+    Name1 = ""    #(char Name1[33])//名字1,用来显示排序对象名字 
+    Name2 = ""    #(char Name2[33])//名字2
+    Type2 = 0    #(BYTE Type2)//附加类型,用来表示排序对象的类型,比如,玩家所属职业门派,宠物类型等
+    Value1 = 0    #(DWORD Value1)//自定义值1
+    Value2 = 0    #(DWORD Value2)//自定义值2
+    CmpValue = 0    #(DWORD CmpValue)// 比较权值
+    CmpValue2 = 0    #(DWORD CmpValue2)// 比较权值
+    CmpValue3 = 0    #(DWORD CmpValue3)// 比较权值
+    data = None
+
+    def __init__(self):
+        self.Clear()
+        return
+
+    def ReadData(self, _lpData, _pos=0, _Len=0):
+        self.Clear()
+        self.ID,_pos = CommFunc.ReadDWORD(_lpData, _pos)
+        self.Name1,_pos = CommFunc.ReadString(_lpData, _pos,33)
+        self.Name2,_pos = CommFunc.ReadString(_lpData, _pos,33)
+        self.Type2,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        self.Value1,_pos = CommFunc.ReadDWORD(_lpData, _pos)
+        self.Value2,_pos = CommFunc.ReadDWORD(_lpData, _pos)
+        self.CmpValue,_pos = CommFunc.ReadDWORD(_lpData, _pos)
+        self.CmpValue2,_pos = CommFunc.ReadDWORD(_lpData, _pos)
+        self.CmpValue3,_pos = CommFunc.ReadDWORD(_lpData, _pos)
+        return _pos
+
+    def Clear(self):
+        self.ID = 0
+        self.Name1 = ""
+        self.Name2 = ""
+        self.Type2 = 0
+        self.Value1 = 0
+        self.Value2 = 0
+        self.CmpValue = 0
+        self.CmpValue2 = 0
+        self.CmpValue3 = 0
+        return
+
+    def GetLength(self):
+        length = 0
+        length += 4
+        length += 33
+        length += 33
+        length += 1
+        length += 4
+        length += 4
+        length += 4
+        length += 4
+        length += 4
+
+        return length
+
+    def GetBuffer(self):
+        data = ''
+        data = CommFunc.WriteDWORD(data, self.ID)
+        data = CommFunc.WriteString(data, 33, self.Name1)
+        data = CommFunc.WriteString(data, 33, self.Name2)
+        data = CommFunc.WriteBYTE(data, self.Type2)
+        data = CommFunc.WriteDWORD(data, self.Value1)
+        data = CommFunc.WriteDWORD(data, self.Value2)
+        data = CommFunc.WriteDWORD(data, self.CmpValue)
+        data = CommFunc.WriteDWORD(data, self.CmpValue2)
+        data = CommFunc.WriteDWORD(data, self.CmpValue3)
+        return data
+
+    def OutputString(self):
+        DumpString = '''
+                                ID:%d,
+                                Name1:%s,
+                                Name2:%s,
+                                Type2:%d,
+                                Value1:%d,
+                                Value2:%d,
+                                CmpValue:%d,
+                                CmpValue2:%d,
+                                CmpValue3:%d
+                                '''\
+                                %(
+                                self.ID,
+                                self.Name1,
+                                self.Name2,
+                                self.Type2,
+                                self.Value1,
+                                self.Value2,
+                                self.CmpValue,
+                                self.CmpValue2,
+                                self.CmpValue3
+                                )
+        return DumpString
+
+
+class  tagGCCrossBillboardInfo(Structure):
+    Head = tagHead()
+    Type = 0    #(BYTE Type)//榜单类型
+    GroupValue1 = 0    #(BYTE GroupValue1)// 分组值1
+    GroupValue2 = 0    #(BYTE GroupValue2)// 分组值2,与分组值1组合归为同组榜单数据
+    BillboardCount = 0    #(BYTE BillboardCount)
+    CrossBillboardDataList = list()    #(vector<tagGCCrossBillboardData> CrossBillboardDataList)
+    data = None
+
+    def __init__(self):
+        self.Clear()
+        self.Head.Cmd = 0xC0
+        self.Head.SubCmd = 0x07
+        return
+
+    def ReadData(self, _lpData, _pos=0, _Len=0):
+        self.Clear()
+        _pos = self.Head.ReadData(_lpData, _pos)
+        self.Type,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        self.GroupValue1,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        self.GroupValue2,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        self.BillboardCount,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        for i in range(self.BillboardCount):
+            temCrossBillboardDataList = tagGCCrossBillboardData()
+            _pos = temCrossBillboardDataList.ReadData(_lpData, _pos)
+            self.CrossBillboardDataList.append(temCrossBillboardDataList)
+        return _pos
+
+    def Clear(self):
+        self.Head = tagHead()
+        self.Head.Clear()
+        self.Head.Cmd = 0xC0
+        self.Head.SubCmd = 0x07
+        self.Type = 0
+        self.GroupValue1 = 0
+        self.GroupValue2 = 0
+        self.BillboardCount = 0
+        self.CrossBillboardDataList = list()
+        return
+
+    def GetLength(self):
+        length = 0
+        length += self.Head.GetLength()
+        length += 1
+        length += 1
+        length += 1
+        length += 1
+        for i in range(self.BillboardCount):
+            length += self.CrossBillboardDataList[i].GetLength()
+
+        return length
+
+    def GetBuffer(self):
+        data = ''
+        data = CommFunc.WriteString(data, self.Head.GetLength(), self.Head.GetBuffer())
+        data = CommFunc.WriteBYTE(data, self.Type)
+        data = CommFunc.WriteBYTE(data, self.GroupValue1)
+        data = CommFunc.WriteBYTE(data, self.GroupValue2)
+        data = CommFunc.WriteBYTE(data, self.BillboardCount)
+        for i in range(self.BillboardCount):
+            data = CommFunc.WriteString(data, self.CrossBillboardDataList[i].GetLength(), self.CrossBillboardDataList[i].GetBuffer())
+        return data
+
+    def OutputString(self):
+        DumpString = '''
+                                Head:%s,
+                                Type:%d,
+                                GroupValue1:%d,
+                                GroupValue2:%d,
+                                BillboardCount:%d,
+                                CrossBillboardDataList:%s
+                                '''\
+                                %(
+                                self.Head.OutputString(),
+                                self.Type,
+                                self.GroupValue1,
+                                self.GroupValue2,
+                                self.BillboardCount,
+                                "..."
+                                )
+        return DumpString
+
+
+m_NAtagGCCrossBillboardInfo=tagGCCrossBillboardInfo()
+ChNetPackDict[eval("0x%02x%02x"%(m_NAtagGCCrossBillboardInfo.Head.Cmd,m_NAtagGCCrossBillboardInfo.Head.SubCmd))] = m_NAtagGCCrossBillboardInfo
 
 
 #------------------------------------------------------
@@ -25809,6 +26057,427 @@
 
 
 #------------------------------------------------------
+# AA 32 跨服充值排行活动信息 #tagMCCACTGBillboardInfo
+
+class  tagMCCACTGBillboardAwardItem(Structure):
+    _pack_ = 1
+    _fields_ = [
+                  ("ItemID", c_int),    
+                  ("ItemCount", c_ushort),    
+                  ("IsBind", c_ubyte),    # 是否拍品
+                  ]
+
+    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.ItemID = 0
+        self.ItemCount = 0
+        self.IsBind = 0
+        return
+
+    def GetLength(self):
+        return sizeof(tagMCCACTGBillboardAwardItem)
+
+    def GetBuffer(self):
+        return string_at(addressof(self), self.GetLength())
+
+    def OutputString(self):
+        DumpString = '''// AA 32 跨服充值排行活动信息 //tagMCCACTGBillboardInfo:
+                                ItemID:%d,
+                                ItemCount:%d,
+                                IsBind:%d
+                                '''\
+                                %(
+                                self.ItemID,
+                                self.ItemCount,
+                                self.IsBind
+                                )
+        return DumpString
+
+
+class  tagMCCACTGBillboardDabiao(Structure):
+    AwardIndex = 0    #(BYTE AwardIndex)// 奖励索引 0~31
+    NeedRMB = 0    #(DWORD NeedRMB)// 所需充值RMB
+    AwardItemCount = 0    #(BYTE AwardItemCount)// 奖励物品数
+    AwardItemList = list()    #(vector<tagMCCACTGBillboardAwardItem> AwardItemList)// 奖励物品信息
+    data = None
+
+    def __init__(self):
+        self.Clear()
+        return
+
+    def ReadData(self, _lpData, _pos=0, _Len=0):
+        self.Clear()
+        self.AwardIndex,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        self.NeedRMB,_pos = CommFunc.ReadDWORD(_lpData, _pos)
+        self.AwardItemCount,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        for i in range(self.AwardItemCount):
+            temAwardItemList = tagMCCACTGBillboardAwardItem()
+            _pos = temAwardItemList.ReadData(_lpData, _pos)
+            self.AwardItemList.append(temAwardItemList)
+        return _pos
+
+    def Clear(self):
+        self.AwardIndex = 0
+        self.NeedRMB = 0
+        self.AwardItemCount = 0
+        self.AwardItemList = list()
+        return
+
+    def GetLength(self):
+        length = 0
+        length += 1
+        length += 4
+        length += 1
+        for i in range(self.AwardItemCount):
+            length += self.AwardItemList[i].GetLength()
+
+        return length
+
+    def GetBuffer(self):
+        data = ''
+        data = CommFunc.WriteBYTE(data, self.AwardIndex)
+        data = CommFunc.WriteDWORD(data, self.NeedRMB)
+        data = CommFunc.WriteBYTE(data, self.AwardItemCount)
+        for i in range(self.AwardItemCount):
+            data = CommFunc.WriteString(data, self.AwardItemList[i].GetLength(), self.AwardItemList[i].GetBuffer())
+        return data
+
+    def OutputString(self):
+        DumpString = '''
+                                AwardIndex:%d,
+                                NeedRMB:%d,
+                                AwardItemCount:%d,
+                                AwardItemList:%s
+                                '''\
+                                %(
+                                self.AwardIndex,
+                                self.NeedRMB,
+                                self.AwardItemCount,
+                                "..."
+                                )
+        return DumpString
+
+
+class  tagMCCACTGBillboardOrder(Structure):
+    OrderA = 0    #(BYTE OrderA)// 名次A
+    OrderB = 0    #(BYTE OrderB)// 至名次B
+    NeedRMB = 0    #(DWORD NeedRMB)// 所需充值RMB,未达标的该名次空,排名后面的玩家向下顺延
+    AwardItemCount = 0    #(BYTE AwardItemCount)// 奖励物品数
+    AwardItemList = list()    #(vector<tagMCCACTGBillboardAwardItem> AwardItemList)// 奖励物品信息
+    data = None
+
+    def __init__(self):
+        self.Clear()
+        return
+
+    def ReadData(self, _lpData, _pos=0, _Len=0):
+        self.Clear()
+        self.OrderA,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        self.OrderB,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        self.NeedRMB,_pos = CommFunc.ReadDWORD(_lpData, _pos)
+        self.AwardItemCount,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        for i in range(self.AwardItemCount):
+            temAwardItemList = tagMCCACTGBillboardAwardItem()
+            _pos = temAwardItemList.ReadData(_lpData, _pos)
+            self.AwardItemList.append(temAwardItemList)
+        return _pos
+
+    def Clear(self):
+        self.OrderA = 0
+        self.OrderB = 0
+        self.NeedRMB = 0
+        self.AwardItemCount = 0
+        self.AwardItemList = list()
+        return
+
+    def GetLength(self):
+        length = 0
+        length += 1
+        length += 1
+        length += 4
+        length += 1
+        for i in range(self.AwardItemCount):
+            length += self.AwardItemList[i].GetLength()
+
+        return length
+
+    def GetBuffer(self):
+        data = ''
+        data = CommFunc.WriteBYTE(data, self.OrderA)
+        data = CommFunc.WriteBYTE(data, self.OrderB)
+        data = CommFunc.WriteDWORD(data, self.NeedRMB)
+        data = CommFunc.WriteBYTE(data, self.AwardItemCount)
+        for i in range(self.AwardItemCount):
+            data = CommFunc.WriteString(data, self.AwardItemList[i].GetLength(), self.AwardItemList[i].GetBuffer())
+        return data
+
+    def OutputString(self):
+        DumpString = '''
+                                OrderA:%d,
+                                OrderB:%d,
+                                NeedRMB:%d,
+                                AwardItemCount:%d,
+                                AwardItemList:%s
+                                '''\
+                                %(
+                                self.OrderA,
+                                self.OrderB,
+                                self.NeedRMB,
+                                self.AwardItemCount,
+                                "..."
+                                )
+        return DumpString
+
+
+class  tagMCCACTGBillboardTempInfo(Structure):
+    TemplateID = 0    #(BYTE TemplateID)// 活动模板ID
+    DabiaoAwardCount = 0    #(BYTE DabiaoAwardCount)// 达标奖励档数
+    DabiaoAwardInfo = list()    #(vector<tagMCCACTGBillboardDabiao> DabiaoAwardInfo)// 达标奖励信息
+    OrderAwardCount = 0    #(BYTE OrderAwardCount)// 排行奖励档数
+    OrderAwardInfo = list()    #(vector<tagMCCACTGBillboardOrder> OrderAwardInfo)// 排行奖励信息
+    data = None
+
+    def __init__(self):
+        self.Clear()
+        return
+
+    def ReadData(self, _lpData, _pos=0, _Len=0):
+        self.Clear()
+        self.TemplateID,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        self.DabiaoAwardCount,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        for i in range(self.DabiaoAwardCount):
+            temDabiaoAwardInfo = tagMCCACTGBillboardDabiao()
+            _pos = temDabiaoAwardInfo.ReadData(_lpData, _pos)
+            self.DabiaoAwardInfo.append(temDabiaoAwardInfo)
+        self.OrderAwardCount,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        for i in range(self.OrderAwardCount):
+            temOrderAwardInfo = tagMCCACTGBillboardOrder()
+            _pos = temOrderAwardInfo.ReadData(_lpData, _pos)
+            self.OrderAwardInfo.append(temOrderAwardInfo)
+        return _pos
+
+    def Clear(self):
+        self.TemplateID = 0
+        self.DabiaoAwardCount = 0
+        self.DabiaoAwardInfo = list()
+        self.OrderAwardCount = 0
+        self.OrderAwardInfo = list()
+        return
+
+    def GetLength(self):
+        length = 0
+        length += 1
+        length += 1
+        for i in range(self.DabiaoAwardCount):
+            length += self.DabiaoAwardInfo[i].GetLength()
+        length += 1
+        for i in range(self.OrderAwardCount):
+            length += self.OrderAwardInfo[i].GetLength()
+
+        return length
+
+    def GetBuffer(self):
+        data = ''
+        data = CommFunc.WriteBYTE(data, self.TemplateID)
+        data = CommFunc.WriteBYTE(data, self.DabiaoAwardCount)
+        for i in range(self.DabiaoAwardCount):
+            data = CommFunc.WriteString(data, self.DabiaoAwardInfo[i].GetLength(), self.DabiaoAwardInfo[i].GetBuffer())
+        data = CommFunc.WriteBYTE(data, self.OrderAwardCount)
+        for i in range(self.OrderAwardCount):
+            data = CommFunc.WriteString(data, self.OrderAwardInfo[i].GetLength(), self.OrderAwardInfo[i].GetBuffer())
+        return data
+
+    def OutputString(self):
+        DumpString = '''
+                                TemplateID:%d,
+                                DabiaoAwardCount:%d,
+                                DabiaoAwardInfo:%s,
+                                OrderAwardCount:%d,
+                                OrderAwardInfo:%s
+                                '''\
+                                %(
+                                self.TemplateID,
+                                self.DabiaoAwardCount,
+                                "...",
+                                self.OrderAwardCount,
+                                "..."
+                                )
+        return DumpString
+
+
+class  tagMCCACTGBillboardInfo(Structure):
+    Head = tagHead()
+    ServerInfoLen = 0    #(BYTE ServerInfoLen)
+    ServerIDRangeInfo = ""    #(String ServerIDRangeInfo)//开放该活动的服务器ID范围列表,json格式 [[IDA, IDB], ...], [] 为全服
+    GroupValue1 = 0    #(BYTE GroupValue1)// 活动榜单分组值1,用于查询对应榜单
+    StartDate = ""    #(char StartDate[10])// 开始日期 y-m-d
+    EndtDate = ""    #(char EndtDate[10])// 结束日期 y-m-d
+    TemplateID = 0    #(BYTE TemplateID)// 当前活动模板ID
+    TemplateCount = 0    #(BYTE TemplateCount)
+    TempInfo = list()    #(vector<tagMCCACTGBillboardTempInfo> TempInfo)// 模板信息
+    data = None
+
+    def __init__(self):
+        self.Clear()
+        self.Head.Cmd = 0xAA
+        self.Head.SubCmd = 0x32
+        return
+
+    def ReadData(self, _lpData, _pos=0, _Len=0):
+        self.Clear()
+        _pos = self.Head.ReadData(_lpData, _pos)
+        self.ServerInfoLen,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        self.ServerIDRangeInfo,_pos = CommFunc.ReadString(_lpData, _pos,self.ServerInfoLen)
+        self.GroupValue1,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        self.StartDate,_pos = CommFunc.ReadString(_lpData, _pos,10)
+        self.EndtDate,_pos = CommFunc.ReadString(_lpData, _pos,10)
+        self.TemplateID,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        self.TemplateCount,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        for i in range(self.TemplateCount):
+            temTempInfo = tagMCCACTGBillboardTempInfo()
+            _pos = temTempInfo.ReadData(_lpData, _pos)
+            self.TempInfo.append(temTempInfo)
+        return _pos
+
+    def Clear(self):
+        self.Head = tagHead()
+        self.Head.Clear()
+        self.Head.Cmd = 0xAA
+        self.Head.SubCmd = 0x32
+        self.ServerInfoLen = 0
+        self.ServerIDRangeInfo = ""
+        self.GroupValue1 = 0
+        self.StartDate = ""
+        self.EndtDate = ""
+        self.TemplateID = 0
+        self.TemplateCount = 0
+        self.TempInfo = list()
+        return
+
+    def GetLength(self):
+        length = 0
+        length += self.Head.GetLength()
+        length += 1
+        length += len(self.ServerIDRangeInfo)
+        length += 1
+        length += 10
+        length += 10
+        length += 1
+        length += 1
+        for i in range(self.TemplateCount):
+            length += self.TempInfo[i].GetLength()
+
+        return length
+
+    def GetBuffer(self):
+        data = ''
+        data = CommFunc.WriteString(data, self.Head.GetLength(), self.Head.GetBuffer())
+        data = CommFunc.WriteBYTE(data, self.ServerInfoLen)
+        data = CommFunc.WriteString(data, self.ServerInfoLen, self.ServerIDRangeInfo)
+        data = CommFunc.WriteBYTE(data, self.GroupValue1)
+        data = CommFunc.WriteString(data, 10, self.StartDate)
+        data = CommFunc.WriteString(data, 10, self.EndtDate)
+        data = CommFunc.WriteBYTE(data, self.TemplateID)
+        data = CommFunc.WriteBYTE(data, self.TemplateCount)
+        for i in range(self.TemplateCount):
+            data = CommFunc.WriteString(data, self.TempInfo[i].GetLength(), self.TempInfo[i].GetBuffer())
+        return data
+
+    def OutputString(self):
+        DumpString = '''
+                                Head:%s,
+                                ServerInfoLen:%d,
+                                ServerIDRangeInfo:%s,
+                                GroupValue1:%d,
+                                StartDate:%s,
+                                EndtDate:%s,
+                                TemplateID:%d,
+                                TemplateCount:%d,
+                                TempInfo:%s
+                                '''\
+                                %(
+                                self.Head.OutputString(),
+                                self.ServerInfoLen,
+                                self.ServerIDRangeInfo,
+                                self.GroupValue1,
+                                self.StartDate,
+                                self.EndtDate,
+                                self.TemplateID,
+                                self.TemplateCount,
+                                "..."
+                                )
+        return DumpString
+
+
+m_NAtagMCCACTGBillboardInfo=tagMCCACTGBillboardInfo()
+ChNetPackDict[eval("0x%02x%02x"%(m_NAtagMCCACTGBillboardInfo.Head.Cmd,m_NAtagMCCACTGBillboardInfo.Head.SubCmd))] = m_NAtagMCCACTGBillboardInfo
+
+
+#------------------------------------------------------
+# AA 33 跨服充值排行活动玩家信息 #tagMCCACTGBillboardPlayerInfo
+
+class  tagMCCACTGBillboardPlayerInfo(Structure):
+    _pack_ = 1
+    _fields_ = [
+                  ("Cmd", c_ubyte),
+                  ("SubCmd", c_ubyte),
+                  ("CTGRMBTotal", c_int),    # 活动已累计充值RMB
+                  ("DabiaoAwardRecord", c_int),    # 达标奖励记录,与达标奖励索引位或运算判断是否已领取
+                  ]
+
+    def __init__(self):
+        self.Clear()
+        self.Cmd = 0xAA
+        self.SubCmd = 0x33
+        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 = 0xAA
+        self.SubCmd = 0x33
+        self.CTGRMBTotal = 0
+        self.DabiaoAwardRecord = 0
+        return
+
+    def GetLength(self):
+        return sizeof(tagMCCACTGBillboardPlayerInfo)
+
+    def GetBuffer(self):
+        return string_at(addressof(self), self.GetLength())
+
+    def OutputString(self):
+        DumpString = '''// AA 33 跨服充值排行活动玩家信息 //tagMCCACTGBillboardPlayerInfo:
+                                Cmd:%s,
+                                SubCmd:%s,
+                                CTGRMBTotal:%d,
+                                DabiaoAwardRecord:%d
+                                '''\
+                                %(
+                                self.Cmd,
+                                self.SubCmd,
+                                self.CTGRMBTotal,
+                                self.DabiaoAwardRecord
+                                )
+        return DumpString
+
+
+m_NAtagMCCACTGBillboardPlayerInfo=tagMCCACTGBillboardPlayerInfo()
+ChNetPackDict[eval("0x%02x%02x"%(m_NAtagMCCACTGBillboardPlayerInfo.Cmd,m_NAtagMCCACTGBillboardPlayerInfo.SubCmd))] = m_NAtagMCCACTGBillboardPlayerInfo
+
+
+#------------------------------------------------------
 # AA 09 消费返利活动信息 #tagMCCostRebateInfo
 
 class  tagMCCostRebateAwardItem(Structure):
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/IpyGameDataPY.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/IpyGameDataPY.py
index 7bd3602..0d51728 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/IpyGameDataPY.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/IpyGameDataPY.py
@@ -1505,6 +1505,21 @@
                         ("DWORD", "Weight", 0),
                         ),
 
+                "CrossActCTGBillboardDabiao":(
+                        ("DWORD", "TemplateID", 1),
+                        ("DWORD", "CTGNeed", 0),
+                        ("BYTE", "AwardIndex", 0),
+                        ("list", "AwardItemList", 0),
+                        ),
+
+                "CrossActCTGBillboardOrder":(
+                        ("DWORD", "TemplateID", 1),
+                        ("WORD", "OrderA", 0),
+                        ("WORD", "OrderB", 0),
+                        ("DWORD", "CTGAtleast", 0),
+                        ("list", "AwardItemList", 0),
+                        ),
+
                 "MysteryShop":(
                         ("list", "LVRange", 0),
                         ("DWORD", "GoodsID", 0),
@@ -4764,6 +4779,38 @@
     def GetIsBind(self): return self.IsBind # 是否绑定
     def GetWeight(self): return self.Weight # 权重
 
+# 跨服充值排行模板达标奖励表
+class IPY_CrossActCTGBillboardDabiao():
+    
+    def __init__(self):
+        self.TemplateID = 0
+        self.CTGNeed = 0
+        self.AwardIndex = 0
+        self.AwardItemList = []
+        return
+        
+    def GetTemplateID(self): return self.TemplateID # 模板ID
+    def GetCTGNeed(self): return self.CTGNeed # 需充值RMB
+    def GetAwardIndex(self): return self.AwardIndex # 奖励记录索引,从0开始,同个模板不可重复,不可变更
+    def GetAwardItemList(self): return self.AwardItemList # 奖励物品列表[[物品ID,个数,是否拍品], ...]
+
+# 跨服充值排行模板名次奖励表
+class IPY_CrossActCTGBillboardOrder():
+    
+    def __init__(self):
+        self.TemplateID = 0
+        self.OrderA = 0
+        self.OrderB = 0
+        self.CTGAtleast = 0
+        self.AwardItemList = []
+        return
+        
+    def GetTemplateID(self): return self.TemplateID # 模板ID
+    def GetOrderA(self): return self.OrderA # 名次A
+    def GetOrderB(self): return self.OrderB # 至名次B
+    def GetCTGAtleast(self): return self.CTGAtleast # 至少充值RMB
+    def GetAwardItemList(self): return self.AwardItemList # 奖励物品列表[[物品ID,个数,是否拍品], ...]
+
 # 神秘商店表
 class IPY_MysteryShop():
     
@@ -5430,6 +5477,10 @@
         self.ipyActLuckyTreasureLen = len(self.ipyActLuckyTreasureCache)
         self.ipyLuckyTreasureTemplateCache = self.__LoadFileData("LuckyTreasureTemplate", IPY_LuckyTreasureTemplate)
         self.ipyLuckyTreasureTemplateLen = len(self.ipyLuckyTreasureTemplateCache)
+        self.ipyCrossActCTGBillboardDabiaoCache = self.__LoadFileData("CrossActCTGBillboardDabiao", IPY_CrossActCTGBillboardDabiao)
+        self.ipyCrossActCTGBillboardDabiaoLen = len(self.ipyCrossActCTGBillboardDabiaoCache)
+        self.ipyCrossActCTGBillboardOrderCache = self.__LoadFileData("CrossActCTGBillboardOrder", IPY_CrossActCTGBillboardOrder)
+        self.ipyCrossActCTGBillboardOrderLen = len(self.ipyCrossActCTGBillboardOrderCache)
         self.ipyMysteryShopCache = self.__LoadFileData("MysteryShop", IPY_MysteryShop)
         self.ipyMysteryShopLen = len(self.ipyMysteryShopCache)
         self.ipyEquipPlaceIndexMapCache = self.__LoadFileData("EquipPlaceIndexMap", IPY_EquipPlaceIndexMap)
@@ -5932,6 +5983,10 @@
     def GetActLuckyTreasureByIndex(self, index): return self.ipyActLuckyTreasureCache[index]
     def GetLuckyTreasureTemplateCount(self): return self.ipyLuckyTreasureTemplateLen
     def GetLuckyTreasureTemplateByIndex(self, index): return self.ipyLuckyTreasureTemplateCache[index]
+    def GetCrossActCTGBillboardDabiaoCount(self): return self.ipyCrossActCTGBillboardDabiaoLen
+    def GetCrossActCTGBillboardDabiaoByIndex(self, index): return self.ipyCrossActCTGBillboardDabiaoCache[index]
+    def GetCrossActCTGBillboardOrderCount(self): return self.ipyCrossActCTGBillboardOrderLen
+    def GetCrossActCTGBillboardOrderByIndex(self, index): return self.ipyCrossActCTGBillboardOrderCache[index]
     def GetMysteryShopCount(self): return self.ipyMysteryShopLen
     def GetMysteryShopByIndex(self, index): return self.ipyMysteryShopCache[index]
     def GetEquipPlaceIndexMapCount(self): return self.ipyEquipPlaceIndexMapLen
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 9f49826..a62af50 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/ChPlayer.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/ChPlayer.py
@@ -110,6 +110,7 @@
 import PlayerFeastRedPacket
 import PlayerLuckyTreasure
 import Item_ResetAttrPoint
+import CrossActCTGBillboard
 import CrossRealmPlayer
 import ChNetSendPack
 import FamilyRobBoss
@@ -638,6 +639,8 @@
     #通知基础属性
     NotifyPlayerBasePoint(curPlayer)
     
+    #跨服充值排行
+    CrossActCTGBillboard.OnPlayerLogin(curPlayer)
     #消费返利
     PlayerCostRebate.OnPlayerLogin(curPlayer)
     #累计充值
@@ -5398,6 +5401,9 @@
     # 领取节日巡礼积分奖励
     elif rewardType == ChConfig.Def_RewardType_FeastWeekPartyPoint:
         PlayerFeastWeekParty.GetFeastWeekPartyPointAward(curPlayer, dataEx, dataExStr)
+    # 领取跨服充值排行活动达标奖励
+    elif rewardType == ChConfig.Def_RewardType_CACTGBillboardDabiao:
+        CrossActCTGBillboard.GetDabiaoAward(curPlayer, dataEx)
     #缥缈奇遇领取
     elif rewardType == ChConfig.Def_RewardType_FairyAdventuresAward:
         PlayerFairyDomain.GetFairyAdventuresAward(curPlayer, dataEx, dataExStr)
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/CrossActCTGBillboard.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/CrossActCTGBillboard.py
new file mode 100644
index 0000000..965bf5c
--- /dev/null
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/CrossActCTGBillboard.py
@@ -0,0 +1,288 @@
+#!/usr/bin/python
+# -*- coding: GBK -*-
+#-------------------------------------------------------------------------------
+#
+##@package Player.CrossActCTGBillboard
+#
+# @todo:跨服运营活动 - 充值排行
+# @author hxp
+# @date 2020-01-13
+# @version 1.0
+#
+# 详细描述: 跨服运营活动 - 充值排行
+#
+#-------------------------------------------------------------------------------
+#"""Version = 2020-01-13 17:00"""
+#-------------------------------------------------------------------------------
+
+import ChConfig
+import ShareDefine
+import PlayerControl
+import NetPackCommon
+import PlayerBillboard
+import CrossRealmPlayer
+import ChPyNetSendPack
+import ItemControler
+import IPY_GameWorld
+import IpyGameDataPY
+import GameWorld
+
+def OnPlayerLogin(curPlayer):
+    isReset = __CheckPlayerCrossActCTGBillboard(curPlayer)
+    if not isReset:
+        actInfo = CrossRealmPlayer.GetPlayerCrossActInfo(curPlayer, ShareDefine.CrossActName_CTGBillboard)
+        # 活动中同步活动信息
+        if actInfo.get(ShareDefine.ActKey_State):
+            Sync_CrossActCTGBillboardInfo(curPlayer)
+            Sync_CrossActCTGBillboardPlayerInfo(curPlayer)
+            UpdateCTGRMBCrossBillboard(curPlayer, actInfo)
+    return
+
+def RefreshCrossActCTGBillboardInfo():
+    ## 收到GameServer同步的活动信息,刷新活动信息
+    playerManager = GameWorld.GetPlayerManager()
+    for index in xrange(playerManager.GetPlayerCount()):
+        curPlayer = playerManager.GetPlayerByIndex(index)
+        if curPlayer.GetID() == 0:
+            continue
+        __CheckPlayerCrossActCTGBillboard(curPlayer)
+    return
+
+def __CheckPlayerCrossActCTGBillboard(curPlayer):
+    ## 检查玩家累计充值活动数据信息
+    
+    playerID = curPlayer.GetPlayerID()
+    
+    actInfo = CrossRealmPlayer.GetPlayerCrossActInfo(curPlayer, ShareDefine.CrossActName_CTGBillboard)
+    cfgID = actInfo.get(ShareDefine.ActKey_CfgID, 0)
+    actID = actInfo.get(ShareDefine.ActKey_ID, 0)
+    state = actInfo.get(ShareDefine.ActKey_State, 0)
+    dayIndex = actInfo.get(ShareDefine.ActKey_DayIndex, 0)
+    templateID = actInfo.get(ShareDefine.ActKey_TemplateID, 0)
+    
+    playerActID = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_CA_CTGBillboardID) # 玩家身上的活动ID
+    playerTemplateID = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_CA_CTGBillboardTemplateID)
+    
+    # 活动ID 相同的话不处理
+    if actID == playerActID:
+        GameWorld.DebugLog("跨服充值排行活动ID不变,不处理!cfgID=%s,dayIndex=%s,templateID=%s" % (cfgID, dayIndex, templateID), playerID)
+        if state:
+            if playerTemplateID != templateID and templateID:
+                PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_CA_CTGBillboardTemplateID, templateID)
+                GameWorld.DebugLog("    活动模板ID变更,更新玩家身上模板ID记录!playerTemplateID=%s,updTemplateID=%s" 
+                                   % (playerTemplateID, templateID), playerID)
+                Sync_CrossActCTGBillboardInfo(curPlayer)
+                
+        return
+    
+    GameWorld.DebugLog("跨服充值排行活动重置! cfgID=%s,actID=%s,playerActID=%s,state=%s" % (cfgID, actID, playerActID, state), playerID)
+    
+    if not state:
+        CrossRealmPlayer.NotifyCrossActEnd(curPlayer, ShareDefine.CrossActName_CTGBillboard)
+        
+    if playerActID and playerTemplateID:
+        __SendDabiaoAwardMail(curPlayer, playerTemplateID)
+        
+    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_CA_CTGBillboardID, actID)
+    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_CA_CTGBillboardTemplateID, templateID)
+    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_CA_CTGBillboardRMB, 0)
+    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_CA_CTGBillboardAward, 0)
+    
+    Sync_CrossActCTGBillboardInfo(curPlayer)
+    Sync_CrossActCTGBillboardPlayerInfo(curPlayer)
+    return True
+
+def __SendDabiaoAwardMail(curPlayer, playerTemplateID):
+    ## 补发未领取的达标奖励
+    
+    totalRMB = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_CA_CTGBillboardRMB)
+    if not totalRMB:
+        return
+    
+    ipyDataList = IpyGameDataPY.GetIpyGameDataList("CrossActCTGBillboardDabiao", playerTemplateID)
+    if not ipyDataList:
+        return
+    
+    playerID = curPlayer.GetPlayerID()
+    awardRecord = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_CA_CTGBillboardAward)
+    batchPlayerIDList, batchAddItemList, batchParamList = [], [], []
+    for ipyData in ipyDataList:
+        ctgNeed = ipyData.GetCTGNeed()
+        awardIndex = ipyData.GetAwardIndex()
+        if totalRMB < ctgNeed:
+            continue
+        if awardRecord & pow(2, awardIndex):
+            continue
+        batchPlayerIDList.append([playerID])
+        batchAddItemList.append(ipyData.GetAwardItemList())
+        batchParamList.append([ctgNeed])
+        awardRecord = awardRecord | pow(2, awardIndex)
+        
+    if not batchPlayerIDList:
+        return
+    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_CA_CTGBillboardAward, awardRecord)
+    
+    GameWorld.DebugLog("补发跨服充值排行活动未领取达标奖励!", playerID)
+    PlayerControl.SendMailBatch("CACTGBillboardDabiao", batchPlayerIDList, batchAddItemList, batchParamList)
+    return
+
+def GetDabiaoAward(curPlayer, awardIndex):
+    ## 手动领取达标奖励
+    
+    actInfo = CrossRealmPlayer.GetPlayerCrossActInfo(curPlayer, ShareDefine.CrossActName_CTGBillboard)
+    state = actInfo.get(ShareDefine.ActKey_State, 0)
+    if not state:
+        GameWorld.DebugLog("非活动中")
+        return
+    
+    totalRMB = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_CA_CTGBillboardRMB)
+    awardRecord = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_CA_CTGBillboardAward)
+    if awardRecord & pow(2, awardIndex):
+        GameWorld.DebugLog("已领取过该奖励! awardIndex=%s" % awardIndex)
+        return
+        
+    playerTemplateID = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_CA_CTGBillboardTemplateID)
+    ipyDataList = IpyGameDataPY.GetIpyGameDataList("CrossActCTGBillboardDabiao", playerTemplateID)
+    if not ipyDataList:
+        return
+    
+    awardItemList = []
+    for ipyData in ipyDataList:
+        ctgNeed = ipyData.GetCTGNeed()
+        if awardIndex == ipyData.GetAwardIndex():
+            if totalRMB < ctgNeed:
+                GameWorld.DebugLog("充值额度未达标,无法领取! awardIndex=%s,totalRMB=%s,ctgNeed=%s" 
+                                   % (awardIndex, totalRMB, ctgNeed))
+                return
+            awardItemList = ipyData.GetAwardItemList()
+            break
+        
+    GameWorld.DebugLog("领取跨服充值活动达标奖励!awardIndex=%s,awardItemList=%s" % (awardIndex, awardItemList))
+    if not awardItemList:
+        return
+    
+    if not ItemControler.CheckPackSpaceEnough(curPlayer, awardItemList):
+        return
+    
+    updAwardRecord = awardRecord | pow(2, awardIndex)
+    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_CA_CTGBillboardAward, updAwardRecord)
+    Sync_CrossActCTGBillboardPlayerInfo(curPlayer)
+    
+    for itemID, itemCount, isAuctionItem in awardItemList:
+        ItemControler.GivePlayerItem(curPlayer, itemID, itemCount, isAuctionItem, [IPY_GameWorld.rptItem], 
+                                     event=["CrossActCTGBillboard", False, {}])
+        
+    return
+
+def AddCTGRMB(curPlayer, addRMB):
+    ## 增加活动已累计充值RMB
+    actInfo = CrossRealmPlayer.GetPlayerCrossActInfo(curPlayer, ShareDefine.CrossActName_CTGBillboard) 
+    if not actInfo:
+        return
+    
+    if not actInfo.get(ShareDefine.ActKey_State):
+        GameWorld.DebugLog("玩家区服ID跨服充值排行非活动中!playerServerID=%s" % GameWorld.GetPlayerServerID(curPlayer))
+        return
+    
+    totalRMB = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_CA_CTGBillboardRMB) + addRMB
+    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_CA_CTGBillboardRMB, totalRMB)
+    
+    GameWorld.DebugLog("跨服充值排行活动增加玩家累计充值RMB: addRMB=%s,totalRMB=%s" % (addRMB, totalRMB), curPlayer.GetPlayerID())
+    Sync_CrossActCTGBillboardPlayerInfo(curPlayer)
+    UpdateCTGRMBCrossBillboard(curPlayer, actInfo)
+    return
+
+def UpdateCTGRMBCrossBillboard(curPlayer, actInfo):
+    ## 更新跨服充值活动榜
+    totalRMB = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_CA_CTGBillboardRMB)
+    if not totalRMB:
+        return
+    cfgID = actInfo.get(ShareDefine.ActKey_CfgID, 0)
+    if not cfgID:
+        return
+    cmpValue = totalRMB
+    PlayerBillboard.UpdatePlayerCrossBillboard(curPlayer, ShareDefine.Def_CBT_ActCTG, cfgID, cmpValue)
+    return
+
+def Sync_CrossActCTGBillboardPlayerInfo(curPlayer):
+    ## 通知活动玩家数据信息
+    playerActInfo = ChPyNetSendPack.tagMCCACTGBillboardPlayerInfo()
+    playerActInfo.CTGRMBTotal = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_CA_CTGBillboardRMB)
+    playerActInfo.DabiaoAwardRecord = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_CA_CTGBillboardAward)
+    NetPackCommon.SendFakePack(curPlayer, playerActInfo)
+    return
+
+def Sync_CrossActCTGBillboardInfo(curPlayer):
+    ## 通知活动信息
+    
+    actInfo = CrossRealmPlayer.GetPlayerCrossActInfo(curPlayer, ShareDefine.CrossActName_CTGBillboard)
+    if not actInfo:
+        return
+    
+    if not actInfo.get(ShareDefine.ActKey_State):
+        return
+    
+    ipyDataDict = actInfo.get(ShareDefine.ActKey_IpyDataInfo, {})
+    if not ipyDataDict:
+        return 0
+    
+    templateIDList = ipyDataDict.get("TemplateIDList", [])
+    if not templateIDList:
+        return
+    
+    actPack = ChPyNetSendPack.tagMCCACTGBillboardInfo()
+    actPack.ServerIDRangeInfo = str(actInfo.get(ShareDefine.ActKey_ServerIDRangeList, []))
+    actPack.ServerInfoLen = len(actPack.ServerIDRangeInfo)
+    actPack.GroupValue1 = actInfo.get(ShareDefine.ActKey_CfgID, 0)
+    actPack.StartDate = ipyDataDict.get("StartDate", "")
+    actPack.EndtDate = ipyDataDict.get("EndDate", "")
+    actPack.TemplateID = actInfo.get(ShareDefine.ActKey_TemplateID, 0)
+    actPack.TempInfo = []
+    for templateID in templateIDList:
+        tempInfo = ChPyNetSendPack.tagMCCACTGBillboardTempInfo()
+        
+        # 达标
+        tempInfo.TemplateID = templateID
+        tempInfo.DabiaoAwardInfo = []
+        dabiaoIpyDataList = IpyGameDataPY.GetIpyGameDataList("CrossActCTGBillboardDabiao", templateID)
+        if dabiaoIpyDataList:
+            for dabiaoIpyData in dabiaoIpyDataList:
+                dabiaoInfo = ChPyNetSendPack.tagMCCACTGBillboardDabiao()
+                dabiaoInfo.NeedRMB = dabiaoIpyData.GetCTGNeed()
+                dabiaoInfo.AwardIndex = dabiaoIpyData.GetAwardIndex()
+                dabiaoInfo.AwardItemList = []
+                for itemID, itemCount, isBind in dabiaoIpyData.GetAwardItemList():
+                    itemInfo = ChPyNetSendPack.tagMCCACTGBillboardAwardItem()
+                    itemInfo.ItemID = itemID
+                    itemInfo.ItemCount = itemCount
+                    itemInfo.IsBind = isBind
+                    dabiaoInfo.AwardItemList.append(itemInfo)
+                dabiaoInfo.AwardItemCount = len(dabiaoInfo.AwardItemList)
+                tempInfo.DabiaoAwardInfo.append(dabiaoInfo)
+        tempInfo.DabiaoAwardCount = len(tempInfo.DabiaoAwardInfo)
+        
+        # 排行
+        tempInfo.OrderAwardInfo = []
+        orderIpyDataList = IpyGameDataPY.GetIpyGameDataList("CrossActCTGBillboardOrder", templateID)
+        if orderIpyDataList:
+            for orderIpyData in orderIpyDataList:
+                orderInfo = ChPyNetSendPack.tagMCCACTGBillboardOrder()
+                orderInfo.OrderA = orderIpyData.GetOrderA()
+                orderInfo.OrderB = orderIpyData.GetOrderB()
+                orderInfo.NeedRMB = orderIpyData.GetCTGAtleast()
+                orderInfo.AwardItemList = []
+                for itemID, itemCount, isBind in orderIpyData.GetAwardItemList():
+                    itemInfo = ChPyNetSendPack.tagMCCACTGBillboardAwardItem()
+                    itemInfo.ItemID = itemID
+                    itemInfo.ItemCount = itemCount
+                    itemInfo.IsBind = isBind
+                    orderInfo.AwardItemList.append(itemInfo)
+                orderInfo.AwardItemCount = len(orderInfo.AwardItemList)
+                tempInfo.OrderAwardInfo.append(orderInfo)
+        tempInfo.OrderAwardCount = len(tempInfo.OrderAwardInfo)
+        
+        actPack.TempInfo.append(tempInfo)
+        
+    actPack.TemplateCount = len(actPack.TempInfo)
+    NetPackCommon.SendFakePack(curPlayer, actPack)
+    return
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 8eca865..ca42a7b 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/CrossRealmPlayer.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/CrossRealmPlayer.py
@@ -15,10 +15,13 @@
 #"""Version = 2018-12-21 18:00"""
 #-------------------------------------------------------------------------------
 import GameWorld
+import PyGameData
 import ReadChConfig
 import PlayerControl
 import IpyGameDataPY
 import IPY_GameWorld
+import ChPyNetSendPack
+import NetPackCommon
 import ShareDefine
 import ChConfig
 import FBLogic
@@ -157,3 +160,37 @@
     if PlayerControl.GetCrossMapID(curPlayer):
         PlayerControl.SetCrossMapID(curPlayer, 0)
     return
+
+def GetPlayerCrossActInfo(curPlayer, actName):
+    ## 获取跨服玩家对应的跨服活动信息
+    actInfoDict = PyGameData.g_crossActInfoDict.get(actName, {})
+    if not actInfoDict:
+        return {}
+    playerServerID = GameWorld.GetPlayerServerID(curPlayer)
+    for actInfo in actInfoDict.values():
+        if ShareDefine.ActKey_ServerIDRangeList not in actInfo:
+            continue
+        serverIDRangeList = actInfo[ShareDefine.ActKey_ServerIDRangeList]
+        if not serverIDRangeList:
+            # 全服开启
+            return actInfo
+        for serverIDA, serverIDB in serverIDRangeList:
+            if serverIDA <= playerServerID <= serverIDB:
+                return actInfo
+    return {}
+
+def NotifyCrossActEnd(curPlayer, actName):
+    '''通知跨服运营活动结束
+                    防止跨服服务器与子服时间不一致导致可能出现活动实际已关闭
+                    但是前端根据本服服务器时间判断还未关闭,可能引起玩家误以为活动未关闭而引发的一系列问题
+                    前端跨服活动显隐规则:
+                    显示:根据通知的活动包 且 时间>=活动开始日期 才显示
+                    关闭:收到后端通知的活动结束包 或 时间>=活动结束日期 则直接关闭活动界面
+    '''
+    
+    clientPack = ChPyNetSendPack.tagGCCrossActEnd()
+    clientPack.ActName = actName
+    clientPack.ActNameLen = len(clientPack.ActName)
+    NetPackCommon.SendFakePack(curPlayer, clientPack)
+    return
+
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerBillboard.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerBillboard.py
index a03c9d4..860f197 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerBillboard.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerBillboard.py
@@ -20,6 +20,7 @@
 import ChConfig
 import PlayerControl
 import OpenServerCampaign
+import CrossRealmPlayer
 import GameFuncComm
 import EventReport
 
@@ -86,7 +87,38 @@
     sendMsg = "%s" % ({"Type":bType, "Type2":bType2, "ID":bID, "ID2":bID2, "Name1":bName, "Name2":bName2, "ExInfo":exInfo,
                        "Value1":value1, "Value2":value2, "CmpValue":cmpValue, "CmpValue2":cmpValue2, "CmpValue3":cmpValue3}) 
     GameWorld.GetPlayerManager().GameServer_QueryPlayerResult(0, 0, 0, "UpdateBillboard", sendMsg, len(sendMsg))
-    GameWorld.DebugLog("同步GameServer排行榜:bType=%s,%s" % (bType, sendMsg))
+    GameWorld.DebugLog("同步GameServer排行榜:bType=%s,cmpValue=%s, %s" % (bType, cmpValue, sendMsg), bID)
+    return
+
+def UpdatePlayerCrossBillboard(curPlayer, bType, groupValue1, cmpValue, cmpValue2=0, cmpValue3=0, value1=0, value2=0, 
+                               groupValue2=0):
+    ## 更新玩家跨服排行榜
+    
+    #if not cmpValue and not cmpValue2 and not cmpValue3:
+    #    return
+    
+    #if not __CanPlayerBillboardComm(curPlayer):
+    #    return
+    
+    playerJob = GetBillboardJob(curPlayer)
+    playerID = curPlayer.GetID()
+    playerName = CrossRealmPlayer.GetCrossPlayerName(curPlayer)
+    playerOpInfo = GetBillboardOperateInfo(curPlayer)
+    if bType in ShareDefine.BTValue1_OfficialRankList:
+        value1 = curPlayer.GetOfficialRank()
+    id2 = 0
+    GameServer_UpdateCrossBillboard(bType, groupValue1, playerID, playerName, playerOpInfo, playerJob, value1, value2, 
+                                    cmpValue, cmpValue2, cmpValue3, groupValue2, id2)
+    return
+
+def GameServer_UpdateCrossBillboard(bType, groupValue1, dataID, name1, name2, type2, value1, value2, cmpValue, 
+                                    cmpValue2=0, cmpValue3=0, groupValue2=0, id2=0):
+    sendMsg = "%s" % ({"Type":bType, "GroupValue1":groupValue1, "Type2":type2, "ID":dataID, "ID2":id2, "Name1":name1, "Name2":name2,
+                       "Value1":value1, "Value2":value2, "CmpValue":cmpValue, "CmpValue2":cmpValue2, "CmpValue3":cmpValue3,
+                       "GroupValue2":groupValue2}) 
+    GameWorld.GetPlayerManager().GameServer_QueryPlayerResult(0, 0, 0, "UpdateCrossBillboard", sendMsg, len(sendMsg))
+    GameWorld.DebugLog("同步GameServer跨服排行榜:bType=%s,groupValue1=%s,groupValue2=%s,cmpValue=%s, %s" 
+                       % (bType, groupValue1, groupValue2, cmpValue, sendMsg), dataID)
     return
 
 def UpdatePlayerFPTotalBillboard(curPlayer, isForceUpdate=False, isCheckRule=True):
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/PyGameData.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/PyGameData.py
index 1eb4e41..b011cfd 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/PyGameData.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/PyGameData.py
@@ -68,7 +68,8 @@
 
 g_bzzdRefreshNPCListDict = {} # 仙界秘境所需击杀的NPC队列 {lineID:[npcID, npcID, ...], ...}
 
-g_operationActionDict = {} # {actName:actInfo, ...}
+g_operationActionDict = {} # 本服运营活动信息 {actName:actInfo, ...}
+g_crossActInfoDict = {} # 跨服运营活动信息 {actName:actInfo, ...}
 
 g_npcKillerInfo = {} # NPC击杀者信息 {(lineID, objID, npcID):[killerDict, curTeam, hurtType, hurtID], ...}
 

--
Gitblit v1.8.0