From 7d7da6a8246577a11c38219eaedb451178769ec8 Mon Sep 17 00:00:00 2001
From: hxp <ale99527@vip.qq.com>
Date: 星期五, 14 九月 2018 17:15:52 +0800
Subject: [PATCH] 3494 【后端】开服前14天运营活动定制 3443 【后端】Boss复活活动,时间段支持日期跨天或日期支持重置时间点设置(如0点或5点) 1972 【后端】运营活动支持循环广播

---
 ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/GameWorldActionControl.py |  218 ++++++++++++++++++++++++++++--------------------------
 1 files changed, 114 insertions(+), 104 deletions(-)

diff --git a/ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/GameWorldActionControl.py b/ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/GameWorldActionControl.py
index a78c850..46d63f1 100644
--- a/ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/GameWorldActionControl.py
+++ b/ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/GameWorldActionControl.py
@@ -54,7 +54,7 @@
 ATTR_CALL_TIME = ['weekday', 'year', 'month', 'day', 'hour', 'minute']
 
 (
-OperationAction_OpenServerDay, # 信息所属开服天
+OperationAction_ReloadSign, # 信息重载标记
 OperationAction_TodayInfo, # 当日的活动信息
 OperationAction_MapServerInfo, # 同步地图的活动信息
 ) = range(3)
@@ -101,7 +101,7 @@
         dictName = ChConfig.Def_WorldKey_OperationActionState % actName
         state = gameWorld.GetDictByKey(dictName)
         
-        sendMapServerMsgDict = mapServerInfoDict.get(actName, {}) if state else {}
+        sendMapServerMsgDict = mapServerInfoDict.get(actName, {})
         sendMapServerMsgDict[ShareDefine.ActKey_State] = state
         GameWorld.SendMapServerMsgEx(ShareDefine.Def_Notify_WorldKey_OperationActionInfo % actName, sendMapServerMsgDict)
         
@@ -113,26 +113,32 @@
     key = "OperationActionInfo"
     openServerDay = PlayerDBGSEvent.GetDBGSTrig_ByKey(PlayerDBGSEvent.Def_ServerDay) + 1
     OperationActionInfo = IpyGameDataPY.GetConfigEx(key)
-    if OperationActionInfo and OperationActionInfo[OperationAction_OpenServerDay] == openServerDay:
+    serverTime = GameWorld.GetServerTime()
+    curHour = serverTime.hour
+    reloadSignHour = 0 if curHour < 5 else 5
+    reloadSign = "%s_%s" % (openServerDay, reloadSignHour)
+    if OperationActionInfo and OperationActionInfo[OperationAction_ReloadSign] == reloadSign:
         #GameWorld.DebugLog("已经加载过本日运营活动处理信息!openServerDay=%s" % openServerDay)
         return False, OperationActionInfo
     
     # 因为后面的时间判断都是精确到分的,而处理此逻辑的时候可能不是0秒,所以这里的datetime取当前时间精确到分的
-    serverTime = GameWorld.GetServerTime()
     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)
-    GameWorld.Log("加载本日运营活动信息: %s, openServerDay=%s" % (curDateTime, openServerDay))
     
+    customMaxServerDay = 14 # 定制运营活动最大开服天
     operationActionDict = {}
     mapServerOperationActionDict = {}
     serverID = GameWorld.GetServerID()
     ipyDataMgr = IpyGameDataPY.IPY_Data()
     
+    GameWorld.Log("===== 加载本日运营活动信息: %s, serverID=%s,openServerDay=%s,customMaxServerDay=%s,reloadSign=%s =====" 
+                  % (curDateTime, serverID, openServerDay, customMaxServerDay, reloadSign))
+    
     for actName in ShareDefine.OperationActionNameList:
         
         # 取出本活动所属本服ID的所有配置
         curServerActIpyDataList = __GetOperationActionServerIpyDataList(ipyDataMgr, serverID, actName)
-        
+        GameWorld.Log("加载运营活动: actName=%s,可处理条数=%s" % (actName, len(curServerActIpyDataList)))
         needStartList = [] # [startDateTime, ...]
         needEndList = [] # [endDateTime, ...]
         needNotifyDict = {} # {notifyDateTime:[notifyKey, [参数]], ...}
