ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/GameWorldActionControl.py
@@ -20,26 +20,24 @@
import ChConfig
import datetime
import GameWorld
import ReadChConfig
import PlayerControl
import ShareDefine
#import PlayerExam
import PlayerDBGSEvent
import MergeBroadcast
#import PlayerManorWar
#import GameWorldShopItem
#import GameWorldActionTeHui
import GameWorldAverageLv
#import GameWorldMergeBoss
#import GameWorldMergeKing
#import GameWorldMergePK
import CrossRealmPK
import GameWorldFamilyWar
import PlayerFamilyParty
import IpyGameDataPY
import PlayerXMZZ
import PlayerFamilySWRH
import GameWorldBoss
import PlayerFamilyRedPacket
import PlayerFairyCeremony
import PlayerNewFairyCeremony
import PlayerUniversalGameRec
import GameWorldAverageLv
import PlayerFamilyBoss
import PlayerHorsePetBoss
import CrossActionControl
import GameWorldProcess
import ChPyNetSendPack
import NetPackCommon
@@ -48,8 +46,6 @@
from types import IntType
import time
#---------------------------------------------------------------------
MaxCustomServerDay = 14 # 最大定制开服天数
#年月日时间格式
Time_YmdFormat = ChConfig.TYPE_Time_YmdFormat
@@ -63,6 +59,10 @@
) = range(3)
def OnPlayerLogin(curPlayer):
    if GameWorld.IsCrossServer():
        # 跨服不处理运营活动
        return
    
    isReload, OperationActionInfo = __GetOperationActionInfo()
    operationActionDict = OperationActionInfo[OperationAction_TodayInfo]
@@ -81,16 +81,33 @@
        ipyData = operationActionDict[ShareDefine.OperationActionName_FairyCeremony][0]
        if ipyData:
            PlayerFairyCeremony.Sync_OperationAction_FairyCeremony(ipyData, curPlayer)
    # 新仙界盛典活动进行中
    if ShareDefine.OperationActionName_NewFairyCeremony in operationActionDict:
        ipyData = operationActionDict[ShareDefine.OperationActionName_NewFairyCeremony][0]
        if ipyData:
            PlayerNewFairyCeremony.Sync_OperationAction_NewFairyCeremony(ipyData, curPlayer)
    # 多倍修行点活动进行中
    if ShareDefine.OperationActionName_RealmPoint in operationActionDict:
        ipyData = operationActionDict[ShareDefine.OperationActionName_RealmPoint][0]
        if ipyData:
            Sync_OperationAction_RealmPoint(ipyData, curPlayer)
    # 节日红包活动进行中
    if ShareDefine.OperationActionName_FeastRedPacket in operationActionDict:
        ipyData = operationActionDict[ShareDefine.OperationActionName_FeastRedPacket][0]
        if ipyData:
            PlayerFamilyRedPacket.Sync_FeastRedPacket(ipyData, curPlayer)
    # 幸运鉴宝活动进行中
    if ShareDefine.OperationActionName_LuckyTreasure in operationActionDict:
        PlayerUniversalGameRec.SendUniversalGameRecInfo(curPlayer, ShareDefine.Def_UniversalGameRecType_LuckyTreasure)
    return
def SendMapServerOperationActionState():
    # 地图启动成功时通知本日运行活动相关状态
    if GameWorld.IsCrossServer():
        # 跨服不处理运营活动
        return
    CrossActionControl.SendMapServerCrossActionState()
    
    isReload, OperationActionInfo = __GetOperationActionInfo()
    mapServerInfoDict = OperationActionInfo[OperationAction_MapServerInfo]
@@ -99,27 +116,53 @@
        # 如果是重读的,则在内层已经同步了,此处不重复同步
        return
    
    gameWorld = GameWorld.GetGameWorld()
    for actName in ShareDefine.OperationActionNameList:
        dictName = ChConfig.Def_WorldKey_OperationActionState % actName
        state = gameWorld.GetDictByKey(dictName)
        sendMapServerMsgDict = mapServerInfoDict.get(actName, {})
        sendMapServerMsgDict[ShareDefine.ActKey_State] = state
        GameWorld.SendMapServerMsgEx(ShareDefine.Def_Notify_WorldKey_OperationActionInfo % actName, sendMapServerMsgDict)
        if actName in ShareDefine.MultiActNumOperationActNameList:
            for actNumMapMsgDict in sendMapServerMsgDict.values():
                GameWorld.SendMapServerMsgEx(ShareDefine.Def_Notify_WorldKey_OperationActionInfo % actName, actNumMapMsgDict)
        else:
            GameWorld.SendMapServerMsgEx(ShareDefine.Def_Notify_WorldKey_OperationActionInfo % actName, sendMapServerMsgDict)
        
    return
def GetOperationActNum(actName, ipyData=None):
    ''' 获取运营活动分组编号
        加入了分组编号概念,但由于有些活动配表还是旧规则配置,为了做规则兼容旧配表,减少配置表改动及代码改动这里做下自适应分配默认分组编号
        活动类型定义:
        1-默认(仅可配置开服天、日期、周循环W开头+数字,优先级 开服天 > 日期 > 周x)
                                        非开服配置的开服前X天不开,不受合服影响,功能配置表可配置前X天后交叉可开,每日重置的活动前X天后默认可开
        2-合服(仅可配置Mix开头+数字,如Mix1代表合服第1天,以此类推)
        3-节日(仅可配置日期,不受开服、合服影响)
        活动分组编号 = 活动类型 * 10 + 不同界面编号
    '''
    if ipyData and hasattr(ipyData, "ActNum"):
        return ipyData.GetActNum()
    # 原节日活动的还是默认节日活动
    if actName in ShareDefine.FeastOperationActionNameList:
        return ShareDefine.ActType_Feast * 10
    # 其他默认常规,这里不考虑合服类型的了,新版本合服类型已独立出去,按 ipyData 配置
    return ShareDefine.ActType_OpenComm * 10
def GetOperationActType(actNum):
    ## 运营活动类型
    return actNum / 10
def __GetOperationActionInfo(isRefreshState=True):
    # @return: isReload, OperationActionInfo
    
    key = "OperationActionInfo"
    openServerDay = PlayerDBGSEvent.GetDBGSTrig_ByKey(PlayerDBGSEvent.Def_ServerDay) + 1
    isMixServer = PlayerDBGSEvent.GetDBGSTrig_ByKey(PlayerDBGSEvent.Def_IsMixServer)
    mixServerDay = PlayerDBGSEvent.GetDBGSTrig_ByKey(PlayerDBGSEvent.Def_MixServerDay) + 1
    OperationActionInfo = IpyGameDataPY.GetConfigEx(key)
    serverTime = GameWorld.GetServerTime()
    curHour = serverTime.hour
    reloadSignHour = 0 if curHour < 5 else 5
    reloadSign = "%s_%s" % (openServerDay, reloadSignHour)
    reloadSign = [openServerDay, isMixServer, mixServerDay, reloadSignHour]
    if OperationActionInfo and OperationActionInfo[OperationAction_ReloadSign] == reloadSign:
        #GameWorld.DebugLog("已经加载过本日运营活动处理信息!openServerDay=%s" % openServerDay)
        return False, OperationActionInfo
@@ -128,47 +171,141 @@
    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)
    
    customMaxServerDay = MaxCustomServerDay # 定制运营活动最大开服天
    operationActionDict = {}
    startDateInCustomCanOpenList = IpyGameDataPY.GetFuncEvalCfg("OperationAction", 2) # 开始天在定制天内在定制天结束后可继续开启的活动列表
    customMaxServerDay = IpyGameDataPY.GetFuncCfg("OperationAction", 1) # 定制运营活动最大开服天
    maxCustomServerDayMix = IpyGameDataPY.GetFuncCfg("MixServer", 1) # 定制运营活动最大合服天
    operationTodayActionDict = {}
    mapServerOperationActionDict = {}
    serverID = GameWorld.GetServerID()
    platform = GameWorld.GetPlatform()
    serverGroupID = GameWorld.GetServerGroupID()
    ipyDataMgr = IpyGameDataPY.IPY_Data()
    curWeekday = curDateTime.weekday() + 1 # 今天星期几, 1代表星期1
    
    GameWorld.Log("===== 加载本日运营活动信息: %s, serverID=%s,openServerDay=%s,customMaxServerDay=%s,reloadSign=%s ====="
                  % (curDateTime, serverID, openServerDay, customMaxServerDay, reloadSign))
    GameWorld.Log("===== 加载本日运营活动信息: %s, serverGroupID=%s,openServerDay=%s,customMaxServerDay=%s,isMixServer=%s,mixServerDay=%s,maxCustomServerDayMix=%s,reloadSign=%s ====="
                  % (curDateTime, serverGroupID, openServerDay, customMaxServerDay, isMixServer, mixServerDay, maxCustomServerDayMix, reloadSign))
    GameWorld.Log("    今日周%s" % (curWeekday))
    
    for actName in ShareDefine.OperationActionNameList:
        
        if actName not in mapServerOperationActionDict:
            mapServerOperationActionDict[actName] = {}
        # 取出本活动所属本服ID的所有配置
        curServerActIpyDataList = __GetOperationActionServerIpyDataList(ipyDataMgr, serverID, actName)
        GameWorld.Log("加载运营活动: actName=%s,可处理条数=%s" % (actName, len(curServerActIpyDataList)))
        needStartList = [] # [startDateTime, ...]
        needEndList = [] # [endDateTime, ...]
        needNotifyDict = {} # {notifyDateTime:[notifyKey, [参数]], ...}
        activityIpyData = None # 活动中的的配置,取需要处理的配置中开始时间最晚的,反之开关时间头尾相连的时候无法开启后面的活动
        # 注意:每个活动配置会有多个活动时间点,但是有且只能生效一条活动配置,换句话说就是每个活动配置时间不允许交叉
        GameWorld.Log("加载运营活动: actName=%s,platform=%s,serverGroupID=%s" % (actName, platform, serverGroupID))
        curServerActIpyDataList = __GetOperationActionServerIpyDataList(ipyDataMgr, platform, serverGroupID, actName)
        GameWorld.Log("    可处理条数=%s" % (len(curServerActIpyDataList)))
        actNumDisableWeekIpyDataInfo = __GetOperationActionDisableWeekIpyDataInfo(actName, curDateTime, curServerActIpyDataList)
        for ipyData in curServerActIpyDataList:
            
            platformList = [] if not hasattr(ipyData, "PlatformList") else ipyData.GetPlatformList()
            serverGroupIDList = [] if not hasattr(ipyData, "ServerGroupIDList") else ipyData.GetServerGroupIDList()
            serverGroupIDListExcept = [] if not hasattr(ipyData, "ServerGroupIDListExcept") else ipyData.GetServerGroupIDListExcept()
            cfgID = ipyData.GetCfgID()
            startDateStr = ipyData.GetStartDate()
            endDateStr = ipyData.GetEndDate()
            GameWorld.Log("    cfgID=%s,mark=%s,serverIDList=%s,startDateStr=%s,endDateStr=%s,openServerDay=%s,curDateTime=%s"
                          % (cfgID, ipyData.GetActMark(), ipyData.GetServerIDList(), startDateStr, endDateStr, openServerDay, curDateTime))
            # 按开服天开的
            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))
            actNum = GetOperationActNum(actName, ipyData)
            actType = GetOperationActType(actNum)
            GameWorld.Log("    cfgID=%s,actNum=%s,startDateStr=%s,endDateStr=%s,openServerDay=%s,isMixServer=%s,mixServerDay=%s,curDateTime=%s,platformList=%s,serverGroupIDList=%s,Except=%s"
                          % (cfgID, actNum, startDateStr, endDateStr, openServerDay, isMixServer, mixServerDay, curDateTime, platformList, serverGroupIDList, serverGroupIDListExcept))
            if actName in ShareDefine.MultiActNumOperationActNameList:
                # 多活动分组编号的需要把所有配置的 actNum 都登记进来,以确保地图能正确进行逻辑
                if actNum not in mapServerOperationActionDict[actName]:
                    mapServerOperationActionDict[actName][actNum] = {ShareDefine.ActKey_ActNum:actNum}
                curActTodayInfo = operationTodayActionDict.get(actName, {}).get(actNum)
            else:
                curActTodayInfo = operationTodayActionDict.get(actName)
            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)
            # 开服常规:  开服天 > 日期 > 周x   (不受合服天影响,合服活动新增一套独立的活动,还是走运营活动配置)
            if actType == ShareDefine.ActType_OpenComm:
                actByWeek = (startDateStr.startswith("W") and endDateStr.startswith("W")) # 按周x开
                actByDate = (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))
                # 常规配置: 开服前X天不开,不受合服影响,功能配置表可配置 开服前X天后交叉可开,每日重置的活动默认可开
                elif actByWeek or actByDate:
                    if openServerDay <= customMaxServerDay:
                        GameWorld.Log("        按日期/周开的在开服定制限制天内,不处理! cfgID=%s,%s ~ %s,openServerDay=%s" % (cfgID, startDateStr, endDateStr, openServerDay))
                        continue
                    disableWeekIpyDataInfo = actNumDisableWeekIpyDataInfo.get(actNum, {})
                    if cfgID in disableWeekIpyDataInfo:
                        startWeekDate, endWeekDate, ymdCfgID, ymdStartDate, ymdEndDate = disableWeekIpyDataInfo[cfgID]
                        GameWorld.Log("        常规活动,按星期开启的在按日期开启的时间内,不处理! cfgID=%s,%s(%s) ~ %s(%s) in ymdCfgID=%s,%s ~ %s"
                                      % (cfgID, startWeekDate, startDateStr, endWeekDate, endDateStr, ymdCfgID, ymdStartDate, ymdEndDate))
                        continue
                    if actByWeek:
                        startWeekday = int(startDateStr[1:])
                        endWeekday = int(endDateStr[1:])
                        startWeekDate = curDateTime + datetime.timedelta(days=(startWeekday - curWeekday))
                        endWeekDate = curDateTime + datetime.timedelta(days=(endWeekday - curWeekday))
                        startDateStr = "%d-%d-%d" % (startWeekDate.year, startWeekDate.month, startWeekDate.day)
                        endDateStr = "%d-%d-%d" % (endWeekDate.year, endWeekDate.month, endWeekDate.day)
                        GameWorld.Log("        星期X转化为日期: %s ~ %s" % (startDateStr, endDateStr))
                    curServerOpenDateTime = curDateTime + datetime.timedelta(days=(1 - openServerDay)) # 开服第一天的日期
                    customMaxServerDateTime = curDateTime + datetime.timedelta(days=(customMaxServerDay - 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
                else:
                    GameWorld.Log("        开服常规活动,配置时间格式不支持,不处理! cfgID=%s,startDateStr=%s,endDateStr=%s" % (cfgID, startDateStr, endDateStr))
                    continue
                openServerDateTime = curDateTime + datetime.timedelta(days=(startServerDay-openServerDay))
                endServerDateTime = curDateTime + datetime.timedelta(days=(endServerDay-openServerDay))
            # 合服活动: 只受合服天影响
            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))
                GameWorld.Log("        合服天转化为日期: %s ~ %s" % (startDateStr, endDateStr))
                
            elif openServerDay <= customMaxServerDay:
                GameWorld.Log("        按日期开的在开服定制限制天内,不处理! cfgID=%s,%s ~ %s,openServerDay=%s" % (cfgID, startDateStr, endDateStr, openServerDay))
            # 节日活动:只受日期影响
            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, "GetStartTimeList") and hasattr(ipyData, "GetEndTimeList"):
