9265 【BT5】【后端】53、新增幸运云购(调整为跨服节日活动模式;跨服节日活动管理优化)
17个文件已修改
1132 ■■■■ 已修改文件
PySysDB/PySysDBG.h 24 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/CoreServerGroup/GameServer/Script/ChPyNetPack.py 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/CoreServerGroup/GameServer/Script/ChPyNetSendPack.py 202 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/CoreServerGroup/GameServer/Script/GM/Commands/GMT_CrossActServerIDChange.py 5 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/CoreServerGroup/GameServer/Script/GM/Commands/LuckyCloudBuy.py 16 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/CrossActionControl.py 180 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/CrossLuckyCloudBuy.py 394 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/CrossRealmMsg.py 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/GameWorldProcess.py 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/CoreServerGroup/GameServer/Script/IpyGameDataPY.py 64 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/CoreServerGroup/GameServer/Script/ShareDefine.py 5 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetPack.py 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetSendPack.py 202 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GM/Commands/LuckyCloudBuy.py 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/CrossRealmPlayer.py 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerLuckyCloudBuy.py 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ShareDefine.py 5 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
PySysDB/PySysDBG.h
@@ -905,12 +905,36 @@
    WORD        LVLimit;    //限制等级
};
//跨服幸运云购表
struct tagCrossActLuckyCloudBuy
{
    DWORD        _CfgID;    //配置ID
    char        ActGroupName;    //活动组名(同组活动的名字需相同)
    BYTE        ZoneID;        //组内分组编号
    list        ServerIDRangeList;    //活动的账号服务器ID范围列表 [[serverIDA, serverIDB], ...]
    char        StartDate;    //开启日期
    char        EndDate;    //结束日期
    list        TemplateIDList;    //模板ID列表
};
//跨服幸运云购模板表
struct tagCrossActLuckyCloudBuyTemplate
{
    DWORD        _TemplateID;    //模板ID
    list        BaseAwardInfo;    //每次购买固定奖励 [[物品ID,个数,是否拍品], ...]
    list        RandAwardWeightInfo;    //每次购买随机奖励权重信息 [[权重,物品ID,个数,是否拍品], ...]
    list        SuperItemWeightInfo;    //大奖随机权重信息  [[权重,物品ID,个数,是否拍品,价值货币类型,货币值], ...]
};
//跨服充值排行活动时间表
struct tagCrossActCTGBillboard
{
    DWORD        _CfgID;    //配置ID
    char        ActGroupName;    //活动组名(同组活动的名字需相同)
    BYTE        ZoneID;        //组内分组编号
    list        ServerIDRangeList;    //活动的账号服务器ID范围列表 [[serverIDA, serverIDB], ...]
    char        StartDate;    //开启日期
    char        EndDate;    //结束日期
ServerPython/CoreServerGroup/GameServer/Script/ChPyNetPack.py
@@ -4042,7 +4042,7 @@
    _fields_ = [
                  ("Cmd", c_ubyte),
                  ("SubCmd", c_ubyte),
                  ("ZoneID", c_ubyte),    #查询分区ID,分区同跨服PK分区
                  ("ZoneID", c_ubyte),    #查询分区ID
                  ]
    def __init__(self):
ServerPython/CoreServerGroup/GameServer/Script/ChPyNetSendPack.py
@@ -13376,7 +13376,9 @@
class  tagGCLuckyCloudBuyLotteryRecInfo(Structure):
    Head = tagHead()
    ZoneID = 0    #(BYTE ZoneID)// 分区
    ZoneCount = 0    #(BYTE ZoneCount)// 分区数
    ZoneIDList = list()    #(vector<BYTE> ZoneIDList)// 所有分区ID列表
    ZoneID = 0    #(BYTE ZoneID)// 返回记录分区ID
    Count = 0    #(WORD Count)
    LotteryRecList = list()    #(vector<tagGCLuckyCloudBuyLotteryRec> LotteryRecList)
    data = None
@@ -13390,6 +13392,10 @@
    def ReadData(self, _lpData, _pos=0, _Len=0):
        self.Clear()
        _pos = self.Head.ReadData(_lpData, _pos)
        self.ZoneCount,_pos = CommFunc.ReadBYTE(_lpData, _pos)
        for i in range(self.ZoneCount):
            value,_pos=CommFunc.ReadBYTE(_lpData,_pos)
            self.ZoneIDList.append(value)
        self.ZoneID,_pos = CommFunc.ReadBYTE(_lpData, _pos)
        self.Count,_pos = CommFunc.ReadWORD(_lpData, _pos)
        for i in range(self.Count):
@@ -13403,6 +13409,8 @@
        self.Head.Clear()
        self.Head.Cmd = 0xC0
        self.Head.SubCmd = 0x14
        self.ZoneCount = 0
        self.ZoneIDList = list()
        self.ZoneID = 0
        self.Count = 0
        self.LotteryRecList = list()
@@ -13411,6 +13419,8 @@
    def GetLength(self):
        length = 0
        length += self.Head.GetLength()
        length += 1
        length += 1 * self.ZoneCount
        length += 1
        length += 2
        for i in range(self.Count):
@@ -13421,6 +13431,9 @@
    def GetBuffer(self):
        data = ''
        data = CommFunc.WriteString(data, self.Head.GetLength(), self.Head.GetBuffer())
        data = CommFunc.WriteBYTE(data, self.ZoneCount)
        for i in range(self.ZoneCount):
            data = CommFunc.WriteBYTE(data, self.ZoneIDList[i])
        data = CommFunc.WriteBYTE(data, self.ZoneID)
        data = CommFunc.WriteWORD(data, self.Count)
        for i in range(self.Count):
@@ -13430,12 +13443,16 @@
    def OutputString(self):
        DumpString = '''
                                Head:%s,
                                ZoneCount:%d,
                                ZoneIDList:%s,
                                ZoneID:%d,
                                Count:%d,
                                LotteryRecList:%s
                                '''\
                                %(
                                self.Head.OutputString(),
                                self.ZoneCount,
                                "...",
                                self.ZoneID,
                                self.Count,
                                "..."
@@ -13504,6 +13521,7 @@
class  tagGCLuckyCloudBuyNumRecInfo(Structure):
    Head = tagHead()
    RemainCount = 0    #(WORD RemainCount)// 开奖剩余份数
    Count = 0    #(WORD Count)
    BuyNumRecList = list()    #(vector<tagGCLuckyCloudBuyNumRec> BuyNumRecList)
    data = None
@@ -13517,6 +13535,7 @@
    def ReadData(self, _lpData, _pos=0, _Len=0):
        self.Clear()
        _pos = self.Head.ReadData(_lpData, _pos)
        self.RemainCount,_pos = CommFunc.ReadWORD(_lpData, _pos)
        self.Count,_pos = CommFunc.ReadWORD(_lpData, _pos)
        for i in range(self.Count):
            temBuyNumRecList = tagGCLuckyCloudBuyNumRec()
@@ -13529,6 +13548,7 @@
        self.Head.Clear()
        self.Head.Cmd = 0xC0
        self.Head.SubCmd = 0x13
        self.RemainCount = 0
        self.Count = 0
        self.BuyNumRecList = list()
        return
@@ -13536,6 +13556,7 @@
    def GetLength(self):
        length = 0
        length += self.Head.GetLength()
        length += 2
        length += 2
        for i in range(self.Count):
            length += self.BuyNumRecList[i].GetLength()
@@ -13545,6 +13566,7 @@
    def GetBuffer(self):
        data = ''
        data = CommFunc.WriteString(data, self.Head.GetLength(), self.Head.GetBuffer())
        data = CommFunc.WriteWORD(data, self.RemainCount)
        data = CommFunc.WriteWORD(data, self.Count)
        for i in range(self.Count):
            data = CommFunc.WriteString(data, self.BuyNumRecList[i].GetLength(), self.BuyNumRecList[i].GetBuffer())
@@ -13553,11 +13575,13 @@
    def OutputString(self):
        DumpString = '''
                                Head:%s,
                                RemainCount:%d,
                                Count:%d,
                                BuyNumRecList:%s
                                '''\
                                %(
                                self.Head.OutputString(),
                                self.RemainCount,
                                self.Count,
                                "..."
                                )
@@ -13571,24 +13595,16 @@
#------------------------------------------------------
# C0 12 幸运云购轮次信息 #tagGCLuckyCloudBuyRoundInfo
class  tagGCLuckyCloudBuyRoundInfo(Structure):
class  tagGCLuckyCloudBuyRoundItem(Structure):
    _pack_ = 1
    _fields_ = [
                  ("Cmd", c_ubyte),
                  ("SubCmd", c_ubyte),
                  ("RoundID", c_int),    # 轮次唯一ID标识,当收到的轮次ID变更时,前端需清空购买号码记录缓存
                  ("RoundNum", c_ubyte),    # 今日第几轮
                  ("SuperItemID", c_int),    # 大奖物品ID
                  ("SuperItemCount", c_ubyte),    # 大奖物品个数
                  ("SuperItemMoneyType", c_ubyte),    # 大奖价值货币类型
                  ("SuperItemMoneyValue", c_int),    # 大奖价值
                  ("RemainCount", c_ushort),    # 开奖剩余份数
                  ("ItemID", c_int),
                  ("ItemCount", c_ushort),
                  ("IsBind", c_ubyte),    # 是否拍品
                  ]
    def __init__(self):
        self.Clear()
        self.Cmd = 0xC0
        self.SubCmd = 0x12
        return
    def ReadData(self, stringData, _pos=0, _len=0):
@@ -13597,51 +13613,177 @@
        return _pos + self.GetLength()
    def Clear(self):
        self.Cmd = 0xC0
        self.SubCmd = 0x12
        self.RoundID = 0
        self.RoundNum = 0
        self.SuperItemID = 0
        self.SuperItemCount = 0
        self.SuperItemMoneyType = 0
        self.SuperItemMoneyValue = 0
        self.RemainCount = 0
        self.ItemID = 0
        self.ItemCount = 0
        self.IsBind = 0
        return
    def GetLength(self):
        return sizeof(tagGCLuckyCloudBuyRoundInfo)
        return sizeof(tagGCLuckyCloudBuyRoundItem)
    def GetBuffer(self):
        return string_at(addressof(self), self.GetLength())
    def OutputString(self):
        DumpString = '''// C0 12 幸运云购轮次信息 //tagGCLuckyCloudBuyRoundInfo:
                                Cmd:%s,
                                SubCmd:%s,
                                ItemID:%d,
                                ItemCount:%d,
                                IsBind:%d
                                '''\
                                %(
                                self.ItemID,
                                self.ItemCount,
                                self.IsBind
                                )
        return DumpString
class  tagGCLuckyCloudBuyRoundInfo(Structure):
    Head = tagHead()
    ZoneID = 0    #(BYTE ZoneID)// 所属分区ID
    StartDate = ""    #(char StartDate[10])// 开始日期 y-m-d
    EndtDate = ""    #(char EndtDate[10])// 结束日期 y-m-d
    RoundID = 0    #(DWORD RoundID)// 轮次唯一ID标识,当收到的轮次ID变更时,前端需清空购买号码记录缓存
    RoundNum = 0    #(BYTE RoundNum)// 今日第几轮
    SuperItemID = 0    #(DWORD SuperItemID)// 大奖物品ID
    SuperItemCount = 0    #(BYTE SuperItemCount)// 大奖物品个数
    SuperItemMoneyType = 0    #(BYTE SuperItemMoneyType)// 大奖价值货币类型
    SuperItemMoneyValue = 0    #(DWORD SuperItemMoneyValue)// 大奖价值
    BaseItemCount = 0    #(BYTE BaseItemCount)// 每次购买固定奖励物品数
    BaseItemList = list()    #(vector<tagGCLuckyCloudBuyRoundItem> BaseItemList)// 每次购买固定奖励物品信息
    RandItemCount = 0    #(BYTE RandItemCount)// 每次购买随机奖励物品数
    RandItemList = list()    #(vector<tagGCLuckyCloudBuyRoundItem> RandItemList)// 每次购买随机奖励物品信息
    data = None
    def __init__(self):
        self.Clear()
        self.Head.Cmd = 0xC0
        self.Head.SubCmd = 0x12
        return
    def ReadData(self, _lpData, _pos=0, _Len=0):
        self.Clear()
        _pos = self.Head.ReadData(_lpData, _pos)
        self.ZoneID,_pos = CommFunc.ReadBYTE(_lpData, _pos)
        self.StartDate,_pos = CommFunc.ReadString(_lpData, _pos,10)
        self.EndtDate,_pos = CommFunc.ReadString(_lpData, _pos,10)
        self.RoundID,_pos = CommFunc.ReadDWORD(_lpData, _pos)
        self.RoundNum,_pos = CommFunc.ReadBYTE(_lpData, _pos)
        self.SuperItemID,_pos = CommFunc.ReadDWORD(_lpData, _pos)
        self.SuperItemCount,_pos = CommFunc.ReadBYTE(_lpData, _pos)
        self.SuperItemMoneyType,_pos = CommFunc.ReadBYTE(_lpData, _pos)
        self.SuperItemMoneyValue,_pos = CommFunc.ReadDWORD(_lpData, _pos)
        self.BaseItemCount,_pos = CommFunc.ReadBYTE(_lpData, _pos)
        for i in range(self.BaseItemCount):
            temBaseItemList = tagGCLuckyCloudBuyRoundItem()
            _pos = temBaseItemList.ReadData(_lpData, _pos)
            self.BaseItemList.append(temBaseItemList)
        self.RandItemCount,_pos = CommFunc.ReadBYTE(_lpData, _pos)
        for i in range(self.RandItemCount):
            temRandItemList = tagGCLuckyCloudBuyRoundItem()
            _pos = temRandItemList.ReadData(_lpData, _pos)
            self.RandItemList.append(temRandItemList)
        return _pos
    def Clear(self):
        self.Head = tagHead()
        self.Head.Clear()
        self.Head.Cmd = 0xC0
        self.Head.SubCmd = 0x12
        self.ZoneID = 0
        self.StartDate = ""
        self.EndtDate = ""
        self.RoundID = 0
        self.RoundNum = 0
        self.SuperItemID = 0
        self.SuperItemCount = 0
        self.SuperItemMoneyType = 0
        self.SuperItemMoneyValue = 0
        self.BaseItemCount = 0
        self.BaseItemList = list()
        self.RandItemCount = 0
        self.RandItemList = list()
        return
    def GetLength(self):
        length = 0
        length += self.Head.GetLength()
        length += 1
        length += 10
        length += 10
        length += 4
        length += 1
        length += 4
        length += 1
        length += 1
        length += 4
        length += 1
        for i in range(self.BaseItemCount):
            length += self.BaseItemList[i].GetLength()
        length += 1
        for i in range(self.RandItemCount):
            length += self.RandItemList[i].GetLength()
        return length
    def GetBuffer(self):
        data = ''
        data = CommFunc.WriteString(data, self.Head.GetLength(), self.Head.GetBuffer())
        data = CommFunc.WriteBYTE(data, self.ZoneID)
        data = CommFunc.WriteString(data, 10, self.StartDate)
        data = CommFunc.WriteString(data, 10, self.EndtDate)
        data = CommFunc.WriteDWORD(data, self.RoundID)
        data = CommFunc.WriteBYTE(data, self.RoundNum)
        data = CommFunc.WriteDWORD(data, self.SuperItemID)
        data = CommFunc.WriteBYTE(data, self.SuperItemCount)
        data = CommFunc.WriteBYTE(data, self.SuperItemMoneyType)
        data = CommFunc.WriteDWORD(data, self.SuperItemMoneyValue)
        data = CommFunc.WriteBYTE(data, self.BaseItemCount)
        for i in range(self.BaseItemCount):
            data = CommFunc.WriteString(data, self.BaseItemList[i].GetLength(), self.BaseItemList[i].GetBuffer())
        data = CommFunc.WriteBYTE(data, self.RandItemCount)
        for i in range(self.RandItemCount):
            data = CommFunc.WriteString(data, self.RandItemList[i].GetLength(), self.RandItemList[i].GetBuffer())
        return data
    def OutputString(self):
        DumpString = '''
                                Head:%s,
                                ZoneID:%d,
                                StartDate:%s,
                                EndtDate:%s,
                                RoundID:%d,
                                RoundNum:%d,
                                SuperItemID:%d,
                                SuperItemCount:%d,
                                SuperItemMoneyType:%d,
                                SuperItemMoneyValue:%d,
                                RemainCount:%d
                                BaseItemCount:%d,
                                BaseItemList:%s,
                                RandItemCount:%d,
                                RandItemList:%s
                                '''\
                                %(
                                self.Cmd,
                                self.SubCmd,
                                self.Head.OutputString(),
                                self.ZoneID,
                                self.StartDate,
                                self.EndtDate,
                                self.RoundID,
                                self.RoundNum,
                                self.SuperItemID,
                                self.SuperItemCount,
                                self.SuperItemMoneyType,
                                self.SuperItemMoneyValue,
                                self.RemainCount
                                self.BaseItemCount,
                                "...",
                                self.RandItemCount,
                                "..."
                                )
        return DumpString
m_NAtagGCLuckyCloudBuyRoundInfo=tagGCLuckyCloudBuyRoundInfo()
ChNetPackDict[eval("0x%02x%02x"%(m_NAtagGCLuckyCloudBuyRoundInfo.Cmd,m_NAtagGCLuckyCloudBuyRoundInfo.SubCmd))] = m_NAtagGCLuckyCloudBuyRoundInfo
ChNetPackDict[eval("0x%02x%02x"%(m_NAtagGCLuckyCloudBuyRoundInfo.Head.Cmd,m_NAtagGCLuckyCloudBuyRoundInfo.Head.SubCmd))] = m_NAtagGCLuckyCloudBuyRoundInfo
#------------------------------------------------------
ServerPython/CoreServerGroup/GameServer/Script/GM/Commands/GMT_CrossActServerIDChange.py
@@ -45,7 +45,7 @@
    crossActInfoDict = CrossActionControl.GetCrossActInfoDict()
    backMsg = {"crossActInfoDict":crossActInfoDict}
    if errInfo:
        backMsg["ErrorInfo"] = errInfo
        backMsg["ErrorInfo"] = errInfo.decode(ShareDefine.Def_Game_Character_Encoding).encode(GameWorld.GetCharacterEncoding())
        GMCommon.GMCommandResult(orderId, gmCmdDict, GMCommon.Def_ParamErr, backMsg)
        return
    
@@ -66,6 +66,9 @@
        if len(kspList) != 3:
            continue
        actName, cfgID, _ = kspList
        if actName not in ShareDefine.CrossActLockServerGroupIDList:
            errInfo = "%s 不允许修改,可以直接修改活动配置表进行热更!" % actName
            return errInfo
        try:
            cfgID = int(cfgID)
            changeServerIDList = eval(v)
ServerPython/CoreServerGroup/GameServer/Script/GM/Commands/LuckyCloudBuy.py
@@ -19,6 +19,8 @@
import CrossLuckyCloudBuy
import IpyGameDataPY
import PyGameData
import CrossActionControl
import ShareDefine
#---------------------------------------------------------------------
#全局变量
@@ -57,14 +59,12 @@
        PyGameData.g_luckyCloudBuyNumDict = {}
        PyGameData.g_luckyCloudBuyLotteryDict = {}
        
        crossZoneName = GameWorld.GetCrossZoneName()
        crossZoneList = IpyGameDataPY.GetIpyGameDataByCondition("CrossZonePK", {"CrossZoneName":crossZoneName}, True)
        if not crossZoneList:
            return
        for zoneIpyData in crossZoneList:
            zoneID = zoneIpyData.GetZoneID()
            CrossLuckyCloudBuy.DoStartNewRoundLuckyCloudBuy(zoneID, 1)
        crossActInfoDict = CrossActionControl.GetCrossActInfoDict()
        curActInfoDict = crossActInfoDict.get(ShareDefine.CrossActName_LuckyCloudBuy, {})
        for cfgID, actInfoDict in curActInfoDict.items():
            if not actInfoDict[ShareDefine.ActKey_State]:
                continue
            CrossLuckyCloudBuy.DoStartNewRoundLuckyCloudBuy(cfgID, 1)
            
    # 添加云购记录
    elif value1 == 1:
ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/CrossActionControl.py
@@ -32,7 +32,8 @@
(
CrossAct_ReloadSign, # 信息重载标记
CrossAct_TodayInfo, # 当日的活动信息
) = range(2)
CrossAct_CfgIDInfo, # 处理的cfgID信息
) = range(3)
def OnPlayerLogin(curPlayer):
    return
@@ -70,6 +71,55 @@
            
