From cc1dc60daab5a6a9c2f1aa23c10736af2227d521 Mon Sep 17 00:00:00 2001
From: hxp <ale99527@vip.qq.com>
Date: 星期四, 04 三月 2021 14:05:52 +0800
Subject: [PATCH] 8650 【主干】【BT2】活动规则优化(多活动支持的改为单表模式,增加活动分组编号字段区分不同的活动编号;常规活动改为不受合服影响,合服活动独立出来;累计充值活动、集字活动适配为新模式);

---
 ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/GameWorldActionControl.py |  743 ++++++++++++++++++++++++++++++++++----------------------
 1 files changed, 451 insertions(+), 292 deletions(-)

diff --git a/ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/GameWorldActionControl.py b/ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/GameWorldActionControl.py
index 087a71b..efd3f40 100644
--- a/ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/GameWorldActionControl.py
+++ b/ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/GameWorldActionControl.py
@@ -116,16 +116,40 @@
         # 如果是重读的,则在内层已经同步了,此处不重复同步
         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
@@ -150,8 +174,9 @@
     startDateInCustomCanOpenList = IpyGameDataPY.GetFuncEvalCfg("OperationAction", 2) # 开始天在定制天内在定制天结束后可继续开启的活动列表
     customMaxServerDay = IpyGameDataPY.GetFuncCfg("OperationAction", 1) # 定制运营活动最大开服天
     maxCustomServerDayMix = IpyGameDataPY.GetFuncCfg("MixServer", 1) # 定制运营活动最大合服天
-    operationActionDict = {}
+    operationTodayActionDict = {}
     mapServerOperationActionDict = {}
+    platform = GameWorld.GetPlatform()
     serverGroupID = GameWorld.GetServerGroupID()
     ipyDataMgr = IpyGameDataPY.IPY_Data()
     curWeekday = curDateTime.weekday() + 1 # 今天星期几, 1代表星期1
@@ -162,51 +187,103 @@
     
     for actName in ShareDefine.OperationActionNameList:
         
+        if actName not in mapServerOperationActionDict:
+            mapServerOperationActionDict[actName] = {}
+            
         # 取出本活动所属本服ID的所有配置
-        GameWorld.Log("加载运营活动: actName=%s" % (actName))
-        curServerActIpyDataList = __GetOperationActionServerIpyDataList(ipyDataMgr, serverGroupID, actName)
+        GameWorld.Log("加载运营活动: actName=%s,platform=%s,serverGroupID=%s" % (actName, platform, serverGroupID))
+        curServerActIpyDataList = __GetOperationActionServerIpyDataList(ipyDataMgr, platform, serverGroupID, actName)
         GameWorld.Log("    可处理条数=%s" % (len(curServerActIpyDataList)))
-        disableWeekIpyDataInfo, customOpenServerDayState, customMixServerDayState = __GetOperationActionDisableWeekIpyDataInfo(actName, curDateTime, curServerActIpyDataList)
-        GameWorld.Log("    是否有配开服天活动=%s, 是否有配合服天活动=%s" % (customOpenServerDayState, customMixServerDayState))
-        needStartList = [] # [startDateTime, ...]
-        needEndList = [] # [endDateTime, ...]
-        needNotifyDict = {} # {notifyDateTime:[notifyKey, [参数]], ...}
-        activityIpyData = None # 活动中的的配置,取需要处理的配置中开始时间最晚的,反之开关时间头尾相连的时候无法开启后面的活动
-        # 注意:每个活动配置会有多个活动时间点,但是有且只能生效一条活动配置,换句话说就是每个活动配置时间不允许交叉
+        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,serverGroupIDList=%s,Except=%s,startDateStr=%s,endDateStr=%s,openServerDay=%s,isMixServer=%s,mixServerDay=%s,maxCustomServerDayMix=%s,curDateTime=%s" 
-                          % (cfgID, serverGroupIDList, serverGroupIDListExcept, startDateStr, endDateStr, openServerDay, isMixServer, mixServerDay, maxCustomServerDayMix, curDateTime))
-            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
+            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)
-            # 活动优先级为   开服天=合服天>运营日期>运营周天
-            # 按开服天开的
-            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))
+                
+            # 开服常规:  开服天 > 日期 > 周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))
-                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 startDateStr.startswith("Mix") and endDateStr.startswith("Mix"):
+                
+            # 合服活动: 只受合服天影响
+            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
@@ -215,47 +292,22 @@
                 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))