@@ -191,6 +328,9 @@
            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点
@@ -199,57 +339,68 @@
            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
            startList = [] # [startDateTime, ...]
            endList = [] # [endDateTime, ...]
            startNotifyDict = {} # {notifyDateTime:notifyInfo, ...}
            endNotifyDict = {} # {notifyDateTime:notifyInfo, ...}
            loopNotifyDict = {} # {notifyDateTime:notifyInfo, ...}
            isActivity = False # 有需要处理开关时间的(开始、结束)
            notifyDict = {}
            isActTime = (startDayDate <= curDateTime < endDayDate)
            isEnd = (curDateTime == endDayDate)
            isNotify = False
            isAdvanceNotice = False
            isEnd = False
            # 没配置时分的代表全天, 只要开始或结束时分没配都算
            if not startHMStrList or not endHMStrList:
                startDateTime = startDayDate
                endDateTime = endDayDate
                startList.append(startDateTime)
                endList.append(endDateTime)
                # 同一个活动类型是不允许时间上配置有重叠的,所以一个活动类型满足活动中的时间的有且仅有一条配置
                # 策划可能同时配置多个时间,但是活动中的有且仅有一条配置
                if startDayDate <= curDateTime <= endDayDate:
                    needStartList.append(startDateTime)
                    needEndList.append(endDateTime)
                    isActivity = True
                    isEnd = (curDateTime == endDayDate)
            # 每天按时段开启的,支持多时段
            else:
                if startDayDate <= curDateTime <= endDayDate:
                    isEnd = (curDateTime == endDayDate)
                    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)
                        needStartList.append(startDateTime)
                        needEndList.append(endDateTime)
                        isActivity = True
            if advanceMinutes and startDayDate:
                advanceNoticeDateTime = startDayDate + datetime.timedelta(minutes=-advanceMinutes)
                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))
            GameWorld.Log("        needStartList=%s" % (needStartList))
            GameWorld.Log("        need  EndList=%s" % (needEndList))
            
            for dtIndex, startDateTime in enumerate(startList):
                endDateTime = endList[dtIndex]
@@ -275,7 +426,7 @@
                    loopCount, loopMaxCount = 0, 100
                    while loopMinutes and loopNotifyKey and loopCount < loopMaxCount:
                        loopCount += 1
                        notifyDateTime = startDateTime + datetime.timedelta(minutes=loopMinutes*loopCount)
                        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:
@@ -286,47 +437,48 @@
                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()))
                needNotifyDict.update(startNotifyDict)
                needNotifyDict.update(endNotifyDict)
                needNotifyDict.update(loopNotifyDict)
                notifyDict.update(startNotifyDict)
                notifyDict.update(endNotifyDict)
                notifyDict.update(loopNotifyDict)
                
            if not isActivity and not isNotify and not isAdvanceNotice:
                continue
            GameWorld.Log("        需要处理的运营活动信息: cfgID=%s,isActTime=%s,isEnd=%s,isNotify=%s,isAdvanceNotice=%s" % (cfgID, isActTime, isEnd, isNotify, isAdvanceNotice))
            
            GameWorld.Log("        需要处理的运营活动信息: cfgID=%s,isAdvanceNotice=%s,isActivity=%s,isEnd=%s,isNotify=%s" % (cfgID, isAdvanceNotice, isActivity, isEnd, isNotify))
            # 当天有需要激活活动或者提前预告活动的取非结束的为准,如果有多个非结束的一般就是策划在活动时间上配置交叉,这种是不允许的
            if isActivity or isAdvanceNotice:
                if not activityIpyData or (isActivity and not isEnd):
                    activityIpyData = ipyData
                    activityInfoDict = {ShareDefine.ActKey_CfgID:cfgID}
            # 兼容新旧运营活动逻辑处理数据
            if actName in ShareDefine.MultiActNumOperationActNameList:
                if actName not in operationTodayActionDict:
                    operationTodayActionDict[actName] = {} # 今日有需要处理的才初始化
                operationTodayActionDict[actName][actNum] = [ipyData, startList, endList, notifyDict]
            else:
                operationTodayActionDict[actName] = [ipyData, startList, endList, notifyDict]
            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 startDayDate <= curDateTime < endDayDate:
                        dayIndex = 0
                        actIDDateTime = startDayDate
                        isDayRest = 0 if not hasattr(ipyData, "GetIsDayReset") else ipyData.GetIsDayReset()
                        # 按时段开的默认每天重置
                        if isDayRest or (startHMStrList and endHMStrList):
                            dayIndex = (curDateTime - startDayDate).days
                            actIDDateTime += datetime.timedelta(days=dayIndex)
                        actID = int(time.mktime(actIDDateTime.timetuple())) # 默认取开始时间点的time值作为活动ID
                        activityInfoDict[ShareDefine.ActKey_DayIndex] = dayIndex
                        activityInfoDict[ShareDefine.ActKey_ID] = actID
                        GameWorld.Log("        isDayRest=%s,actIDDateTime=%s,actID=%s" % (isDayRest, actIDDateTime, actID))
                    needStartList.sort()
                    needEndList.sort()
                dayIndex = (curDateTime - startDayDate).days
                actIDDateTime = startDayDate
                isDayRest = 0 if not hasattr(ipyData, "GetIsDayReset") else ipyData.GetIsDayReset()
                # 按时段开的默认每天重置
                if isDayRest or (startHMStrList and endHMStrList):
                    actIDDateTime += datetime.timedelta(days=dayIndex)
                actID = int(time.mktime(actIDDateTime.timetuple())) # 默认取开始时间点的time值作为活动ID
                activityInfoDict[ShareDefine.ActKey_DayIndex] = dayIndex
                activityInfoDict[ShareDefine.ActKey_ID] = actID
                GameWorld.Log("        isDayRest=%s,actIDDateTime=%s,actID=%s" % (isDayRest, actIDDateTime, actID))
                GameWorld.Log("        activityInfoDict=%s" % (activityInfoDict))
                # 兼容新旧运营活动逻辑处理数据
                if actName in ShareDefine.MultiActNumOperationActNameList:
                    mapServerOperationActionDict[actName][actNum] = activityInfoDict
                else:
                    mapServerOperationActionDict[actName] = activityInfoDict
                    GameWorld.Log("        activityInfoDict=%s" % (activityInfoDict))
                    
        if activityIpyData or needStartList or needEndList or needNotifyDict:
            # activityIpyData 可能为None
            operationActionDict[actName] = [activityIpyData, needStartList, needEndList, needNotifyDict]
    OperationActionInfo = IpyGameDataPY.SetConfigEx(key, [reloadSign, operationActionDict, mapServerOperationActionDict])
    OperationActionInfo = IpyGameDataPY.SetConfigEx(key, [reloadSign, operationTodayActionDict, mapServerOperationActionDict])
    
    GameWorld.Log("本日运营活动信息加载完毕!reloadSign=%s,isRefreshState=%s" % (reloadSign, isRefreshState))
    GameWorld.Log("    operationActionDict=%s" % operationActionDict)
    GameWorld.Log("    operationTodayActionDict=%s" % operationTodayActionDict)
    GameWorld.Log("    mapServerOperationActionDict=%s" % mapServerOperationActionDict)
    GameWorld.Log("=============================================================")
    if isRefreshState:
@@ -334,49 +486,192 @@
        
    return True, OperationActionInfo
