8677 【BT】【后端】跨服冲榜活动; 新增跨服活动时间管理模块、跨服榜单;跨服邮件;跨服广播优化;相关GM命令、后台工具;

# Conflicts:
# ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/GameWorldProcess.py
# ServerPython/CoreServerGroup/GameServer/Script/ShareDefine.py
# ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChConfig.py
# ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerCoin.py
# ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerEventCounter.py
# ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ShareDefine.py
23个文件已修改
7个文件已添加
4157 ■■■■■ 已修改文件
PySysDB/PySysDBG.h 27 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
PySysDB/PySysDBPY.h 21 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/CoreServerGroup/GameServer/PyNetPack.ini 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/CoreServerGroup/GameServer/Script/ChPyNetPack.py 60 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/CoreServerGroup/GameServer/Script/ChPyNetSendPack.py 669 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/CoreServerGroup/GameServer/Script/GM/Commands/BillboardDataCross.py 107 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/CoreServerGroup/GameServer/Script/GM/Commands/GMT_CrossActServerIDChange.py 170 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/CoreServerGroup/GameServer/Script/GM/Commands/GMT_QueryBillboardCross.py 88 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/CoreServerGroup/GameServer/Script/GM/GMShell.py 25 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/CrossActCTGBillboard.py 100 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/CrossActionControl.py 523 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/CrossBillboard.py 552 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/CrossRealmMsg.py 27 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/GameWorldActionControl.py 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/CoreServerGroup/GameServer/Script/IpyGameDataPY.py 73 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerCompensation.py 232 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerControl.py 37 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerDBGSEvent.py 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerQuery.py 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/CoreServerGroup/GameServer/Script/PyDataManager.py 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/CoreServerGroup/GameServer/Script/PyGameData.py 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/CoreServerGroup/GameServer/Script/PyGameDataStruct.py 251 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetPack.py 60 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetSendPack.py 669 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/IpyGameDataPY.py 55 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/ChPlayer.py 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/CrossActCTGBillboard.py 288 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/CrossRealmPlayer.py 37 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerBillboard.py 34 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/PyGameData.py 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
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
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
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
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):
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):
ServerPython/CoreServerGroup/GameServer/Script/GM/Commands/BillboardDataCross.py
New file
@@ -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
ServerPython/CoreServerGroup/GameServer/Script/GM/Commands/GMT_CrossActServerIDChange.py
New file
@@ -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 ""
ServerPython/CoreServerGroup/GameServer/Script/GM/Commands/GMT_QueryBillboardCross.py
New file
@@ -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
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日志!")
ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/CrossActCTGBillboard.py
New file
@@ -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
ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/CrossActionControl.py
New file
@@ -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
ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/CrossBillboard.py
New file
@@ -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
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)
            
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
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
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
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)
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' #参数为运营活动名
#运营活动开启时世界等级,参数为运营活动名
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)
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()
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, ...}
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
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):
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):
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
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)
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/CrossActCTGBillboard.py
New file
@@ -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
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
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):
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], ...}