+                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:
-                if startDateStr.startswith("W") and endDateStr.startswith("W"):
-                    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))
-                    
-                if actName not in ShareDefine.FeastOperationActionNameList:
-                    if customOpenServerDayState and openServerDay <= customMaxServerDay:
-                        GameWorld.Log("        按日期/周开的在开服定制限制天内,不处理! cfgID=%s,%s ~ %s,openServerDay=%s" % (cfgID, startDateStr, endDateStr, openServerDay))
-                        continue
-                    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 customOpenServerDayState and curServerOpenDateTime <= curStartDateTime <= customMaxServerDateTime:
-                        if actName not in startDateInCustomCanOpenList:
-                            GameWorld.Log("        按日期/周开的开始日期在开服定制限制天内,不处理! cfgID=%s,curServerOpenDateTime=%s<=curStartDateTime=%s<=customMaxServerDateTime=%s" % (cfgID, curServerOpenDateTime, curStartDateTime, customMaxServerDateTime))
-                            continue
-                    
-                    if isMixServer:
-                        if customMixServerDayState and mixServerDay <= maxCustomServerDayMix:
-                            GameWorld.Log("        按日期/周开的在合服定制限制天内,不处理! cfgID=%s,%s ~ %s,mixServerDay=%s" % (cfgID, startDateStr, endDateStr, mixServerDay))
-                            continue
-                        mixStartServerDateTime = curDateTime + datetime.timedelta(days=(1-mixServerDay)) # 合服第一天的日期
-                        customMaxServerDateTime = curDateTime + datetime.timedelta(days=(maxCustomServerDayMix-mixServerDay))
-                        curStartDateTime = datetime.datetime.strptime("%s %02d:%02d:%02d" % (startDateStr, customMaxServerDateTime.hour, customMaxServerDateTime.minute, 
-                                                                                             customMaxServerDateTime.second), ChConfig.TYPE_Time_Format)
-                        if customMixServerDayState and mixStartServerDateTime <= curStartDateTime <= customMaxServerDateTime:
-                            if actName not in startDateInCustomCanOpenList:
-                                GameWorld.Log("        按日期/周开的开始日期在合服定制限制天内,不处理! cfgID=%s,mixStartServerDateTime=%s<=curStartDateTime=%s<=customMaxServerDateTime=%s" % (cfgID, mixStartServerDateTime, curStartDateTime, customMaxServerDateTime))
-                                continue
-                    
+                GameWorld.Log("        非法配置,未知活动类型,不处理! cfgID=%s,actNum=%s" % (cfgID, actNum))
+                continue
+            
             if hasattr(ipyData, "GetStartTimeList") and hasattr(ipyData, "GetEndTimeList"):
                 startHMStrList = ipyData.GetStartTimeList()
                 endHMStrList = ipyData.GetEndTimeList()
@@ -287,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)
-                    
+                
             # 每天按时段开启的,支持多时段
-            elif startDayDate <= curDateTime <= endDayDate:
-                isEnd = (curDateTime == endDayDate)
-                if not isEnd:
-                    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)
+            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))
-            GameWorld.Log("        needStartList=%s" % (needStartList))
-            GameWorld.Log("        need  EndList=%s" % (needEndList))
             
             for dtIndex, startDateTime in enumerate(startList):
                 endDateTime = endList[dtIndex]
@@ -363,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:
@@ -374,49 +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 == ShareDefine.OperationActionName_LoginAward:
-                        #活动每天的世界等级
-                        activityInfoDict[ShareDefine.ActKey_WorldLVList] = GameWorldAverageLv.GetWorldLVListByTime(startDayDate, (endDayDate - startDayDate).days)
+            # 兼容新旧运营活动逻辑处理数据
+            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 = (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))
-                        
-                    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:
@@ -424,7 +486,7 @@
         
     return True, OperationActionInfo
 
-def __GetOperationActionServerIpyDataList(ipyDataMgr, serverGroupID, actName):
+def __GetOperationActionServerIpyDataList(ipyDataMgr, platform, serverGroupID, actName):
     ## 获取运营活动本服务器对应的配置数据列表
     
     if not hasattr(ipyDataMgr, "Get%sCount" % actName):