@@ -140,8 +146,26 @@
         # 注意:每个活动配置会有多个活动时间点,但是有且只能生效一条活动配置,换句话说就是每个活动配置时间不允许交叉
         for ipyData in curServerActIpyDataList:
             
+            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)
+                if openServerDay > endServerDay:
+                    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))
+                
+            elif openServerDay <= customMaxServerDay:
+                GameWorld.Log("        按日期开的在开服定制限制天内,不处理! cfgID=%s,%s ~ %s,openServerDay=%s" % (cfgID, startDateStr, endDateStr, openServerDay))
+                continue
             
             if hasattr(ipyData, "GetStartTimeList") and hasattr(ipyData, "GetEndTimeList"):
                 startHMStrList = ipyData.GetStartTimeList()
@@ -152,23 +176,41 @@
                 
             notifyInfoDictStart = ipyData.GetNotifyInfoStart() if hasattr(ipyData, "GetNotifyInfoStart") else {}
             notifyInfoDictEnd = ipyData.GetNotifyInfoEnd() if hasattr(ipyData, "GetNotifyInfoEnd") else {}
+            notifyInfoLoopInfo = ipyData.GetNotifyInfoLoop() if hasattr(ipyData, "GetNotifyInfoLoop") else {} # [循环分钟, 广播key]
             
             if len(startHMStrList) != len(endHMStrList):
-                GameWorld.ErrLog("活动配置开始及结束时间个数不匹配! actName=%s,cfgID=%s" % (actName, ipyData.GetCfgID()))
+                GameWorld.ErrLog("        活动配置开始及结束时间个数不匹配! actName=%s,cfgID=%s,startHMStrList=%s,endHMStrList=%s" 
+                                 % (actName, cfgID, startHMStrList, endHMStrList))
                 continue
+            
+            resetType = 0 if not hasattr(ipyData, "GetResetType") else ipyData.GetResetType() # 重置类型,0-0点重置;1-5点重置
+            if resetType == 1:
+                startDayDate = datetime.datetime.strptime("%s 05:00:00" % (startDateStr), ChConfig.TYPE_Time_Format)
+                endDayDate = datetime.datetime.strptime("%s 05:00:00" % (endDateStr), ChConfig.TYPE_Time_Format) # 结束日期5点
+            else:
+                startDayDate = datetime.datetime.strptime("%s 00:00:00" % (startDateStr), ChConfig.TYPE_Time_Format)
+                endDayDate = datetime.datetime.strptime("%s 00:00:00" % (endDateStr), ChConfig.TYPE_Time_Format) + datetime.timedelta(days=1) # 结束日期隔天0点
+                
+            advanceMinutes = 0 if not hasattr(ipyData, "GetAdvanceMinutes") else ipyData.GetAdvanceMinutes() # 提前通知时间,分钟,暂只支持按天的
+            GameWorld.Log("        resetType=%s,startDayDate=%s,endDayDate=%s,startHMStrList=%s,endHMStrList=%s,advanceMinutes=%s" 
+                          % (resetType, startDayDate, endDayDate, startHMStrList, endHMStrList, advanceMinutes))
             
             startList = [] # [startDateTime, ...]
             endList = [] # [endDateTime, ...]
+            startNotifyDict = {} # {notifyDateTime:notifyInfo, ...}
+            endNotifyDict = {} # {notifyDateTime:notifyInfo, ...}
+            loopNotifyDict = {} # {notifyDateTime:notifyInfo, ...}
             isActivity = False # 有需要处理开关时间的(开始、结束)
             isNotify = False
+            isAdvanceNotice = False
             # 没配置时分的代表全天, 只要开始或结束时分没配都算
             if not startHMStrList or not endHMStrList:
-                startDayDate = datetime.datetime.strptime("%s 00:00:00" % (startDateStr), ChConfig.TYPE_Time_Format) # 开始天0点
-                endDayDate = datetime.datetime.strptime("%s 00:00:00" % (endDateStr), ChConfig.TYPE_Time_Format) + datetime.timedelta(days=1) # 结束天隔天0点
                 startDateTime = startDayDate
                 endDateTime = endDayDate
                 startList.append(startDateTime)
                 endList.append(endDateTime)