def __GetOperationActionServerIpyDataList(ipyDataMgr, serverID, actName):
def __GetOperationActionServerIpyDataList(ipyDataMgr, platform, serverGroupID, actName):
    ## 获取运营活动本服务器对应的配置数据列表
    
    # 所有配置先按活动标识归组
    actGroupDict = {} # {ActMark:{ServerIDTuple:[ipyData, ...], ...}, ...}
    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)
        actMark = ipyData.GetActMark()
        serverIDTuple = tuple(ipyData.GetServerIDList())
        ipyData = getattr(ipyDataMgr, "Get%sByIndex" % actName)(cfgIndex)
        platformList = [] if not hasattr(ipyData, "PlatformList") else ipyData.GetPlatformList()
        serverGroupIDList = [] if not hasattr(ipyData, "ServerGroupIDList") else ipyData.GetServerGroupIDList()
        serverGroupIDListExcept = [] if not hasattr(ipyData, "ServerGroupIDListExcept") else ipyData.GetServerGroupIDListExcept()
        
        serverIpyDataDict = actGroupDict.get(actMark, {})
        ipyDataList = serverIpyDataDict.get(serverIDTuple, [])
        ipyDataList.append(ipyData)
        serverIpyDataDict[serverIDTuple] = ipyDataList
        actGroupDict[actMark] = serverIpyDataDict
        if platformList and platform not in platformList:
            continue
        
    # 取出所属本服ID的所有配置
    curServerActIpyDataList = []
    for actMark, serverIpyDataDict in actGroupDict.items():
        generalIpyDataList = []
        isGeneral = True
        for serverIDTuple, ipyDataList in serverIpyDataDict.items():
            if not serverIDTuple:
                generalIpyDataList = ipyDataList
                continue
            for serverIDInfo in serverIDTuple:
                if (isinstance(serverIDInfo, int) and serverIDInfo == serverID) \
                    or ((isinstance(serverIDInfo, list) or isinstance(serverIDInfo, tuple)) \
                        and len(serverIDInfo) == 2 and serverIDInfo[0] <= serverID <= serverIDInfo[1]):
                    curServerActIpyDataList += ipyDataList
                    isGeneral = False
        # 排除的服务器组ID列表
        if serverGroupIDListExcept:
            isExcept = False
            for serverGroupIDInfo in serverGroupIDListExcept:
                if (isinstance(serverGroupIDInfo, int) and serverGroupIDInfo == serverGroupID) \
                    or ((isinstance(serverGroupIDInfo, list) or isinstance(serverGroupIDInfo, tuple)) \
                        and len(serverGroupIDInfo) == 2 and serverGroupIDInfo[0] <= serverGroupID <= serverGroupIDInfo[1]):
                    isExcept = True
                    break
        if isGeneral:
            curServerActIpyDataList += generalIpyDataList
            if isExcept:
                continue
        if not serverGroupIDList:
            curServerActIpyDataList.append(ipyData)
        else:
            for serverGroupIDInfo in serverGroupIDList:
                if (isinstance(serverGroupIDInfo, int) and serverGroupIDInfo == serverGroupID) \
                    or ((isinstance(serverGroupIDInfo, list) or isinstance(serverGroupIDInfo, tuple)) \
                        and len(serverGroupIDInfo) == 2 and serverGroupIDInfo[0] <= serverGroupID <= serverGroupIDInfo[1]):
                    curServerActIpyDataList.append(ipyData)
                    break
    return curServerActIpyDataList
def __GetOperationActionDisableWeekIpyDataInfo(actName, curDateTime, curServerActIpyDataList):
    ## 获取不可用的按星期X开启的配置数据信息,按星期X开启的 活动优先级小于按日期的,当有重叠时以日期的为准
    curWeekday = curDateTime.weekday() + 1 # 今天星期几, 1代表星期1
    actNumWeekYMDIpyDataInfo = {} # {actNum:[weekIpyDataList, ymdIpyDatList], ...}
    for ipyData in curServerActIpyDataList:
        startDateStr = ipyData.GetStartDate()
        endDateStr = ipyData.GetEndDate()
        actNum = GetOperationActNum(actName, ipyData)
        actType = GetOperationActType(actNum)
        # 这里只处理常规运营活动,日期优先级大于周
        if actType != ShareDefine.ActType_OpenComm:
            continue
        if actNum not in actNumWeekYMDIpyDataInfo:
            weekIpyDataList, ymdIpyDatList = [], []
            actNumWeekYMDIpyDataInfo[actNum] = [weekIpyDataList, ymdIpyDatList]
        weekIpyDataList, ymdIpyDatList = actNumWeekYMDIpyDataInfo[actNum]
        # 按星期X的
        if startDateStr.startswith("W"):
            startWeekday = int(startDateStr[1:])
            endWeekday = int(endDateStr[1:])
            startWeekDate = curDateTime + datetime.timedelta(days=(startWeekday - curWeekday))
            endWeekDate = curDateTime + datetime.timedelta(days=(endWeekday - curWeekday))
            weekIpyDataList.append([ipyData, startWeekDate, endWeekDate])
        # 按日期的
        elif startDateStr.count("-") == 2:
            ymdIpyData = ipyData
            ymdStartDate = datetime.datetime.strptime("%s %02d:%02d:00" % (startDateStr, curDateTime.hour, curDateTime.minute), ChConfig.TYPE_Time_Format)
            ymdEndDate = datetime.datetime.strptime("%s %02d:%02d:00" % (endDateStr, curDateTime.hour, curDateTime.minute), ChConfig.TYPE_Time_Format)
            ymdIpyDatList.append([ymdIpyData, ymdStartDate, ymdEndDate])
        else:
            # 只处理按星期、按日期的,其他的不处理
            pass
    actNumDisableWeekIpyDataInfo = {} # {actNum:{cfgID:[info], ...}, ...}
    for actNum, weekYMDIpyDataInfo in actNumWeekYMDIpyDataInfo.items():
        weekIpyDataList, ymdIpyDatList = weekYMDIpyDataInfo
        for ipyData, startWeekDate, endWeekDate in weekIpyDataList:
            cfgID = ipyData.GetCfgID()
            for ymdIpyData, ymdStartDate, ymdEndDate in ymdIpyDatList:
                if ymdStartDate <= startWeekDate <= ymdEndDate or ymdStartDate <= endWeekDate <= ymdEndDate:
                    if actNum not in actNumDisableWeekIpyDataInfo:
                        actNumDisableWeekIpyDataInfo[actNum] = {}
                    ymdCfgID = ymdIpyData.GetCfgID()
                    actNumDisableWeekIpyDataInfo[actNum][cfgID] = [startWeekDate, endWeekDate, ymdCfgID, ymdStartDate, ymdEndDate]
    return actNumDisableWeekIpyDataInfo
def TransferOperationActDBKeyValue():
    '''  服务器启动时调用
            支持多活动的数据转移,旧版本db活动数据转移到新版本,分两种情况
    1. 原已支持多活动的:  手动根据原编号规则进行指定转移,这个维护一次后代码可删除
    2. 原不支持多活动的,自动根据原活动类型进行适配转移即可,由于合服相关的独立出来了,所以只需要处理常规的及节日类型
                           这个代码可以一直放着,后续增加支持多活动类型的配置到  MultiActNumOperationActNameList 即可
           注:不支持多活动的,暂还是用旧的key记录数据
    '''
    GameWorld.Log("=== 转移运营活动旧版本数据到新版本 ===")
    # 1. 原已支持的  - 维护后过一次后可删除或注释掉,目前只有累计充值、集字,线上版本分支 gt_1.100.4
    transferDict = {
                    ShareDefine.OperationActionName_TotalRecharge:[
                            # 原常规每日累充  转移 到 10
                            [PlayerDBGSEvent.Def_OperationActID % ShareDefine.OperationActionName_TotalRecharge,
                             PlayerDBGSEvent.Def_OperationActID % ShareDefine.OperationActionName_TotalRecharge + "_%s" % 10,
                             ],
                            [PlayerDBGSEvent.Def_OActWorldLV % ShareDefine.OperationActionName_TotalRecharge,
                             PlayerDBGSEvent.Def_OActWorldLV % ShareDefine.OperationActionName_TotalRecharge + "_%s" % 10,
                             ],
                            # 原常规多日累充2  转移 到 11
                            [PlayerDBGSEvent.Def_OperationActID % (ShareDefine.OperationActionName_TotalRecharge + "2"),
                             PlayerDBGSEvent.Def_OperationActID % ShareDefine.OperationActionName_TotalRecharge + "_%s" % 11,
                             ],
                            [PlayerDBGSEvent.Def_OActWorldLV % (ShareDefine.OperationActionName_TotalRecharge + "2"),
                             PlayerDBGSEvent.Def_OActWorldLV % ShareDefine.OperationActionName_TotalRecharge + "_%s" % 11,
                             ],
                            # 原节日多日累充3  转移 到 31
                            [PlayerDBGSEvent.Def_OperationActID % (ShareDefine.OperationActionName_TotalRecharge + "3"),
                             PlayerDBGSEvent.Def_OperationActID % ShareDefine.OperationActionName_TotalRecharge + "_%s" % 31,
                             ],
                            [PlayerDBGSEvent.Def_OActWorldLV % (ShareDefine.OperationActionName_TotalRecharge + "3"),
                             PlayerDBGSEvent.Def_OActWorldLV % ShareDefine.OperationActionName_TotalRecharge + "_%s" % 31,
                             ],
                                                                   ],
                    ShareDefine.OperationActionName_CollectWords:[
                            # 只配置了常规日期的,可不处理
                                                                  ],
                    }
    for actName, transferKeyList in transferDict.items():
        for oldKey, newKey in transferKeyList:
            value = PlayerDBGSEvent.GetDBGSTrig_ByKey(oldKey)
            if not value:
                continue
            GameWorld.Log("    转移旧运营活动dbKey值到新key: actName=%s,oldKey=%s,newKey=%s,value=%s" % (actName, oldKey, newKey, value))
            PlayerDBGSEvent.SetDBGSTrig_ByKey(newKey, value)
            PlayerDBGSEvent.DelDBGSTrig_ByKey(oldKey)
    # 2. 新增支持的 - 可当做常规代码一直留着
    for actName in ShareDefine.MultiActNumOperationActNameList:
        if actName in transferDict:
            # 特殊处理转化的活动不进行常规处理
            continue
        actIDKeyOld = PlayerDBGSEvent.Def_OperationActID % actName
        worldLVKeyOld = PlayerDBGSEvent.Def_OActWorldLV % actName
        actNum = GetOperationActNum(actName)
        actIDKeyNew = actIDKeyOld + "_%s" % actNum
        worldLVKeyNew = worldLVKeyOld + "_%s" % actNum
        dbActID = PlayerDBGSEvent.GetDBGSTrig_ByKey(actIDKeyOld)
        dbWorldLV = PlayerDBGSEvent.GetDBGSTrig_ByKey(worldLVKeyOld)
        if not dbActID:
            continue
        GameWorld.Log("    转移旧运营活动dbKey值到新key: actName=%s" % actName)
        PlayerDBGSEvent.SetDBGSTrig_ByKey(actIDKeyNew, dbActID)
        PlayerDBGSEvent.DelDBGSTrig_ByKey(actIDKeyOld)
        GameWorld.Log("        actIDKeyOld=%s,actIDKeyNew=%s,dbActID=%s" % (actIDKeyOld, actIDKeyNew, dbActID))
        if dbWorldLV:
            PlayerDBGSEvent.SetDBGSTrig_ByKey(worldLVKeyNew, dbWorldLV)
            PlayerDBGSEvent.DelDBGSTrig_ByKey(worldLVKeyOld)
            GameWorld.Log("        worldLVKeyOld=%s,worldLVKeyNew=%s,dbWorldLV=%s" % (worldLVKeyOld, worldLVKeyNew, dbWorldLV))
    GameWorld.Log("===================================")
    return