    return
def GetCrossActZoneID(actName, serverGroupID):
    ## 获取子服ID所属跨服活动分区, 跨服、子服通用
    actInfoDict = GetCrossActInfoByServerGroupID(actName, serverGroupID)
    if not actInfoDict:
        return
    cfgID = actInfoDict.get(ShareDefine.ActKey_CfgID)
    ipyDataInfo = actInfoDict.get(ShareDefine.ActKey_IpyDataInfo)
    if not ipyDataInfo:
        GameWorld.ErrLog("ActKey_IpyDataInfo为空, 找不到跨服活动所属分区! actName=%s, serverGroupID=%s, cfgID=%s"
                         % (actName, serverGroupID, cfgID))
        return
    return ipyDataInfo.get("ZoneID")
def GetCrossActInfoByServerGroupID(actName, serverGroupID):
    '''获取子服ID所属跨服活动信息, 跨服、子服通用
        @param serverGroupID: 服务器ID或服务器分ID
                                跨服活动表配置的是服务器ID,而子服合服后以主服的服务器ID作为服务器组ID,所以两种服务器ID在此函数中通用
        @return: None or ActKey_IpyDataInfo
    '''
    crossActInfoDict = PyGameData.g_crossActInfoDict
    if crossActInfoDict and actName in crossActInfoDict:
        curActInfoDict = crossActInfoDict[actName]
        for actInfoDict in curActInfoDict.values():
            if not actInfoDict.get(ShareDefine.ActKey_State, 0):
                continue
            serverIDRangeList = actInfoDict.get(ShareDefine.ActKey_ServerIDRangeList)
            if not serverIDRangeList:
                continue
            for groupInfo in serverIDRangeList:
                if (isinstance(groupInfo, int) and serverGroupID == groupInfo) \
                    or ((isinstance(groupInfo, tuple) or isinstance(groupInfo, list)) \
                        and len(groupInfo) == 2 and groupInfo[0] <= serverGroupID <= groupInfo[1]):
                    return actInfoDict
    GameWorld.DebugLog("找不到服务器组ID对应跨服活动分区! actName=%s, serverGroupID=%s" % (actName, serverGroupID))
    return
def GetCrossActInfoByCfgID(actName, cfgID):
    crossActInfoDict = GetCrossActInfoDict()
    if actName not in crossActInfoDict:
        return
    curActInfoDict = crossActInfoDict[actName]
    if cfgID not in curActInfoDict:
        return
    return curActInfoDict[cfgID]
def GetCrossActInfoDict():
    if PyGameData.g_crossActInfoDict == None:
        PyGameData.g_crossActInfoDict = {}
@@ -91,8 +141,10 @@
            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}
            # 活动ID、状态、模板信息单独存储,重置活动判断用
            dbInfo = {ShareDefine.ActKey_ID:actID, ShareDefine.ActKey_State:state, ShareDefine.ActKey_TemplateID:templateID,
                      ShareDefine.ActKey_CfgID:cfgID, ShareDefine.ActKey_ServerIDRangeList:serverIDRangeList}
            actInfo = {}
            actInfo.update(dbInfo)
            actInfo[ShareDefine.ActKey_DBInfo] = dbInfo
            actInfoDict[cfgID] = actInfo
@@ -104,6 +156,7 @@
def __GetParseIpyDataList(ipyDataMgr, actName, actInfoDict):
    ## 获取需要处理的合法分组活动配置列表,已经在活动中的必须要处理
    
    groupNameList = [] # 确保分组顺序
    groupInfo = {}
    actCfgCount = getattr(ipyDataMgr, "Get%sCount" % actName)()
    for cfgIndex in xrange(actCfgCount):
@@ -111,11 +164,13 @@
        actGroupName = ipyData.GetActGroupName()
        if actGroupName not in groupInfo:
            groupInfo[actGroupName] = []
            groupNameList.append(actGroupName)
        groupIpyDataList = groupInfo[actGroupName]
        groupIpyDataList.append(ipyData)
        
    parseIpyDataList = []
    for actGroupName, groupIpyDataList in groupInfo.items():
    for actGroupName in groupNameList:
        groupIpyDataList = groupInfo[actGroupName]
        allOpen = False
        cfgIDList = []
        allServerIDRangeList = []
@@ -128,6 +183,7 @@
                actInfo = actInfoDict[cfgID]
                # 已经在活动中的记录必须要处理
                parseIpyDataList.append(ipyData)
                if actName in ShareDefine.CrossActLockServerGroupIDList:
                serverIDRangeList = actInfo[ShareDefine.ActKey_ServerIDRangeList]
                GameWorld.Log("    使用已经在活动中的记录的区服分组: cfgID=%s,serverIDRangeList=%s" 
                              % (cfgID, serverIDRangeList))
@@ -185,6 +241,7 @@
    curDateTime = datetime.datetime.strptime(curDateTimeStr, ChConfig.TYPE_Time_Format)
    
    actTimeInfoDict = {}
    actCfgIDInfoDict = {}
    ipyDataMgr = IpyGameDataPY.IPY_Data()
    
    GameWorld.Log("=============================================================")
@@ -207,9 +264,10 @@
        parseIpyDataList = __GetParseIpyDataList(ipyDataMgr, actName, curActInfoDict)
        for ipyData in parseIpyDataList:
            cfgID = ipyData.GetCfgID()
            actGroupName = ipyData.GetActGroupName()
            startDateStr = ipyData.GetStartDate()
            endDateStr = ipyData.GetEndDate()
            GameWorld.Log("    cfgID=%s,startDateStr=%s,endDateStr=%s,curDateTime=%s" % (cfgID, startDateStr, endDateStr, curDateTime))
            GameWorld.Log("    cfgID=%s,actGroupName==%s,startDateStr=%s,endDateStr=%s,curDateTime=%s" % (cfgID, actGroupName, startDateStr, endDateStr, curDateTime))
            if not startDateStr:
                startDateStr = curDateStr
                GameWorld.Log("        开始日期为空,默认每天,今日为: startDateStr=%s" % startDateStr)
@@ -328,6 +386,9 @@
            if actName not in actTimeInfoDict:
                actTimeInfoDict[actName] = {}
            actTimeInfoDict[actName][cfgID] = [ipyData, startList, endList, notifyDict]
            if actName not in actCfgIDInfoDict:
                actCfgIDInfoDict[actName] = [[], []]
            endCfgIDList, actCfgIDList = actCfgIDInfoDict[actName]
            
            if actName not in crossActInfoDict:
                crossActInfoDict[actName] = {}