+                # 同一个活动类型是不允许时间上配置有重叠的,所以一个活动类型满足活动中的时间的有且仅有一条配置
+                # 策划可能同时配置多个时间,但是活动中的有且仅有一条配置
                 if startDayDate <= curDateTime <= endDayDate:
                     needStartList.append(startDateTime)
                     needEndList.append(endDateTime)
@@ -176,8 +218,6 @@
                     
             # 每天按时段开启的,支持多时段
             else:
-                startDayDate = datetime.datetime.strptime("%s 00:00:00" % (startDateStr), ChConfig.TYPE_Time_Format) # 开始天0点
-                endDayDate = datetime.datetime.strptime("%s 23:59:59" % (endDateStr), ChConfig.TYPE_Time_Format) # 结束天23点59分59秒
                 if startDayDate <= curDateTime <= endDayDate:
                     for hmIndex, startHMStr in enumerate(startHMStrList):
                         endHMStr = endHMStrList[hmIndex]
@@ -194,42 +234,93 @@
                         needEndList.append(endDateTime)
                         isActivity = True
                         
+            if advanceMinutes and startDayDate:
+                advanceNoticeDateTime = startDayDate + datetime.timedelta(minutes=-advanceMinutes)
+                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]
                 # 广播 - 相对实际开始时间
                 for notifyMinute, notifyInfo in notifyInfoDictStart.items():
                     notifyDateTime = startDateTime + datetime.timedelta(minutes=notifyMinute)
                     if notifyDateTime.year == curDateTime.year and notifyDateTime.month == curDateTime.month and notifyDateTime.day == curDateTime.day:
-                        needNotifyDict[notifyDateTime] = notifyInfo
+                        startNotifyDict[notifyDateTime] = notifyInfo
                         isNotify = True
                     
                 # 广播 - 相对实际结束时间
                 for notifyMinute, notifyInfo in notifyInfoDictEnd.items():
                     notifyDateTime = endDateTime + datetime.timedelta(minutes=notifyMinute)
                     if notifyDateTime.year == curDateTime.year and notifyDateTime.month == curDateTime.month and notifyDateTime.day == curDateTime.day:
-                        needNotifyDict[notifyDateTime] = notifyInfo
+                        endNotifyDict[notifyDateTime] = notifyInfo
                         isNotify = True
-                       
-            if not isActivity and not isNotify:
+                        
+                # 广播 - 循环广播
+                if notifyInfoLoopInfo and len(notifyInfoLoopInfo) == 2:
+                    loopMinutes, loopNotifyKey = notifyInfoLoopInfo
+                    notifyInfo = [loopNotifyKey, []] # 循环广播的默认无参数,不做支持
+                    loopCount, loopMaxCount = 0, 100
+                    while loopMinutes and loopNotifyKey and loopCount < loopMaxCount:
+                        loopCount += 1
+                        notifyDateTime = startDateTime + datetime.timedelta(minutes=loopMinutes*loopCount)
+                        if notifyDateTime >= endDateTime:
+                            break
+                        if notifyDateTime.year == curDateTime.year and notifyDateTime.month == curDateTime.month and notifyDateTime.day == curDateTime.day:
+                            loopNotifyDict[notifyDateTime] = notifyInfo
+                            isNotify = True
+                            
+            if startNotifyDict or endNotifyDict or loopNotifyDict:
+                GameWorld.Log("        startNotifyDict: minutes=%s, %s" % (notifyInfoDictStart.keys(), startNotifyDict))
+                GameWorld.Log("        end  NotifyDict: minutes=%s, %s" % (notifyInfoDictEnd.keys(), endNotifyDict))
+                GameWorld.Log("        loop NotifyDict: lopInfo=%s, %s" % (notifyInfoLoopInfo, loopNotifyDict.keys()))
+                needNotifyDict.update(startNotifyDict)
+                needNotifyDict.update(endNotifyDict)
+                needNotifyDict.update(loopNotifyDict)
+                
+            if not isActivity and not isNotify and not isAdvanceNotice:
                 continue
             
-            GameWorld.Log("    本日需要处理的运营活动信息: actName=%s,cfgID=%s,actMark=%s" % (actName, ipyData.GetCfgID(), ipyData.GetActMark()))
-            if isActivity:
+            GameWorld.Log("        需要处理的运营活动信息: cfgID=%s,isAdvanceNotice=%s,isActivity=%s,isNotify=%s" % (cfgID, isAdvanceNotice, isActivity, isNotify))
+            # 当天有需要激活活动或者提前预告活动的取开始时间较早的为准
+            if isActivity or isAdvanceNotice:
                 if not activityIpyData or activityIpyData.GetStartDate() < ipyData.GetStartDate():
                     activityIpyData = ipyData