def Dispose_OperationActionState(reloadRefresh=False):
    # 运营活动状态处理, 每天0点会强制同步当天的运营活动详情到地图服务器
    
    if GameWorld.IsCrossServer():
        # 跨服不处理运营活动
        CrossActionControl.Dispose_CrossActState(reloadRefresh)
        return
    isReload, OperationActionInfo = __GetOperationActionInfo(False) # 这里必须传False
    isReload = isReload or reloadRefresh
    operationActionDict = OperationActionInfo[OperationAction_TodayInfo]
    operationTodayActionDict = OperationActionInfo[OperationAction_TodayInfo]
    mapServerInfoDict = OperationActionInfo[OperationAction_MapServerInfo]
    
    gameWorld = GameWorld.GetGameWorld()
@@ -388,98 +683,146 @@
    
    for actName in ShareDefine.OperationActionNameList:
        
        state = 0 # 默认关闭
        ipyData = None
        if actName in operationActionDict:
            #startList = [] # [startDateTime, ...]
            #endList = [] # [endDateTime, ...]
            #notifyDict = {} # {notifyDateTime:[notifyKey, [参数]], ...}
            #ipyData 可能为 None
            ipyData, startList, endList, notifyDict = operationActionDict[actName]
            # 精确匹配开启
            if curDateTime in startList:
                state = startList.index(curDateTime) + 1 # 也是代表第几个时间段
            # 精确匹配关闭
            elif curDateTime in endList:
                state = 0
            # goon ״̬
            else:
                for dIndex, startDateTime in enumerate(startList):
                    endDateTime = endList[dIndex]
                    if startDateTime < curDateTime < endDateTime:
                        state = dIndex + 1
                        break
            # 全服广播提示信息
            if curDateTime in notifyDict:
                notifyKey, paramList = notifyDict[curDateTime]
                PlayerControl.WorldNotify(0, notifyKey, paramList)
        dictName = ChConfig.Def_WorldKey_OperationActionState % actName
        preState = gameWorld.GetDictByKey(dictName)
        if not isReload and preState == state:
            #已经是这个状态了
        if actName not in mapServerInfoDict:
            continue
        #更新字典值
        gameWorld.SetDict(dictName, state)
        sendMapServerMsgDict = mapServerInfoDict.get(actName, {})
        
        dbOperationActIDKey = PlayerDBGSEvent.Def_OperationActID % actName
        curActID = sendMapServerMsgDict.get(ShareDefine.ActKey_ID)
        if state >= 1 and curActID and PlayerDBGSEvent.GetDBGSTrig_ByKey(dbOperationActIDKey) != curActID:
            PlayerDBGSEvent.SetDBGSTrig_ByKey(dbOperationActIDKey, curActID)
            if actName in ShareDefine.NeedWorldLVOperationActNameList:
                #记录开启时世界等级
                worldLV = PlayerDBGSEvent.GetDBGSTrig_ByKey(ShareDefine.Def_Notify_WorldKey_WorldAverageLv)
                PlayerDBGSEvent.SetDBGSTrig_ByKey(PlayerDBGSEvent.Def_OActWorldLV % actName, worldLV)
        if actName in ShareDefine.MultiActNumOperationActNameList:
            curActMapInfoDictList = mapServerInfoDict[actName].values()
        else:
            curActMapInfoDictList = [mapServerInfoDict[actName]]
        for sendMapServerMsgDict in curActMapInfoDictList:
            state = 0 # 默认关闭
            ipyData = None
            actNum = sendMapServerMsgDict.get(ShareDefine.ActKey_ActNum, 0)
            if actName in operationTodayActionDict:
                todayActInfoList = []
                if actName in ShareDefine.MultiActNumOperationActNameList:
                    if actNum in operationTodayActionDict[actName]:
                        todayActInfoList = operationTodayActionDict[actName][actNum]
                else:
                    todayActInfoList = operationTodayActionDict[actName]
                if isinstance(todayActInfoList, list) and len(todayActInfoList) == 4:
                    #startList = [] # [startDateTime, ...]
                    #endList = [] # [endDateTime, ...]
                    #notifyDict = {} # {notifyDateTime:[notifyKey, [参数]], ...}
                    #ipyData 可能为 None
                    ipyData, startList, endList, notifyDict = todayActInfoList
                    # ״̬
                    for dIndex, startDateTime in enumerate(startList):
                        endDateTime = endList[dIndex]
                        if startDateTime <= curDateTime < endDateTime:
                            state = dIndex + 1 # 代表第几个时间段
                            break
                    # 全服广播提示信息
                    if curDateTime in notifyDict:
                        notifyKey, paramList = notifyDict[curDateTime]
                        PlayerControl.WorldNotify(0, notifyKey, paramList)
            dictName = ChConfig.Def_WorldKey_OperationActionState % actName
            if actName in ShareDefine.MultiActNumOperationActNameList:
                dictName += "_%s" % actNum
            preState = gameWorld.GetDictByKey(dictName)
            if not isReload and preState == state:
                #已经是这个状态了
                continue
            GameWorld.Log("运营活动变更: actName=%s,actNum=%s,preState=%s,state=%s,dictName=%s" % (actName, actNum, preState, state, dictName))
            #更新字典值
            gameWorld.SetDict(dictName, state)
            dbOperationActIDKey = PlayerDBGSEvent.Def_OperationActID % actName
            dbOperationActWorldLVKey = PlayerDBGSEvent.Def_OActWorldLV % actName
            if actName in ShareDefine.MultiActNumOperationActNameList:
                dbOperationActIDKey += "_%s" % actNum
                dbOperationActWorldLVKey += "_%s" % actNum
                
            #此处为活动开启时
            if actName == ShareDefine.OperationActionName_BossReborn:
                #重置BOSS复活点
                GameWorldBoss.ResetBossRebornPoint()
            dbActID = PlayerDBGSEvent.GetDBGSTrig_ByKey(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))
                PlayerDBGSEvent.SetDBGSTrig_ByKey(dbOperationActIDKey, curActID)
                if curActID:
                    if actName in ShareDefine.NeedWorldLVOperationActNameList:
                        #记录开启时世界等级
                        worldLV = PlayerDBGSEvent.GetDBGSTrig_ByKey(ShareDefine.Def_Notify_WorldKey_WorldAverageLv)
                        PlayerDBGSEvent.SetDBGSTrig_ByKey(dbOperationActWorldLVKey, worldLV)
                        GameWorld.Log("    记录活动开启时世界等级: worldLV=%s" % (worldLV))
                    #此处为活动开启时
                    if actName == ShareDefine.OperationActionName_BossReborn:
                        #重置BOSS复活点
                        GameWorldBoss.ResetBossRebornPoint()
                    elif actName == ShareDefine.OperationActionName_FairyCeremony:
                        #重置仙界盛典
                        PlayerFairyCeremony.ResetFairyCeremony()
                    elif actName == ShareDefine.OperationActionName_NewFairyCeremony:
                        #重置仙界盛典
                        PlayerNewFairyCeremony.ResetNewFairyCeremony()
                    elif actName == ShareDefine.OperationActionName_FeastRedPacket:
                        #重置节日红包
                        if ipyData:
                            PlayerFamilyRedPacket.OnResetFeastRedPacket(ipyData, dayIndex)
                    elif actName == ShareDefine.OperationActionName_FlashSale:
                        #限时抢购重置购买次数 本次活动每场不能重复
                        #dayIndex = sendMapServerMsgDict.get(ShareDefine.ActKey_DayIndex, 0)
                        PlayerStore.ResetFlashSaleBuyCnt(ipyData)
            else:
                GameWorld.Log("    dbActID不变: dbActID=%s,curActID=%s" % (dbActID, curActID))
            if state and actName in ShareDefine.NeedWorldLVOperationActNameList:
                actWorldLV = PlayerDBGSEvent.GetDBGSTrig_ByKey(dbOperationActWorldLVKey)
                sendMapServerMsgDict[ShareDefine.ActKey_WorldLV] = actWorldLV
                GameWorld.Log("    活动世界等级: actWorldLV=%s" % (actWorldLV))
            if actName == ShareDefine.OperationActionName_ExpRate:
                if isReload and ipyData:
                    Sync_OperationAction_ExpRate(ipyData)
            elif actName == ShareDefine.OperationActionName_CostRebate:
                if isReload and ipyData:
                    pass
            elif actName == ShareDefine.OperationActionName_BossReborn:
                if isReload and ipyData:
                    GameWorldBoss.SetBossRebornNeedPoint(True)
            elif actName == ShareDefine.OperationActionName_FairyCeremony:
                #重置仙界盛典
                PlayerFairyCeremony.ResetFairyCeremony()
                if isReload and ipyData:
                    PlayerFairyCeremony.Sync_OperationAction_FairyCeremony(ipyData)
                if preState != state and state == 0:
                    PlayerFairyCeremony.OnFairyCeremonyEnd()
            elif actName == ShareDefine.OperationActionName_NewFairyCeremony:
                if isReload and ipyData:
                    PlayerNewFairyCeremony.Sync_OperationAction_NewFairyCeremony(ipyData)
                if preState != state and state == 0:
                    PlayerNewFairyCeremony.OnNewFairyCeremonyEnd()
            
            elif actName == ShareDefine.OperationActionName_RealmPoint:
                if isReload and ipyData:
                    Sync_OperationAction_RealmPoint(ipyData)
            elif actName == ShareDefine.OperationActionName_FeastRedPacket:
                if isReload and ipyData:
                    PlayerFamilyRedPacket.Sync_FeastRedPacket(ipyData)
            #通知Mapserver,设置字典
            #GameWorld.SendMapServerMsgEx(dictName, state) # 运营活动不单独通知活动状态,需与活动信息整合后一起通知
            
        if state == 1 and actName in ShareDefine.NeedWorldLVOperationActNameList:
            actWorldLV = PlayerDBGSEvent.GetDBGSTrig_ByKey(PlayerDBGSEvent.Def_OActWorldLV % actName)
            sendMapServerMsgDict[ShareDefine.ActKey_WorldLV] = actWorldLV
        if actName == ShareDefine.OperationActionName_ExpRate:
            if isReload and ipyData:
                Sync_OperationAction_ExpRate(ipyData)
        elif actName == ShareDefine.OperationActionName_CostRebate:
            if isReload and ipyData:
                pass
        elif actName == ShareDefine.OperationActionName_BossReborn:
            if isReload and ipyData:
                GameWorldBoss.SetBossRebornNeedPoint(True)
        elif actName == ShareDefine.OperationActionName_FairyCeremony:
            if isReload and ipyData:
                PlayerFairyCeremony.Sync_OperationAction_FairyCeremony(ipyData)
            if preState != state and state == 0:
                PlayerFairyCeremony.OnFairyCeremonyEnd()
        elif actName == ShareDefine.OperationActionName_RealmPoint:
            if isReload and ipyData:
                Sync_OperationAction_RealmPoint(ipyData)
        elif actName == ShareDefine.OperationActionName_FlashSale:
            if ipyData and preState != state:
                dayIndex = sendMapServerMsgDict.get(ShareDefine.ActKey_DayIndex, 0)
                PlayerStore.ResetFlashSaleBuyCnt(ipyData, dayIndex, state)
        #通知Mapserver,设置字典
        #GameWorld.SendMapServerMsgEx(dictName, state) # 运营活动不单独通知活动状态,需与活动信息整合后一起通知
        sendMapServerMsgDict[ShareDefine.ActKey_State] = state
        GameWorld.SendMapServerMsgEx(ShareDefine.Def_Notify_WorldKey_OperationActionInfo % actName, sendMapServerMsgDict)
        GameWorld.Log("运营活动变更: actName=%s,preState=%s,state=%s,dictName=%s, %s" % (actName, preState, state, dictName, sendMapServerMsgDict))
            sendMapServerMsgDict[ShareDefine.ActKey_State] = state
            GameWorld.SendMapServerMsgEx(ShareDefine.Def_Notify_WorldKey_OperationActionInfo % actName, sendMapServerMsgDict)
            GameWorld.Log("    sendMapServerMsgDict: %s" % (sendMapServerMsgDict))
            if actName in ShareDefine.MultiActNumOperationActNameList:
                mapServerInfoDict[actName][actNum] = sendMapServerMsgDict
            else:
                mapServerInfoDict[actName] = sendMapServerMsgDict
    return