@@ -346,12 +407,35 @@
            GameWorld.Log("        ipyDataDict=%s" % ipyDataDict)
            
            curCfgActInfoDict.update({ShareDefine.ActKey_CfgID:cfgID, ShareDefine.ActKey_IpyDataInfo:ipyDataDict})
            if ShareDefine.ActKey_ServerIDRangeList not in curCfgActInfoDict:
            if ShareDefine.ActKey_ServerIDRangeList not in curCfgActInfoDict or actName not in ShareDefine.CrossActLockServerGroupIDList:
                # 没有的话则使用配置中的,防止配置修改导致服务器ID分区变动引起的活动数据异常,除非后台工具强制修改
                curCfgActInfoDict[ShareDefine.ActKey_ServerIDRangeList] = ipyData.GetServerIDRangeList()
                
            actID, dayIndex, templateID = 0, 0, 0
            if isActTime:
                ''' 注: 检查是否已经存在活动中的分组,有的话强制将其置为结算状态,有且仅有一个活动中的组,后面的强制覆盖前面的
                parseIpyDataList  确保同一活动组名的serverID不会重复
                                        这里进一步确保不同活动组名的不会同时开启活动,有且仅有一个活动中的活动组
                '''
                for befIpyData in parseIpyDataList:
                    befCfgID = befIpyData.GetCfgID()
                    befActGroupName = befIpyData.GetActGroupName()
                    if befActGroupName == actGroupName:
                        break
                    if befCfgID not in actCfgIDList:
                        continue
                    actCfgIDList.remove(befCfgID)
                    if befCfgID in curActInfoDict:
                        befCfgActInfoDict = curActInfoDict[befCfgID]
                        befCfgActInfoDict[ShareDefine.ActKey_ID] = 0 # 活动ID强制置为0
                    if befCfgID in endCfgIDList:
                        continue
                    endCfgIDList.append(befCfgID)
                    GameWorld.Log("        前面存在活动的分组,则强制结束活动! befCfgID=%s,befActGroupName=%s" % (befCfgID, befActGroupName))
                if cfgID not in actCfgIDList:
                    actCfgIDList.append(cfgID)
                dayIndex = (curDateTime - startDayDate).days
                actIDDateTime = startDayDate
                isDayReset = 0 if not hasattr(ipyData, "GetIsDayReset") else ipyData.GetIsDayReset()
@@ -367,15 +451,18 @@
                    templateID = templateIDList[-1] if dayIndex >= len(templateIDList) else templateIDList[dayIndex]
                    
                    # 其他特殊模板ID获取处理,有需要的单独处理即可,根据活动规则自行扩展...  
            else:
                if cfgID not in endCfgIDList:
                    endCfgIDList.append(cfgID)
                    
            curCfgActInfoDict.update({ShareDefine.ActKey_ID:actID, ShareDefine.ActKey_TemplateID:templateID, 
                                      ShareDefine.ActKey_DayIndex:dayIndex})
            
    CrossActInfo = IpyGameDataPY.SetConfigEx(key, [reloadSign, actTimeInfoDict])
    CrossActInfo = IpyGameDataPY.SetConfigEx(key, [reloadSign, actTimeInfoDict, actCfgIDInfoDict])
    
    GameWorld.Log("本日跨服运营活动信息加载完毕!reloadSign=%s,isRefreshState=%s" % (reloadSign, isRefreshState))
    GameWorld.Log("    actTimeInfoDict=%s" % actTimeInfoDict)
    GameWorld.Log("    actCfgIDInfoDict=%s" % actCfgIDInfoDict)
    GameWorld.Log("    crossActInfoDict=%s" % crossActInfoDict)
    GameWorld.Log("=============================================================")
    if isRefreshState:
@@ -388,6 +475,7 @@
    isReload, CrossActInfo = __GetCrossActInfo(False) # 这里必须传False
    isReload = isReload or reloadRefresh
    actTimeInfoDict = CrossActInfo[CrossAct_TodayInfo]
    actCfgIDInfoDict = CrossActInfo[CrossAct_CfgIDInfo]
    
    crossActInfoDict = GetCrossActInfoDict()
    
@@ -398,28 +486,38 @@
    
    sysnCrossActInfoDict = {}
    for actName in ShareDefine.CrossActNameList:
        if actName not in actTimeInfoDict or actName not in crossActInfoDict:
        if actName not in actTimeInfoDict or actName not in crossActInfoDict or actName not in actCfgIDInfoDict:
            continue
        
        for ipyData, startList, endList, notifyDict in actTimeInfoDict[actName].values():
        timeInfoDict = actTimeInfoDict[actName]
        endCfgIDList, actCfgIDList = actCfgIDInfoDict[actName]
        # 可能一条cfgID处理结束,另一条cfgID处理开始,也可能同一条cfgID即结束同时又开始(如每天重置的)
        cfgIDList = endCfgIDList + actCfgIDList
        for cfgID in cfgIDList:
            if cfgID not in timeInfoDict:
                continue
            ipyData, startList, endList, notifyDict = timeInfoDict[cfgID]
            
            state = 0 # 默认关闭
            cfgID = ipyData.GetCfgID()
            groupName = ipyData.GetActGroupName()
            zoneID = ipyData.GetZoneID()
            
            if cfgID not in crossActInfoDict[actName]:
                crossActInfoDict[actName][cfgID] = {}
            actInfoDict = crossActInfoDict[actName][cfgID]
            
            # ״̬
            if cfgID not in endCfgIDList:
            for dIndex, startDateTime in enumerate(startList):
                endDateTime = endList[dIndex]
                if startDateTime <= curDateTime < endDateTime:
                    state = dIndex + 1 # 也是代表第几个时间段
                    break
                
            serverIDRangeList = actInfoDict.get(ShareDefine.ActKey_ServerIDRangeList)
            # 全服广播提示信息
            if curDateTime in notifyDict:
                serverIDRangeList = actInfoDict.get(ShareDefine.ActKey_ServerIDRangeList)
                if serverIDRangeList != None:
                    notifyKey, paramList = notifyDict[curDateTime]
                    country = 0
@@ -430,41 +528,50 @@
                
            dbInfo = actInfoDict.get(ShareDefine.ActKey_DBInfo, {})
            dbState = dbInfo.get(ShareDefine.ActKey_State, 0)
            dbCfgID = dbInfo.get(ShareDefine.ActKey_CfgID, 0)
            dbActID = dbInfo.get(ShareDefine.ActKey_ID, 0)
            dbTemplateID = dbInfo.get(ShareDefine.ActKey_TemplateID, 0)
            dbServerIDRangeList = dbInfo.get(ShareDefine.ActKey_ServerIDRangeList, None)
            forceReset = False
            if dbCfgID == cfgID and dbServerIDRangeList != serverIDRangeList:
                forceReset = True
            
            actID = actInfoDict.get(ShareDefine.ActKey_ID, 0)
            templateID = actInfoDict.get(ShareDefine.ActKey_TemplateID, 0)
            if not isReload and dbState == state and dbActID == actID:
            if not isReload and dbState == state and dbActID == actID and not forceReset:
                #已经是这个状态了
                continue
            GameWorld.Log("跨服运营活动变更: actName=%s,cfgID=%s,dbState=%s -> state=%s, dbActID=%s -> actID=%s"
                          % (actName, cfgID, dbState, state, dbActID, actID))
            GameWorld.Log("跨服运营活动状态: actName=%s,cfgID=%s,groupName=%s,zoneID=%s,dbState=%s -> state=%s, dbActID=%s -> actID=%s,forceReset=%s"
                          % (actName, cfgID, groupName, zoneID, dbState, state, dbActID, actID, forceReset))
            
            if dbActID != actID:
                GameWorld.Log("    活动ID变更: actName=%s,cfgID=%s,dbActID=%s -> actID=%s,dbTemplateID=%s"
                              % (actName, cfgID, dbActID, actID, dbTemplateID))
            # 更新状态
            actInfoDict[ShareDefine.ActKey_State] = state
            dbInfo = {ShareDefine.ActKey_ID:actID, ShareDefine.ActKey_State:state, ShareDefine.ActKey_TemplateID:templateID,
                      ShareDefine.ActKey_CfgID:cfgID, ShareDefine.ActKey_ServerIDRangeList:serverIDRangeList}
            actInfoDict[ShareDefine.ActKey_DBInfo] = dbInfo
            #GameWorld.Log("    活动状态同步信息: actName=%s,cfgID=%s,groupName=%s,zoneID=%s,actInfoDict=%s" % (actName, cfgID, groupName, zoneID, actInfoDict))
            if actName not in sysnCrossActInfoDict:
                sysnCrossActInfoDict[actName] = {}
            sysnCrossActInfoDict[actName][cfgID] = actInfoDict
            if dbActID != actID or forceReset:
                GameWorld.Log("    活动ID变更: actName=%s,cfgID=%s,groupName=%s,zoneID=%s,dbActID=%s -> actID=%s,forceReset=%s,dbTemplateID=%s"
                              % (actName, cfgID, groupName, zoneID, dbActID, actID, forceReset, 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
                elif actName == ShareDefine.CrossActName_LuckyCloudBuy:
                    import CrossLuckyCloudBuy
                    CrossLuckyCloudBuy.OnLuckyCloudBuyReset(ipyData, state)
            
            # 非活动中的处理完关闭后,最后删除
            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))
                #GameWorld.Log("    移除结束的活动: actName=%s,cfgID=%s,crossActInfoDict=%s" % (actName, cfgID, crossActInfoDict))
                
    # 同步子服务器
    serverGroupIDList = []
