hxp
3 天以前 540eced2499bf2814f3264c0d41eb0e9c52b9957
462 【付费活动】限时冲刺-服务端(轮回殿)
1个文件已添加
9个文件已修改
1044 ■■■■ 已修改文件
PySysDB/PySysDBPY.h 7 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChConfig.py 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorld.py 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorldLogic/GameWorldAction.py 782 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorldLogic/GameWorldEvent.py 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/IpyGameDataPY.py 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/ChPlayer.py 11 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerActLunhuidian.py 7 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerEventCounter.py 107 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ShareDefine.py 97 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
PySysDB/PySysDBPY.h
@@ -2121,9 +2121,12 @@
//轮回殿活动时间表
struct tagActLunhuidian
struct ActLunhuidian
{
    DWORD        _CfgID;    //配置ID
    list        PlatformList;    //活动平台列表["平台A", "平台A", ...],配[]代表所有
    list        ServerIDList;    //服务器ID列表
    BYTE        ActNum;    //活动分组编号, 活动类型 * 10 + 不同界面编号
    char        StartDate;    //开启日期
    char        EndDate;    //结束日期
    WORD        LVLimit;    //限制等级
@@ -2135,7 +2138,7 @@
//轮回殿活动奖励表
struct tagActLunhuidianAward
struct ActLunhuidianAward
{
    BYTE        _RoundType;    //轮回类型
    DWORD        NeedValue;    //奖励所需值
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChConfig.py
@@ -2450,6 +2450,7 @@
#玩家时间的记录格式
TYPE_Time_Format = "%Y-%m-%d %H:%M:%S"
TYPE_Time_Format_Day = "%Y-%m-%d"
TYPE_Time_Format_Ymd = "%Y-%m-%d"
TYPE_Time_Format_YmdHMS = "%Y%m%d%H%M%S"
TYPE_Time_Format_YmdH = "%Y%m%d%H"
#---------------------------------------------------------------------
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorld.py
@@ -700,20 +700,21 @@
        return startDateStr, endDateStr
    
    # 开服天
    import DBDataMgr
    if startDateStr.isdigit():
        diffDay = GetGameWorld().GetGameWorldDictByKey(ShareDefine.Def_Notify_WorldKey_ServerDay) + 1
        diffDay = DBDataMgr.GetEventTrigMgr().GetValue(ShareDefine.Def_ServerDay) + 1
        startDateTime = curDateTime + datetime.timedelta(days=(int(startDateStr)-diffDay))
        endDateTime = curDateTime + datetime.timedelta(days=(int(endDateStr)-diffDay))
        
    # K开服天
    elif startDateStr.startswith("K"):
        diffDay = GetGameWorld().GetGameWorldDictByKey(ShareDefine.Def_Notify_WorldKey_ServerDay) + 1
        diffDay = DBDataMgr.GetEventTrigMgr().GetValue(ShareDefine.Def_ServerDay) + 1
        startDateTime = curDateTime + datetime.timedelta(days=(ToIntDef(startDateStr[1:])-diffDay))
        endDateTime = curDateTime + datetime.timedelta(days=(ToIntDef(endDateStr[1:])-diffDay))
        