def Sync_OperationAction_ExpRate(ipyData, curPlayer=None):
@@ -527,6 +870,7 @@
    multiRealmPointInfo.EndtDate = GameWorld.GetOperationActionDateStr(ipyData.GetEndDate(), openServerDay)
    multiRealmPointInfo.Multiple = ipyData.GetMultiple()
    multiRealmPointInfo.LimitLV = ipyData.GetLVLimit()
    multiRealmPointInfo.LimitPoint = ipyData.GetPointLimit()
    if not curPlayer:
        # 全服广播在线玩家
        playerManager = GameWorld.GetPlayerManager()
@@ -546,9 +890,12 @@
    # 获取本日待处理的日常活动信息
    key = "TodayDailyActionInfo"
    openServerDay = PlayerDBGSEvent.GetDBGSTrig_ByKey(PlayerDBGSEvent.Def_ServerDay) + 1
    isMixServer = PlayerDBGSEvent.GetDBGSTrig_ByKey(PlayerDBGSEvent.Def_IsMixServer)
    mixServerDay = PlayerDBGSEvent.GetDBGSTrig_ByKey(PlayerDBGSEvent.Def_MixServerDay) + 1
    loadSign = [openServerDay, isMixServer, mixServerDay]
    TodayDailyActionInfo = IpyGameDataPY.GetConfigEx(key)
    if TodayDailyActionInfo and TodayDailyActionInfo[0] == openServerDay:
        #GameWorld.DebugLog("已经加载过本日日常活动处理信息!openServerDay=%s" % openServerDay)
    if TodayDailyActionInfo and TodayDailyActionInfo[0] == loadSign:
        #GameWorld.DebugLog("已经加载过本日日常活动处理信息!loadSign=%s" % loadSign)
        return TodayDailyActionInfo[1]
    
    todayActionInfo = []
@@ -559,17 +906,21 @@
    curDateStr = GameWorld.ChangeTimeNumToStr(curTime, ChConfig.TYPE_Time_YmdFormat) # 当天日期
    
    openServerWeekday = GameWorldProcess.GetOpenServerWeekday() # 服务器开服时是星期几
    curMaxCustomServerDay = MaxCustomServerDay - openServerWeekday + 1 # 最大有效定制开服天
    curMaxCustomServerDay = IpyGameDataPY.GetFuncCfg("OperationAction", 1) - openServerWeekday + 1 # 最大有效定制开服天
    maxCustomServerDayMix = IpyGameDataPY.GetFuncCfg("MixServer", 1)
    GameWorld.Log("===== 加载今天日常活动信息 =====")
    GameWorld.Log("    开服是星期%s, 开服第%s天, 当前星期%s" % (openServerWeekday, openServerDay, weekDay))
    GameWorld.Log("    最大有效定制开服天: %s" % (curMaxCustomServerDay))
    GameWorld.Log("开服是星期%s, 开服第%s天, 当前星期%s" % (openServerWeekday, openServerDay, weekDay))
    GameWorld.Log("最大有效定制开服天: %s" % (curMaxCustomServerDay))
    GameWorld.Log("是否合服: %s, 合服天: %s, 最大定制合服天: %s" % (isMixServer, mixServerDay, maxCustomServerDayMix))
    
    customDailyIDList = []
    dailyTimeInfoList = []
    # 暂固定前2周定制有效, 为方便GM命令测试,这里用开服天做判断,不用开服周
    if openServerDay <= curMaxCustomServerDay:
        customIpyDataList = IpyGameDataPY.GetIpyGameDataListNotLog("DailyActionCustom", openServerWeekday)
        GameWorld.Log("    本周定制的日常活动条数: %s" % len(customIpyDataList))
        if not customIpyDataList:
            customIpyDataList = []
        GameWorld.Log("    本周定制的开服日常活动条数: %s" % len(customIpyDataList))
        customIDList = []
        todayCustomIDList = []
        for customIpyData in customIpyDataList:
@@ -580,12 +931,28 @@
            customIDList.append(dataID)
            if customIpyData.GetOpenServerDay() == openServerDay:
                todayCustomIDList.append(dataID)
                isCustom = True
                dailyTimeInfoList.append([isCustom, customIpyData.GetOpenTimeList(), customIpyData])
                GameWorld.Log("    增加本日日常活动信息: isCustom=%s,dailyID=%s,dataID=%s" % (isCustom, dailyID, dataID))
        GameWorld.Log("    本周定制的日常配置表ID列表: %s" % (customIDList))
        GameWorld.Log("    本周定制的日常活动ID列表: %s" % (customDailyIDList))
        GameWorld.Log("    今天定制的日常表ID列表=%s" % (todayCustomIDList))
                customType = 1
                dailyTimeInfoList.append([customType, customIpyData.GetOpenTimeList(), customIpyData])
                GameWorld.Log("    增加本日开服日常活动信息: customType=%s,dailyID=%s,dataID=%s" % (customType, dailyID, dataID))
        GameWorld.Log("    本周定制的开服日常配置表ID列表: %s" % (customIDList))
        GameWorld.Log("    本周定制的开服日常活动ID列表: %s" % (customDailyIDList))
        GameWorld.Log("    今天定制的开服日常表ID列表=%s" % (todayCustomIDList))
    elif isMixServer and mixServerDay <= maxCustomServerDayMix:
        todayCustomIDList = [] # 今天定制的数据表ID
        ipyDataMgr = IpyGameDataPY.IPY_Data()
        for i in xrange(ipyDataMgr.GetDailyActionCustomMixCount()):
            customIpyData = ipyDataMgr.GetDailyActionCustomMixByIndex(i)
            dataID = customIpyData.GetID()
            dailyID = customIpyData.GetDailyID()
            if dailyID not in customDailyIDList:
                customDailyIDList.append(dailyID)
            if customIpyData.GetMixServerDay() == mixServerDay:
                todayCustomIDList.append(dataID)
                customType = 2
                dailyTimeInfoList.append([customType, customIpyData.GetOpenTimeList(), customIpyData])
                GameWorld.Log("    增加本日合服日常活动信息: customType=%s,dailyID=%s,dataID=%s" % (customType, dailyID, dataID))
        GameWorld.Log("    定制的合服日常活动ID列表: %s" % (customDailyIDList))
        GameWorld.Log("    今天定制的合服日常表ID列表=%s" % (todayCustomIDList))
    else:
        GameWorld.Log("    超过最大定制开服天,不定制,走常规日常配置!")
    
@@ -613,10 +980,11 @@
            GameWorld.Log("    不是日常活动开启星期: dailyID=%s,openWeekLimit=%s" % (dailyID, openTimeDict.keys()))
            continue
        openTimeList = openTimeDict["0"] if "0" in openTimeDict else openTimeDict[weekDay]
        dailyTimeInfoList.append([False, openTimeList, dailyIpyData])
        customType = 0
        dailyTimeInfoList.append([customType, openTimeList, dailyIpyData])
        
    GameWorld.Log("    -----------------------")
    for isCustom, openTimeList, ipyData in dailyTimeInfoList:
    for customType, openTimeList, ipyData in dailyTimeInfoList:
        dailyID = ipyData.GetDailyID()
        notifyInfoDict = ipyData.GetNotifyInfo()
        
@@ -651,11 +1019,11 @@
                notifyDict[(notifyDateTime.hour, notifyDateTime.minute)] = notifyInfo
                
        todayActionInfo.append([dailyID, openList, overList, goonStateDict, notifyDict])
        GameWorld.Log("    增加本日日常活动信息: isCustom=%s,dailyID=%s,openList=%s,overList=%s,goonStateDict=%s,notifyDict=%s"
                      % (int(isCustom), dailyID, openList, overList, goonStateDict, notifyDict))
        GameWorld.Log("    增加本日限时日常活动信息: customType=%s,dailyID=%s,openList=%s,overList=%s,goonStateDict=%s,notifyDict=%s"
                      % (customType, dailyID, openList, overList, goonStateDict, notifyDict))
        
    TodayDailyActionInfo = IpyGameDataPY.SetConfigEx(key, [openServerDay, todayActionInfo])
    GameWorld.Log("本日日常活动信息加载完毕!")
    TodayDailyActionInfo = IpyGameDataPY.SetConfigEx(key, [loadSign, todayActionInfo])
    GameWorld.Log("本日日常活动信息加载完毕! loadSign=%s" % loadSign)
    GameWorld.Log("=============================================================")
    return TodayDailyActionInfo[1]
@@ -704,7 +1072,8 @@
                PlayerControl.WorldNotify(0, notifyKey, paramList)
                
        dictName = ShareDefine.Def_Notify_WorldKey_DailyActionState % dailyActionID
        if gameWorld.GetDictByKey(dictName) == state:
        beforeState = gameWorld.GetDictByKey(dictName)
        if beforeState == state:
            #已经是这个状态了
            continue
        
@@ -712,13 +1081,14 @@
            # 骑宠争夺活动开始前同步有效人数到地图
            if dailyActionID == ShareDefine.DailyActionID_FamilyRobBoss:
                GameWorldBoss.SyncMapServer_HorsePetRobBossPlayerCount()
                GameWorld.SendMapServerMsgEx(ShareDefine.Def_Notify_WorldKey_ActionBossRebornSign % dailyActionID, int(time.time()))
                
        #通知Mapserver,设置字典
        GameWorld.SendMapServerMsgEx(dictName, state)
        #更新字典值
        gameWorld.SetDict(dictName, state)
        GameWorld.Log("日常活动状态变更: dailyActionID=%s,state=%s,dictName=%s" % (dailyActionID, state, dictName))
        __DoLogic_GameServer_ActionState(dictName, state)
        __DoLogic_GameServer_ActionState(dictName, state, beforeState)
        
    return
@@ -765,7 +1135,7 @@
                    FBStateEndTimeNotResetIDList.append(dataID)
        FBStateEndTimeNotResetIDList.sort()
        
        # 加载定制表
        # 加载开服定制表
        customStateTimeDict = {}
        for i in xrange(ipyDataMgr.GetFBStateTimeCustomCount()):
            customIpyData = ipyDataMgr.GetFBStateTimeCustomByIndex(i)