@@ -435,8 +497,12 @@
     actCfgCount = getattr(ipyDataMgr, "Get%sCount" % actName)()
     for cfgIndex in xrange(actCfgCount):
         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()
+        
+        if platformList and platform not in platformList:
+            continue
         
         # 排除的服务器组ID列表
         if serverGroupIDListExcept:
@@ -464,44 +530,136 @@
 
 def __GetOperationActionDisableWeekIpyDataInfo(actName, curDateTime, curServerActIpyDataList):
     ## 获取不可用的按星期X开启的配置数据信息,按星期X开启的 活动优先级小于按日期的,当有重叠时以日期的为准
-    disableWeekIpyDataInfo = {}
     curWeekday = curDateTime.weekday() + 1 # 今天星期几, 1代表星期1
-    customOpenServerDayState, customMixServerDayState = False, False # 是否有配开服天、合服天活动
-    weekIpyDataList, ymdIpyDatList = [], []
+    actNumWeekYMDIpyDataInfo = {} # {actNum:[weekIpyDataList, ymdIpyDatList], ...}
+    
     for ipyData in curServerActIpyDataList:
         startDateStr = ipyData.GetStartDate()
         endDateStr = ipyData.GetEndDate()
-        if startDateStr.isdigit() or startDateStr.startswith("Mix"):
-            # 开服天、合服天的不处理
-            if startDateStr.isdigit():
-                customOpenServerDayState = True
-            else:
-                customMixServerDayState = True                
+        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))
+            startWeekDate = curDateTime + datetime.timedelta(days=(startWeekday - curWeekday))
+            endWeekDate = curDateTime + datetime.timedelta(days=(endWeekday - curWeekday))
             weekIpyDataList.append([ipyData, startWeekDate, endWeekDate])
         # 按日期的
-        else:
+        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])
             
-    for ipyData, startWeekDate, endWeekDate in weekIpyDataList:
-        cfgID = ipyData.GetCfgID()
-        for ymdIpyData, ymdStartDate, ymdEndDate in ymdIpyDatList:
-            if ymdStartDate <= startWeekDate <= ymdEndDate or ymdStartDate <= endWeekDate <= ymdEndDate \
-                or (actName in ShareDefine.FeastOperationActionNameList and ymdStartDate <= curDateTime <= ymdEndDate):
-                ymdCfgID = ymdIpyData.GetCfgID()
-                disableWeekIpyDataInfo[cfgID] = [startWeekDate, endWeekDate, ymdCfgID, ymdStartDate, ymdEndDate]
-                
-    return disableWeekIpyDataInfo, customOpenServerDayState, customMixServerDayState
+        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点会强制同步当天的运营活动详情到地图服务器
@@ -513,7 +671,7 @@
     
     isReload, OperationActionInfo = __GetOperationActionInfo(False) # 这里必须传False
     isReload = isReload or reloadRefresh
-    operationActionDict = OperationActionInfo[OperationAction_TodayInfo]
+    operationTodayActionDict = OperationActionInfo[OperationAction_TodayInfo]
     mapServerInfoDict = OperationActionInfo[OperationAction_MapServerInfo]
     
     gameWorld = GameWorld.GetGameWorld()
@@ -523,147 +681,148 @@
     curDateTime = datetime.datetime.strptime("%d-%d-%d %d:%d:00" % (curDateTime.year, curDateTime.month, curDateTime.day,
                                                                     curDateTime.hour, curDateTime.minute), ChConfig.TYPE_Time_Format)
     
-    startDateInCustomCanOpenList = IpyGameDataPY.GetFuncEvalCfg("OperationAction", 2) # 开始天在定制天内在定制天结束后可继续开启的活动列表
-    
     for actName in ShareDefine.OperationActionNameList:
         
-        state = 0 # 默认关闭
-        ipyData = None
+        if actName not in mapServerInfoDict:
+            continue
         
-        if actName in operationActionDict:
+        if actName in ShareDefine.MultiActNumOperationActNameList:
+            curActMapInfoDictList = mapServerInfoDict[actName].values()
+        else:
+            curActMapInfoDictList = [mapServerInfoDict[actName]]
             