@@ -493,12 +600,21 @@
    ## 收到跨服服务器同步的跨服运营活动状态
    
    GameWorld.Log("===== 收到跨服服务器同步的跨服运营活动状态: %s" % sysnCrossActInfoDict)
    if PyGameData.g_crossActInfoDict == None:
    if PyGameData.g_crossActInfoDict == None or not sysnCrossActInfoDict:
        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, syncActInfoDict in sysnCrossActInfoDict.items():
        for cfgID, syncActInfo in syncActInfoDict.items():
            if actName not in PyGameData.g_crossActInfoDict:
                PyGameData.g_crossActInfoDict[actName] = {}
            actInfoDict = PyGameData.g_crossActInfoDict[actName]
            actInfoDict[cfgID] = syncActInfo
        if actName == ShareDefine.CrossActName_LuckyCloudBuy:
            import CrossLuckyCloudBuy
            CrossLuckyCloudBuy.Sync_LuckyCloudBuyRoundInfo(None)
        GameWorld.SendMapServerMsgEx(ShareDefine.Def_Notify_WorldKey_CrossActInfo % actName, syncActInfoDict)
        
    # 删除非活动中的
    for actName, actInfoDict in PyGameData.g_crossActInfoDict.items():
ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/CrossLuckyCloudBuy.py
@@ -21,10 +21,10 @@
import PlayerControl
import DataRecordPack
import PlayerCompensation
import CrossActionControl
import ChPyNetSendPack
import IpyGameDataPY
import NetPackCommon
import CrossRealmPK
import PyGameData
import ChConfig
@@ -53,7 +53,7 @@
幸运云购开奖记录
ShareDefine.Def_UniversalGameRecType_LuckyCloudBuyLottery
time:idTime                创建时间(也作为本轮唯一标识ID,用生成时间time值作为唯一ID)
value1:zoneID            分区ID
value1:cfgID*100+zoneID        配置ID*100 + 分区ID
value2:roundNum          今日第几轮
value3:luckyPlayerID     中奖玩家ID
value4:lotteryNum         开奖号码
@@ -92,6 +92,7 @@
    '''
    def __init__(self):
        self.idTime = 0
        self.cfgID = 0
        self.zoneID = 0
        self.roundNum = 0
        self.luckyPlayerID = 0
@@ -99,15 +100,15 @@
        self.lotteryTime = 0
        
        self.luckyPlayerName = ""
        self.serverGroupIDList = [] # 分区信息
        self.serverIDRangeList = [] # 分区信息
        self.superItemInfo = [] # 大奖信息
        self.luckyPlayerAccID = "" # 中奖玩家账号
        return
    
    def GetString(self):
        return {"idTime":self.idTime, "zoneID":self.zoneID, "roundNum":self.roundNum, "luckyPlayerID":self.luckyPlayerID,
        return {"idTime":self.idTime, "cfgID":self.cfgID, "zoneID":self.zoneID, "roundNum":self.roundNum, "luckyPlayerID":self.luckyPlayerID,
                "lotteryNum":self.lotteryNum, "lotteryTime":self.lotteryTime, "luckyPlayerName":self.luckyPlayerName, 
                "serverGroupIDList":self.serverGroupIDList, "superItemInfo":self.superItemInfo, "luckyPlayerAccID":self.luckyPlayerAccID}
                "serverIDRangeList":self.serverIDRangeList, "superItemInfo":self.superItemInfo, "luckyPlayerAccID":self.luckyPlayerAccID}
        
    def SetAttrByDict(self, attrDict):
        for k, v in attrDict.items():
@@ -155,10 +156,11 @@
    
    for index in xrange(recDataList.Count()):
        recData = recDataList.At(index)
        zoneID = recData.GetValue1()
        value1 = recData.GetValue1()
        cfgID, zoneID = value1 / 100, value1 % 100
        lotteryRec = LuckyCloudBuyLottery()
        lotteryRec.idTime = int(recData.GetTime())
        lotteryRec.cfgID = cfgID
        lotteryRec.zoneID = zoneID
        lotteryRec.roundNum = recData.GetValue2()
        lotteryRec.luckyPlayerID = recData.GetValue3()
@@ -167,10 +169,10 @@
        
        lotteryRec.luckyPlayerName = recData.GetStrValue1()
        strValue3 = recData.GetStrValue3()
        lotteryRec.serverGroupIDList, lotteryRec.superItemInfo, lotteryRec.luckyPlayerAccID = [], [], ""
        lotteryRec.serverIDRangeList, lotteryRec.superItemInfo, lotteryRec.luckyPlayerAccID = [], [], ""
        if strValue3:
            groupIDStr, superItemStr, accID = strValue3.split("|")
            lotteryRec.serverGroupIDList = eval(groupIDStr) if (groupIDStr.startswith("[") and groupIDStr.endswith("]")) else []
            serverIDStr, superItemStr, accID = strValue3.split("|")
            lotteryRec.serverIDRangeList = eval(serverIDStr) if (serverIDStr.startswith("[") and serverIDStr.endswith("]")) else []
            lotteryRec.superItemInfo = eval(superItemStr) if (superItemStr.startswith("[") and superItemStr.endswith("]")) else []
            lotteryRec.luckyPlayerAccID = accID
            
@@ -183,7 +185,6 @@
        lotteryRecList.sort(key=operator.attrgetter("idTime"))
        GameWorld.Log("    幸运云购分区开奖记录! zoneID=%s, count=%s" % (zoneID, len(lotteryRecList)))
        
    CheckLuckyCloudBuyZoneInfoChange()
    return
def OnServerClose():
@@ -219,14 +220,14 @@
        for lotteryRec in lotteryRecList:
            recData = recDataList.AddRec()
            recData.SetTime(lotteryRec.idTime)
            recData.SetValue1(lotteryRec.zoneID)
            recData.SetValue1(lotteryRec.cfgID * 100 + lotteryRec.zoneID)
            recData.SetValue2(lotteryRec.roundNum)
            recData.SetValue3(lotteryRec.luckyPlayerID)
            recData.SetValue4(lotteryRec.lotteryNum)
            recData.SetValue5(lotteryRec.lotteryTime)
            
            recData.SetStrValue1(lotteryRec.luckyPlayerName)
            recData.SetStrValue3("%s|%s|%s" % (str(lotteryRec.serverGroupIDList).replace(" ", ""),
            recData.SetStrValue3("%s|%s|%s" % (str(lotteryRec.serverIDRangeList).replace(" ", ""),
                                               str(lotteryRec.superItemInfo).replace(" ", ""), 
                                               lotteryRec.luckyPlayerAccID))
            
@@ -247,7 +248,7 @@
    MaxTime = 3 * 24 * 3600 # 最大保留近3天记录
    for zoneID, lotteryRecList in PyGameData.g_luckyCloudBuyLotteryDict.items():
        doCount = len(lotteryRecList)
        GameWorld.DebugLog("检查幸运云购分区开奖记录是否超时! zoneID=%s,count=%s" % (zoneID, doCount))
        GameWorld.DebugLog("检查幸运云购分区开奖记录是否超时! zoneID=%s,doCount=%s" % (zoneID, doCount))
        while lotteryRecList and doCount > 0:
            doCount -= 1
            lotteryRec = lotteryRecList[0]
@@ -269,99 +270,47 @@
    doLotteryBuyCountPer = IpyGameDataPY.GetFuncCfg("LuckyCloudBuySet", 3)
    doLotteryBuyCount = int(math.ceil(maxBuyCount * doLotteryBuyCountPer / 100.0))
    
    zoneLotteryInfo = {}
    for zoneID, lotteryRecList in PyGameData.g_luckyCloudBuyLotteryDict.items():
        if not lotteryRecList:
            continue
        lastLotteryRec = lotteryRecList[-1] # 取最后一个为最新一期
        cfgID = lastLotteryRec.cfgID
        if lastLotteryRec.lotteryNum:
            GameWorld.Log("OnDay已开奖进入新一天第一轮! zoneID=%s" % zoneID)
            DoStartNewRoundLuckyCloudBuy(zoneID, 1)
            GameWorld.Log("OnDay已开奖进入新一天第一轮! cfgID=%s,zoneID=%s" % (cfgID, zoneID))
            DoStartNewRoundLuckyCloudBuy(cfgID, 1)
            continue
        buyRecList = PyGameData.g_luckyCloudBuyNumDict.get(zoneID, [])
        buyCount = len(buyRecList)
        if len(buyRecList) >= doLotteryBuyCount:
            GameWorld.Log("OnDay未开奖但购买份数超过开奖保底份数! zoneID=%s,buyCount=%s >= %s" % (zoneID, buyCount, doLotteryBuyCount))
            GameWorld.Log("OnDay未开奖但购买份数超过开奖保底份数! cfgID=%s,zoneID=%s,buyCount=%s >= %s" % (cfgID, zoneID, buyCount, doLotteryBuyCount))
            DoLuckyCloudBuyLottery(lastLotteryRec, True, "OnDay")
            continue
        
        GameWorld.Log("已购买份数不足开奖保底份数,重置为新一天的第一轮! zoneID=%s,buyCount=%s < %s" % (zoneID, buyCount, doLotteryBuyCount))
        GameWorld.Log("已购买份数不足开奖保底份数,重置为新一天的第一轮! cfgID=%s,zoneID=%s,buyCount=%s < %s" % (cfgID, zoneID, buyCount, doLotteryBuyCount))
        lastLotteryRec.roundNum = 1
        dataDict = {"Type":"ResetRound"}
        dataDict.update(lastLotteryRec.GetString())
        DataRecordPack.SendEventPack("LuckyCloudBuyLottery", dataDict)
        zoneLotteryInfo[zoneID] = [lastLotteryRec.GetString()]
        
        # 广播子服轮次信息变更
        crossZoneName = GameWorld.GetCrossZoneName()
        zoneIpyData = IpyGameDataPY.GetIpyGameData("CrossZonePK", crossZoneName, zoneID)
        if zoneIpyData:
            serverGroupIDList = zoneIpyData.GetServerGroupIDList()
            zoneLotteryInfo = {zoneID:[lastLotteryRec.GetString()]}
    if zoneLotteryInfo:
            dataMsg = {"syncType":"Update", "zoneLotteryInfo":zoneLotteryInfo}
            CrossRealmMsg.SendMsgToClientServer(ShareDefine.CrossServerMsg_LuckyCloudBuyLottery, dataMsg, serverGroupIDList)
    return
def CheckLuckyCloudBuyZoneInfoChange():
    ## 检查云购分区配置变更
    if not GameWorld.IsCrossServer():
        return
    crossZoneName = GameWorld.GetCrossZoneName()
    crossZoneList = IpyGameDataPY.GetIpyGameDataByCondition("CrossZonePK", {"CrossZoneName":crossZoneName}, True)
    if not crossZoneList:
        return
    checkZoneInfo = {} # 分区调整可能变多、变少、或只调整范围,所以检查的分区要取配置及活动分区数据的所有分区汇总
    for zoneIpyData in crossZoneList:
        zoneID = zoneIpyData.GetZoneID()
        checkZoneInfo[zoneID] = zoneIpyData.GetServerGroupIDList()
    for zoneID in PyGameData.g_luckyCloudBuyLotteryDict.keys():
        if zoneID not in checkZoneInfo:
            checkZoneInfo[zoneID] = None
    haveChange = False
    for zoneID, serverGroupIDList in checkZoneInfo.items():
        lotteryRecList = PyGameData.g_luckyCloudBuyLotteryDict.get(zoneID, [])
        if lotteryRecList:
            lastLotteryRec = lotteryRecList[-1] # 取最后一个为最新一期
            if lastLotteryRec.lotteryNum:
                GameWorld.DebugLog("已开奖,不处理! zoneID=%s" % zoneID)
                continue
            if lastLotteryRec.serverGroupIDList != serverGroupIDList:
                GameWorld.Log("分区信息变更,强制开奖! zoneID=%s,recGroupIDList=%s,serverGroupIDList=%s"
                              % (zoneID, lastLotteryRec.serverGroupIDList, serverGroupIDList))
                DoLuckyCloudBuyLottery(lastLotteryRec, True, "ServerGroupIDChange")
                haveChange = True
            else:
                GameWorld.DebugLog("分区信息不变,不处理! zoneID=%s" % zoneID)
        else:
            GameWorld.Log("配置了新分区,开启新云购! zoneID=%s,serverGroupIDList=%s" % (zoneID, serverGroupIDList))
            DoStartNewRoundLuckyCloudBuy(zoneID, 1)
            haveChange = True
        if serverGroupIDList == None:
            GameWorld.Log("分区被删除! zoneID=%s" % zoneID)
            PyGameData.g_luckyCloudBuyLotteryDict.pop(zoneID, None)
            PyGameData.g_luckyCloudBuyNumDict.pop(zoneID, None)
    if haveChange:
        Sync_LuckyCloudBuyDataToClientServer(GameWorld.GetGameWorld().GetTick())
        CrossRealmMsg.SendMsgToClientServer(ShareDefine.CrossServerMsg_LuckyCloudBuyLottery, dataMsg)
    return
def DoLuckyCloudBuyLottery(lotteryRec, resetRound=False, sign=""):
    ## 云购开奖
    
    idTime = lotteryRec.idTime
    cfgID = lotteryRec.cfgID
    zoneID = lotteryRec.zoneID
    roundNum = lotteryRec.roundNum
    
    lotteryDateStr = GameWorld.ChangeTimeNumToStr(idTime, ChConfig.TYPE_Time_YmdFormat)
    GameWorld.Log("幸运云购开奖: idTime=%s(%s),zoneID=%s,roundNum=%s,resetRound=%s,sign=%s"
                  % (idTime, lotteryDateStr, zoneID, roundNum, resetRound, sign))
    GameWorld.Log("幸运云购开奖: idTime=%s(%s),cfgID=%s,zoneID=%s,roundNum=%s,resetRound=%s,sign=%s"
                  % (idTime, lotteryDateStr, cfgID, zoneID, roundNum, resetRound, sign))
    
    todayLuckyPlayerCountInfo = {} # 当日中奖玩家中奖次数信息 {playerID:count, ...}
    lotteryRecList = PyGameData.g_luckyCloudBuyLotteryDict.get(zoneID, [])
@@ -400,7 +349,6 @@
        playerNumList.append(buyRec.buyNum)
        
    GameWorld.Log("    本轮开奖饼图列表信息: buyCount=%s,randListLen=%s,maxRate=%s" % (len(buyRecList), len(randList), maxRate))
    luckyBuyRec = GameWorld.GetResultByRandomList(randList)
    if luckyBuyRec:
        GameWorld.Log("    幸运中奖号码记录: lotteryNum=%s, %s" % (luckyBuyRec.buyNum, luckyBuyRec.GetString()))
@@ -408,20 +356,14 @@
        lotteryRec.luckyPlayerName = luckyBuyRec.playerName
        lotteryRec.luckyPlayerAccID = luckyBuyRec.accID
        lotteryRec.lotteryNum = luckyBuyRec.buyNum
    else:
        GameWorld.ErrLog("    云购无人购买或开奖异常! cfgID=%s,zoneID=%s" % (cfgID, zoneID))
        maxBuyCount = IpyGameDataPY.GetFuncCfg("LuckyCloudBuySet", 2)
        lotteryRec.lotteryNum = random.randint(1, maxBuyCount)
        GameWorld.Log("    随机中奖号码! lotteryNum=%s" % lotteryRec.lotteryNum)
        lotteryRec.lotteryTime = int(time.time())
        dataDict = {"Type":"Lottery"}
        dataDict.update(lotteryRec.GetString())
        DataRecordPack.SendEventPack("LuckyCloudBuyLottery", dataDict)
        # 广播子服开奖信息
        crossZoneName = GameWorld.GetCrossZoneName()
        zoneIpyData = IpyGameDataPY.GetIpyGameData("CrossZonePK", crossZoneName, zoneID)
        if zoneIpyData:
            serverGroupIDList = zoneIpyData.GetServerGroupIDList()
            zoneLotteryInfo = {zoneID:[lotteryRec.GetString()]}
            dataMsg = {"syncType":"Update", "zoneLotteryInfo":zoneLotteryInfo}
            CrossRealmMsg.SendMsgToClientServer(ShareDefine.CrossServerMsg_LuckyCloudBuyLottery, dataMsg, serverGroupIDList)
            
        # 发邮件
        for playerID, buyNumList in playerNumListDict.items():
@@ -432,19 +374,29 @@
                buyNums = GetMailBuyNums(buyNumList)
                PlayerCompensation.SendMailByKey("LuckyCloudBuyFail", [playerID], [], [lotteryRec.lotteryNum, buyNums], crossMail=True)  
                
    else:
        GameWorld.ErrLog("    云购开奖异常! zoneID=%s" % zoneID)
    dataDict = {"Type":"Lottery"}
    dataDict.update(lotteryRec.GetString())
    DataRecordPack.SendEventPack("LuckyCloudBuyLottery", dataDict)
    # 广播子服开奖信息
    zoneLotteryInfo = {zoneID:[lotteryRec.GetString()]}
    dataMsg = {"syncType":"Update", "zoneLotteryInfo":zoneLotteryInfo}
    CrossRealmMsg.SendMsgToClientServer(ShareDefine.CrossServerMsg_LuckyCloudBuyLottery, dataMsg)
    actInfoDict = CrossActionControl.GetCrossActInfoByCfgID(ShareDefine.CrossActName_LuckyCloudBuy, cfgID)
    if not actInfoDict or not actInfoDict[ShareDefine.ActKey_State]:
        GameWorld.Log("    不在活动中了,不开下一轮! cfgID=%s" % cfgID)
        return
        
    if roundNum >= IpyGameDataPY.GetFuncCfg("LuckyCloudBuySet", 1):
        GameWorld.Log("    当日已达每日云购轮数上限,不开下一轮! roundNum=%s" % roundNum)
        return
    
    nextRoundNum = 1 if resetRound else (roundNum + 1)
    GameWorld.Log("幸运云购开启下一轮! zoneID=%s,roundNum=%s,resetRound=%s,nextRoundNum=%s"
                  % (zoneID, roundNum, resetRound, nextRoundNum))
    GameWorld.Log("幸运云购开启下一轮! cfgID=%s,zoneID=%s,roundNum=%s,resetRound=%s,nextRoundNum=%s"
                  % (cfgID, zoneID, roundNum, resetRound, nextRoundNum))
    # 开始下一轮
    DoStartNewRoundLuckyCloudBuy(zoneID, nextRoundNum)
    return
    return DoStartNewRoundLuckyCloudBuy(cfgID, nextRoundNum)
def GetMailBuyNums(buyNumList):
    buyNumList.sort()
@@ -474,26 +426,60 @@
        
    return buyNums
def DoStartNewRoundLuckyCloudBuy(zoneID, roundNum):
def OnLuckyCloudBuyReset(ipyData, state):
    ## 云购重置
    cfgID = ipyData.GetCfgID()
    zoneID = ipyData.GetZoneID()
    startNewLottery = False
    lotteryRecList = PyGameData.g_luckyCloudBuyLotteryDict.get(zoneID, [])
    lastLotteryRec = None if not lotteryRecList else lotteryRecList[-1]
    if lastLotteryRec and not lastLotteryRec.lotteryNum:
        GameWorld.Log("幸运云购重置,当前轮次未开奖,直接开奖! cfgID=%s,zoneID=%s" % (lastLotteryRec.cfgID, zoneID))
        startNewLottery = DoLuckyCloudBuyLottery(lastLotteryRec, True, "Reset")
    if state and not startNewLottery:
        GameWorld.Log("幸运云购重置,当前没有未开奖的轮次,直接开启新一轮! cfgID=%s,zoneID=%s" % (cfgID, zoneID))
        DoStartNewRoundLuckyCloudBuy(cfgID, 1)
    return
def DoStartNewRoundLuckyCloudBuy(cfgID, roundNum):
    # 开启新一轮云购
    
    crossZoneName = GameWorld.GetCrossZoneName()
    zoneIpyData = IpyGameDataPY.GetIpyGameData("CrossZonePK", crossZoneName, zoneID)
    if not zoneIpyData:
    actInfoDict = CrossActionControl.GetCrossActInfoByCfgID(ShareDefine.CrossActName_LuckyCloudBuy, cfgID)
    if not actInfoDict or not actInfoDict[ShareDefine.ActKey_State]:
        GameWorld.ErrLog("幸运云购非活动中,无法开启! cfgID=%s, roundNum=%s" % (cfgID, roundNum))
        return
    serverGroupIDList = zoneIpyData.GetServerGroupIDList()
    
    superItemInfo = GameWorld.GetResultByRandomList(IpyGameDataPY.GetFuncEvalCfg("LuckyCloudBuyAward", 3), [])
    actIpyData = IpyGameDataPY.GetIpyGameData("CrossActLuckyCloudBuy", cfgID)
    if not actIpyData:
        return
    zoneID = actIpyData.GetZoneID()
    serverIDRangeList = actIpyData.GetServerIDRangeList()
    templateIDList = actIpyData.GetTemplateIDList()
    if not templateIDList:
        return
    dayIndex = actInfoDict.get(ShareDefine.ActKey_DayIndex, 0)
    templateID = templateIDList[dayIndex] if len(templateIDList) > dayIndex else templateIDList[-1]
    templateIpyData = IpyGameDataPY.GetIpyGameData("CrossActLuckyCloudBuyTemplate", templateID)
    if not templateIpyData:
        return
    superItemWeightInfo = templateIpyData.GetSuperItemWeightInfo()
    superItemInfo = GameWorld.GetResultByWeightList(superItemWeightInfo)
    if not superItemInfo or len(superItemInfo) < 3:
        GameWorld.ErrLog("幸运云购生成大奖失败! zoneID=%s,roundNum=%s,superItemInfo=%s" % (zoneID, roundNum, superItemInfo))
        return
    
    lotteryRec = LuckyCloudBuyLottery()
    lotteryRec.idTime = int(time.time())
    lotteryRec.cfgID = cfgID
    lotteryRec.zoneID = zoneID
    lotteryRec.roundNum = roundNum
    
    lotteryRec.serverGroupIDList = serverGroupIDList
    lotteryRec.serverIDRangeList = serverIDRangeList
    lotteryRec.superItemInfo = superItemInfo
    
    if zoneID not in PyGameData.g_luckyCloudBuyLotteryDict:
@@ -510,24 +496,11 @@
    # 广播子服开奖信息
    zoneLotteryInfo = {zoneID:[lotteryRec.GetString()]}
    dataMsg = {"syncType":"New", "zoneLotteryInfo":zoneLotteryInfo}
    CrossRealmMsg.SendMsgToClientServer(ShareDefine.CrossServerMsg_LuckyCloudBuyLottery, dataMsg, serverGroupIDList)
    return
    CrossRealmMsg.SendMsgToClientServer(ShareDefine.CrossServerMsg_LuckyCloudBuyLottery, dataMsg)
    return True
def Sync_LuckyCloudBuyDataToClientServer(tick, serverGroupID=0):
    GameWorld.Log("同步给子服对应的幸运云购信息: syncServerGroupID=%s" % (serverGroupID))
    if serverGroupID:
        ipyData = CrossRealmPK.GetCrossPKServerGroupZone(serverGroupID)
        if not ipyData:
            return
        crossZoneList = [ipyData]
    else:
        crossZoneName = GameWorld.GetCrossZoneName()
        crossZoneList = IpyGameDataPY.GetIpyGameDataByCondition("CrossZonePK", {"CrossZoneName":crossZoneName}, True)
    if not crossZoneList:
        return
    #注: 开奖记录同步所有分区的开奖内容;购买记录仅同步自己分区的记录即可
    
    # 开奖记录
    zoneLotteryInfo = {}
@@ -537,22 +510,18 @@
            zoneLotteryList.append(lotteryRec.GetString())
        zoneLotteryInfo[zoneID] = zoneLotteryList
        
    for zoneIpyData in crossZoneList:
        zoneID = zoneIpyData.GetZoneID()
        serverGroupIDList = [serverGroupID] if serverGroupID else zoneIpyData.GetServerGroupIDList()
        dataMsg = {"syncType":"All", "zoneLotteryInfo":zoneLotteryInfo}
        CrossRealmMsg.SendMsgToClientServer(ShareDefine.CrossServerMsg_LuckyCloudBuyLottery, dataMsg, serverGroupIDList)
    CrossRealmMsg.SendMsgToClientServer(ShareDefine.CrossServerMsg_LuckyCloudBuyLottery, dataMsg)
        
        # 购买记录
    for zoneID in PyGameData.g_luckyCloudBuyLotteryDict.keys():
        zoneBuyNumList = []
        buyRecList = PyGameData.g_luckyCloudBuyNumDict.get(zoneID, [])
        for buyRec in buyRecList:
            zoneBuyNumList.append(buyRec.GetString())
            
        dataMsg = {"syncType":"All", "zoneID":zoneID, "zoneBuyNumList":zoneBuyNumList}
        CrossRealmMsg.SendMsgToClientServer(ShareDefine.CrossServerMsg_LuckyCloudBuyNum, dataMsg, serverGroupIDList)
        CrossRealmMsg.SendMsgToClientServer(ShareDefine.CrossServerMsg_LuckyCloudBuyNum, dataMsg)
        
    return
@@ -563,12 +532,9 @@
    zoneLotteryInfo = msgData["zoneLotteryInfo"]
    
    serverGroupID = GameWorld.GetServerGroupID()
    zoneIpyData = CrossRealmPK.GetCrossPKServerGroupZone(serverGroupID)
    if not zoneIpyData:
        return
    serverZoneID = zoneIpyData.GetZoneID()
    serverZoneID = CrossActionControl.GetCrossActZoneID(ShareDefine.CrossActName_LuckyCloudBuy, serverGroupID)
    syncMapLotteryRec = None # 有需要同步地图的,即有本分区的数据同步
    GameWorld.Log("收到分区云购开奖记录同步信息: syncType=%s,serverZoneID=%s,zoneCount=%s" % (syncType, serverZoneID, len(zoneLotteryInfo)))
    
    if syncType == "All":
        PyGameData.g_luckyCloudBuyLotteryDict = {}
@@ -577,7 +543,7 @@
        if zoneID not in PyGameData.g_luckyCloudBuyLotteryDict:
            PyGameData.g_luckyCloudBuyLotteryDict[zoneID] = []
        lotteryRecList = PyGameData.g_luckyCloudBuyLotteryDict[zoneID]
        GameWorld.Log("收到分区云购开奖记录同步信息: syncType=%s,zoneID=%s,count=%s" % (syncType, zoneID, zoneLotteryList))
        GameWorld.Log("    分区云购开奖记录同步信息: syncType=%s,zoneID=%s,count=%s" % (syncType, zoneID, zoneLotteryList))
        for attrDict in zoneLotteryList:
            if syncType in ["All", "New"]:
                lotteryRec = LuckyCloudBuyLottery()
@@ -588,7 +554,7 @@
                    
                # 本分区新轮次
                if syncType == "New" and zoneID == serverZoneID:
                    GameWorld.Log("    新增云购开奖记录信息: idTime=%s" % lotteryRec.idTime)
                    GameWorld.Log("        本服分区新增云购开奖记录信息: idTime=%s" % lotteryRec.idTime)
                    PyGameData.g_luckyCloudBuyNumDict[zoneID] = []
                    if len(lotteryRec.superItemInfo) >= 2:
                        superItemID, superItemCount = lotteryRec.superItemInfo[0], lotteryRec.superItemInfo[1]
@@ -607,6 +573,7 @@
                        
                        # 本分区开奖记录同步
                        if lotteryRec.lotteryNum:
                            GameWorld.Log("        本服分区更新云购开奖记录信息: idTime=%s" % lotteryRec.idTime)
                            if len(lotteryRec.superItemInfo) >= 2:
                                superItemID, superItemCount = lotteryRec.superItemInfo[0], lotteryRec.superItemInfo[1]
                                PlayerControl.WorldNotify(0, "LuckyCloudBuyClose", [lotteryRec.lotteryNum, lotteryRec.luckyPlayerName, superItemID, superItemCount])
@@ -627,10 +594,9 @@
        return
    
    serverGroupID = GameWorld.GetServerGroupID()
    zoneIpyData = CrossRealmPK.GetCrossPKServerGroupZone(serverGroupID)
    if not zoneIpyData:
    zoneID = CrossActionControl.GetCrossActZoneID(ShareDefine.CrossActName_LuckyCloudBuy, serverGroupID)
    if not zoneID:
        return
    zoneID = zoneIpyData.GetZoneID()
    
    lotteryRecList = PyGameData.g_luckyCloudBuyLotteryDict.get(zoneID, [])
    lastLotteryRec = None if not lotteryRecList else lotteryRecList[-1]
@@ -642,10 +608,9 @@
def ClientServerMsg_LuckyCloudBuy(serverGroupID, msgData):
    ## 收到子服请求幸运云购购买
    
    zoneIpyData = CrossRealmPK.GetCrossPKServerGroupZone(serverGroupID)
    if not zoneIpyData:
    zoneID = CrossActionControl.GetCrossActZoneID(ShareDefine.CrossActName_LuckyCloudBuy, serverGroupID)
    if not zoneID:
        return
    zoneID = zoneIpyData.GetZoneID()
    
    accID = msgData["accID"]
    playerID = msgData["playerID"]
@@ -709,8 +674,7 @@
    
    # 通知子服
    dataMsg = {"syncType":"New", "zoneID":zoneID, "zoneBuyNumList":zoneBuyNumList, "buyPlayer":[serverGroupID, playerID, roundID, buyCount]}
    serverGroupIDList = zoneIpyData.GetServerGroupIDList()
    CrossRealmMsg.SendMsgToClientServer(ShareDefine.CrossServerMsg_LuckyCloudBuyNum, dataMsg, serverGroupIDList)
    CrossRealmMsg.SendMsgToClientServer(ShareDefine.CrossServerMsg_LuckyCloudBuyNum, dataMsg)
    
    # 结算开奖
    if remainCount == buyCount:
@@ -721,10 +685,9 @@
def DoGMLuckyCloudBuy(serverGroupID, buyCount):
    GameWorld.Log("GM添加云购记录! serverGroupID=%s,buyCount=%s" % (serverGroupID, buyCount))
    zoneIpyData = CrossRealmPK.GetCrossPKServerGroupZone(serverGroupID)
    if not zoneIpyData:
    zoneID = CrossActionControl.GetCrossActZoneID(ShareDefine.CrossActName_LuckyCloudBuy, serverGroupID)
    if not zoneID:
        return
    zoneID = zoneIpyData.GetZoneID()
    
    lotteryRecList = PyGameData.g_luckyCloudBuyLotteryDict.get(zoneID, [])
    if not lotteryRecList:
@@ -736,7 +699,7 @@
    remainCount = max(0, maxBuyCount - len(buyRecList))
    buyCount = min(buyCount, remainCount)
    if buyCount <= 0:
        GameWorld.ErrLog("GM幸运云购购买异常!剩余可购买的份数不足!buyCount=%s" % buyCount)
        GameWorld.ErrLog("GM幸运云购购买异常!剩余可购买的份数不足!zoneID=%s,buyCount=%s" % (zoneID, buyCount))
        return
    
    preBuyRec = None if not buyRecList else buyRecList[-1]
@@ -766,8 +729,7 @@
        
    # 通知子服
    dataMsg = {"syncType":"New", "zoneID":zoneID, "zoneBuyNumList":zoneBuyNumList}
    serverGroupIDList = zoneIpyData.GetServerGroupIDList()
    CrossRealmMsg.SendMsgToClientServer(ShareDefine.CrossServerMsg_LuckyCloudBuyNum, dataMsg, serverGroupIDList)
    CrossRealmMsg.SendMsgToClientServer(ShareDefine.CrossServerMsg_LuckyCloudBuyNum, dataMsg)
    
    # 结算开奖
    if remainCount == buyCount:
@@ -780,6 +742,20 @@
    syncType = msgData["syncType"] # All New
    zoneID = msgData["zoneID"]
    zoneBuyNumList = msgData["zoneBuyNumList"]
    curServerGroupID = GameWorld.GetServerGroupID()
    actInfo = CrossActionControl.GetCrossActInfoByServerGroupID(ShareDefine.CrossActName_LuckyCloudBuy, curServerGroupID)
    if not actInfo:
        return
    state = actInfo.get(ShareDefine.ActKey_State)
    ipyDataInfo = actInfo.get(ShareDefine.ActKey_IpyDataInfo)
    if not state or not ipyDataInfo:
        return
    serverZoneID = ipyDataInfo.get("ZoneID")
    if zoneID != serverZoneID:
        GameWorld.DebugLog("不是本服务器分区的云购记录不处理! curServerGroupID=%s,serverZoneID(%s) != zoneID(%s)"
                           % (curServerGroupID, serverZoneID, zoneID))
        return
    
    if syncType == "All":
        PyGameData.g_luckyCloudBuyNumDict = {}
@@ -796,8 +772,6 @@
        if syncType == "New":
            syncRecList.append(buyRec)
    
    if syncType == "New":
        Sync_LuckyCloudBuyRoundInfo(None)
    if syncRecList:
        Sync_LuckyCloudBuyNumRecInfo(None, syncRecList)
        
@@ -805,21 +779,49 @@
    if not buyPlayer:
        return
    serverGroupID, playerID, roundID, buyCount = buyPlayer
    curServerGroupID = GameWorld.GetServerGroupID()
    if curServerGroupID != serverGroupID:
        #GameWorld.DebugLog("非本服玩家购买云购,不通知地图玩家处理!curServerGroupID=%s,buyPlayerServerGroupID=%s"
        #                   % (curServerGroupID, serverGroupID), playerID)
    if serverGroupID != curServerGroupID:
        return
    templateIDList = ipyDataInfo.get("TemplateIDList")
    if not templateIDList:
        return
    dayIndex = actInfo.get(ShareDefine.ActKey_DayIndex, 0)
    templateID = templateIDList[dayIndex] if len(templateIDList) > dayIndex else templateIDList[-1]
    templateIpyData = IpyGameDataPY.GetIpyGameData("CrossActLuckyCloudBuyTemplate", templateID)
    if not templateIpyData:
        return
    baseAwardInfo = templateIpyData.GetBaseAwardInfo()
    randAwardWeightInfo = templateIpyData.GetRandAwardWeightInfo()
    awardItemDict = {}
    for _ in xrange(buyCount):
        awardItemInfo = []
        awardItemInfo += baseAwardInfo
        randItemInfo = GameWorld.GetResultByWeightList(randAwardWeightInfo)
        if randItemInfo:
            awardItemInfo += [randItemInfo]
        for itemID, itemCount, isBind in awardItemInfo:
            if itemID not in awardItemDict:
                awardItemDict[itemID] = [itemCount, isBind]
            else:
                awardItemDict[itemID] = [awardItemDict[itemID][0] + itemCount, isBind]
    awardItemList = []
    for itemID in awardItemDict.keys():
        itemCount, isBind = awardItemDict[itemID]
        awardItemList.append([itemID, itemCount, isBind])
    
    player = GameWorld.GetPlayerManager().FindPlayerByID(playerID)
    if not player:
        GameWorld.Log("玩家不在线先缓存,玩家上线后再同步云购! roundID=%s,buyCount=%s" % (roundID, buyCount), playerID)
        PyGameData.g_unNotifyCloudBuyNumDict[playerID] = [roundID, buyCount]
        GameWorld.Log("玩家不在线先缓存,玩家上线后再同步云购! roundID=%s,buyCount=%s,awardItemList=%s"
                      % (roundID, buyCount, awardItemList), playerID)
        PyGameData.g_unNotifyCloudBuyNumDict[playerID] = [roundID, buyCount, awardItemList]
        return
    
    mapID = player.GetRealMapID()
    sysMsg = str(["LuckyCloudBuyNum", roundID, buyCount])
    sysMsg = str(["LuckyCloudBuyNum", roundID, buyCount, awardItemList])
    player.MapServer_QueryPlayerResult(0, 0, "LuckyCloudBuy", sysMsg, len(sysMsg))
    GameWorld.Log("通知地图跨服云购购买结算: roundID=%s,buyCount=%s,mapID=%s" % (roundID, buyCount, mapID), playerID)
    return
@@ -828,10 +830,10 @@
    playerID = curPlayer.GetPlayerID()
    if playerID not in PyGameData.g_unNotifyCloudBuyNumDict:
        return
    roundID, buyCount = PyGameData.g_unNotifyCloudBuyNumDict.pop(playerID)
    roundID, buyCount, awardItemList = PyGameData.g_unNotifyCloudBuyNumDict.pop(playerID)
    
    mapID = curPlayer.GetRealMapID()
    sysMsg = str(["LuckyCloudBuyNum", roundID, buyCount])
    sysMsg = str(["LuckyCloudBuyNum", roundID, buyCount, awardItemList])
    curPlayer.MapServer_QueryPlayerResult(0, 0, "LuckyCloudBuy", sysMsg, len(sysMsg))
    GameWorld.Log("上线补通知地图跨服云购购买结算: roundID=%s,buyCount=%s,mapID=%s" % (roundID, buyCount, mapID), playerID)
    return
@@ -854,7 +856,7 @@
#struct    tagCGQueryLuckyCloudBuyLotteryRec
#{
#    tagHead        Head;
#    BYTE        ZoneID;    //查询分区ID,分区同跨服PK分区
#    BYTE        ZoneID;    //查询分区ID
#};
def OnQueryLuckyCloudBuyLotteryRec(index, clientData, tick):
    curPlayer = GameWorld.GetPlayerManager().GetPlayerByIndex(index)
@@ -865,30 +867,65 @@
    return
def Sync_LuckyCloudBuyRoundInfo(curPlayer):
    ## 通知活动中的云购活动信息
    serverGroupID = GameWorld.GetServerGroupID()
    zoneIpyData = CrossRealmPK.GetCrossPKServerGroupZone(serverGroupID)
    if not zoneIpyData:
    actInfo = CrossActionControl.GetCrossActInfoByServerGroupID(ShareDefine.CrossActName_LuckyCloudBuy, serverGroupID)
    if not actInfo:
        return
    zoneID = zoneIpyData.GetZoneID()
    state = actInfo.get(ShareDefine.ActKey_State)
    ipyDataInfo = actInfo.get(ShareDefine.ActKey_IpyDataInfo)
    if not state or not ipyDataInfo:
        return
    zoneID = ipyDataInfo.get("ZoneID")
    if not zoneID:
        return
    templateIDList = ipyDataInfo.get("TemplateIDList")
    if not templateIDList:
        return
    dayIndex = actInfo.get(ShareDefine.ActKey_DayIndex, 0)
    templateID = templateIDList[dayIndex] if len(templateIDList) > dayIndex else templateIDList[-1]
    templateIpyData = IpyGameDataPY.GetIpyGameData("CrossActLuckyCloudBuyTemplate", templateID)
    if not templateIpyData:
        return
    baseAwardInfo = templateIpyData.GetBaseAwardInfo()
    randAwardWeightInfo = templateIpyData.GetRandAwardWeightInfo()
    
    lotteryRecList = PyGameData.g_luckyCloudBuyLotteryDict.get(zoneID, [])
    lotteryRec = None if not lotteryRecList else lotteryRecList[-1] # 取最新一期的
    if not lotteryRec:
        return
    
    buyRecList = PyGameData.g_luckyCloudBuyNumDict.get(zoneID, [])
    maxBuyCount = IpyGameDataPY.GetFuncCfg("LuckyCloudBuySet", 2)
    superItemInfo = lotteryRec.superItemInfo + [0, 0, 0, 0, 0]
    superItemID, superItemCount, _, moneyType, moneyValue = superItemInfo[:5]
    clientPack = ChPyNetSendPack.tagGCLuckyCloudBuyRoundInfo()
    clientPack.ZoneID = zoneID
    clientPack.StartDate = ipyDataInfo.get("StartDate", "")
    clientPack.EndtDate = ipyDataInfo.get("EndDate", "")
    clientPack.RoundID = lotteryRec.idTime
    clientPack.RoundNum = lotteryRec.roundNum
    clientPack.SuperItemID = superItemID
    clientPack.SuperItemCount = superItemCount
    clientPack.SuperItemMoneyType = moneyType
    clientPack.SuperItemMoneyValue = moneyValue
    clientPack.RemainCount = max(0, maxBuyCount - len(buyRecList))
    clientPack.BaseItemList = []
    for itemID, itemCount, isBind in baseAwardInfo:
        item = ChPyNetSendPack.tagGCLuckyCloudBuyRoundItem()
        item.ItemID = itemID
        item.ItemCount = itemCount
        item.IsBind = isBind
        clientPack.BaseItemList.append(item)
    clientPack.BaseItemCount = len(clientPack.BaseItemList)
    clientPack.RandItemList = []
    for _, itemID, itemCount, isBind in randAwardWeightInfo:
        item = ChPyNetSendPack.tagGCLuckyCloudBuyRoundItem()
        item.ItemID = itemID
        item.ItemCount = itemCount
        item.IsBind = isBind
        clientPack.RandItemList.append(item)
    clientPack.RandItemCount = len(clientPack.RandItemList)
    
    if not curPlayer:
        playerManager = GameWorld.GetPlayerManager()
@@ -907,23 +944,23 @@
    return
def Sync_LuckyCloudBuyNumRecInfo(curPlayer, syncRecList=None):
    ## 通知活动中的云购活动购买记录信息
    serverGroupID = GameWorld.GetServerGroupID()
    zoneID = CrossActionControl.GetCrossActZoneID(ShareDefine.CrossActName_LuckyCloudBuy, serverGroupID)
    buyRecList = PyGameData.g_luckyCloudBuyNumDict.get(zoneID, [])
    
    if syncRecList == None:
        serverGroupID = GameWorld.GetServerGroupID()
        zoneIpyData = CrossRealmPK.GetCrossPKServerGroupZone(serverGroupID)
        if not zoneIpyData:
            return
        zoneID = zoneIpyData.GetZoneID()
        lotteryRecList = PyGameData.g_luckyCloudBuyLotteryDict.get(zoneID, [])
        lotteryRec = None if not lotteryRecList else lotteryRecList[-1] # 取最新一期的
        if not lotteryRec:
            return
        buyRecList = PyGameData.g_luckyCloudBuyNumDict.get(zoneID, [])
        syncRecList = buyRecList[-50:]
        
    maxBuyCount = IpyGameDataPY.GetFuncCfg("LuckyCloudBuySet", 2)
    clientPack = ChPyNetSendPack.tagGCLuckyCloudBuyNumRecInfo()
    clientPack.RemainCount = max(0, maxBuyCount - len(buyRecList))
    clientPack.BuyNumRecList = []
    for buyRec in syncRecList:
        buyNumInfo = ChPyNetSendPack.tagGCLuckyCloudBuyNumRec()
@@ -950,6 +987,7 @@
    return
def Sync_LuckyCloudBuyLotteryRecInfo(curPlayer, zoneID, syncRec=None):
    ## 通知云购活动分区历史开奖信息
    
    if syncRec == None:        
        lotteryRecList = PyGameData.g_luckyCloudBuyLotteryDict.get(zoneID, [])
@@ -957,6 +995,8 @@
        lotteryRecList = [syncRec]
        
    clientPack = ChPyNetSendPack.tagGCLuckyCloudBuyLotteryRecInfo()
    clientPack.ZoneIDList = PyGameData.g_luckyCloudBuyLotteryDict.keys()
    clientPack.ZoneCount = len(clientPack.ZoneIDList)
    clientPack.ZoneID = zoneID
    clientPack.LotteryRecList = []
    for lotteryRec in lotteryRecList:
ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/CrossRealmMsg.py
@@ -150,8 +150,8 @@
    CrossRealmPlayer.Sync_CrossCommInitDataToClientServer(serverGroupID)
    CrossRealmPK.Sync_CrossPKInitDataToClientServer(tick, serverGroupID)
    CrossBoss.Sync_CrossBossInitDataToClientServer(serverGroupID)
    CrossLuckyCloudBuy.Sync_LuckyCloudBuyDataToClientServer(tick, serverGroupID)
    CrossActionControl.Sync_CrossActInfoToClientServer(serverGroupID)
    CrossLuckyCloudBuy.Sync_LuckyCloudBuyDataToClientServer(tick, serverGroupID)
    PlayerCompensation.Sync_CrossMailPlayerIDToClientServer(serverGroupID)
    return
ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/GameWorldProcess.py
@@ -380,7 +380,6 @@
    return
def OnReloadConfig():
    CrossLuckyCloudBuy.CheckLuckyCloudBuyZoneInfoChange()
    return
#---------------------------------------------------------------------
ServerPython/CoreServerGroup/GameServer/Script/IpyGameDataPY.py
@@ -742,9 +742,27 @@
                        ("WORD", "LVLimit", 0),
                        ),
                "CrossActLuckyCloudBuy":(
                        ("DWORD", "CfgID", 1),
                        ("char", "ActGroupName", 0),
                        ("BYTE", "ZoneID", 0),
                        ("list", "ServerIDRangeList", 0),
                        ("char", "StartDate", 0),
                        ("char", "EndDate", 0),
                        ("list", "TemplateIDList", 0),
                        ),
                "CrossActLuckyCloudBuyTemplate":(
                        ("DWORD", "TemplateID", 1),
                        ("list", "BaseAwardInfo", 0),
                        ("list", "RandAwardWeightInfo", 0),
                        ("list", "SuperItemWeightInfo", 0),
                        ),
                "CrossActCTGBillboard":(
                        ("DWORD", "CfgID", 1),
                        ("char", "ActGroupName", 0),
                        ("BYTE", "ZoneID", 0),
                        ("list", "ServerIDRangeList", 0),
                        ("char", "StartDate", 0),
                        ("char", "EndDate", 0),
@@ -2277,12 +2295,49 @@
    def GetNotifyInfoLoop(self): return self.NotifyInfoLoop # 全服提示信息 - 循环广播[间隔分钟, 广播key]
    def GetLVLimit(self): return self.LVLimit # 限制等级
# 跨服幸运云购表
class IPY_CrossActLuckyCloudBuy():
    def __init__(self):
        self.CfgID = 0
        self.ActGroupName = ""
        self.ZoneID = 0
        self.ServerIDRangeList = []
        self.StartDate = ""
        self.EndDate = ""
        self.TemplateIDList = []
        return
    def GetCfgID(self): return self.CfgID # 配置ID
    def GetActGroupName(self): return self.ActGroupName # 活动组名(同组活动的名字需相同)
    def GetZoneID(self): return self.ZoneID # 组内分组编号
    def GetServerIDRangeList(self): return self.ServerIDRangeList # 活动的账号服务器ID范围列表 [[serverIDA, serverIDB], ...]
    def GetStartDate(self): return self.StartDate # 开启日期
    def GetEndDate(self): return self.EndDate # 结束日期
    def GetTemplateIDList(self): return self.TemplateIDList # 模板ID列表
# 跨服幸运云购模板表
class IPY_CrossActLuckyCloudBuyTemplate():
    def __init__(self):
        self.TemplateID = 0
        self.BaseAwardInfo = []
        self.RandAwardWeightInfo = []
        self.SuperItemWeightInfo = []
        return
    def GetTemplateID(self): return self.TemplateID # 模板ID
    def GetBaseAwardInfo(self): return self.BaseAwardInfo # 每次购买固定奖励 [[物品ID,个数,是否拍品], ...]
    def GetRandAwardWeightInfo(self): return self.RandAwardWeightInfo # 每次购买随机奖励权重信息 [[权重,物品ID,个数,是否拍品], ...]
    def GetSuperItemWeightInfo(self): return self.SuperItemWeightInfo # 大奖随机权重信息  [[权重,物品ID,个数,是否拍品,价值货币类型,货币值], ...]
# 跨服充值排行活动时间表
class IPY_CrossActCTGBillboard():
    
    def __init__(self):
        self.CfgID = 0
        self.ActGroupName = ""
        self.ZoneID = 0
        self.ServerIDRangeList = []
        self.StartDate = ""
        self.EndDate = ""
@@ -2295,6 +2350,7 @@
        
    def GetCfgID(self): return self.CfgID # 配置ID
    def GetActGroupName(self): return self.ActGroupName # 活动组名(同组活动的名字需相同)
    def GetZoneID(self): return self.ZoneID # 组内分组编号
    def GetServerIDRangeList(self): return self.ServerIDRangeList # 活动的账号服务器ID范围列表 [[serverIDA, serverIDB], ...]
    def GetStartDate(self): return self.StartDate # 开启日期
    def GetEndDate(self): return self.EndDate # 结束日期
@@ -2533,6 +2589,10 @@
        self.ipyMarryLen = len(self.ipyMarryCache)
        self.ipyActLuckyTreasureCache = self.__LoadFileData("ActLuckyTreasure", IPY_ActLuckyTreasure)
        self.ipyActLuckyTreasureLen = len(self.ipyActLuckyTreasureCache)
        self.ipyCrossActLuckyCloudBuyCache = self.__LoadFileData("CrossActLuckyCloudBuy", IPY_CrossActLuckyCloudBuy)
        self.ipyCrossActLuckyCloudBuyLen = len(self.ipyCrossActLuckyCloudBuyCache)
        self.ipyCrossActLuckyCloudBuyTemplateCache = self.__LoadFileData("CrossActLuckyCloudBuyTemplate", IPY_CrossActLuckyCloudBuyTemplate)
        self.ipyCrossActLuckyCloudBuyTemplateLen = len(self.ipyCrossActLuckyCloudBuyTemplateCache)
        self.ipyCrossActCTGBillboardCache = self.__LoadFileData("CrossActCTGBillboard", IPY_CrossActCTGBillboard)
        self.ipyCrossActCTGBillboardLen = len(self.ipyCrossActCTGBillboardCache)
        self.ipyCrossActCTGBillboardOrderCache = self.__LoadFileData("CrossActCTGBillboardOrder", IPY_CrossActCTGBillboardOrder)
@@ -2841,6 +2901,10 @@
    def GetMarryByIndex(self, index): return self.ipyMarryCache[index]
    def GetActLuckyTreasureCount(self): return self.ipyActLuckyTreasureLen
    def GetActLuckyTreasureByIndex(self, index): return self.ipyActLuckyTreasureCache[index]
    def GetCrossActLuckyCloudBuyCount(self): return self.ipyCrossActLuckyCloudBuyLen
    def GetCrossActLuckyCloudBuyByIndex(self, index): return self.ipyCrossActLuckyCloudBuyCache[index]
    def GetCrossActLuckyCloudBuyTemplateCount(self): return self.ipyCrossActLuckyCloudBuyTemplateLen
    def GetCrossActLuckyCloudBuyTemplateByIndex(self, index): return self.ipyCrossActLuckyCloudBuyTemplateCache[index]
    def GetCrossActCTGBillboardCount(self): return self.ipyCrossActCTGBillboardLen
    def GetCrossActCTGBillboardByIndex(self, index): return self.ipyCrossActCTGBillboardCache[index]
    def GetCrossActCTGBillboardOrderCount(self): return self.ipyCrossActCTGBillboardOrderLen
ServerPython/CoreServerGroup/GameServer/Script/ShareDefine.py
@@ -288,9 +288,12 @@
#跨服运营活动表名定义
CrossActName_CTGBillboard = "CrossActCTGBillboard" # 充值排行榜
CrossActName_LuckyCloudBuy = "CrossActLuckyCloudBuy" # 幸运云购
#跨服运营活动列表
CrossActNameList = [CrossActName_CTGBillboard]
CrossActNameList = [CrossActName_CTGBillboard, CrossActName_LuckyCloudBuy]
#需要锁定活动分区分配直到活动结束的跨服运营活动,即使热更分区配置,也不会改变正在活动中的分区设定,直到活动结束
CrossActLockServerGroupIDList = [CrossActName_CTGBillboard]
#活动信息字典key定义
ActKey_ID = "ID" # 活动ID,唯一标识的ID,一般是活动开启的time值
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetPack.py
@@ -4042,7 +4042,7 @@
    _fields_ = [
                  ("Cmd", c_ubyte),
                  ("SubCmd", c_ubyte),
                  ("ZoneID", c_ubyte),    #查询分区ID,分区同跨服PK分区
                  ("ZoneID", c_ubyte),    #查询分区ID
                  ]
    def __init__(self):
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetSendPack.py
@@ -13376,7 +13376,9 @@
class  tagGCLuckyCloudBuyLotteryRecInfo(Structure):
    Head = tagHead()
    ZoneID = 0    #(BYTE ZoneID)// 分区
    ZoneCount = 0    #(BYTE ZoneCount)// 分区数
    ZoneIDList = list()    #(vector<BYTE> ZoneIDList)// 所有分区ID列表
    ZoneID = 0    #(BYTE ZoneID)// 返回记录分区ID
    Count = 0    #(WORD Count)
    LotteryRecList = list()    #(vector<tagGCLuckyCloudBuyLotteryRec> LotteryRecList)
    data = None
@@ -13390,6 +13392,10 @@
    def ReadData(self, _lpData, _pos=0, _Len=0):
        self.Clear()
        _pos = self.Head.ReadData(_lpData, _pos)
        self.ZoneCount,_pos = CommFunc.ReadBYTE(_lpData, _pos)
        for i in range(self.ZoneCount):
            value,_pos=CommFunc.ReadBYTE(_lpData,_pos)
            self.ZoneIDList.append(value)
        self.ZoneID,_pos = CommFunc.ReadBYTE(_lpData, _pos)
        self.Count,_pos = CommFunc.ReadWORD(_lpData, _pos)
        for i in range(self.Count):
@@ -13403,6 +13409,8 @@
        self.Head.Clear()
        self.Head.Cmd = 0xC0
        self.Head.SubCmd = 0x14
        self.ZoneCount = 0
        self.ZoneIDList = list()
        self.ZoneID = 0
        self.Count = 0
        self.LotteryRecList = list()
@@ -13411,6 +13419,8 @@
    def GetLength(self):
        length = 0
        length += self.Head.GetLength()
        length += 1
        length += 1 * self.ZoneCount
        length += 1
        length += 2
        for i in range(self.Count):
@@ -13421,6 +13431,9 @@
    def GetBuffer(self):
        data = ''
        data = CommFunc.WriteString(data, self.Head.GetLength(), self.Head.GetBuffer())
        data = CommFunc.WriteBYTE(data, self.ZoneCount)
        for i in range(self.ZoneCount):
            data = CommFunc.WriteBYTE(data, self.ZoneIDList[i])
        data = CommFunc.WriteBYTE(data, self.ZoneID)
        data = CommFunc.WriteWORD(data, self.Count)
        for i in range(self.Count):
@@ -13430,12 +13443,16 @@
    def OutputString(self):
        DumpString = '''
                                Head:%s,
                                ZoneCount:%d,
                                ZoneIDList:%s,
                                ZoneID:%d,
                                Count:%d,
                                LotteryRecList:%s
                                '''\
                                %(
                                self.Head.OutputString(),
                                self.ZoneCount,
                                "...",
                                self.ZoneID,
                                self.Count,
                                "..."
@@ -13504,6 +13521,7 @@
class  tagGCLuckyCloudBuyNumRecInfo(Structure):
    Head = tagHead()
    RemainCount = 0    #(WORD RemainCount)// 开奖剩余份数
    Count = 0    #(WORD Count)
    BuyNumRecList = list()    #(vector<tagGCLuckyCloudBuyNumRec> BuyNumRecList)
    data = None
@@ -13517,6 +13535,7 @@
    def ReadData(self, _lpData, _pos=0, _Len=0):
        self.Clear()
        _pos = self.Head.ReadData(_lpData, _pos)
        self.RemainCount,_pos = CommFunc.ReadWORD(_lpData, _pos)
        self.Count,_pos = CommFunc.ReadWORD(_lpData, _pos)
        for i in range(self.Count):
            temBuyNumRecList = tagGCLuckyCloudBuyNumRec()
@@ -13529,6 +13548,7 @@
        self.Head.Clear()
        self.Head.Cmd = 0xC0
        self.Head.SubCmd = 0x13
        self.RemainCount = 0
        self.Count = 0
        self.BuyNumRecList = list()
        return
@@ -13536,6 +13556,7 @@
    def GetLength(self):
        length = 0
        length += self.Head.GetLength()
        length += 2
        length += 2
        for i in range(self.Count):
            length += self.BuyNumRecList[i].GetLength()
@@ -13545,6 +13566,7 @@
    def GetBuffer(self):
        data = ''
        data = CommFunc.WriteString(data, self.Head.GetLength(), self.Head.GetBuffer())
        data = CommFunc.WriteWORD(data, self.RemainCount)
        data = CommFunc.WriteWORD(data, self.Count)
        for i in range(self.Count):
            data = CommFunc.WriteString(data, self.BuyNumRecList[i].GetLength(), self.BuyNumRecList[i].GetBuffer())
@@ -13553,11 +13575,13 @@
    def OutputString(self):
        DumpString = '''
                                Head:%s,
                                RemainCount:%d,
                                Count:%d,
                                BuyNumRecList:%s
                                '''\
                                %(
                                self.Head.OutputString(),
                                self.RemainCount,
                                self.Count,
                                "..."
                                )
@@ -13571,24 +13595,16 @@
#------------------------------------------------------
# C0 12 幸运云购轮次信息 #tagGCLuckyCloudBuyRoundInfo
class  tagGCLuckyCloudBuyRoundInfo(Structure):
class  tagGCLuckyCloudBuyRoundItem(Structure):
    _pack_ = 1
    _fields_ = [
                  ("Cmd", c_ubyte),
                  ("SubCmd", c_ubyte),
                  ("RoundID", c_int),    # 轮次唯一ID标识,当收到的轮次ID变更时,前端需清空购买号码记录缓存
                  ("RoundNum", c_ubyte),    # 今日第几轮
                  ("SuperItemID", c_int),    # 大奖物品ID
                  ("SuperItemCount", c_ubyte),    # 大奖物品个数
                  ("SuperItemMoneyType", c_ubyte),    # 大奖价值货币类型
                  ("SuperItemMoneyValue", c_int),    # 大奖价值
                  ("RemainCount", c_ushort),    # 开奖剩余份数
                  ("ItemID", c_int),
                  ("ItemCount", c_ushort),
                  ("IsBind", c_ubyte),    # 是否拍品
                  ]
    def __init__(self):
        self.Clear()
        self.Cmd = 0xC0
        self.SubCmd = 0x12
        return
    def ReadData(self, stringData, _pos=0, _len=0):
@@ -13597,51 +13613,177 @@
        return _pos + self.GetLength()
    def Clear(self):
        self.Cmd = 0xC0
        self.SubCmd = 0x12
        self.RoundID = 0
        self.RoundNum = 0
        self.SuperItemID = 0
        self.SuperItemCount = 0
        self.SuperItemMoneyType = 0
        self.SuperItemMoneyValue = 0
        self.RemainCount = 0
        self.ItemID = 0
        self.ItemCount = 0
        self.IsBind = 0
        return
    def GetLength(self):
        return sizeof(tagGCLuckyCloudBuyRoundInfo)
        return sizeof(tagGCLuckyCloudBuyRoundItem)
    def GetBuffer(self):
        return string_at(addressof(self), self.GetLength())
    def OutputString(self):
        DumpString = '''// C0 12 幸运云购轮次信息 //tagGCLuckyCloudBuyRoundInfo:
                                Cmd:%s,
                                SubCmd:%s,
                                ItemID:%d,
                                ItemCount:%d,
                                IsBind:%d
                                '''\
                                %(
                                self.ItemID,
                                self.ItemCount,
                                self.IsBind
                                )
        return DumpString
class  tagGCLuckyCloudBuyRoundInfo(Structure):
    Head = tagHead()
    ZoneID = 0    #(BYTE ZoneID)// 所属分区ID
    StartDate = ""    #(char StartDate[10])// 开始日期 y-m-d
    EndtDate = ""    #(char EndtDate[10])// 结束日期 y-m-d
    RoundID = 0    #(DWORD RoundID)// 轮次唯一ID标识,当收到的轮次ID变更时,前端需清空购买号码记录缓存
    RoundNum = 0    #(BYTE RoundNum)// 今日第几轮
    SuperItemID = 0    #(DWORD SuperItemID)// 大奖物品ID
    SuperItemCount = 0    #(BYTE SuperItemCount)// 大奖物品个数
    SuperItemMoneyType = 0    #(BYTE SuperItemMoneyType)// 大奖价值货币类型
    SuperItemMoneyValue = 0    #(DWORD SuperItemMoneyValue)// 大奖价值
    BaseItemCount = 0    #(BYTE BaseItemCount)// 每次购买固定奖励物品数
    BaseItemList = list()    #(vector<tagGCLuckyCloudBuyRoundItem> BaseItemList)// 每次购买固定奖励物品信息
    RandItemCount = 0    #(BYTE RandItemCount)// 每次购买随机奖励物品数
    RandItemList = list()    #(vector<tagGCLuckyCloudBuyRoundItem> RandItemList)// 每次购买随机奖励物品信息
    data = None
    def __init__(self):
        self.Clear()
        self.Head.Cmd = 0xC0
        self.Head.SubCmd = 0x12
        return
    def ReadData(self, _lpData, _pos=0, _Len=0):
        self.Clear()
        _pos = self.Head.ReadData(_lpData, _pos)
        self.ZoneID,_pos = CommFunc.ReadBYTE(_lpData, _pos)
        self.StartDate,_pos = CommFunc.ReadString(_lpData, _pos,10)
        self.EndtDate,_pos = CommFunc.ReadString(_lpData, _pos,10)
        self.RoundID,_pos = CommFunc.ReadDWORD(_lpData, _pos)
        self.RoundNum,_pos = CommFunc.ReadBYTE(_lpData, _pos)
        self.SuperItemID,_pos = CommFunc.ReadDWORD(_lpData, _pos)
        self.SuperItemCount,_pos = CommFunc.ReadBYTE(_lpData, _pos)
        self.SuperItemMoneyType,_pos = CommFunc.ReadBYTE(_lpData, _pos)
        self.SuperItemMoneyValue,_pos = CommFunc.ReadDWORD(_lpData, _pos)
        self.BaseItemCount,_pos = CommFunc.ReadBYTE(_lpData, _pos)
        for i in range(self.BaseItemCount):
            temBaseItemList = tagGCLuckyCloudBuyRoundItem()
            _pos = temBaseItemList.ReadData(_lpData, _pos)
            self.BaseItemList.append(temBaseItemList)
        self.RandItemCount,_pos = CommFunc.ReadBYTE(_lpData, _pos)
        for i in range(self.RandItemCount):
            temRandItemList = tagGCLuckyCloudBuyRoundItem()
            _pos = temRandItemList.ReadData(_lpData, _pos)
            self.RandItemList.append(temRandItemList)
        return _pos
    def Clear(self):
        self.Head = tagHead()
        self.Head.Clear()
        self.Head.Cmd = 0xC0
        self.Head.SubCmd = 0x12
        self.ZoneID = 0
        self.StartDate = ""
        self.EndtDate = ""
        self.RoundID = 0
        self.RoundNum = 0
        self.SuperItemID = 0
        self.SuperItemCount = 0
        self.SuperItemMoneyType = 0
        self.SuperItemMoneyValue = 0
        self.BaseItemCount = 0
        self.BaseItemList = list()
        self.RandItemCount = 0
        self.RandItemList = list()
        return
    def GetLength(self):
        length = 0
        length += self.Head.GetLength()
        length += 1
        length += 10
        length += 10
        length += 4
        length += 1
        length += 4
        length += 1
        length += 1
        length += 4
        length += 1
        for i in range(self.BaseItemCount):
            length += self.BaseItemList[i].GetLength()
        length += 1
        for i in range(self.RandItemCount):
            length += self.RandItemList[i].GetLength()
        return length
    def GetBuffer(self):
        data = ''
        data = CommFunc.WriteString(data, self.Head.GetLength(), self.Head.GetBuffer())
        data = CommFunc.WriteBYTE(data, self.ZoneID)
        data = CommFunc.WriteString(data, 10, self.StartDate)
        data = CommFunc.WriteString(data, 10, self.EndtDate)
        data = CommFunc.WriteDWORD(data, self.RoundID)
        data = CommFunc.WriteBYTE(data, self.RoundNum)
        data = CommFunc.WriteDWORD(data, self.SuperItemID)
        data = CommFunc.WriteBYTE(data, self.SuperItemCount)
        data = CommFunc.WriteBYTE(data, self.SuperItemMoneyType)
        data = CommFunc.WriteDWORD(data, self.SuperItemMoneyValue)
        data = CommFunc.WriteBYTE(data, self.BaseItemCount)
        for i in range(self.BaseItemCount):
            data = CommFunc.WriteString(data, self.BaseItemList[i].GetLength(), self.BaseItemList[i].GetBuffer())
        data = CommFunc.WriteBYTE(data, self.RandItemCount)
        for i in range(self.RandItemCount):
            data = CommFunc.WriteString(data, self.RandItemList[i].GetLength(), self.RandItemList[i].GetBuffer())
        return data
    def OutputString(self):
        DumpString = '''
                                Head:%s,
                                ZoneID:%d,
                                StartDate:%s,
                                EndtDate:%s,
                                RoundID:%d,
                                RoundNum:%d,
                                SuperItemID:%d,
                                SuperItemCount:%d,
                                SuperItemMoneyType:%d,
                                SuperItemMoneyValue:%d,
                                RemainCount:%d
                                BaseItemCount:%d,
                                BaseItemList:%s,
                                RandItemCount:%d,
                                RandItemList:%s
                                '''\
                                %(
                                self.Cmd,
                                self.SubCmd,
                                self.Head.OutputString(),
                                self.ZoneID,
                                self.StartDate,
                                self.EndtDate,
                                self.RoundID,
                                self.RoundNum,
                                self.SuperItemID,
                                self.SuperItemCount,
                                self.SuperItemMoneyType,
                                self.SuperItemMoneyValue,
                                self.RemainCount
                                self.BaseItemCount,
                                "...",
                                self.RandItemCount,
                                "..."
                                )
        return DumpString
m_NAtagGCLuckyCloudBuyRoundInfo=tagGCLuckyCloudBuyRoundInfo()
ChNetPackDict[eval("0x%02x%02x"%(m_NAtagGCLuckyCloudBuyRoundInfo.Cmd,m_NAtagGCLuckyCloudBuyRoundInfo.SubCmd))] = m_NAtagGCLuckyCloudBuyRoundInfo
ChNetPackDict[eval("0x%02x%02x"%(m_NAtagGCLuckyCloudBuyRoundInfo.Head.Cmd,m_NAtagGCLuckyCloudBuyRoundInfo.Head.SubCmd))] = m_NAtagGCLuckyCloudBuyRoundInfo
#------------------------------------------------------
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GM/Commands/LuckyCloudBuy.py
@@ -28,9 +28,9 @@
def OnExec(curPlayer, msgList):
    
    if not msgList:
        GameWorld.DebugAnswer(curPlayer, "重置所有数据: FairyCard 0")
        GameWorld.DebugAnswer(curPlayer, "重置本人数据: FairyCard 0 1")
        GameWorld.DebugAnswer(curPlayer, "添加云购记录: FairyCard 1 份数")
        GameWorld.DebugAnswer(curPlayer, "重置所有数据: LuckyCloudBuy 0")
        GameWorld.DebugAnswer(curPlayer, "重置本人数据: LuckyCloudBuy 0 1")
        GameWorld.DebugAnswer(curPlayer, "添加云购记录: LuckyCloudBuy 1 份数")
        return
    
    isSendGameServer = False
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/CrossRealmPlayer.py
@@ -168,6 +168,8 @@
        return {}
    playerServerID = GameWorld.GetPlayerServerID(curPlayer)
    for actInfo in actInfoDict.values():
        if not actInfo.get(ShareDefine.ActKey_State, 0):
            continue
        if ShareDefine.ActKey_ServerIDRangeList not in actInfo:
            continue
        serverIDRangeList = actInfo[ShareDefine.ActKey_ServerIDRangeList]
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerLuckyCloudBuy.py
@@ -146,7 +146,7 @@
def CrossServerMsg_LuckyCloudBuyNum(curPlayer, msgData):
        
    playerID = curPlayer.GetPlayerID()
    _, roundID, buyCount = msgData
    _, roundID, buyCount, awardItemList = msgData
    
    # 消耗钱及奖励必须执行,增加次数需同一个轮次ID
    playerRoundID = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_LuckyCloudBuy_RoundID)
@@ -167,24 +167,6 @@
        PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_LuckyCloudBuy_BuyCount, updBuyCount)
        GameWorld.Log("    更新幸运云购购买次数: updBuyCount=%s" % (updBuyCount), playerID)
        
    baseAwardList = IpyGameDataPY.GetFuncEvalCfg("LuckyCloudBuyAward", 1) # 固定奖励列表
    randAwardList = IpyGameDataPY.GetFuncEvalCfg("LuckyCloudBuyAward", 2) # 随机饼图奖励列表
    awardItemDict = {}
    for _ in range(buyCount):
        itemList = []
        itemList += baseAwardList
        randItemInfo = GameWorld.GetResultByRandomList(randAwardList)
        if randItemInfo:
            itemList.append(randItemInfo)
        for itemID, itemCount, isAuctionItem in itemList:
            if itemID not in awardItemDict:
                awardItemDict[itemID] = [itemID, itemCount, isAuctionItem]
            else:
                awardItemDict[itemID] = [itemID, itemCount + awardItemDict[itemID][1], isAuctionItem]
    awardItemList = awardItemDict.values()
    GameWorld.Log("    结算幸运云购购买奖励: awardItemList=%s" % str(awardItemList), playerID)
    ItemControler.GivePlayerItemOrMail(curPlayer, awardItemList, event=["LuckyCloudBuy", False, {}])
    
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ShareDefine.py
@@ -288,9 +288,12 @@
#跨服运营活动表名定义
CrossActName_CTGBillboard = "CrossActCTGBillboard" # 充值排行榜
CrossActName_LuckyCloudBuy = "CrossActLuckyCloudBuy" # 幸运云购
#跨服运营活动列表
CrossActNameList = [CrossActName_CTGBillboard]
CrossActNameList = [CrossActName_CTGBillboard, CrossActName_LuckyCloudBuy]
#需要锁定活动分区分配直到活动结束的跨服运营活动,即使热更分区配置,也不会改变正在活动中的分区设定,直到活动结束
CrossActLockServerGroupIDList = [CrossActName_CTGBillboard]
#活动信息字典key定义
ActKey_ID = "ID" # 活动ID,唯一标识的ID,一般是活动开启的time值