@@ -788,18 +1158,45 @@
                    FBStateEndTimeNotResetCustomIDList.append(dataID)
        FBStateEndTimeNotResetCustomIDList.sort()
        
        notResetIDList = IpyGameDataPY.SetConfigEx(key, [FBStateEndTimeNotResetIDList, FBStateEndTimeNotResetCustomIDList])
        # 加载合服定制表
        customMixStateTimeDict = {}
        for i in xrange(ipyDataMgr.GetFBStateTimeCustomMixCount()):
            customIpyData = ipyDataMgr.GetFBStateTimeCustomMixByIndex(i)
            dataID = customIpyData.GetID()
            dataMapID = customIpyData.GetDataMapID()
            openMixDay = customIpyData.GetMixServerDay()
            startHour, startMinute = customIpyData.GetStartHour(), customIpyData.GetStartMinute()
            endHour, endMinute = customIpyData.GetEndHour(), customIpyData.GetEndMinute()
            startTimeList, endTimeDict = customMixStateTimeDict.get(dataMapID, [[], {}])
            startTimeList.append([openMixDay, startHour, startMinute])
            endTimeDict[dataID] = [openMixDay, endHour, endMinute]
            customMixStateTimeDict[dataMapID] = [startTimeList, endTimeDict]
        FBStateEndTimeNotResetCustomMixIDList = []
        for dataMapID, timeInfo in customMixStateTimeDict.items():
            startTimeList, endTimeDict = timeInfo
            for dataID, endTime in endTimeDict.items():
                # 结束时间属于某一条的开启时间,则不重置,具体状态由另一条决定
                if endTime in startTimeList:
                    FBStateEndTimeNotResetCustomMixIDList.append(dataID)
        FBStateEndTimeNotResetCustomMixIDList.sort()
        notResetIDList = IpyGameDataPY.SetConfigEx(key, [FBStateEndTimeNotResetIDList, FBStateEndTimeNotResetCustomIDList, FBStateEndTimeNotResetCustomMixIDList])
        GameWorld.Log("加载副本状态结束时间不需要重置状态值的数据ID列表:")
        GameWorld.Log("    不需要重置的常规ID: %s" % FBStateEndTimeNotResetIDList)
        GameWorld.Log("    不需要重置的定制ID: %s" % FBStateEndTimeNotResetCustomIDList)
        GameWorld.Log("    不需要重置的常规常规ID: %s" % FBStateEndTimeNotResetIDList)
        GameWorld.Log("    不需要重置的开服定制ID: %s" % FBStateEndTimeNotResetCustomIDList)
        GameWorld.Log("    不需要重置的合服定制ID: %s" % FBStateEndTimeNotResetCustomMixIDList)
    return notResetIDList
def __GetTodayFBStateTimeInfo():
    key = "TodayFBStateTimeInfo"
    openServerDay = PlayerDBGSEvent.GetDBGSTrig_ByKey(PlayerDBGSEvent.Def_ServerDay) + 1
    isMixServer = PlayerDBGSEvent.GetDBGSTrig_ByKey(PlayerDBGSEvent.Def_IsMixServer)
    mixServerDay = PlayerDBGSEvent.GetDBGSTrig_ByKey(PlayerDBGSEvent.Def_MixServerDay) + 1
    loadSign = [openServerDay, isMixServer, mixServerDay]
    TodayFBStateTimeInfo = IpyGameDataPY.GetConfigEx(key)
    if TodayFBStateTimeInfo and TodayFBStateTimeInfo[0] == openServerDay:
        #GameWorld.DebugLog("已经加载过本日副本状态处理信息!openServerDay=%s" % openServerDay)
    if TodayFBStateTimeInfo and TodayFBStateTimeInfo[0] == loadSign:
        #GameWorld.DebugLog("已经加载过本日副本状态处理信息!loadSign=%s" % loadSign)
        return TodayFBStateTimeInfo[1]
    
    openServerDay = PlayerDBGSEvent.GetDBGSTrig_ByKey(PlayerDBGSEvent.Def_ServerDay) + 1
@@ -811,10 +1208,12 @@
        GameWorld.ErrLog("获取开服是星期几数据错误!openServerWeekday=%s" % openServerWeekday)
        return []
    
    curMaxCustomServerDay = MaxCustomServerDay - openServerWeekday + 1 # 最大有效定制开服天
    curMaxCustomServerDay = IpyGameDataPY.GetFuncCfg("OperationAction", 1) - openServerWeekday + 1 # 最大有效定制开服天
    maxCustomServerDayMix = IpyGameDataPY.GetFuncCfg("MixServer", 1)
    GameWorld.Log("===== 加载今天副本状态时间表 =====")
    GameWorld.Log("    开服是星期%s, 开服第%s天, 当前星期%s,%s点%s分 !" % (openServerWeekday, openServerDay, curWeekDay, curHour, curMinute))
    GameWorld.Log("    最大有效定制开服天: %s" % (curMaxCustomServerDay))
    GameWorld.Log("开服是星期%s, 开服第%s天, 当前星期%s,%s点%s分 !" % (openServerWeekday, openServerDay, curWeekDay, curHour, curMinute))
    GameWorld.Log("最大有效定制开服天: %s" % (curMaxCustomServerDay))
    GameWorld.Log("是否合服: %s, 合服天: %s, 最大定制合服天: %s" % (isMixServer, mixServerDay, maxCustomServerDayMix))
    
    ipyDataMgr = IpyGameDataPY.IPY_Data()
    
@@ -823,7 +1222,9 @@
    # 暂固定前2周定制有效, 为方便GM命令测试,这里用开服天做判断,不用开服周
    if openServerDay <= curMaxCustomServerDay:
        customIpyDataList = IpyGameDataPY.GetIpyGameDataListNotLog("FBStateTimeCustom", openServerWeekday)
        GameWorld.Log("    本周定制的副本活动条数: %s" % len(customIpyDataList))
        if not customIpyDataList:
            customIpyDataList = []
        GameWorld.Log("    本周定制的开服副本活动条数: %s" % len(customIpyDataList))
        customIDList = [] # 本周定制的数据表ID
        todayCustomIDList = [] # 今天定制的数据表ID
        for customIpyData in customIpyDataList:
@@ -834,12 +1235,28 @@
            customIDList.append(dataID)
            if customIpyData.GetOpenServerDay() == openServerDay:
                todayCustomIDList.append(dataID)
                isCustom, startWeekDay, endWeekDay = True, curWeekDay, curWeekDay
                fbStateTimeInfoList.append([isCustom, startWeekDay, endWeekDay, customIpyData])
                GameWorld.Log("    今天要处理的副本状态配置: 是否定制=%s,dataID=%s" % (isCustom, dataID))
        GameWorld.Log("    本周定制的配置表ID列表: %s" % (customIDList))
        GameWorld.Log("    本周定制的副本地图列表: %s" % (customMapIDList))
        GameWorld.Log("    今天定制的表ID列表=%s" % (todayCustomIDList))
                customType, startWeekDay, endWeekDay = 1, curWeekDay, curWeekDay
                fbStateTimeInfoList.append([customType, startWeekDay, endWeekDay, customIpyData])
                GameWorld.Log("    今天要处理的开服副本状态配置: customType=%s,dataID=%s" % (customType, dataID))
        GameWorld.Log("    本周定制的开服副本表ID列表: %s" % (customIDList))
        GameWorld.Log("    本周定制的开服副本地图列表: %s" % (customMapIDList))
        GameWorld.Log("    今天定制的开服副本表ID列表=%s" % (todayCustomIDList))
    elif isMixServer and mixServerDay <= maxCustomServerDayMix:
        todayCustomIDList = [] # 今天定制的数据表ID
        ipyDataMgr = IpyGameDataPY.IPY_Data()
        for i in xrange(ipyDataMgr.GetFBStateTimeCustomMixCount()):
            customIpyData = ipyDataMgr.GetFBStateTimeCustomMixByIndex(i)
            dataID = customIpyData.GetID()
            dataMapID = customIpyData.GetDataMapID()
            if dataMapID not in customMapIDList:
                customMapIDList.append(dataMapID)
            if customIpyData.GetMixServerDay() == mixServerDay:
                todayCustomIDList.append(dataID)
                customType, startWeekDay, endWeekDay = 2, curWeekDay, curWeekDay
                fbStateTimeInfoList.append([customType, startWeekDay, endWeekDay, customIpyData])
                GameWorld.Log("    今天要处理的合服副本状态配置: customType=%s,dataID=%s" % (customType, dataID))
        GameWorld.Log("    定制的合服副本地图列表: %s" % (customMapIDList))
        GameWorld.Log("    今天定制的合服副本表ID列表=%s" % (todayCustomIDList))
    else:
        GameWorld.Log("    超过最大定制开服天,不定制,走常规副本状态时间!")
        