    # 合服天
    elif startDateStr.startswith("Mix"):
        diffDay = GetGameWorld().GetGameWorldDictByKey(ShareDefine.Def_Notify_WorldKey_MixServerDay) + 1
        diffDay = DBDataMgr.GetEventTrigMgr().GetValue(ShareDefine.Def_MixServerDay) + 1
        startDateTime = curDateTime + datetime.timedelta(days=(int(startDateStr[3:])-diffDay))
        endDateTime = curDateTime + datetime.timedelta(days=(int(endDateStr[3:])-diffDay))
        
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorldLogic/GameWorldAction.py
New file
@@ -0,0 +1,782 @@
#!/usr/bin/python
# -*- coding: GBK -*-
#-------------------------------------------------------------------------------
#
##@package GameWorldLogic.GameWorldAction
#
# @todo:活动时间控制器
# @author hxp
# @date 2026-02-08
# @version 1.0
#
# 详细描述: 活动时间控制器
#
#-------------------------------------------------------------------------------
#"""Version = 2026-02-08 16:00"""
#-------------------------------------------------------------------------------
import GameWorld
import DBDataMgr
import ShareDefine
import PlayerActLunhuidian
import IpyGameDataPY
import PlayerControl
import PyGameData
import ChConfig
import datetime
import time
(
OperationAction_ReloadSign, # 信息重载标记
OperationAction_TodayInfo, # 当日的活动信息
) = range(2)
def GetOperationActType(actNum):
    ## 运营活动类型
    return actNum / 10
def OnProcessGameAction(curTime):
    ## 定时处理游戏的活动时间
    Dispose_OperationActionState()
    #Dispose_DailyActionState()
    #Dispose_FBStateTime()
    return
def __GetOperationActionInfo():
    # @return: isReload, OperationActionInfo
    key = "OperationActionInfo"
    openServerDay = DBDataMgr.GetEventTrigMgr().GetValue(ShareDefine.Def_ServerDay) + 1
    isMixServer = DBDataMgr.GetEventTrigMgr().GetValue(ShareDefine.Def_IsMixServer)
    mixServerDay = DBDataMgr.GetEventTrigMgr().GetValue(ShareDefine.Def_MixServerDay) + 1
    OperationActionInfo = IpyGameDataPY.GetConfigEx(key)
    serverTime = GameWorld.GetServerTime()
    #curHour = serverTime.hour
    reloadSignHour = 0 #0 if curHour < 5 else 5 废弃5点刷新逻辑
    reloadSign = [openServerDay, isMixServer, mixServerDay, reloadSignHour]
    if OperationActionInfo and OperationActionInfo[OperationAction_ReloadSign] == reloadSign:
        #GameWorld.DebugLog("已经加载过本日运营活动处理信息!openServerDay=%s" % openServerDay)
        return False, OperationActionInfo
    # 因为后面的时间判断都是精确到分的,而处理此逻辑的时候可能不是0秒,所以这里的datetime取当前时间精确到分的
    curDateTimeStr = "%d-%d-%d %02d:%02d:00" % (serverTime.year, serverTime.month, serverTime.day, serverTime.hour, serverTime.minute)
    curDateTime = datetime.datetime.strptime(curDateTimeStr, ChConfig.TYPE_Time_Format)
    startDateInCustomCanOpenList = IpyGameDataPY.GetFuncEvalCfg("OperationAction", 2) # 开始天在定制天内在定制天结束后可继续开启的活动列表
    customMaxServerDay = IpyGameDataPY.GetFuncCfg("OperationAction", 1) # 定制运营活动最大开服天
    #maxCustomServerDayMix = IpyGameDataPY.GetFuncCfg("MixServer", 1) # 定制运营活动最大合服天
    operationTodayActionDict = {}
    PyGameData.g_operationActionDict = {}
    platform = GameWorld.GetPlatform()
    serverID = GameWorld.GetGameWorld().GetServerID()
    ipyDataMgr = IpyGameDataPY.IPY_Data()
    curWeekday = curDateTime.weekday() + 1 # 今天星期几, 1代表星期1
    GameWorld.Log("===== 加载本日运营活动信息: %s, serverID=%s,openServerDay=%s,customMaxServerDay=%s,isMixServer=%s,mixServerDay=%s,reloadSign=%s ====="
                  % (curDateTime, serverID, openServerDay, customMaxServerDay, isMixServer, mixServerDay, reloadSign))
    GameWorld.Log("    今日周%s" % (curWeekday))
    for actName in ShareDefine.OperationActionNameList:
        if actName not in PyGameData.g_operationActionDict:
            PyGameData.g_operationActionDict[actName] = {}
        # 取出本活动所属本服ID的所有配置
        GameWorld.Log("加载运营活动: actName=%s,platform=%s,serverID=%s" % (actName, platform, serverID))
        curServerActIpyDataList = __GetOperationActionServerIpyDataList(ipyDataMgr, platform, serverID, actName)
        GameWorld.Log("    可处理条数=%s" % (len(curServerActIpyDataList)))
        coverDisableLoopIpyDataInfo, disableLoopCfgIDDict, otherLoopCfgIDDict, coverDisableWeekIpyDataInfo, disableWeekCfgIDDict, kOpenServerActInfo = \
            __GetOperationActionDisableIpyDataInfo(actName, curDateTime, curServerActIpyDataList)
        GameWorld.Log("    kOpenServerActInfo=%s" % kOpenServerActInfo)
        for ipyData in curServerActIpyDataList:
            platformList = [] if not hasattr(ipyData, "GetPlatformList") else ipyData.GetPlatformList()
            serverIDList = [] if not hasattr(ipyData, "GetServerIDList") else ipyData.GetServerIDList()
            serverIDListExcept = [] if not hasattr(ipyData, "GetServerIDListExcept") else ipyData.GetServerIDListExcept()
            cfgID = ipyData.GetCfgID()
            startDateStr = ipyData.GetStartDate()
            endDateStr = ipyData.GetEndDate()
            actNum = ipyData.GetActNum()
            actType = GetOperationActType(actNum)
            if kOpenServerActInfo and actNum in kOpenServerActInfo:
                kOpenServerCfgIDInfo = kOpenServerActInfo[actNum]
                actCustomServerDayMax = max(max(kOpenServerCfgIDInfo.values()), customMaxServerDay)
            else:
                actCustomServerDayMax = customMaxServerDay
            GameWorld.Log("    cfgID=%s,actNum=%s,startDateStr=%s,endDateStr=%s,openServerDay=%s,actCustomServerDayMax=%s,isMixServer=%s,mixServerDay=%s,curDateTime=%s,platformList=%s,serverIDList=%s,Except=%s"
                          % (cfgID, actNum, startDateStr, endDateStr, openServerDay, actCustomServerDayMax, isMixServer, mixServerDay, curDateTime, platformList, serverIDList, serverIDListExcept))
            actIDDateTimeSpec = None # 特殊指定的活动ID日期
            startDateSync = None # 特殊同步前端显示用的开始日期,一般用于与开服前X天交叉的活动
            # 多活动分组编号支持
            if actNum not in PyGameData.g_operationActionDict[actName]:
                PyGameData.g_operationActionDict[actName][actNum] = {ShareDefine.ActKey_ActNum:actNum}
            curActTodayInfo = operationTodayActionDict.get(actName, {}).get(actNum)
            if not startDateStr:
                startDateStr = "%d-%d-%d" % (serverTime.year, serverTime.month, serverTime.day)
                GameWorld.Log("        开始日期为空,默认每天,今日为: startDateStr=%s" % startDateStr)
            if not endDateStr:
                endDateStr = "%d-%d-%d" % (serverTime.year, serverTime.month, serverTime.day)
                GameWorld.Log("        结束日期为空,默认每天,今日为: endDateStr=%s" % endDateStr)
            actByLoopYmd = startDateStr.startswith("L") # 按日期循环
            # 根据日期循环的通用
            if actByLoopYmd:
                if cfgID in coverDisableLoopIpyDataInfo:
                    loopStartDate, loopEndDate, ymdCfgID, ymdStartDate, ymdEndDate = coverDisableLoopIpyDataInfo[cfgID]
                    GameWorld.Log("        按日期循环的在按日期开启的时间内,不处理! cfgID=%s,%s(%s) ~ %s(%s) in ymdCfgID=%s,%s ~ %s"
                                  % (cfgID, loopStartDate, startDateStr, loopEndDate, endDateStr, ymdCfgID, ymdStartDate, ymdEndDate))
                    continue
                if cfgID in disableLoopCfgIDDict:
                    GameWorld.Log("        按日期循环的未到开启循环日期或已结束循环日期,不处理! cfgID=%s,startDateStr=%s,endDateStr=%s" % (cfgID, startDateStr, endDateStr))
                    continue
                if cfgID in otherLoopCfgIDDict:
                    loopCfgIDList, startDateStr, endDateStr, loopIndex, loopTimes = otherLoopCfgIDDict[cfgID]
                    GameWorld.Log("        按日期循环的还未循环到当前配置,不处理! cfgID=%s,startDateStr=%s,endDateStr=%s,loopCfgIDList=%s,loopIndex=%s,loopTimes=%s"
                                  % (cfgID, startDateStr, endDateStr, loopCfgIDList, loopIndex, loopTimes))
                    continue
                startDateStr, endDateStr = GameWorld.GetOperationActionDateStr(ipyData)
            # 开服常规:  开服天 > 日期 > 周x=日期循环   (不受合服天影响,合服活动新增一套独立的活动,还是走运营活动配置)
            if actType == ShareDefine.ActType_OpenComm:
                actByWeek = (startDateStr.startswith("W") and endDateStr.startswith("W")) # 按周x开
                actByDate = (not actByLoopYmd and not actByWeek and startDateStr.count("-") == 2 and endDateStr.count("-") == 2) # 按日期开
                # 开服天的
                if startDateStr.isdigit() and endDateStr.isdigit():
                    startServerDay, endServerDay = int(startDateStr), int(endDateStr)
                    #结束日可能还需要处理广播之类,所以这里需要+1
                    if openServerDay > endServerDay + 1:
                        GameWorld.Log("        当前开服天超过活动结束开服天,不处理! cfgID=%s,%s ~ %s < openServerDay(%s)" % (cfgID, startDateStr, endDateStr, openServerDay))
                        continue
                    openServerDateTime = curDateTime + datetime.timedelta(days=(startServerDay - openServerDay))
                    endServerDateTime = curDateTime + datetime.timedelta(days=(endServerDay - openServerDay))
                    startDateStr = "%d-%d-%d" % (openServerDateTime.year, openServerDateTime.month, openServerDateTime.day)
                    endDateStr = "%d-%d-%d" % (endServerDateTime.year, endServerDateTime.month, endServerDateTime.day)
                    GameWorld.Log("        开服天转化为日期: %s ~ %s" % (startDateStr, endDateStr))
                # K开头的
                elif startDateStr.startswith("K"):
                    startServerDay, endServerDay = GameWorld.ToIntDef(startDateStr[1:]), GameWorld.ToIntDef(endDateStr[1:])
                    #结束日可能还需要处理广播之类,所以这里需要+1
                    if openServerDay > endServerDay + 1:
                        GameWorld.Log("        当前开服天超过活动结束K开服天,不处理! cfgID=%s,%s ~ %s < openServerDay(%s)" % (cfgID, startDateStr, endDateStr, openServerDay))
                        continue
                    openServerDateTime = curDateTime + datetime.timedelta(days=(startServerDay - openServerDay))
                    endServerDateTime = curDateTime + datetime.timedelta(days=(endServerDay - openServerDay))
                    startDateStr = "%d-%d-%d" % (openServerDateTime.year, openServerDateTime.month, openServerDateTime.day)
                    endDateStr = "%d-%d-%d" % (endServerDateTime.year, endServerDateTime.month, endServerDateTime.day)
                    GameWorld.Log("        K开服天转化为日期: %s ~ %s" % (startDateStr, endDateStr))
                # 常规配置: 开服前X天不开,不受合服影响,功能配置表可配置 开服前X天后交叉可开,每日重置的活动默认可开
                elif actByWeek or actByDate or actByLoopYmd:
                    if openServerDay <= actCustomServerDayMax:
                        GameWorld.Log("        按日期/周开的在开服定制限制天内,不处理! cfgID=%s,%s ~ %s,openServerDay=%s,actCustomServerDayMax=%s,K开服天信息=%s"
                                      % (cfgID, startDateStr, endDateStr, openServerDay, actCustomServerDayMax, kOpenServerActInfo))
                        continue
                    if cfgID in coverDisableWeekIpyDataInfo:
                        startWeekDate, endWeekDate, ymdCfgID, ymdStartDate, ymdEndDate = coverDisableWeekIpyDataInfo[cfgID]
                        GameWorld.Log("        常规活动,按星期开启的在按日期开启的时间内,不处理! cfgID=%s,%s(%s) ~ %s(%s) in ymdCfgID=%s,%s ~ %s"
                                      % (cfgID, startWeekDate, startDateStr, endWeekDate, endDateStr, ymdCfgID, ymdStartDate, ymdEndDate))
                        continue
                    if cfgID in disableWeekCfgIDDict:
                        GameWorld.Log("        常规活动,按星期开启的未到开启循环日期或已结束循环日期,不处理! cfgID=%s,startDateStr=%s,endDateStr=%s, %s"
                                      % (cfgID, startDateStr, endDateStr, str(disableWeekCfgIDDict[cfgID])))
                        continue
                    if actByWeek:
                        startDateStr, endDateStr = GameWorld.GetOperationActionDateStr(ipyData)
                        GameWorld.Log("        星期X转化为日期: %s ~ %s" % (startDateStr, endDateStr))
                    curServerOpenDateTime = curDateTime + datetime.timedelta(days=(1 - openServerDay)) # 开服第一天的日期
                    customMaxServerDateTime = curDateTime + datetime.timedelta(days=(actCustomServerDayMax - openServerDay))
                    curStartDateTime = datetime.datetime.strptime("%s %02d:%02d:%02d" % (startDateStr, customMaxServerDateTime.hour, customMaxServerDateTime.minute,
                                                                                         customMaxServerDateTime.second), ChConfig.TYPE_Time_Format)
                    if curServerOpenDateTime <= curStartDateTime <= customMaxServerDateTime:
                        # 每日重置的默认交叉后可开启
                        isDayRest = 0 if not hasattr(ipyData, "GetIsDayReset") else ipyData.GetIsDayReset()
                        if not isDayRest and actName not in startDateInCustomCanOpenList:
                            GameWorld.Log("        按日期/周开的开始日期在开服定制限制天内,不处理! cfgID=%s,curServerOpenDateTime=%s<=curStartDateTime=%s<=customMaxServerDateTime=%s" % (cfgID, curServerOpenDateTime, curStartDateTime, customMaxServerDateTime))
                            continue
                        # 非每日重置的 且 开始天在定制天内在定制天结束后可继续开启的活动
                        # 注: 为防止开始日期与开服天内的活动开始天对应日期刚好同一天导致活动ID一样,所以这里默认将开始日期改为定制天后一天
                        if not isDayRest and actName in startDateInCustomCanOpenList:
                            actIDDateTimeSpec = datetime.datetime.strptime("%d-%d-%d 00:00:00"
                                                                           % (customMaxServerDateTime.year, customMaxServerDateTime.month, customMaxServerDateTime.day),
                                                                           ChConfig.TYPE_Time_Format) + datetime.timedelta(days=1)
                            GameWorld.Log("        开服天后可开启的非每日重置活动! 活动ID日期特殊设置为开服定制天结束后一天! cfgID=%s,actIDDateTimeSpec=%s" % (cfgID, actIDDateTimeSpec))
                        # 特殊同步的开始日期,无视是否每日重置
                        if actName in startDateInCustomCanOpenList:
                            startDateSync = datetime.datetime.strptime("%d-%d-%d 00:00:00"
                                                                       % (customMaxServerDateTime.year, customMaxServerDateTime.month, customMaxServerDateTime.day),
                                                                       ChConfig.TYPE_Time_Format) + datetime.timedelta(days=1)
                            startDateSync = "%d-%d-%d" % (startDateSync.year, startDateSync.month, startDateSync.day)
                else:
                    GameWorld.Log("        开服常规活动,配置时间格式不支持,不处理! cfgID=%s,startDateStr=%s,endDateStr=%s" % (cfgID, startDateStr, endDateStr))
                    continue
            # 合服活动: 只受合服天影响
            elif actType == ShareDefine.ActType_MixServer:
                if not startDateStr.startswith("Mix") or not endDateStr.startswith("Mix"):
                    GameWorld.Log("        合服活动,配置非合服天,不处理! cfgID=%s,startDateStr=%s,endDateStr=%s" % (cfgID, startDateStr, endDateStr))
                    continue
                if not isMixServer:
                    GameWorld.Log("        非合服服务器,不处理! cfgID=%s,%s ~ %s" % (cfgID, startDateStr, endDateStr))
                    continue
                startMixServerDay, endMixServerDay = int(startDateStr[3:]), int(endDateStr[3:])
                #结束日可能还需要处理广播之类,所以这里需要+1
                if mixServerDay > endMixServerDay + 1:
                    GameWorld.Log("        当前合服天超过活动结束合服天,不处理! cfgID=%s,%s ~ %s < mixServerDay(%s)" % (cfgID, startDateStr, endDateStr, mixServerDay))
                    continue
                openServerDateTime = curDateTime + datetime.timedelta(days=(startMixServerDay - mixServerDay))
                endServerDateTime = curDateTime + datetime.timedelta(days=(endMixServerDay - mixServerDay))
                startDateStr = "%d-%d-%d" % (openServerDateTime.year, openServerDateTime.month, openServerDateTime.day)
                endDateStr = "%d-%d-%d" % (endServerDateTime.year, endServerDateTime.month, endServerDateTime.day)
                GameWorld.Log("        合服天转化为日期: %s ~ %s" % (startDateStr, endDateStr))
            # 节日活动:只受日期影响
            elif actType == ShareDefine.ActType_Feast:
                if startDateStr.count("-") != 2 or endDateStr.count("-") != 2:
                    GameWorld.Log("        节日活动,配置非日期,不处理! cfgID=%s,startDateStr=%s,endDateStr=%s" % (cfgID, startDateStr, endDateStr))
                    continue
            else:
                GameWorld.Log("        非法配置,未知活动类型,不处理! cfgID=%s,actNum=%s" % (cfgID, actNum))
                continue
            if hasattr(ipyData, "GetJoinStartTime") and hasattr(ipyData, "GetJoinEndTime"):
                joinStartTimeStr = ipyData.GetJoinStartTime()
                joinEndTimeStr = ipyData.GetJoinEndTime()
            else:
                joinStartTimeStr = ""
                joinEndTimeStr = ""
            if hasattr(ipyData, "GetStartTimeList") and hasattr(ipyData, "GetEndTimeList"):
                startHMStrList = ipyData.GetStartTimeList()
                endHMStrList = ipyData.GetEndTimeList()
            else:
                startHMStrList = []
                endHMStrList = []
            notifyInfoDictStart = ipyData.GetNotifyInfoStart() if hasattr(ipyData, "GetNotifyInfoStart") else {}
            notifyInfoDictEnd = ipyData.GetNotifyInfoEnd() if hasattr(ipyData, "GetNotifyInfoEnd") else {}
            notifyInfoLoopInfo = ipyData.GetNotifyInfoLoop() if hasattr(ipyData, "GetNotifyInfoLoop") else {} # [循环分钟, 广播key, [广播参数列表可选]]
            if len(startHMStrList) != len(endHMStrList):
                GameWorld.ErrLog("        活动配置开始及结束时间个数不匹配! actName=%s,cfgID=%s,startHMStrList=%s,endHMStrList=%s"
                                 % (actName, cfgID, startHMStrList, endHMStrList))
                continue
            isDayRest = 0 if not hasattr(ipyData, "GetIsDayReset") else ipyData.GetIsDayReset()
            resetType = 0 if not hasattr(ipyData, "GetResetType") else ipyData.GetResetType() # 重置类型,0-0点重置;1-5点重置
            if resetType == 1:
                startDayDate = datetime.datetime.strptime("%s 05:00:00" % (startDateStr), ChConfig.TYPE_Time_Format)
                endDayDate = datetime.datetime.strptime("%s 05:00:00" % (endDateStr), ChConfig.TYPE_Time_Format) # 结束日期5点
            elif resetType == 2:
                startDayDate = datetime.datetime.strptime("%s 05:00:00" % (startDateStr), ChConfig.TYPE_Time_Format)
                endDayDate = datetime.datetime.strptime("%s 00:00:00" % (endDateStr), ChConfig.TYPE_Time_Format) + datetime.timedelta(days=1) # 结束日期隔天0点
            else:
                startDayDate = datetime.datetime.strptime("%s 00:00:00" % (startDateStr), ChConfig.TYPE_Time_Format)
                endDayDate = datetime.datetime.strptime("%s 00:00:00" % (endDateStr), ChConfig.TYPE_Time_Format) + datetime.timedelta(days=1) # 结束日期隔天0点
            advanceMinutes = 0 if not hasattr(ipyData, "GetAdvanceMinutes") else ipyData.GetAdvanceMinutes() # 提前通知时间,分钟,暂只支持按天的
            GameWorld.Log("        resetType=%s,startDayDate=%s,endDayDate=%s,startHMStrList=%s,endHMStrList=%s,advanceMinutes=%s"
                          % (resetType, startDayDate, endDayDate, startHMStrList, endHMStrList, advanceMinutes))
            advanceNoticeDateTime = None
            startDayDateJudge = startDayDate # 用于判断是否需要处理的起始时间,一般是活动开始时间,如果有提前广播或预告则时间会提前
            # 提前预告
            if advanceMinutes:
                advanceNoticeDateTime = startDayDate + datetime.timedelta(minutes= -advanceMinutes)
                startDayDateJudge = advanceNoticeDateTime
            # 提前广播
            minNotifyStartMinute = 0 if not notifyInfoDictStart else min(notifyInfoDictStart.keys())
            if minNotifyStartMinute < 0:
                minNotifyStartDateTime = startDayDate + datetime.timedelta(minutes=minNotifyStartMinute)
                if minNotifyStartDateTime < startDayDateJudge:
                    startDayDateJudge = minNotifyStartDateTime
            if curDateTime < startDayDateJudge or curDateTime > endDayDate: # 结束时间点的时候可能需要处理广播之类的
                GameWorld.Log("        非活动时间!不处理!")
                continue
            #注: 同个活动编号可配置多个时间不交叉的活动,如果多个时间配置同时满足条件,则只会以最后一个为准,提前预告、广播除外
            if curActTodayInfo and curDateTime < startDayDate:
                activityIpyData = curActTodayInfo[0]
                ## 防止未真正开始的活动需要提前预告,而导致覆盖掉了实际正在进行中的活动,一般是活动时间配置连续的时候可能出现该情况
                GameWorld.Log("        已经存在需要处理的配置ID(%s)! 当前需要提前通知或广播的活动未达到活动开始时间,不处理!cfgID=%s,advanceMinutes=%s,minNotifyStartMinute=%s,startDayDateJudge=%s"
                              % (activityIpyData.GetCfgID(), cfgID, advanceMinutes, minNotifyStartMinute, startDayDateJudge))
                continue
            #注:刚好是结束的时间点,防范已经有需要处理的配置被覆盖
            if curActTodayInfo and curDateTime == endDayDate:
                activityIpyData = curActTodayInfo[0]
                GameWorld.Log("        已经存在需要处理的配置ID(%s)! 当前刚好结束的时间点,不处理!cfgID=%s" % (activityIpyData.GetCfgID(), cfgID))
                continue
            startList = [] # [startDateTime, ...]
            endList = [] # [endDateTime, ...]
            startNotifyDict = {} # {notifyDateTime:notifyInfo, ...}
            endNotifyDict = {} # {notifyDateTime:notifyInfo, ...}
            loopNotifyDict = {} # {notifyDateTime:notifyInfo, ...}
            notifyDict = {}
            isActTime = (startDayDate <= curDateTime < endDayDate)
            isEnd = (curDateTime == endDayDate)
            isNotify = False
            isAdvanceNotice = False
            # 没配置时分的代表全天, 只要开始或结束时分没配都算
            if not startHMStrList or not endHMStrList:
                startDateTime = startDayDate
                endDateTime = endDayDate
                startList.append(startDateTime)
                endList.append(endDateTime)
            # 每天按时段开启的,支持多时段
            else:
                for hmIndex, startHMStr in enumerate(startHMStrList):
                    endHMStr = endHMStrList[hmIndex]
                    # 每天开的, 实际开关时间只取今天的日期; 这里有个问题,全服广播的时间不是今天的, 暂不做支持,之后真有这种需求再说
                    startTimeStr = "%d-%d-%d %s:00" % (curDateTime.year, curDateTime.month, curDateTime.day, startHMStr)
                    endTimeStr = "%d-%d-%d %s:00" % (curDateTime.year, curDateTime.month, curDateTime.day, endHMStr)
                    startDateTime = datetime.datetime.strptime(startTimeStr, ChConfig.TYPE_Time_Format)
                    endDateTime = datetime.datetime.strptime(endTimeStr, ChConfig.TYPE_Time_Format)
                    startList.append(startDateTime)
                    endList.append(endDateTime)
            if advanceNoticeDateTime:
                if advanceNoticeDateTime.year == curDateTime.year and advanceNoticeDateTime.month == curDateTime.month and advanceNoticeDateTime.day == curDateTime.day:
                    isAdvanceNotice = True
                GameWorld.Log("        advanceNoticeDateTime=%s,isAdvanceNotice=%s" % (advanceNoticeDateTime, isAdvanceNotice))
            GameWorld.Log("        startList=%s" % (startList))
            GameWorld.Log("        end  List=%s" % (endList))
            joinStartTimeList, joinEndTimeList = [], [] # 可指定活动可参与的时间点,不影响活动状态,只影响活动某些功能的参与时机,如上榜类
            if joinStartTimeStr:
                if isDayRest:
                    joinStartTimeList.append(datetime.datetime.strptime("%d-%d-%d %s:00" % (curDateTime.year, curDateTime.month, curDateTime.day, joinStartTimeStr), ChConfig.TYPE_Time_Format))
                    joinEndTimeList.append(datetime.datetime.strptime("%d-%d-%d %s:00" % (curDateTime.year, curDateTime.month, curDateTime.day, joinEndTimeStr), ChConfig.TYPE_Time_Format))
                else:
                    joinStartTimeList.append(datetime.datetime.strptime("%s %s:00" % (startDateStr, joinStartTimeStr), ChConfig.TYPE_Time_Format))
                    joinEndTimeList.append(datetime.datetime.strptime("%s %s:00" % (endDateStr, joinEndTimeStr), ChConfig.TYPE_Time_Format))
            GameWorld.Log("        joinStartTimeList=%s" % (joinStartTimeList))
            GameWorld.Log("        joinEndTime  List=%s" % (joinEndTimeList))
            for dtIndex, startDateTime in enumerate(startList):
                endDateTime = endList[dtIndex]
                # 广播 - 相对实际开始时间
                for notifyMinute, notifyInfo in notifyInfoDictStart.items():
                    notifyDateTime = startDateTime + datetime.timedelta(minutes=notifyMinute)
                    if notifyDateTime.year == curDateTime.year and notifyDateTime.month == curDateTime.month and notifyDateTime.day == curDateTime.day:
                        startNotifyDict[notifyDateTime] = notifyInfo
                        isNotify = True
                # 广播 - 相对实际结束时间
                for notifyMinute, notifyInfo in notifyInfoDictEnd.items():
                    notifyDateTime = endDateTime + datetime.timedelta(minutes=notifyMinute)
                    if notifyDateTime.year == curDateTime.year and notifyDateTime.month == curDateTime.month and notifyDateTime.day == curDateTime.day:
                        endNotifyDict[notifyDateTime] = notifyInfo
                        isNotify = True
                # 广播 - 循环广播
                if notifyInfoLoopInfo and len(notifyInfoLoopInfo) >= 2:
                    loopMinutes, loopNotifyKey = notifyInfoLoopInfo[:2]
                    loopNotifyParamList = notifyInfoLoopInfo[2] if len(notifyInfoLoopInfo) > 2 else []
                    notifyInfo = [loopNotifyKey, loopNotifyParamList] # 循环广播的默认无参数
                    loopCount, loopMaxCount = 0, 100
                    while loopMinutes and loopNotifyKey and loopCount < loopMaxCount:
                        loopCount += 1
                        notifyDateTime = startDateTime + datetime.timedelta(minutes=loopMinutes * loopCount)
                        if notifyDateTime >= endDateTime:
                            break
                        if notifyDateTime.year == curDateTime.year and notifyDateTime.month == curDateTime.month and notifyDateTime.day == curDateTime.day:
                            loopNotifyDict[notifyDateTime] = notifyInfo
                            isNotify = True
            if startNotifyDict or endNotifyDict or loopNotifyDict:
                GameWorld.Log("        startNotifyDict: minutes=%s, %s" % (notifyInfoDictStart.keys(), startNotifyDict))
                GameWorld.Log("        end  NotifyDict: minutes=%s, %s" % (notifyInfoDictEnd.keys(), endNotifyDict))
                GameWorld.Log("        loop NotifyDict: lopInfo=%s, %s" % (notifyInfoLoopInfo, loopNotifyDict.keys()))
                notifyDict.update(startNotifyDict)
                notifyDict.update(endNotifyDict)
                notifyDict.update(loopNotifyDict)
            GameWorld.Log("        需要处理的运营活动信息: cfgID=%s,isActTime=%s,isEnd=%s,isNotify=%s,isAdvanceNotice=%s" % (cfgID, isActTime, isEnd, isNotify, isAdvanceNotice))
            if actName not in operationTodayActionDict:
                operationTodayActionDict[actName] = {} # 今日有需要处理的才初始化
            operationTodayActionDict[actName][actNum] = [ipyData, startList, endList, notifyDict, joinStartTimeList, joinEndTimeList]
            if isActTime:
                activityInfoDict = {ShareDefine.ActKey_CfgID:cfgID, ShareDefine.ActKey_ActNum:actNum}
                #if actName == ShareDefine.OperationActionName_LoginAward:
                #    #活动每天的世界等级
                #    activityInfoDict[ShareDefine.ActKey_WorldLVList] = GameWorldAverageLv.GetWorldLVListByTime(startDayDate, (endDayDate - startDayDate).days)
                if startDateSync:
                    activityInfoDict[ShareDefine.ActKey_StartDateSync] = startDateSync
                    GameWorld.Log("        startDateSync=%s" % (startDateSync))
                dayIndex = (curDateTime - startDayDate).days
                if ipyData.GetStartDate().startswith("K"):
                    startServerDay = GameWorld.ToIntDef(ipyData.GetStartDate()[1:])
                    # 按时段开的默认每天重置
                    if isDayRest or (startHMStrList and endHMStrList):
                        actID = startServerDay + dayIndex
                    else:
                        actID = startServerDay
                    GameWorld.Log("        isDayRest=%s,startServerDay=%s,actID=%s" % (isDayRest, startServerDay, actID))
                else:
                    actIDDateTime = startDayDate
                    # 按时段开的默认每天重置
                    if isDayRest or (startHMStrList and endHMStrList):
                        actIDDateTime += datetime.timedelta(days=dayIndex)
                    if actIDDateTimeSpec:
                        actIDDateTime = actIDDateTimeSpec
                    actID = int(time.mktime(actIDDateTime.timetuple())) # 默认取开始时间点的time值作为活动ID
                    GameWorld.Log("        isDayRest=%s,actIDDateTime=%s,actID=%s" % (isDayRest, actIDDateTime, actID))
                activityInfoDict[ShareDefine.ActKey_DayIndex] = dayIndex
                activityInfoDict[ShareDefine.ActKey_ID] = actID
                GameWorld.Log("        activityInfoDict=%s" % (activityInfoDict))
                PyGameData.g_operationActionDict[actName][actNum] = activityInfoDict
    OperationActionInfo = IpyGameDataPY.SetConfigEx(key, [reloadSign, operationTodayActionDict])
    GameWorld.Log("本日运营活动信息加载完毕!reloadSign=%s" % (reloadSign))
    #GameWorld.Log("    operationTodayActionDict=%s" % operationTodayActionDict)
    GameWorld.Log("    PyGameData.g_operationActionDict=%s" % PyGameData.g_operationActionDict)
    GameWorld.Log("=============================================================")
    return True, OperationActionInfo
def __GetOperationActionServerIpyDataList(ipyDataMgr, platform, serverID, actName):
    ## 获取运营活动本服务器对应的配置数据列表
    if not hasattr(ipyDataMgr, "Get%sCount" % actName):
        GameWorld.ErrLog("没有该运营活动类型对应活动时间表! actName=%s" % actName)
        return []
    curServerActIpyDataList = []
    actCfgCount = getattr(ipyDataMgr, "Get%sCount" % actName)()
    for cfgIndex in xrange(actCfgCount):
        ipyData = getattr(ipyDataMgr, "Get%sByIndex" % actName)(cfgIndex)
        platformList = [] if not hasattr(ipyData, "GetPlatformList") else ipyData.GetPlatformList()
        serverIDList = [] if not hasattr(ipyData, "GetServerIDList") else ipyData.GetServerIDList()
        serverIDListExcept = [] if not hasattr(ipyData, "GetServerIDListExcept") else ipyData.GetServerIDListExcept()
        if platformList and platform not in platformList:
            continue
        # 排除的服务器组ID列表
        if serverIDListExcept:
            isExcept = False
            for serverIDInfo in serverIDListExcept:
                if GameWorld.CheckServerIDInList(serverID, serverIDInfo):
                    isExcept = True
                    break
            if isExcept:
                continue
        if not serverIDList:
            curServerActIpyDataList.append(ipyData)
        else:
            for serverIDInfo in serverIDList:
                if GameWorld.CheckServerIDInList(serverID, serverIDInfo):
                    curServerActIpyDataList.append(ipyData)
                    break
    return curServerActIpyDataList
def __GetOperationActionDisableIpyDataInfo(actName, curDateTime, curServerActIpyDataList):
    ## 获取不可用的按星期X开启的配置数据信息,按星期X开启的 活动优先级小于按日期的,当有重叠时以日期的为准
    # 优先级 日期 > 按日期循环 > 按星期循环
    actNumYMDIpyDataInfo = {} # {actNum:ymdIpyDataList, ...} # 配置日期的
    actNumLoopIpyDataInfo = {} # {actNum:{loopKey:[loopCfgIDList, loopDateInfo]}, ...} # 按日期循环的
    actNumWeekIpyDataInfo = {} # {actNum:weekIpyDataList, ...} # 按星期循环的
    disableWeekCfgIDDict = {} # {cfgID:[startDateStr, endDateStr], ...} # 未开始循环的星期
    disableLoopCfgIDDict = {} # {cfgID:[startDateStr, endDateStr], ...} # 未开始循环的日期
    kOpenServerActInfo = {} # 以K为开头的开服天活动中信息 {actNum:{cftID:endOpenServerDay, ...}, ...}
    curDateTimeYmdStr = "%d-%d-%d" % (curDateTime.year, curDateTime.month, curDateTime.day)
    curDateTimeYmd = GameWorld.ChangeStrToDatetime(curDateTimeYmdStr, ChConfig.TYPE_Time_Format_Ymd)
    for ipyData in curServerActIpyDataList:
        cfgID = ipyData.GetCfgID()
        startDateStr = ipyData.GetStartDate()
        endDateStr = ipyData.GetEndDate()
        actNum = ipyData.GetActNum()
        # 按星期X的
        if startDateStr.startswith("W"):
            if actNum not in actNumWeekIpyDataInfo:
                actNumWeekIpyDataInfo[actNum] = []
            weekIpyDataList = actNumWeekIpyDataInfo[actNum]
            startDateStr, endDateStr = GameWorld.GetOperationActionDateStr(ipyData)
            startWeekDate = GameWorld.ChangeStrToDatetime(startDateStr, ChConfig.TYPE_Time_Format_Ymd)
            endWeekDate = GameWorld.ChangeStrToDatetime(endDateStr, ChConfig.TYPE_Time_Format_Ymd)
            if startWeekDate > curDateTimeYmd or curDateTimeYmd > endWeekDate: # 还未开始的循环 or 已经强制结束的循环
                disableWeekCfgIDDict[cfgID] = [startDateStr, endDateStr]
            else:
                weekIpyDataList.append([cfgID, startWeekDate, endWeekDate])
        # 指定开服天的,不受开服前7天配置影响
        elif endDateStr.startswith("K"):
            endKOpenServerDay = GameWorld.ToIntDef(endDateStr[1:])
            if endKOpenServerDay:
                if actNum not in kOpenServerActInfo:
                    kOpenServerActInfo[actNum] = {}
                kOpenServerCfgIDInfo = kOpenServerActInfo[actNum]
                kOpenServerCfgIDInfo[cfgID] = endKOpenServerDay
        # 按日期循环
        elif startDateStr.startswith("L"):
            loopStartDate, loopEndDate, loopTimes = GameWorld.GetOperationActionLoopDate(startDateStr, endDateStr, curDateTime)
            if loopStartDate > curDateTimeYmd or curDateTimeYmd > loopEndDate: # 还未开始的循环 or 已经强制结束的循环
                disableLoopCfgIDDict[cfgID] = [startDateStr, endDateStr]
            else:
                loopKey = (startDateStr, endDateStr) # 同个循环周期的视为同一组
                if actNum not in actNumLoopIpyDataInfo:
                    actNumLoopIpyDataInfo[actNum] = {}
                loopIpyDataDict = actNumLoopIpyDataInfo[actNum]
                if loopKey not in loopIpyDataDict:
                    loopCfgIDList, loopDateInfo = [], [loopStartDate, loopEndDate, loopTimes]
                    loopIpyDataDict[loopKey] = [loopCfgIDList, loopDateInfo]
                loopCfgIDList, loopDateInfo = loopIpyDataDict[loopKey]
                loopCfgIDList.append(cfgID)
        # 按日期的
        elif startDateStr.count("-") == 2:
            if actNum not in actNumYMDIpyDataInfo:
                actNumYMDIpyDataInfo[actNum] = []
            ymdIpyDataList = actNumYMDIpyDataInfo[actNum]
            ymdStartDate = GameWorld.ChangeStrToDatetime(startDateStr, ChConfig.TYPE_Time_Format_Ymd)
            ymdEndDate = GameWorld.ChangeStrToDatetime(endDateStr, ChConfig.TYPE_Time_Format_Ymd)
            ymdIpyDataList.append([cfgID, ymdStartDate, ymdEndDate])
        else:
            # 其他的不处理
            pass
    nowLoopYMDIpyDataInfo = {} # {actNum:loopIpyDataList, ...} # # 日期循环中当前在循环的
    otherLoopCfgIDDict = {} # {cfgID:[info], ...} # 日期循环中不是当前循环的其他循环
    coverDisableLoopIpyDataInfo = {} # {cfgID:[info], ...} # 被日期覆盖的日期循环
    for actNum, loopIpyDataDict in actNumLoopIpyDataInfo.items():
        ymdIpyDataList = actNumYMDIpyDataInfo.get(actNum, [])
        if actNum not in nowLoopYMDIpyDataInfo:
            nowLoopYMDIpyDataInfo[actNum] = []
        loopIpyDataList = nowLoopYMDIpyDataInfo[actNum]
        for loopKey, loopInfo in loopIpyDataDict.items():
            startDateStr, endDateStr = loopKey
            loopCfgIDList, loopDateInfo = loopInfo
            loopStartDate, loopEndDate, loopTimes = loopDateInfo
            loopIndex = (loopTimes - 1) % len(loopCfgIDList) # 当前循环次数对应的循环索引
            curLoopCfgID = 0
            for index, loopCfgID in enumerate(loopCfgIDList):
                if index == loopIndex: # 当前循环的
                    curLoopCfgID = loopCfgID
                    loopIpyDataList.append([loopCfgID, loopStartDate, loopEndDate])
                else:
                    otherLoopCfgIDDict[loopCfgID] = [loopCfgIDList, startDateStr, endDateStr, loopIndex, loopTimes]
            for ymdCfgID, ymdStartDate, ymdEndDate in ymdIpyDataList:
                if ymdStartDate <= loopStartDate <= ymdEndDate or ymdStartDate <= loopEndDate <= ymdEndDate:
                    coverDisableLoopIpyDataInfo[curLoopCfgID] = [loopStartDate, loopEndDate, ymdCfgID, ymdStartDate, ymdEndDate]
    coverDisableWeekIpyDataInfo = {} # {cfgID:[info], ...} # 被日期覆盖的星期循环
    for actNum, weekIpyDataList in actNumWeekIpyDataInfo.items():
        ymdIpyDataList = actNumYMDIpyDataInfo.get(actNum, [])
        loopIpyDatList = nowLoopYMDIpyDataInfo.get(actNum, [])
        for weekCfgID, startWeekDate, endWeekDate in weekIpyDataList:
            # 被常规日期覆盖的
            for ymdCfgID, ymdStartDate, ymdEndDate in ymdIpyDataList:
                if ymdStartDate <= startWeekDate <= ymdEndDate or ymdStartDate <= endWeekDate <= ymdEndDate:
                    coverDisableWeekIpyDataInfo[weekCfgID] = [startWeekDate, endWeekDate, ymdCfgID, ymdStartDate, ymdEndDate]
            # 被循环日期覆盖的
            for loopCfgID, loopStartDate, loopEndDate in loopIpyDatList:
                if loopStartDate <= startWeekDate <= loopEndDate or loopStartDate <= endWeekDate <= loopEndDate:
                    coverDisableWeekIpyDataInfo[weekCfgID] = [startWeekDate, endWeekDate, loopCfgID, loopStartDate, loopEndDate]
    return coverDisableLoopIpyDataInfo, disableLoopCfgIDDict, otherLoopCfgIDDict, coverDisableWeekIpyDataInfo, disableWeekCfgIDDict, kOpenServerActInfo
def Dispose_OperationActionState():
    # 运营活动状态处理
    if GameWorld.IsCrossCenter():
        # 跨服活动管理,待扩展,由跨服中心统一管理
        #CrossActionControl.Dispose_CrossActState(reloadRefresh)
        return
    if not GameWorld.IsMainServer():
        return
    isReload, OperationActionInfo = __GetOperationActionInfo()
    operationTodayActionDict = OperationActionInfo[OperationAction_TodayInfo]
    mapServerInfoDict = PyGameData.g_operationActionDict #OperationActionInfo[OperationAction_MapServerInfo]
    gameWorld = GameWorld.GetGameWorld()
    dbEventMgr = DBDataMgr.GetEventTrigMgr()
    # 这里时间需精确到分钟,不然后面的比较会匹配不到
    curDateTime = GameWorld.GetServerTime()
    curDateTime = datetime.datetime.strptime("%d-%d-%d %d:%d:00" % (curDateTime.year, curDateTime.month, curDateTime.day,
                                                                    curDateTime.hour, curDateTime.minute), ChConfig.TYPE_Time_Format)
    syncMapList = []
    for actName in ShareDefine.OperationActionNameList:
        if actName not in mapServerInfoDict:
            continue
        curActMapInfoDictList = mapServerInfoDict[actName].values()
        for sendMapServerMsgDict in curActMapInfoDictList:
            state = 0 # 默认关闭
            stateJoin = ShareDefine.ActStateJoin_None # 可参与状态,0-参与前;1-可参与;2-参与结束
            ipyData = None
            actNum = sendMapServerMsgDict.get(ShareDefine.ActKey_ActNum, 0)
            if actName in operationTodayActionDict:
                todayActInfoList = []
                if actNum in operationTodayActionDict[actName]:
                    todayActInfoList = operationTodayActionDict[actName][actNum]
                if isinstance(todayActInfoList, list) and len(todayActInfoList) == 6:
                    #startList = [] # [startDateTime, ...]
                    #endList = [] # [endDateTime, ...]
                    #notifyDict = {} # {notifyDateTime:[notifyKey, [参数]], ...}
                    #ipyData 可能为 None
                    ipyData, startList, endList, notifyDict, joinStartTimeList, joinEndTimeList = todayActInfoList
                    # ״̬
                    for dIndex, startDateTime in enumerate(startList):
                        endDateTime = endList[dIndex]
                        if startDateTime <= curDateTime < endDateTime:
                            state = dIndex + 1 # 代表第几个时间段
                            break
                    if joinStartTimeList:
                        for jIndex, joinStartDateTime in enumerate(joinStartTimeList):
                            endJoinDateTime = joinEndTimeList[jIndex]
                            if joinStartDateTime <= curDateTime < endJoinDateTime:
                                stateJoin = ShareDefine.ActStateJoin_Start
                                break
                            elif curDateTime >= endJoinDateTime:
                                stateJoin = ShareDefine.ActStateJoin_End
                    else:
                        stateJoin = ShareDefine.ActStateJoin_Start if state else ShareDefine.ActStateJoin_None
                    # 全服广播提示信息
                    if curDateTime in notifyDict:
                        notifyKey, paramList = notifyDict[curDateTime]
                        PlayerControl.WorldNotify(0, notifyKey, paramList)
            dictName = ShareDefine.Def_WorldKey_OperationActionState % (actName, actNum)
            dictNameJoin = ShareDefine.Def_WorldKey_OperationActionStateJoin % (actName, actNum)
            preState = gameWorld.GetGameWorldDictByKey(dictName)
            preStateJoin = gameWorld.GetGameWorldDictByKey(dictNameJoin)
            if not isReload and preState == state and preStateJoin == stateJoin:
                #GameWorld.DebugLog("运营活动已经是这个状态了: actName=%s,actNum=%s,preState=%s,state=%s,preStateJoin=%s,stateJoin=%s" % (actName, actNum, preState, state, preStateJoin, stateJoin))
                continue
            GameWorld.Log("运营活动变更: actName=%s,actNum=%s,preState=%s,state=%s,preStateJoin=%s,stateJoin=%s,isReload=%s"
                          % (actName, actNum, preState, state, preStateJoin, stateJoin, isReload))
            #更新字典值
            gameWorld.SetGameWorldDict(dictName, state)
            gameWorld.SetGameWorldDict(dictNameJoin, stateJoin)
            dbOperationActIDKey = ShareDefine.Def_OperationActID % (actName, actNum)
            dbActID = dbEventMgr.GetValue(dbOperationActIDKey)
            curActID = sendMapServerMsgDict.get(ShareDefine.ActKey_ID, 0)
            #dayIndex = sendMapServerMsgDict.get(ShareDefine.ActKey_DayIndex, 0)
            if dbActID != curActID:
                GameWorld.Log("    dbActID变更: dbActID=%s,curActID=%s" % (dbActID, curActID))
                dbEventMgr.SetValue(dbOperationActIDKey, curActID)
                # 结束旧的
                if dbActID:
                    pass
                    #if actName == ShareDefine.OperationActionName_Gubao:
                    #    PlayerActGubao.OnActEnd(actNum, ipyData, dayIndex)
                if curActID:
                    pass
                    #此处为活动开启时
                    #if actName == ShareDefine.OperationActionName_Gubao:
                    #    PlayerActGubao.OnActStart(actNum, ipyData)
                #else:
                #    if actName == ShareDefine.OperationActionName_GarbageSorting:
                #        PlayerActGarbageSorting.OnActEnd(actNum)
            else:
                GameWorld.Log("    dbActID不变: dbActID=%s,curActID=%s" % (dbActID, curActID))
            # 活动中刷新,每次都需要刷新的逻辑,包含重读配置等
            if state:
                pass
                #if actName == ShareDefine.OperationActionName_Gubao:
                #    PlayerActGubao.OnActInStateRefresh(actNum, ipyData)
            # 仅活动有配置参与时间段的会触发
            if curActID and dbActID == curActID and preStateJoin != stateJoin:
                GameWorld.Log("    参与状态变更: preStateJoin=%s,stateJoin=%s" % (preStateJoin, stateJoin))
                # 参与开始
                if stateJoin == ShareDefine.ActStateJoin_Start:
                    pass
                # 参与结束
                elif stateJoin == ShareDefine.ActStateJoin_End:
                    pass
                    #if actName == ShareDefine.OperationActionName_Gubao:
                    #    PlayerActGubao.OnActJoinEnd(actNum, ipyData, dayIndex)
            if ipyData:
                pass
            #if actName == ShareDefine.OperationActionName_ExpRate:
            #    if isReload and ipyData:
            #        Sync_OperationAction_ExpRate(ipyData)
            #通知Mapserver,设置字典
            #GameWorld.SendMapServerMsgEx(dictName, state) # 运营活动不单独通知活动状态,需与活动信息整合后一起通知
            sendMapServerMsgDict[ShareDefine.ActKey_State] = state
            sendMapServerMsgDict[ShareDefine.ActKey_StateJoin] = stateJoin
            mapServerInfoDict[actName][actNum] = sendMapServerMsgDict
            syncMapList.append([actName, actNum, sendMapServerMsgDict])
    if syncMapList:
        GameWorld.Log("=============================================================")
        for actName, actNum, actInfo in syncMapList:
            OnMapOperationActionRefresh(actName, actNum, actInfo) # 通知地图玩家刷新活动相关
    return
def OnMapOperationActionRefresh(actName, actNum, actInfo):
    ## 处理类似之前由GameServer通知MapServer的运营活动刷新
    GameWorld.Log("OperationActionRefresh: %s,actNum=%s,%s" % (actName, actNum, actInfo))
    if actName == ShareDefine.OperationActionName_Lunhuidian:
        PlayerActLunhuidian.RefreshActLunhuidianActionInfo(actNum)
    return
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorldLogic/GameWorldEvent.py
@@ -25,6 +25,7 @@
import IPY_GameWorld
import DataRecordPack
import PlayerEventCounter
import GameWorldAction
import PlayerViewCache
import PlayerControl
import NetPackCommon
@@ -335,15 +336,13 @@
    DoCheckNewServerOpen(tick)
    DBDataMgr.OnMinute(curTime)
    DoLogic_GameWorldEvenByTime(tick)
    GameWorldAction.OnProcessGameAction(curTime)
    