+                    activityInfoDict = {ShareDefine.ActKey_CfgID:cfgID}
+                    
+                    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()
+                    
+                    mapServerOperationActionDict[actName] = activityInfoDict
+                    GameWorld.Log("        activityInfoDict=%s" % (activityInfoDict))
                     
         if activityIpyData or needStartList or needEndList or needNotifyDict:
             # activityIpyData 可能为None
             operationActionDict[actName] = [activityIpyData, needStartList, needEndList, needNotifyDict]
-            # 新增运营活动只要在此处添加同步MapServer所需要的数据字典即可,其他逻辑均为公共逻辑
-            mapServerOperationActionDict[actName] = __GetOperationActionMapServerInfoDict(curDateTime, actName, activityIpyData)
             
-    OperationActionInfo = IpyGameDataPY.SetConfigEx(key, [openServerDay, operationActionDict, mapServerOperationActionDict])
+    OperationActionInfo = IpyGameDataPY.SetConfigEx(key, [reloadSign, operationActionDict, mapServerOperationActionDict])
     
-    GameWorld.Log("本日运营活动信息加载完毕!isRefreshState=%s" % isRefreshState)
+    GameWorld.Log("本日运营活动信息加载完毕!reloadSign=%s,isRefreshState=%s" % (reloadSign, isRefreshState))
     GameWorld.Log("    operationActionDict=%s" % operationActionDict)
     GameWorld.Log("    mapServerOperationActionDict=%s" % mapServerOperationActionDict)
-    
+    GameWorld.Log("=============================================================")
     if isRefreshState:
         Dispose_OperationActionState(True)
         
@@ -271,87 +362,6 @@
         if isGeneral:
             curServerActIpyDataList += generalIpyDataList
     return curServerActIpyDataList