@@ -853,43 +1270,43 @@
            GameWorld.Log("    dataID=%s,dataMapID=%s, 在本周定制的副本地图列表里,不处理!" % (dataID, dataMapID))
            continue
        # 暂不支持跨天的活动
        isCustom, startWeekDay, endWeekDay = False, fbStateTimeIpyData.GetStartWeekday(), fbStateTimeIpyData.GetStartWeekday()
        customType, startWeekDay, endWeekDay = 0, fbStateTimeIpyData.GetStartWeekday(), fbStateTimeIpyData.GetStartWeekday()
        if curWeekDay != startWeekDay:
            GameWorld.Log("    dataID=%s,dataMapID=%s, 不是本天的副本活动,不处理!curWeekDay=%s,startWeekDay=%s"
            GameWorld.Log("    dataID=%s,dataMapID=%s, 不是本天的副本活动,不处理! curWeekDay=%s,startWeekDay=%s"
                          % (dataID, dataMapID, curWeekDay, startWeekDay))
            continue 
        fbStateTimeInfoList.append([isCustom, startWeekDay, endWeekDay, fbStateTimeIpyData])
        GameWorld.Log("    今天要处理的副本状态配置: 是否定制=%s,dataID=%s" % (isCustom, dataID))
        fbStateTimeInfoList.append([customType, startWeekDay, endWeekDay, fbStateTimeIpyData])
        GameWorld.Log("    今天要处理的副本状态配置: customType=%s,dataID=%s" % (customType, dataID))
        
    TodayFBStateTimeInfo = IpyGameDataPY.SetConfigEx(key, [openServerDay, fbStateTimeInfoList])
    GameWorld.Log("本日副本活动状态信息加载完毕!")
    TodayFBStateTimeInfo = IpyGameDataPY.SetConfigEx(key, [loadSign, fbStateTimeInfoList])
    GameWorld.Log("本日副本活动状态信息加载完毕! loadSign=%s" % loadSign)
    GameWorld.Log("=============================================================")
    return TodayFBStateTimeInfo[1]
def Dispose_FBStateTime():
    ## 副本状态时间表状态处理, 支持 goon作用,开关服状态不受影响,服务器重新启动会自动变更为所有时间段的状态值
    
    FBStateEndTimeNotResetIDList, FBStateEndTimeNotResetCustomIDList = __GetFBStateEndTimeNotResetIDList()
    openServerDay = PlayerDBGSEvent.GetDBGSTrig_ByKey(PlayerDBGSEvent.Def_ServerDay) + 1
    FBStateEndTimeNotResetIDList, FBStateEndTimeNotResetCustomIDList, FBStateEndTimeNotResetCustomMixIDList = __GetFBStateEndTimeNotResetIDList()
    #openServerDay = PlayerDBGSEvent.GetDBGSTrig_ByKey(PlayerDBGSEvent.Def_ServerDay) + 1
    curDateTime = GameWorld.GetServerTime()
    curWeekDay, curHour, curMinute = curDateTime.weekday() + 1, curDateTime.hour, curDateTime.minute
    
    curTimeWHM = curWeekDay * 10000 + curHour * 100 + curMinute
    
    openServerWeekday = GameWorldProcess.GetOpenServerWeekday() # 服务器开服时是星期几
    GameWorld.DebugLog("副本状态时间表状态处理...开服是星期%s, 开服第%s天, 当前星期%s,%s点%s分"
                       % (openServerWeekday, openServerDay, curWeekDay, curHour, curMinute))
    GameWorld.DebugLog("    FBStateEndTimeNotResetIDList=%s" % (FBStateEndTimeNotResetIDList))
    GameWorld.DebugLog("    FBStateEndTimeNotResetCustomIDList=%s" % (FBStateEndTimeNotResetCustomIDList))
    #openServerWeekday = GameWorldProcess.GetOpenServerWeekday() # 服务器开服时是星期几
    #GameWorld.DebugLog("副本状态时间表状态处理...开服是星期%s, 开服第%s天, 当前星期%s,%s点%s分"
    #                   % (openServerWeekday, openServerDay, curWeekDay, curHour, curMinute))
    #GameWorld.DebugLog("    FBStateEndTimeNotResetIDList=%s" % (FBStateEndTimeNotResetIDList))
    #GameWorld.DebugLog("    FBStateEndTimeNotResetCustomIDList=%s" % (FBStateEndTimeNotResetCustomIDList))
    #GameWorld.DebugLog("    FBStateEndTimeNotResetCustomMixIDList=%s" % (FBStateEndTimeNotResetCustomMixIDList))
    
    gameWorld = GameWorld.GetGameWorld()
    fbStateTimeInfoList = __GetTodayFBStateTimeInfo()
    
    for isCustom, startWeekDay, endWeekDay, ipyData in fbStateTimeInfoList:
    for customType, startWeekDay, endWeekDay, ipyData in fbStateTimeInfoList:
        dataID = ipyData.GetID()
        dataMapID = ipyData.GetDataMapID()
        GameWorld.DebugLog("    isCustom=%s,dataID=%s,dataMapID=%s" % (isCustom, dataID, dataMapID))
        #GameWorld.DebugLog("    customType=%s,dataID=%s,dataMapID=%s" % (customType, dataID, dataMapID))
        startHour, startMinute = ipyData.GetStartHour(), ipyData.GetStartMinute()
        endHour, endMinute = ipyData.GetEndHour(), ipyData.GetEndMinute()
        # 星期配置0代表每天
@@ -922,7 +1339,9 @@
            #GameWorld.DebugLog("        当前是开始时间!")
        # 是结束时间
        elif curTimeWHM == endTimeWHM:
            if (isCustom and dataID not in FBStateEndTimeNotResetCustomIDList) or (not isCustom and dataID not in FBStateEndTimeNotResetIDList):
            if (customType == 1 and dataID not in FBStateEndTimeNotResetCustomIDList) \
                or (customType == 2 and dataID not in FBStateEndTimeNotResetCustomMixIDList) \
                or (not customType and dataID not in FBStateEndTimeNotResetIDList):
                isReset = True
            #GameWorld.DebugLog("        当前是结束时间! isReset=%s,FBStateEndTimeNotResetIDList=%s" % (isReset, FBStateEndTimeNotResetIDList))
        # 结束时间是下周
@@ -954,11 +1373,12 @@
        #    GameWorld.DebugLog("        副本可否进入已经是该值: dataMapID=%s,updCanEnter=%s,canEnterKey=%s" % (dataMapID, updCanEnter, canEnterKey))            
            
        fbFuncStateKey = ShareDefine.Def_Notify_WorldKey_FBFuncState % dataMapID
        if gameWorld.GetDictByKey(fbFuncStateKey) != updStateValue:
        beforeState = gameWorld.GetDictByKey(fbFuncStateKey)
        if beforeState != updStateValue:
            GameWorld.SendMapServerMsgEx(fbFuncStateKey, updStateValue) #通知Mapserver,设置字典
            gameWorld.SetDict(fbFuncStateKey, updStateValue) #更新字典值
            GameWorld.Log("副本状态变更: dataMapID=%s,updStateValue=%s,fbFuncStateKey=%s" % (dataMapID, updStateValue, fbFuncStateKey))
            __DoLogic_GameServer_ActionState(fbFuncStateKey, updStateValue)
            __DoLogic_GameServer_ActionState(fbFuncStateKey, updStateValue, beforeState)
        #else:
        #    GameWorld.DebugLog("        副本状态已经是该值: dataMapID=%s,updStateValue=%s,fbFuncStateKey=%s" % (dataMapID, updStateValue, fbFuncStateKey))
            
@@ -1047,87 +1467,6 @@
    GameWorld.SendMapServerMsgEx(ShareDefine.Def_Notify_WorldKey_FBOpenRecord, fbOpenRecord)
    return
## 处理重开服务器后, 活动继续开启逻辑根据天数
#  @param tick 当前时间
#  @return None
def Dispose_Action_GoOn_ByDay(tick):
    #已固定在每整分钟触发,故暂不需要时间间隔控制
    #if not GameWorld.SetWorldDictKey(ChConfig.TYPE_ActionOpenAndCloseByDayCountGoOn, tick):
    #    #间隔未到
    #    return
    if GameWorld.IsMergeServer():
        return
    Dispose_ActionGoOnByDayKey()
    return
## 设定上次开启活动时间距离现在天数事件
#  @param None:
#  @return: None
def DoLogic_ServerLastOpenActionDay():
    #是跨服服务器
    if GameWorld.IsMergeServer():
        if not PlayerDBGSEvent.GetDBGSTrig_ByKey(PlayerDBGSEvent.Def_MergeServerOpenActionDay):
            return
        PlayerDBGSEvent.SetDBGSTrig_ServerTime(PlayerDBGSEvent.Def_MergeServerOpenActionDay)
        #通知子服务器天数
        SendBroadcastMergeOpenActionDay()
        return
    DoLogic_ActionByDayKeyOnDay()
    #上次开启活动时间距离现在天数
    lastOpenActionDay = PlayerDBGSEvent.GetDBGSTrig_ByKey(PlayerDBGSEvent.Def_ServerLastOpenActionDay)
    openServerDay = PlayerDBGSEvent.GetDBGSTrig_ByKey(PlayerDBGSEvent.Def_ServerDay)
    initDayList = ReadChConfig.GetEvalChConfig('ActionControlByDayInitOpenServerDay')
    if openServerDay < initDayList[0]:
        #开服时间未超过30天
        return
    #新一轮活动从头开始
    if lastOpenActionDay >= initDayList[1] or openServerDay == initDayList[2]:
        NewRingOpenActionDay()
        return
    PlayerDBGSEvent.SetDBGSTrig_ServerTime(PlayerDBGSEvent.Def_ServerLastOpenActionDay)
    return
## 新一轮活动开始
#  @param None:
#  @return:
def NewRingOpenActionDay():
    #设置字典值从1开始, 跟SetDBGSTrig_ServerTime接口同步
    PlayerDBGSEvent.SetDBGSTrig_ByKey(PlayerDBGSEvent.Def_ServerLastOpenActionDay, 1)
    # 活动天数重设
    OpenActionDay_Reset()
    return
#------------------------------------------------------------------------------
## 活动天数重设
#  @param None
#  @return None
def OpenActionDay_Reset():
    # 设置国王战开始
    #PlayerDBGSEvent.SetDBGSTrig_ByKey(PlayerDBGSEvent.Def_MergeWarStart, 1)
    return
### 检查key是否处理
#def __CheckIsProcessDictName(dictName):
#
#    # 非跨服服务器不处理某些key
#    if dictName in [ShareDefine.Def_Notify_WorldKey_Merge_King] and not GameWorld.IsMergeServer():
#        return False
#
#    return True
## 当前时间与指定时间比较
#  @param curTime 当前服务器时间 
#  @param timeInfo 指定时间 [[3,4(星期几)], 年,月,日,时,分] 
@@ -1185,36 +1524,13 @@
##处理GameServer活动状态
# @param dictName 字典名
# @param isOpen 是否开启
# @param beforeState 状态变更前的值,部分判断处理
# @return 返回值无意义
# @remarks 
def __DoLogic_GameServer_ActionState(dictName, isOpen):
    #===============================================================================================
    # #领地争夺战
    # if dictName == ShareDefine.Def_Notify_WorldKey_ManorWar:
    #    PlayerManorWar.ManorWar_ChangeState(isOpen)
    # #跨服boss
    # elif dictName == ShareDefine.Def_Notify_WorldKey_MergeBoss:
    #    GameWorldMergeBoss.MergeBoss_ChangeState(isOpen)
    # #跨服PK
    # elif dictName == ShareDefine.Def_Notify_WorldKey_Merge_PK:
    #    GameWorldMergePK.OnMergePKMatchStateChange(isOpen)
    # #跨服王者争霸
    # elif dictName == ShareDefine.Def_Notify_WorldKey_Merge_King:
    #    GameWorldMergeKing.OnMergeKingStateChange(isOpen)
    # #答题活动
    # elif dictName == ShareDefine.Def_Notify_WorldKey_Game_EXAM:
    #    PlayerExam.Exam_ChangeState(isOpen)
    # #特惠活动
    # elif dictName in ShareDefine.TeHuiTypeKeyDict.values():
    #    GameWorldActionTeHui.OnTeHuiActionChange(dictName, isOpen)
    # #商店状态变更
    # elif dictName.startswith(ShareDefine.Def_Notify_WorldKey_ShopState[:-2]):
    #    GameWorldShopItem.OnShopStateChange(dictName, isOpen)
    #===============================================================================================
def __DoLogic_GameServer_ActionState(dictName, isOpen, beforeState=0):
    #仙盟宴会 
    if dictName == ShareDefine.Def_Notify_WorldKey_FBFuncState % ChConfig.Def_FBMapID_FamilyParty:
        PlayerFamilyParty.FamilyPartyStateChange(isOpen)
    if dictName == ShareDefine.Def_Notify_WorldKey_DailyActionState % ShareDefine.DailyActionID_FamilyParty:
        PlayerFamilyParty.FamilyPartyStateChange(isOpen, beforeState)
    #仙盟联赛
    elif dictName == ShareDefine.Def_Notify_WorldKey_FBFuncState % ChConfig.Def_FBMapID_FamilyWar:
        GameWorldFamilyWar.OnFamilyWarStateChange(isOpen)
@@ -1227,215 +1543,16 @@
    #骑宠争夺
    elif dictName == ShareDefine.Def_Notify_WorldKey_DailyActionState % ShareDefine.DailyActionID_FamilyRobBoss:
        GameWorldBoss.OnHorsePetRobBossActionChange(isOpen)
    return
#------------------------------------------------------------------------------
## 通知子服务器天数
#  @param param: None
#  @return: None
def SendBroadcastMergeOpenActionDay():
    mergeServerOpenActionDay = PlayerDBGSEvent.GetDBGSTrig_ByKey(PlayerDBGSEvent.Def_MergeServerOpenActionDay)
    MergeBroadcast.SendBroadcastMerge(ChConfig.Def_MergeServerOpenActionDay, 0, {"Day":mergeServerOpenActionDay})
    #跨服PK
    elif dictName == ShareDefine.Def_Notify_WorldKey_DailyActionState % ShareDefine.DailyActionID_CrossReamPK:
        CrossRealmPK.OnCrossRealmPKDailyActionStateChange(isOpen)
    #仙盟BOSS
    elif dictName in [ShareDefine.Def_Notify_WorldKey_DailyActionState % ShareDefine.DailyActionID_FamilyBoss1]:
        PlayerFamilyBoss.OnAllFamilyBossStateChange(isOpen)
    #骑宠BOSS
    elif dictName in [ShareDefine.Def_Notify_WorldKey_DailyActionState % ShareDefine.DailyActionID_HorsePetBoss]:
        PlayerHorsePetBoss.OnHorsePetBossStateChange(isOpen)
    return
#-------------------------------------------------------------------------------
## 根据活动开启的活动事件OnDay
#  @param None:
#  @return: None
def DoLogic_ActionByDayKeyOnDay():
    openServerDay = PlayerDBGSEvent.GetDBGSTrig_ByKey(PlayerDBGSEvent.Def_ServerDay)
    isMixServer = PlayerDBGSEvent.GetDBGSTrig_ByKey(PlayerDBGSEvent.Def_IsMixServer)
    mixServerDay = PlayerDBGSEvent.GetDBGSTrig_ByKey(PlayerDBGSEvent.Def_MixServerDay)
    repeatDayInfo = ReadChConfig.GetEvalChConfig('ActionControlByDayKeyRepeat')
    startRepeatOpenDay, startRepeatMixDay, repeatList = repeatDayInfo
    # 不是循环阶段
    if openServerDay < startRepeatOpenDay or (isMixServer and mixServerDay < startRepeatMixDay):
        GameWorld.Log("没有正式进入周期循环,不处理!")
        return
    Def_RepeatOrderKey = PlayerDBGSEvent.Def_TeHuiRepeatOrderKey
    Def_RepeatNumKey = PlayerDBGSEvent.Def_TeHuiRepeatNumKey
    # 强制更新一次世界等级
    GameWorldAverageLv.OpenWorldAverageLv()
    repeatOrder = PlayerDBGSEvent.GetDBGSTrig_ByKey(Def_RepeatOrderKey)
    repeatOrder = "" if not repeatOrder else str(repeatOrder)
    preRepeatNum = PlayerDBGSEvent.GetDBGSTrig_ByKey(Def_RepeatNumKey)
    preRepeatNum = "" if not preRepeatNum else str(preRepeatNum)
    worldAverageLV = PlayerDBGSEvent.GetDBGSTrig_ByKey(ShareDefine.Def_Notify_WorldKey_WorldAverageLv)
    GameWorld.Log("处理周期循环: openServerDay=%s,isMixServer=%s,mixServerDay=%s" % (openServerDay, isMixServer, mixServerDay))
    GameWorld.Log("    startRepeatOpenDay=%s,startRepeatMixDay=%s,repeatOrder=%s,preRepeatNum=%s,worldAverageLV=%s"
                  % (startRepeatOpenDay, startRepeatMixDay, repeatOrder, preRepeatNum, worldAverageLV))
    # 开始循环
    if openServerDay == startRepeatOpenDay or (isMixServer and mixServerDay == startRepeatMixDay):
        repeatOrder = ""
        for i, repeatInfo in enumerate(repeatList, 1):
            if i > 9:
                break
            needWorldAverageLV = repeatInfo[0]
            if worldAverageLV < needWorldAverageLV:
                continue
            repeatOrder = "%s%s" % (repeatOrder, i)
        PlayerDBGSEvent.SetDBGSTrig_ByKey(Def_RepeatOrderKey, GameWorld.ToIntDef(repeatOrder))
        GameWorld.Log("    开始循环, 生成循环编号顺序: %s" % repeatOrder)
    # 还没全部开始循环,则判断是否有动态新插入的循环
    elif len(repeatOrder) < len(repeatList):
        GameWorld.Log("    还没全部开始循环,判断是否有动态新插入的循环..")
        for i, repeatInfo in enumerate(repeatList, 1):
            if i > 9:
                break
            if str(i) in repeatOrder: # 已经在循环里的不处理
                continue
            needWorldAverageLV = repeatInfo[0]
            if worldAverageLV < needWorldAverageLV:
                continue
            # 插入新循环
            if preRepeatNum in repeatOrder:
                insertIndex = repeatOrder.index(preRepeatNum)
                repeatOrder = repeatOrder[:insertIndex + 1] + str(i) + repeatOrder[insertIndex + 1:]
            else:
                repeatOrder = str(i)
            PlayerDBGSEvent.SetDBGSTrig_ByKey(Def_RepeatOrderKey, GameWorld.ToIntDef(repeatOrder))
            GameWorld.Log("        编号%s, needWorldAverageLV=%s,插入循环,更新循环编号顺序: %s" % (i, needWorldAverageLV, repeatOrder))
            break
    if not repeatOrder:
        GameWorld.Log("    没有可循环的活动!")
        return
    # 进入下一天循环编号
    if preRepeatNum and preRepeatNum in repeatOrder:
        nextRepeatIndex = repeatOrder.index(preRepeatNum) + 1
        nextRepeatIndex = 0 if nextRepeatIndex >= len(repeatOrder) else nextRepeatIndex
    else:
        nextRepeatIndex = 0
    nextRepeatNum = GameWorld.ToIntDef(repeatOrder[nextRepeatIndex])
    PlayerDBGSEvent.SetDBGSTrig_ByKey(Def_RepeatNumKey, nextRepeatNum)
    if nextRepeatNum <= 0 or nextRepeatNum > len(repeatList):
        GameWorld.Log("    下一个循环编号错误!nextRepeatNum=%s" % nextRepeatNum)
        return
    GameWorld.Log("    过天变更循环活动状态, nextRepeatNum=%s" % nextRepeatNum)
    gameWorld = GameWorld.GetGameWorld()
    nextRepeatDict = repeatList[nextRepeatNum - 1][1]
    for dictName, signID in nextRepeatDict.items():
        # 已经是这个值不处理
        if gameWorld.GetDictByKey(dictName) == signID:
            #GameWorld.DebugLog("    已经是这个值不处理dictName=%s,signID=%s"  % (dictName,signID))
            continue
        # 默认当前的0点开始到当天的23点59分
        curDay, beginDay, beginH, beginM, endDay, endH, endM = 0, 0, 0, 0, 0, 23, 59
        __ChangeDA_ActionSign(gameWorld, dictName, signID, curDay, beginDay, beginH, beginM, endDay, endH, endM)
    return
## 处理重开服务器后, 活动继续开启逻辑根据天数key
#  @param None
#  @return None
def Dispose_ActionGoOnByDayKey():
    if GameWorld.IsMergeServer():
        return
    GameWorld.DebugLog("处理特惠状态信息...")
    openServerDay = PlayerDBGSEvent.GetDBGSTrig_ByKey(PlayerDBGSEvent.Def_ServerDay)
    isMixServer = PlayerDBGSEvent.GetDBGSTrig_ByKey(PlayerDBGSEvent.Def_IsMixServer)
    mixServerDay = PlayerDBGSEvent.GetDBGSTrig_ByKey(PlayerDBGSEvent.Def_MixServerDay)
    allActionGoOnInfo = ReadChConfig.GetEvalChConfig("ActionControlByDayKeyGoOn")
    if not isMixServer:
        __DoActionGoOnByDayKeyCheck(allActionGoOnInfo[0], openServerDay)
    else:
        __DoActionGoOnByDayKeyCheck(allActionGoOnInfo[1], mixServerDay)
    return
## 按天开启可循环活动检查
#  @param controlList:
#  @return: None
def __DoActionGoOnByDayKeyCheck(goOnList, curDay):
    curTime = GameWorld.GetServerTime()
    gameWorld = GameWorld.GetGameWorld()
    for goOnControl in goOnList:
        beginDay, beginH, beginM = goOnControl[0]
        endDay, endH, endM = goOnControl[1]
        if curDay < beginDay or curDay > endDay:
            #活动不在这一时间段
            #GameWorld.DebugLog("活动不在这一时间段curDay=%s < beginDay=%s or curDay > endDay=%s"
            #                   % (curDay,beginDay,endDay))
            continue
        dictName = goOnControl[2]  # 字典名
        signID = goOnControl[3]  # 标记
        # 已经是这个值不处理
        if gameWorld.GetDictByKey(dictName) == signID:
            #GameWorld.DebugLog("已经是这个值不处理dictName=%s,signID=%s"  % (dictName,signID))
            continue
        beginTime = ['-', '-', '-', '-', beginH, beginM]
        endTime = ['-', '-', '-', '-', endH, endM]
        #还没开始
        if curDay == beginDay and CompareActTime(curTime, beginTime) == ChConfig.Def_Cmp_Lower:
            #GameWorld.DebugLog("还没开始...")
            continue
        #已经结束
        if curDay == endDay and CompareActTime(curTime, endTime) == ChConfig.Def_Cmp_Greater:
            #GameWorld.DebugLog("已经结束...")
            continue
        __ChangeDA_ActionSign(gameWorld, dictName, signID, curDay, beginDay, beginH, beginM, endDay, endH, endM)
    return
def __ChangeDA_ActionSign(gameWorld, dictName, signID, curDay, beginDay, beginH, beginM, endDay, endH, endM):
    # 计算开始及结束日期
    beginTime, endTime = GetBeginEndTimeByDay(dictName, curDay, beginDay, beginH, beginM, endDay, endH, endM)
    actionID = int(time.time())
    GameWorld.Log('活动状态变更: dictName=%s,signID=%s,beginTime=%s,endTime=%s,actionID=%s'
                  % (dictName, signID, beginTime, endTime, actionID))
    #潜规则:在ChConfig活动相关设置中,提取了字典名
    gameWorld.SetDict(dictName, signID)
    gameWorld.SetDict(ShareDefine.Def_Notify_WorldKey_DayAction_BeginTime % dictName, beginTime)
    gameWorld.SetDict(ShareDefine.Def_Notify_WorldKey_DayAction_EndTime % dictName, endTime)
    # 标记活动唯一id
    actionIDKey = ShareDefine.Def_Notify_WorldKey_DayAction_ID % dictName
    gameWorld.SetDict(actionIDKey, actionID)
    #通知Mapserver,设置字典
    GameWorld.SendMapServerMsgEx(actionIDKey, actionID)
    GameWorld.SendMapServerMsgEx(dictName, signID)
    #处理GameServer活动逻辑
    __DoLogic_GameServer_ActionState(dictName, signID)
    return
## 获取开启结束时间
#  @param tick
#  @return None
def GetBeginEndTimeByDay(dictName, curDay, beginDay, beginH, beginM, endDay, endH, endM):
    beginDiffDays = max(0, curDay - beginDay)
    beginDateTime = GameWorld.GetDatetimeBySubDays(beginDiffDays)
    beginDateTimeStr = str(beginDateTime).split(".")[0]
    beginDateTimeStr = "%s %02d:%02d:00" % (beginDateTimeStr[:10], beginH, beginM)
    beginTimeNum = GameWorld.ChangeTimeStrToNum(beginDateTimeStr, ChConfig.TYPE_Time_Format)
    endDiffDays = max(0, endDay - curDay)
    endDateTime = GameWorld.GetDatetimeByDiffDays(endDiffDays)
    endDateTimeStr = str(endDateTime).split(".")[0]
    endDateTimeStr = "%s %02d:%02d:59" % (endDateTimeStr[:10], endH, endM)
    endTimeNum = GameWorld.ChangeTimeStrToNum(endDateTimeStr, ChConfig.TYPE_Time_Format)
    return beginTimeNum, endTimeNum