-            #startList = [] # [startDateTime, ...]
-            #endList = [] # [endDateTime, ...]
-            #notifyDict = {} # {notifyDateTime:[notifyKey, [参数]], ...}
-            #ipyData 可能为 None
-            ipyData, startList, endList, notifyDict = operationActionDict[actName]
+        for sendMapServerMsgDict in curActMapInfoDictList:
             
-            if actName in startDateInCustomCanOpenList:
-                # 由于某些活动的开始天允许和前定制X天有交叉的情况出现(实际不开,会等定制结束后才接下去开)
-                # 所以会有时间交叉的情况出现,这种活动goon单独判断
-                # 为防止动到其他活动,允许交叉的活动另外处理,理论上可以统一逻辑,为保险起见分开处理
-                
-                # 精确匹配开启
-                if curDateTime in startList:
-                    state = startList.index(curDateTime) + 1 # 也是代表第几个时间段
-                # 精确匹配关闭
-                elif curDateTime in endList:
-                    state = 0
-                    
-                # goon 状态
-                for dIndex, startDateTime in enumerate(startList):
-                    endDateTime = endList[dIndex]
-                    if startDateTime < curDateTime < endDateTime:
-                        state = dIndex + 1
-                        break
-                    
-            else:
-                # 精确匹配开启
-                if curDateTime in startList:
-                    state = startList.index(curDateTime) + 1 # 也是代表第几个时间段
-                # 精确匹配关闭
-                elif curDateTime in endList:
-                    state = 0
-                # goon 状态
+            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
+                        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
+                
+            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)
                     
-            # 全服广播提示信息
-            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:
-            #已经是这个状态了
-            continue
-        GameWorld.Log("运营活动变更: actName=%s,preState=%s,state=%s,dictName=%s" % (actName, preState, state, dictName))
-        #更新字典值
-        gameWorld.SetDict(dictName, state)
-        sendMapServerMsgDict = mapServerInfoDict.get(actName, {})
-        
-        dbOperationActIDKey = PlayerDBGSEvent.Def_OperationActID % actName
-        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)
+            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_NewFairyCeremony:
+                if isReload and ipyData:
+                    PlayerNewFairyCeremony.Sync_OperationAction_NewFairyCeremony(ipyData)
+                if preState != state and state == 0:
+                    PlayerNewFairyCeremony.OnNewFairyCeremonyEnd()
             
-            if curActID:
-                if actName in ShareDefine.NeedWorldLVOperationActNameList:
-                    #记录开启时世界等级
-                    worldLV = PlayerDBGSEvent.GetDBGSTrig_ByKey(ShareDefine.Def_Notify_WorldKey_WorldAverageLv)
-                    PlayerDBGSEvent.SetDBGSTrig_ByKey(PlayerDBGSEvent.Def_OActWorldLV % actName, worldLV)
-                    GameWorld.Log("    记录活动开启时世界等级: worldLV=%s" % (worldLV))
+            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)
                     
-                #此处为活动开启时
-                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))
+            #通知Mapserver,设置字典
+            #GameWorld.SendMapServerMsgEx(dictName, state) # 运营活动不单独通知活动状态,需与活动信息整合后一起通知
             
-        if actName in ShareDefine.NeedWorldLVOperationActNameList:
-            actWorldLV = PlayerDBGSEvent.GetDBGSTrig_ByKey(PlayerDBGSEvent.Def_OActWorldLV % actName)
-            sendMapServerMsgDict[ShareDefine.ActKey_WorldLV] = actWorldLV
-            GameWorld.Log("    活动世界等级: actWorldLV=%s" % (actWorldLV))
+            sendMapServerMsgDict[ShareDefine.ActKey_State] = state
+            GameWorld.SendMapServerMsgEx(ShareDefine.Def_Notify_WorldKey_OperationActionInfo % actName, sendMapServerMsgDict)
             
-        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_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) # 运营活动不单独通知活动状态,需与活动信息整合后一起通知
-        
-        sendMapServerMsgDict[ShareDefine.ActKey_State] = state
-        GameWorld.SendMapServerMsgEx(ShareDefine.Def_Notify_WorldKey_OperationActionInfo % actName, sendMapServerMsgDict)
-        
-        GameWorld.Log("    sendMapServerMsgDict: %s" % (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):

--
Gitblit v1.8.0