    #每5分钟
    if curMinute % 5 == 0:
        OnMinute_5(curTime, tick)
        
    #其他功能逻辑
    #GameWorldActionControl.Dispose_OperationActionState()
    #GameWorldActionControl.Dispose_DailyActionState()
    #GameWorldActionControl.Dispose_FBStateTime()
    PlayerControl.OnMinute(curTime)
    PlayerFamily.OnMinute()
    PlayerOnline.OnMinute()
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/IpyGameDataPY.py
@@ -1696,6 +1696,9 @@
                "ActLunhuidian":(
                        ("DWORD", "CfgID", 1),
                        ("list", "PlatformList", 0),
                        ("list", "ServerIDList", 0),
                        ("BYTE", "ActNum", 0),
                        ("char", "StartDate", 0),
                        ("char", "EndDate", 0),
                        ("WORD", "LVLimit", 0),
@@ -4571,13 +4574,16 @@
        return
        
    def GetCfgID(self): return self.attrTuple[0] # 配置ID DWORD
    def GetStartDate(self): return self.attrTuple[1] # 开启日期 char
    def GetEndDate(self): return self.attrTuple[2] # 结束日期 char
    def GetLVLimit(self): return self.attrTuple[3] # 限制等级 WORD
    def GetResetType(self): return self.attrTuple[4] # 重置类型,0-0点重置;1-5点重置 BYTE
    def GetRoundSetInfo(self): return self.attrTuple[5] # 开放轮回设定 dict
    def GetRoundCTGIDInfo(self): return self.attrTuple[6] # 轮回类型对应充值ID列表 dict
    def GetRoundShopTypeInfo(self): return self.attrTuple[7] # 轮回类型对应商店类型 dict
    def GetPlatformList(self): return self.attrTuple[1] # 活动平台列表["平台A", "平台A", ...],配[]代表所有 list
    def GetServerIDList(self): return self.attrTuple[2] # 服务器ID列表 list
    def GetActNum(self): return self.attrTuple[3] # 活动分组编号, 活动类型 * 10 + 不同界面编号 BYTE
    def GetStartDate(self): return self.attrTuple[4] # 开启日期 char
    def GetEndDate(self): return self.attrTuple[5] # 结束日期 char
    def GetLVLimit(self): return self.attrTuple[6] # 限制等级 WORD
    def GetResetType(self): return self.attrTuple[7] # 重置类型,0-0点重置;1-5点重置 BYTE
    def GetRoundSetInfo(self): return self.attrTuple[8] # 开放轮回设定 dict
    def GetRoundCTGIDInfo(self): return self.attrTuple[9] # 轮回类型对应充值ID列表 dict
    def GetRoundShopTypeInfo(self): return self.attrTuple[10] # 轮回类型对应商店类型 dict
# 轮回殿活动奖励表
class IPY_ActLunhuidianAward():
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/ChPlayer.py
@@ -482,7 +482,7 @@
    EventReport.WriteEvent_login(curPlayer)
    
    # 合服首登处理
    __DoMixServerFirstLogin(curPlayer)
    #__DoMixServerFirstLogin(curPlayer)
    PlayerBillboard.BillboardOnLogin(curPlayer)
    
    #玩家扩展信息
@@ -580,8 +580,6 @@
    PlayerActTask.OnPlayerLogin(curPlayer)
    # 运势活动
    PlayerActYunshi.OnPlayerLogin(curPlayer)
    # 轮回殿活动
    PlayerActLunhuidian.OnPlayerLogin(curPlayer)
    # 登录活动
    PlayerActLoginNew.OnPlayerLogin(curPlayer)
    # 节日登录活动
@@ -687,6 +685,7 @@
        OpenServerActivity.OnPlayerLogin(curPlayer)
        PlayerPreset.OnPlayerLogin(curPlayer)
        CrossPlayer.OnPlayerLogin(curPlayer)
        PlayerActLunhuidian.OnPlayerLogin(curPlayer)
        
        __OnFixVersion(curPlayer) # 修正线上玩家数据用,暂时放最后
        # 上线查询一次充值订单
@@ -3399,6 +3398,9 @@
    # 开服庆典积分阶段奖励 
    elif rewardType == ChConfig.Def_RewardType_OSACelebrationPointAward:
        OpenServerActivity.GetOSACelebrationPointAward(curPlayer, dataEx)
    # 轮回殿奖励
    elif rewardType == ChConfig.Def_RewardType_LunhuidianAward:
        PlayerActLunhuidian.GetLunhuidianAward(curPlayer, dataEx, dataExStr)
        
        
    # 每日免费直购礼包
@@ -3455,9 +3457,6 @@
    # 寻宝累计次数奖励
    elif rewardType == ChConfig.Def_RewardType_TreasureCntAward:
        PlayerTreasure.GetTreasureCntAward(curPlayer, dataEx, dataExStr)
    # 轮回殿奖励
    elif rewardType == ChConfig.Def_RewardType_LunhuidianAward:
        PlayerActLunhuidian.GetLunhuidianAward(curPlayer, dataEx, dataExStr)
    #历史累计充值领取
    elif rewardType == ChConfig.Def_RewardType_HistoryChargeAward:
        PlayerGoldGift.OnGetHistoryRechargeAward(curPlayer, dataEx)
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerActLunhuidian.py
@@ -24,6 +24,7 @@
import NetPackCommon
import ItemControler
import PlayerCoin
import PlayerMail
import GameWorld
import ChConfig
@@ -176,7 +177,7 @@
        return
    GameWorld.Log("处理补发轮回奖励完毕: actNum=%s,roundType=%s,roundMax=%s,curRound=%s,curValue=%s,awardState=%s,mailItemList=%s" 
                       % (actNum, roundType, roundMax, curRound, curValue, awardState, mailItemList), playerID)
    PlayerControl.SendMailByKey("LunhuidianUnget", [playerID], mailItemList)
    PlayerMail.SendMailByKey("LunhuidianUnget", playerID, mailItemList)
    return
def GetRoundSetValue(roundSet, setIndex): return roundSet[setIndex] if len(roundSet) > setIndex else 0
@@ -338,7 +339,9 @@
                award = ChPyNetSendPack.tagMCActLunhuidianAward()
                award.AwardIndex = awardIpyData.GetAwardIndex()
                award.NeedValue = awardIpyData.GetNeedValue()
                for itemID, itemCount, isAuctionItem in awardIpyData.GetAwardItemList():
                for itemInfo in awardIpyData.GetAwardItemList():
                    itemID, itemCount = itemInfo[:2]
                    isAuctionItem = itemInfo[2] if len(itemInfo) > 2 else 0
                    item = ChPyNetSendPack.tagMCActLunhuidianItem()
                    item.ItemID = itemID
                    item.ItemCount = itemCount
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerEventCounter.py
@@ -37,29 +37,11 @@
import ChItem
import GameLogic_Tianzi
import PlayerGoldInvest
import PlayerActCollectWords
import PlayerActTotalRecharge
import PlayerActGodGift
import PlayerActFamilyCTGAssist
import PlayerActManyDayRecharge
import PlayerActSingleRecharge
import PlayerActGrowupBuy
import PlayerActTurntable
import PlayerActBuyOne
import PlayerSpringSale
import PlayerFeastLogin
import PlayerFeastWish
import PlayerActTask
import PlayerActYunshi
import PlayerActLunhuidian
import PlayerActBuyCountGift
import PlayerActLoginNew
import PlayerActLogin
import PlayerFlashGiftbag
import PlayerDailyGiftbag
import PlayerOfflineSupport
import PlayerLuckyTreasure
import PlayerFlashSale
import PlayerWishingWell
import PlayerTreasure
import PlayerZhanling
@@ -904,93 +886,8 @@
                PlayerControl.SetCoupleInfo(playerID, coupleInfo)
            return
        
        if key.startswith(ShareDefine.Def_Notify_WorldKey_OperationActionInfo[:-2]):
            keyHead = ShareDefine.Def_Notify_WorldKey_OperationActionInfo[:-2]
            actionName = key[len(keyHead):]
            actInfo = eval(msgValue)
            actNum = actInfo.get(ShareDefine.ActKey_ActNum, 0)
            if actionName in ShareDefine.MultiActNumOperationActNameList:
                if not actNum:
                    GameWorld.ErrLog('MultiActNumOperation can not found actNum. actionName=%s,msg = %s' % (actionName, msg))
                    return
                if actionName not in PyGameData.g_operationActionDict:
                    PyGameData.g_operationActionDict[actionName] = {}
                PyGameData.g_operationActionDict[actionName][actNum] = actInfo
            else:
                PyGameData.g_operationActionDict[actionName] = actInfo
            if actionName == ShareDefine.OperationActionName_ExpRate:
                PlayerControl.RefreshOperationAction_ExpRate()
            elif actionName == ShareDefine.OperationActionName_TotalRecharge:
                PlayerActTotalRecharge.RefreshTotalRechargeActionInfo(actNum)
            elif actionName == ShareDefine.OperationActionName_GodGift:
                PlayerActGodGift.RefreshGodGiftActionInfo(actNum)
            elif actionName == ShareDefine.OperationActionName_ManyDayRecharge:
                PlayerActManyDayRecharge.RefreshManyDayRechargeActionInfo(actNum)
            elif actionName == ShareDefine.OperationActionName_SingleRecharge:
                PlayerActSingleRecharge.RefreshSingleRechargeActionInfo(actNum)
            elif actionName == ShareDefine.OperationActionName_Turntable:
                PlayerActTurntable.RefreshTurntableActionInfo(actNum)
            elif actionName == ShareDefine.OperationActionName_SpringSale:
                PlayerSpringSale.RefreshSpringSaleActionInfo(actNum)
            elif actionName == ShareDefine.OperationActionName_FlashGiftbag:
                PlayerFlashGiftbag.RefreshFlashGiftbagActionInfo(actNum)
            elif actionName == ShareDefine.OperationActionName_DailyGiftbag:
                PlayerDailyGiftbag.RefreshDailyGiftbagActionInfo()
            elif actionName == ShareDefine.OperationActionName_BuyOne:
                PlayerActBuyOne.RefreshBuyOneActionInfo(actNum)
            elif actionName == ShareDefine.OperationActionName_FamilyCTGAssist:
                PlayerActFamilyCTGAssist.RefreshFamilyCTGAssistActionInfo(actNum)
            elif actionName == ShareDefine.OperationActionName_FlashSale:
                PlayerFlashSale.RefreshflashSaleActionInfo(actNum)
            elif actionName == ShareDefine.OperationActionName_WishingWell:
                PlayerWishingWell.RefreshWishingWellAction()
            elif actionName == ShareDefine.OperationActionName_CollectWords:
                PlayerActCollectWords.RefreshActCollectWordsInfo(actNum)
            elif actionName == ShareDefine.OperationActionName_BuyCountGift:
                PlayerActBuyCountGift.RefreshBuyCountGiftActionInfo(actNum)
            elif actionName == ShareDefine.OperationActionName_ActTask:
                PlayerActTask.RefreshActTaskActionInfo(actNum)
            elif actionName == ShareDefine.OperationActionName_Yunshi:
                PlayerActYunshi.RefreshActYunshiActionInfo(actNum)
            elif actionName == ShareDefine.OperationActionName_Lunhuidian:
                PlayerActLunhuidian.RefreshActLunhuidianActionInfo(actNum)
            elif actionName == ShareDefine.OperationActionName_LoginAward:
                PlayerActLogin.RefreshOperationAction_LoginAward()
            elif actionName == ShareDefine.OperationActionName_ActLoginNew:
                PlayerActLoginNew.RefreshActLoginActionInfo(actNum)
            elif actionName == ShareDefine.OperationActionName_FeastLogin:
                PlayerFeastLogin.RefreshFeastLoginActionInfo()
            elif actionName == ShareDefine.OperationActionName_FeastWish:
                PlayerFeastWish.RefreshFeastWishActionInfo()
            elif actionName == ShareDefine.OperationActionName_LuckyTreasure:
                PlayerLuckyTreasure.RefreshLuckyTreasureAction()
            elif actionName == ShareDefine.OperationActionName_GrowupBuy:
                PlayerActGrowupBuy.RefreshGrowupBuyActionInfo()
        if key.startswith(ShareDefine.Def_Notify_WorldKey_OperationActionInfo[:-2]):
            # 运营活动改为通过 GameWorldAction.OnMapOperationActionRefresh 触发刷新
            return
        
        if key.startswith(ShareDefine.Def_Notify_WorldKey_CrossActInfo[:-2]):
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ShareDefine.py
@@ -46,6 +46,7 @@
Def_FamilyCrossState = 'FamilyCrossState' # 本服公会跨服状态, 0-未跨服;1-已跨服
Def_FamilyTransDataTime = 'FamilyTransDataTime' # 本服公会首次跨服互通数据开始传输时间戳,不为0代表传输数据中
Def_OSAAwardState = 'OSAAwardState' #开服冲榜活动结算状态
Def_OperationActID = 'OperationActID_%s_%s' # 运营活动ID的标记,参数(运营活动名, actNum)
#---奇迹, 职业枚举定义---
(
@@ -198,6 +199,9 @@
Def_Notify_WorldKey_CoupleInfo = "CoupleInfo"  # 伴侣信息
Def_WorldKey_OperationActionState = "State_%s_%s"               #运营活动状态,参数为(运营活动名, actNum)
Def_WorldKey_OperationActionStateJoin = "StateJoin_%s_%s"       #运营活动可参与状态,参数为(运营活动名, actNum)
#活动类型定义
ActTypeList = (
ActType_OpenComm, # 开服及常规运营活动 1
@@ -206,6 +210,11 @@
) = range(1, 1 + 3)
#运营活动表名定义
OperationActionName_Lunhuidian = "ActLunhuidian" # 轮回殿活动
#所有的运营活动列表,默认都支持多活动分组编号的活动名
OperationActionNameList = [OperationActionName_Lunhuidian]
OperationActionName_ExpRate = "ActExpRate" # 多倍经验活动
OperationActionName_SpringSale = "ActSpringSale" # 限时特惠活动
OperationActionName_FlashGiftbag = "ActFlashGiftbag" # 限时礼包活动
@@ -232,58 +241,44 @@
OperationActionName_BuyCountGift = "ActBuyCountGift" # 购买次数礼包活动
OperationActionName_FamilyCTGAssist = "ActFamilyCTGAssist" # 仙盟充值协助
OperationActionName_Yunshi = "ActYunshi" # 运势活动
OperationActionName_Lunhuidian = "ActLunhuidian" # 轮回殿活动
#节日活动类型列表 - 该类型无视开服天,日期到了就开启
FeastOperationActionNameList = [OperationActionName_GrowupBuy,
                                OperationActionName_FeastLogin,
                                OperationActionName_FeastWish,
                                ]
#所有的运营活动列表,含节日活动
OperationActionNameList = [OperationActionName_ExpRate,
                           OperationActionName_SpringSale,
                           OperationActionName_FlashGiftbag, OperationActionName_FairyCeremony,
                           OperationActionName_RealmPoint, OperationActionName_FlashSale,
                           OperationActionName_WishingWell, OperationActionName_TotalRecharge,
                           OperationActionName_LoginAward,
                           OperationActionName_NewFairyCeremony, OperationActionName_LuckyTreasure,
                           OperationActionName_DailyGiftbag, OperationActionName_SingleRecharge,
                           OperationActionName_CollectWords, OperationActionName_ManyDayRecharge,
                           OperationActionName_Turntable,
                           OperationActionName_GodGift,
                           OperationActionName_BuyOne,
                           OperationActionName_ActLoginNew, OperationActionName_ActTask,
                           OperationActionName_BuyCountGift, OperationActionName_FamilyCTGAssist,
                           OperationActionName_Yunshi,
                           OperationActionName_Lunhuidian,
                           ] + FeastOperationActionNameList
#需要记录开启活动时的世界等级的运营活动
NeedWorldLVOperationActNameList = [OperationActionName_FairyCeremony, OperationActionName_WishingWell,
                                   OperationActionName_NewFairyCeremony, OperationActionName_FlashSale,
                                   OperationActionName_TotalRecharge,
                                   OperationActionName_FlashGiftbag,
                                   OperationActionName_SpringSale, OperationActionName_LuckyTreasure,
                                   OperationActionName_DailyGiftbag, OperationActionName_GrowupBuy,
                                   OperationActionName_Turntable,
                                   OperationActionName_CollectWords,
                                   OperationActionName_FeastLogin,
                                   OperationActionName_FeastWish,
                                   OperationActionName_ManyDayRecharge, OperationActionName_SingleRecharge,
                                   OperationActionName_GodGift,
                                   ]
#支持多活动分组编号的活动名
MultiActNumOperationActNameList = [OperationActionName_TotalRecharge, OperationActionName_CollectWords,
                                   OperationActionName_FlashGiftbag,
                                   OperationActionName_SpringSale, OperationActionName_FlashSale,
                                   OperationActionName_ManyDayRecharge, OperationActionName_SingleRecharge,
                                   OperationActionName_Turntable,
                                   OperationActionName_GodGift,
                                   OperationActionName_BuyOne,
                                   OperationActionName_ActLoginNew, OperationActionName_ActTask,
                                   OperationActionName_BuyCountGift, OperationActionName_FamilyCTGAssist,
                                   OperationActionName_Yunshi,
                                   OperationActionName_Lunhuidian,
                                   ]
##节日活动类型列表 - 该类型无视开服天,日期到了就开启
#FeastOperationActionNameList = [OperationActionName_GrowupBuy,
#                                OperationActionName_FeastLogin,
#                                OperationActionName_FeastWish,
#                                ]
##所有的运营活动列表,含节日活动
#OperationActionNameList = [OperationActionName_ExpRate,
#                           OperationActionName_SpringSale,
#                           OperationActionName_FlashGiftbag, OperationActionName_FairyCeremony,
#                           OperationActionName_RealmPoint, OperationActionName_FlashSale,
#                           OperationActionName_WishingWell, OperationActionName_TotalRecharge,
#                           OperationActionName_LoginAward,
#                           OperationActionName_NewFairyCeremony, OperationActionName_LuckyTreasure,
#                           OperationActionName_DailyGiftbag, OperationActionName_SingleRecharge,
#                           OperationActionName_CollectWords, OperationActionName_ManyDayRecharge,
#                           OperationActionName_Turntable,
#                           OperationActionName_GodGift,
#                           OperationActionName_BuyOne,
#                           OperationActionName_ActLoginNew, OperationActionName_ActTask,
#                           OperationActionName_BuyCountGift, OperationActionName_FamilyCTGAssist,
#                           OperationActionName_Yunshi,
#                           OperationActionName_Lunhuidian,
#                           ] + FeastOperationActionNameList
##需要记录开启活动时的世界等级的运营活动
#NeedWorldLVOperationActNameList = [OperationActionName_FairyCeremony, OperationActionName_WishingWell,
#                                   OperationActionName_NewFairyCeremony, OperationActionName_FlashSale,
#                                   OperationActionName_TotalRecharge,
#                                   OperationActionName_FlashGiftbag,
#                                   OperationActionName_SpringSale, OperationActionName_LuckyTreasure,
#                                   OperationActionName_DailyGiftbag, OperationActionName_GrowupBuy,
#                                   OperationActionName_Turntable,
#                                   OperationActionName_CollectWords,
#                                   OperationActionName_FeastLogin,
#                                   OperationActionName_FeastWish,
#                                   OperationActionName_ManyDayRecharge, OperationActionName_SingleRecharge,
#                                   OperationActionName_GodGift,
#                                   ]
#跨服运营活动表名定义
CrossActName_Lianqi = "CrossActLianqi" # 炼器 - 跨服