-
-def __GetOperationActionMapServerInfoDict(curDateTime, actName, ipyData):
-    ## 获取运营活动同步到地图服务器的信息字典    
-    if not ipyData:
-        return {}
-    
-    startDateStr = ipyData.GetStartDate()
-    startDayDate = datetime.datetime.strptime("%s 00:00:00" % (startDateStr), ChConfig.TYPE_Time_Format) # 开始天0点
-    dayIndex = (curDateTime - startDayDate).days # 当前日期在活动期间的天索引
-    if dayIndex < 0:
-        GameWorld.DebugLog("        不处理运营地图数据: startDateStr=%s,curDateTime=%s,startDayDate=%s,dayIndex=%s" 
-                           % (startDateStr, curDateTime, startDayDate, dayIndex))
-        return {}
-    
-    actID = int(time.mktime(startDayDate.timetuple()))
-    
-    mapServerInfoDict = {}
-    # 多倍经验活动
-    if actName == ShareDefine.OperationActionName_ExpRate:
-        mapServerInfoDict = {ShareDefine.ActKey_LVLimit:ipyData.GetLVLimit(),
-                             ShareDefine.ActKey_AddExpRate:ipyData.GetAddExpRate()}
-    # 消费返利活动
-    elif actName == ShareDefine.OperationActionName_CostRebate:
-        isDayReset = ipyData.GetIsDayReset()
-        if isDayReset:
-            # 每天重置的活动ID取当天的time值
-            actIDDateStr = "%d-%d-%d 00:00:00" % (curDateTime.year, curDateTime.month, curDateTime.day)
-            actIDDateTime = datetime.datetime.strptime(actIDDateStr, ChConfig.TYPE_Time_Format)
-            actID = int(time.mktime(actIDDateTime.timetuple()))
-        templateIDList = ipyData.GetTemplateIDList()
-        templateID = templateIDList[-1] if dayIndex >= len(templateIDList) else templateIDList[dayIndex]
-        mapServerInfoDict = {ShareDefine.ActKey_ID:actID,
-                             ShareDefine.ActKey_StartDate:ipyData.GetStartDate(),
-                             ShareDefine.ActKey_EndDate:ipyData.GetEndDate(),
-                             ShareDefine.ActKey_LVLimit:ipyData.GetLVLimit(),
-                             ShareDefine.ActKey_IsDayReset:ipyData.GetIsDayReset(),
-                             ShareDefine.ActKey_TemplateID:templateID,
-                             ShareDefine.ActKey_TemplateIDList:templateIDList}
-    # 限时特惠活动
-    elif actName == ShareDefine.OperationActionName_SpringSale:
-        isDayReset = ipyData.GetIsDayReset()
-        if isDayReset:
-            # 每天重置的活动ID取当天的time值
-            actIDDateStr = "%d-%d-%d 00:00:00" % (curDateTime.year, curDateTime.month, curDateTime.day)
-            actIDDateTime = datetime.datetime.strptime(actIDDateStr, ChConfig.TYPE_Time_Format)
-            actID = int(time.mktime(actIDDateTime.timetuple()))
-        shopTypeList = ipyData.GetShopTypeList()
-        todayShopType = shopTypeList[-1] if dayIndex >= len(shopTypeList) else shopTypeList[dayIndex]
-        mapServerInfoDict = {ShareDefine.ActKey_ID:actID,
-                             ShareDefine.ActKey_CfgID:ipyData.GetCfgID(), 
-                             ShareDefine.ActKey_ShopTypeList:todayShopType}
-    # Boss复活活动
-    elif actName == ShareDefine.OperationActionName_BossReborn:
-        mapServerInfoDict = {ShareDefine.ActKey_ID:actID,
-                             ShareDefine.ActKey_TemplateID:ipyData.GetTemplateID(),
-                             ShareDefine.ActKey_StartDate:ipyData.GetStartDate(),
-                             ShareDefine.ActKey_EndDate:ipyData.GetEndDate(),
-                             ShareDefine.ActKey_LVLimit:ipyData.GetLVLimit(),}
-    # 限时礼包活动
-    elif actName == ShareDefine.OperationActionName_FlashGiftbag:
-        isDayReset = ipyData.GetIsDayReset()
-        if isDayReset:
-            # 每天重置的活动ID取当天的time值
-            actIDDateStr = "%d-%d-%d 00:00:00" % (curDateTime.year, curDateTime.month, curDateTime.day)
-            actIDDateTime = datetime.datetime.strptime(actIDDateStr, ChConfig.TYPE_Time_Format)
-            actID = int(time.mktime(actIDDateTime.timetuple()))
-        giftbagTypeList = ipyData.GetGiftbagTypeList()
-        todayGiftbag = giftbagTypeList[-1] if dayIndex >= len(giftbagTypeList) else giftbagTypeList[dayIndex]
-        mapServerInfoDict = {ShareDefine.ActKey_ID:actID,
-                             ShareDefine.ActKey_CfgID:ipyData.GetCfgID(), 
-                             ShareDefine.ActKey_GiftbagTypeList:todayGiftbag}
-    # 仙界盛典活动
-    elif actName == ShareDefine.OperationActionName_FairyCeremony:
-        mapServerInfoDict = {ShareDefine.ActKey_ID:actID}
-    # 多倍修行点活动
-    if actName == ShareDefine.OperationActionName_RealmPoint:
-        mapServerInfoDict = {ShareDefine.ActKey_LVLimit:ipyData.GetLVLimit(),
-                             ShareDefine.ActKey_RealmPointMulti:ipyData.GetMultiple(),
-                             ShareDefine.ActKey_StartDate:ipyData.GetStartDate(),
-                             ShareDefine.ActKey_EndDate:ipyData.GetEndDate(),}
-    return mapServerInfoDict
 
 def Dispose_OperationActionState(reloadRefresh=False):
     # 运营活动状态处理, 每天0点会强制同步当天的运营活动详情到地图服务器
@@ -406,7 +416,7 @@
             continue
         #更新字典值
         gameWorld.SetDict(dictName, state)
-        sendMapServerMsgDict = mapServerInfoDict.get(actName, {}) if state else {}
+        sendMapServerMsgDict = mapServerInfoDict.get(actName, {})
         
         dbOperationActIDKey = PlayerDBGSEvent.Def_OperationActID % actName
         curActID = sendMapServerMsgDict.get(ShareDefine.ActKey_ID)

--
Gitblit v1.8.0