hxp
2025-06-30 388823edfe6308cba6f76ca6dc4f20022c5cb2be
ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/CrossActionControl.py
@@ -22,9 +22,18 @@
import PlayerControl
import IpyGameDataPY
import CrossActCTGBillboard
import PlayerActBossTrial
import PlayerActXianXiaMJ
import PlayerActGubao
import PlayerActHorsePetTrain
import PlayerActLianqi
import PlayerDBGSEvent
import CrossFamilyGCZ
import CrossRealmMsg
import PyGameData
import PlayerFB
import ChConfig
import CommFunc
import datetime
import time
@@ -32,7 +41,8 @@
(
CrossAct_ReloadSign, # 信息重载标记
CrossAct_TodayInfo, # 当日的活动信息
) = range(2)
CrossAct_CfgIDInfo, # 处理的cfgID信息
) = range(3)
def OnPlayerLogin(curPlayer):
    return
@@ -55,6 +65,7 @@
                # 非活动中的,已经结算过了,不需要存储
                continue
            state = actInfo.get(ShareDefine.ActKey_State, 0)
            stateJoin = actInfo.get(ShareDefine.ActKey_StateJoin, 0)
            actID = actInfo.get(ShareDefine.ActKey_ID, 0)
            templateID = actInfo.get(ShareDefine.ActKey_TemplateID, 0)
            serverIDRangeList = actInfo.get(ShareDefine.ActKey_ServerIDRangeList, "")
@@ -65,10 +76,101 @@
            recData.SetValue2(state)
            recData.SetValue3(actID)
            recData.SetValue4(templateID)
            GameWorld.Log("    actName=%s,cfgID=%s,state=%s,actID=%s,templateID=%s,serverIDRangeList=%s"
                          % (actName, cfgID, state, actID, templateID, serverIDRangeList))
            recData.SetValue5(stateJoin)
            GameWorld.Log("    actName=%s,cfgID=%s,state=%s,stateJoin=%s,actID=%s,templateID=%s,serverIDRangeList=%s"
                          % (actName, cfgID, state, stateJoin, actID, templateID, serverIDRangeList))
            
    return
def GetCrossActZoneID(actName, serverGroupID):
    ## 获取子服ID所属跨服活动分区, 跨服、子服通用
    actInfoDict = GetCrossActInfoByServerGroupID(actName, serverGroupID)
    if not actInfoDict:
        return
    cfgID = actInfoDict.get(ShareDefine.ActKey_CfgID)
    ipyDataInfo = actInfoDict.get(ShareDefine.ActKey_IpyDataInfo)
    if not ipyDataInfo:
        GameWorld.ErrLog("ActKey_IpyDataInfo为空, 找不到跨服活动所属分区! actName=%s, serverGroupID=%s, cfgID=%s"
                         % (actName, serverGroupID, cfgID))
        return
    return ipyDataInfo.get("ZoneID")
def GetCrossActInfoByServerGroupID(actName, serverGroupID):
    '''获取子服ID所属跨服活动信息, 跨服、子服通用
        @param serverGroupID: 服务器ID或服务器分ID
                                跨服活动表配置的是服务器ID,而子服合服后以主服的服务器ID作为服务器组ID,所以两种服务器ID在此函数中通用
        @return: None or ActKey_IpyDataInfo
    '''
    crossActInfoDict = PyGameData.g_crossActInfoDict
    if crossActInfoDict and actName in crossActInfoDict:
        curActInfoDict = crossActInfoDict[actName]
        for actInfoDict in curActInfoDict.values():
            if not actInfoDict.get(ShareDefine.ActKey_State, 0):
                continue
            serverIDRangeList = actInfoDict.get(ShareDefine.ActKey_ServerIDRangeList)
            if not serverIDRangeList:
                continue
            for groupInfo in serverIDRangeList:
                if (isinstance(groupInfo, int) and serverGroupID == groupInfo) \
                    or ((isinstance(groupInfo, tuple) or isinstance(groupInfo, list)) \
                        and len(groupInfo) == 2 and groupInfo[0] <= serverGroupID <= groupInfo[1]):
                    return actInfoDict
    GameWorld.DebugLog("找不到服务器组ID对应跨服活动分区! actName=%s, serverGroupID=%s" % (actName, serverGroupID))
    return
def GetCrossActInfoByCfgID(actName, cfgID, zoneID=None):
    ## 获取cfgID对应的跨服活动状态信息,可选验证zoneID是否匹配
    crossActInfoDict = GetCrossActInfoDict()
    if actName not in crossActInfoDict:
        return
    curActInfoDict = crossActInfoDict[actName]
    if cfgID not in curActInfoDict:
        return
    actInfo = curActInfoDict[cfgID]
    if zoneID:
        # 验证分区ID是否正确
        ipyDataDict = actInfo.get(ShareDefine.ActKey_IpyDataInfo, {})
        if not ipyDataDict:
            return
        ipyZoneID = ipyDataDict.get("ZoneID", 0)
        if zoneID != ipyZoneID:
            return
    return actInfo
def GetCrossActInfoByZoneID(actName, zoneID):
    ## 获取分区ID对应的跨服活动信息
    crossActInfoDict = GetCrossActInfoDict()
    if actName not in crossActInfoDict:
        return
    curActInfoDict = crossActInfoDict[actName]
    for actInfo in curActInfoDict.values():
        ipyDataDict = actInfo.get(ShareDefine.ActKey_IpyDataInfo, {})
        if not ipyDataDict:
            return
        ipyZoneID = ipyDataDict.get("ZoneID", 0)
        if zoneID == ipyZoneID:
            return actInfo
    return
def GetCrossActZoneIDList(actName):
    ## 获取跨服活动当前所有分区列表
    crossActInfoDict = GetCrossActInfoDict()
    if actName not in crossActInfoDict:
        return []
    zoneIDList = []
    curActInfoDict = crossActInfoDict[actName]
    for actInfo in curActInfoDict.values():
        ipyDataDict = actInfo.get(ShareDefine.ActKey_IpyDataInfo, {})
        if not ipyDataDict:
            return
        zoneID = ipyDataDict.get("ZoneID", 0)
        if zoneID and zoneID not in zoneIDList:
            zoneIDList.append(zoneID)
    return zoneIDList
def GetCrossActInfoDict():
    if PyGameData.g_crossActInfoDict == None:
@@ -86,13 +188,17 @@
            state = recData.GetValue2()
            actID = recData.GetValue3()
            templateID = recData.GetValue4()
            stateJoin = recData.GetValue5()
            if not state:
                continue
            if actName not in PyGameData.g_crossActInfoDict:
                PyGameData.g_crossActInfoDict[actName] = {}
            actInfoDict = PyGameData.g_crossActInfoDict[actName]
            dbInfo = {ShareDefine.ActKey_ID:actID, ShareDefine.ActKey_State:state, ShareDefine.ActKey_TemplateID:templateID} # 活动ID、状态、模板信息单独存储,重置活动判断用
            actInfo = {ShareDefine.ActKey_CfgID:cfgID, ShareDefine.ActKey_ServerIDRangeList:serverIDRangeList}
            # 活动ID、状态、模板信息单独存储,重置活动判断用
            dbInfo = {ShareDefine.ActKey_ID:actID, ShareDefine.ActKey_State:state, ShareDefine.ActKey_TemplateID:templateID,
                      ShareDefine.ActKey_CfgID:cfgID, ShareDefine.ActKey_ServerIDRangeList:serverIDRangeList,
                      ShareDefine.ActKey_StateJoin:stateJoin}
            actInfo = {}
            actInfo.update(dbInfo)
            actInfo[ShareDefine.ActKey_DBInfo] = dbInfo
            actInfoDict[cfgID] = actInfo
@@ -104,6 +210,7 @@
def __GetParseIpyDataList(ipyDataMgr, actName, actInfoDict):
    ## 获取需要处理的合法分组活动配置列表,已经在活动中的必须要处理
    
    groupNameList = [] # 确保分组顺序
    groupInfo = {}
    actCfgCount = getattr(ipyDataMgr, "Get%sCount" % actName)()
    for cfgIndex in xrange(actCfgCount):
@@ -111,11 +218,13 @@
        actGroupName = ipyData.GetActGroupName()
        if actGroupName not in groupInfo:
            groupInfo[actGroupName] = []
            groupNameList.append(actGroupName)
        groupIpyDataList = groupInfo[actGroupName]
        groupIpyDataList.append(ipyData)
        
    parseIpyDataList = []
    for actGroupName, groupIpyDataList in groupInfo.items():
    for actGroupName in groupNameList:
        groupIpyDataList = groupInfo[actGroupName]
        allOpen = False
        cfgIDList = []
        allServerIDRangeList = []
@@ -128,10 +237,11 @@
                actInfo = actInfoDict[cfgID]
                # 已经在活动中的记录必须要处理
                parseIpyDataList.append(ipyData)
                serverIDRangeList = actInfo[ShareDefine.ActKey_ServerIDRangeList]
                GameWorld.Log("    使用已经在活动中的记录的区服分组: cfgID=%s,serverIDRangeList=%s"
                              % (cfgID, serverIDRangeList))
                if actName in ShareDefine.CrossActLockServerGroupIDList:
                    serverIDRangeList = actInfo[ShareDefine.ActKey_ServerIDRangeList]
                    GameWorld.Log("    使用已经在活动中的记录的区服分组: cfgID=%s,serverIDRangeList=%s"
                                  % (cfgID, serverIDRangeList))
            # 没配置的全服开放
            if not serverIDRangeList:
                allOpen = True
@@ -185,6 +295,7 @@
    curDateTime = datetime.datetime.strptime(curDateTimeStr, ChConfig.TYPE_Time_Format)
    
    actTimeInfoDict = {}
    actCfgIDInfoDict = {}
    ipyDataMgr = IpyGameDataPY.IPY_Data()
    
    GameWorld.Log("=============================================================")
@@ -207,15 +318,28 @@
        parseIpyDataList = __GetParseIpyDataList(ipyDataMgr, actName, curActInfoDict)
        for ipyData in parseIpyDataList:
            cfgID = ipyData.GetCfgID()
            actGroupName = ipyData.GetActGroupName()
            startDateStr = ipyData.GetStartDate()
            endDateStr = ipyData.GetEndDate()
            GameWorld.Log("    cfgID=%s,startDateStr=%s,endDateStr=%s,curDateTime=%s" % (cfgID, startDateStr, endDateStr, curDateTime))
            GameWorld.Log("    cfgID=%s,actGroupName==%s,startDateStr=%s,endDateStr=%s,curDateTime=%s" % (cfgID, actGroupName, startDateStr, endDateStr, curDateTime))
            if not startDateStr:
                startDateStr = curDateStr
                GameWorld.Log("        开始日期为空,默认每天,今日为: startDateStr=%s" % startDateStr)
            if not endDateStr:
                endDateStr = curDateStr
                GameWorld.Log("        结束日期为空,默认每天,今日为: endDateStr=%s" % endDateStr)
            actByWeek = (startDateStr.startswith("W") and endDateStr.startswith("W")) # 按周x开
            if actByWeek:
                startDateStr, endDateStr = GameWorld.GetOperationActionDateStr(ipyData)
                GameWorld.Log("        星期X转化为日期: %s ~ %s" % (startDateStr, endDateStr))
            if hasattr(ipyData, "GetJoinStartTime") and hasattr(ipyData, "GetJoinEndTime"):
                joinStartTimeStr = ipyData.GetJoinStartTime()
                joinEndTimeStr = ipyData.GetJoinEndTime()
            else:
                joinStartTimeStr = ""
                joinEndTimeStr = ""
                
            if hasattr(ipyData, "GetStartTimeList") and hasattr(ipyData, "GetEndTimeList"):
                startHMStrList = ipyData.GetStartTimeList()
@@ -232,6 +356,7 @@
                GameWorld.ErrLog("        活动配置开始及结束时间个数不匹配! actName=%s,cfgID=%s,startHMStrList=%s,endHMStrList=%s" 
                                 % (actName, cfgID, startHMStrList, endHMStrList))
                
            isDayReset = 0 if not hasattr(ipyData, "GetIsDayReset") else ipyData.GetIsDayReset()
            resetType = 0 if not hasattr(ipyData, "GetResetType") else ipyData.GetResetType() # 重置类型,0-0点重置;1-5点重置
            if resetType == 1:
                startDayDate = datetime.datetime.strptime("%s 05:00:00" % (startDateStr), ChConfig.TYPE_Time_Format)
@@ -289,6 +414,17 @@
            GameWorld.Log("        startList=%s" % (startList))
            GameWorld.Log("        end  List=%s" % (endList))
            
            joinStartTimeList, joinEndTimeList = [], [] # 可指定活动可参与的时间点,不影响活动状态,只影响活动某些功能的参与时机,如上榜类
            if joinStartTimeStr:
                if isDayReset:
                    joinStartTimeList.append(datetime.datetime.strptime("%d-%d-%d %s:00" % (curDateTime.year, curDateTime.month, curDateTime.day, joinStartTimeStr), ChConfig.TYPE_Time_Format))
                    joinEndTimeList.append(datetime.datetime.strptime("%d-%d-%d %s:00" % (curDateTime.year, curDateTime.month, curDateTime.day, joinEndTimeStr), ChConfig.TYPE_Time_Format))
                else:
                    joinStartTimeList.append(datetime.datetime.strptime("%s %s:00" % (startDateStr, joinStartTimeStr), ChConfig.TYPE_Time_Format))
                    joinEndTimeList.append(datetime.datetime.strptime("%s %s:00" % (endDateStr, joinEndTimeStr), ChConfig.TYPE_Time_Format))
            GameWorld.Log("        joinStartTimeList=%s" % (joinStartTimeList))
            GameWorld.Log("        joinEndTime  List=%s" % (joinEndTimeList))
            for dtIndex, startDateTime in enumerate(startList):
                endDateTime = endList[dtIndex]
                # 广播 - 相对实际开始时间
@@ -327,7 +463,10 @@
                
            if actName not in actTimeInfoDict:
                actTimeInfoDict[actName] = {}
            actTimeInfoDict[actName][cfgID] = [ipyData, startList, endList, notifyDict]
            actTimeInfoDict[actName][cfgID] = [ipyData, startList, endList, notifyDict, joinStartTimeList, joinEndTimeList]
            if actName not in actCfgIDInfoDict:
                actCfgIDInfoDict[actName] = [[], []]
            endCfgIDList, actCfgIDList = actCfgIDInfoDict[actName]
            
            if actName not in crossActInfoDict:
                crossActInfoDict[actName] = {}
@@ -338,23 +477,46 @@
            
            # ipyData 活动时间表信息由跨服服务器同步子服,活动内容取子服自己的
            ipyDataDict = {}
            for k, v in ipyData.__dict__.items():
                if k in ["NotifyInfoStart", "NotifyInfoEnd", "NotifyInfoLoop", "ServerIDRangeList"]:
            methods = CommFunc.get_class_method(ipyData, "Get") # 获取所有Get开头的方法
            for method_name in methods:
                if method_name in ["GetNotifyInfoStart", "GetNotifyInfoEnd", "GetNotifyInfoLoop", "GetServerIDRangeList"]:
                    continue
                ipyDataDict[k] = v
                ipyDataDict[method_name[3:]] = getattr(ipyData, method_name)()
            ipyDataDict.update({"StartDate":startDateStr, "EndDate":endDateStr})
            GameWorld.Log("        ipyDataDict=%s" % ipyDataDict)
            
            curCfgActInfoDict.update({ShareDefine.ActKey_CfgID:cfgID, ShareDefine.ActKey_IpyDataInfo:ipyDataDict})
            if ShareDefine.ActKey_ServerIDRangeList not in curCfgActInfoDict:
            if ShareDefine.ActKey_ServerIDRangeList not in curCfgActInfoDict or actName not in ShareDefine.CrossActLockServerGroupIDList:
                # 没有的话则使用配置中的,防止配置修改导致服务器ID分区变动引起的活动数据异常,除非后台工具强制修改
                curCfgActInfoDict[ShareDefine.ActKey_ServerIDRangeList] = ipyData.GetServerIDRangeList()
                
            actID, dayIndex, templateID = 0, 0, 0
            if isActTime:
                ''' 注: 检查是否已经存在活动中的分组,有的话强制将其置为结算状态,有且仅有一个活动中的组,后面的强制覆盖前面的
                parseIpyDataList  确保同一活动组名的serverID不会重复
                                        这里进一步确保不同活动组名的不会同时开启活动,有且仅有一个活动中的活动组
                '''
                for befIpyData in parseIpyDataList:
                    befCfgID = befIpyData.GetCfgID()
                    befActGroupName = befIpyData.GetActGroupName()
                    if befActGroupName == actGroupName:
                        break
                    if befCfgID not in actCfgIDList:
                        continue
                    actCfgIDList.remove(befCfgID)
                    if befCfgID in curActInfoDict:
                        befCfgActInfoDict = curActInfoDict[befCfgID]
                        befCfgActInfoDict[ShareDefine.ActKey_ID] = 0 # 活动ID强制置为0
                    if befCfgID in endCfgIDList:
                        continue
                    endCfgIDList.append(befCfgID)
                    GameWorld.Log("        前面存在活动的分组,则强制结束活动! befCfgID=%s,befActGroupName=%s" % (befCfgID, befActGroupName))
                if cfgID not in actCfgIDList:
                    actCfgIDList.append(cfgID)
                dayIndex = (curDateTime - startDayDate).days
                actIDDateTime = startDayDate
                isDayReset = 0 if not hasattr(ipyData, "GetIsDayReset") else ipyData.GetIsDayReset()
                # 按时段开的默认每天重置
                if isDayReset or (startHMStrList and endHMStrList):
                    actIDDateTime += datetime.timedelta(days=dayIndex)
@@ -362,20 +524,23 @@
                GameWorld.Log("        isDayReset=%s,actIDDateTime=%s,actID=%s" % (isDayReset, actIDDateTime, actID))
                
                # 模板ID
                if hasattr(ipyData, "TemplateIDList"):
                if hasattr(ipyData, "GetTemplateIDList"):
                    templateIDList = ipyData.GetTemplateIDList()
                    templateID = templateIDList[-1] if dayIndex >= len(templateIDList) else templateIDList[dayIndex]
                    
                    # 其他特殊模板ID获取处理,有需要的单独处理即可,根据活动规则自行扩展...  
            else:
                if cfgID not in endCfgIDList:
                    endCfgIDList.append(cfgID)
                    
            curCfgActInfoDict.update({ShareDefine.ActKey_ID:actID, ShareDefine.ActKey_TemplateID:templateID, 
                                      ShareDefine.ActKey_DayIndex:dayIndex})
            
    CrossActInfo = IpyGameDataPY.SetConfigEx(key, [reloadSign, actTimeInfoDict])
    CrossActInfo = IpyGameDataPY.SetConfigEx(key, [reloadSign, actTimeInfoDict, actCfgIDInfoDict])
    
    GameWorld.Log("本日跨服运营活动信息加载完毕!reloadSign=%s,isRefreshState=%s" % (reloadSign, isRefreshState))
    GameWorld.Log("    actTimeInfoDict=%s" % actTimeInfoDict)
    GameWorld.Log("    actCfgIDInfoDict=%s" % actCfgIDInfoDict)
    GameWorld.Log("    crossActInfoDict=%s" % crossActInfoDict)
    GameWorld.Log("=============================================================")
    if isRefreshState:
@@ -388,6 +553,7 @@
    isReload, CrossActInfo = __GetCrossActInfo(False) # 这里必须传False
    isReload = isReload or reloadRefresh
    actTimeInfoDict = CrossActInfo[CrossAct_TodayInfo]
    actCfgIDInfoDict = CrossActInfo[CrossAct_CfgIDInfo]
    
    crossActInfoDict = GetCrossActInfoDict()
    
@@ -395,31 +561,93 @@
    curDateTime = GameWorld.GetServerTime()
    curDateTime = datetime.datetime.strptime("%d-%d-%d %d:%d:00" % (curDateTime.year, curDateTime.month, curDateTime.day,
                                                                    curDateTime.hour, curDateTime.minute), ChConfig.TYPE_Time_Format)
    actChangeList = []
    actStateChangeList = []
    sysnCrossActInfoDict = {}
    flowStateErrorResetList = []
    for actName in ShareDefine.CrossActNameList:
        if actName not in actTimeInfoDict or actName not in crossActInfoDict:
        if actName not in actTimeInfoDict or actName not in crossActInfoDict or actName not in actCfgIDInfoDict:
            continue
        for ipyData, startList, endList, notifyDict in actTimeInfoDict[actName].values():
        timeInfoDict = actTimeInfoDict[actName]
        endCfgIDList, actCfgIDList = actCfgIDInfoDict[actName]
        # 可能一条cfgID处理结束,另一条cfgID处理开始,也可能同一条cfgID即结束同时又开始(如每天重置的)
        cfgIDList = endCfgIDList + actCfgIDList
        for cfgID in cfgIDList:
            if cfgID not in timeInfoDict:
                continue
            ipyData, startList, endList, notifyDict, joinStartTimeList, joinEndTimeList = timeInfoDict[cfgID]
            
            isEnd = True
            state = 0 # 默认关闭
            stateJoin = ShareDefine.ActStateJoin_None # 可参与状态,0-参与前;1-可参与;2-参与结束
            cfgID = ipyData.GetCfgID()
            groupName = ipyData.GetActGroupName()
            zoneID = ipyData.GetZoneID()
            actFlowID = ipyData.GetActFlowID() if hasattr(ipyData, "GetActFlowID") else 0 # 活动流程ID
            actStartDataTime = None
            
            if cfgID not in crossActInfoDict[actName]:
                crossActInfoDict[actName][cfgID] = {}
            actInfoDict = crossActInfoDict[actName][cfgID]
            
            # ״̬
            for dIndex, startDateTime in enumerate(startList):
                endDateTime = endList[dIndex]
                if startDateTime <= curDateTime < endDateTime:
                    state = dIndex + 1 # 也是代表第几个时间段
                    break
            if cfgID not in endCfgIDList:
                for dIndex, startDateTime in enumerate(startList):
                    endDateTime = endList[dIndex]
                    if startDateTime <= curDateTime < endDateTime:
                        state = dIndex + 1 # 也是代表第几个时间段
                        actStartDataTime = startDateTime
                        break
                if endList:
                    isEnd = (curDateTime >= endList[-1])
                if joinStartTimeList:
                    for jIndex, joinStartDateTime in enumerate(joinStartTimeList):
                        endJoinDateTime = joinEndTimeList[jIndex]
                        if joinStartDateTime <= curDateTime < endJoinDateTime:
                            stateJoin = ShareDefine.ActStateJoin_Start
                            break
                        elif curDateTime >= endJoinDateTime:
                            stateJoin = ShareDefine.ActStateJoin_End
                else:
                    stateJoin = ShareDefine.ActStateJoin_Start if state else ShareDefine.ActStateJoin_None
            actID = actInfoDict.get(ShareDefine.ActKey_ID, 0)
            templateID = actInfoDict.get(ShareDefine.ActKey_TemplateID, 0)
            serverIDRangeList = actInfoDict.get(ShareDefine.ActKey_ServerIDRangeList)
            dbInfo = actInfoDict.get(ShareDefine.ActKey_DBInfo, {})
            dbState = dbInfo.get(ShareDefine.ActKey_State, 0)
            dbStateJoin = dbInfo.get(ShareDefine.ActKey_StateJoin, 0)
            dbCfgID = dbInfo.get(ShareDefine.ActKey_CfgID, 0)
            dbActID = dbInfo.get(ShareDefine.ActKey_ID, 0)
            dbTemplateID = dbInfo.get(ShareDefine.ActKey_TemplateID, 0)
            dbServerIDRangeList = dbInfo.get(ShareDefine.ActKey_ServerIDRangeList, None)
            forceReset = False
            if dbCfgID == cfgID and dbServerIDRangeList != serverIDRangeList:
                forceReset = True
            errStateActID = 0
            if state and actFlowID: # 有活动流程ID的,实际状态按取活动流程对应状态
                errStateActID = PlayerDBGSEvent.GetDBGSTrig_ByKey(PlayerDBGSEvent.Def_ActFlowStateError % (actName, zoneID))
                # 已经是不同活动了,强制重置异常状态标记,防止影响新活动
                if errStateActID and (errStateActID != actID or not dbState):
                    GameWorld.Log("按流程走的活动流程上次异常,新活动重置状态! %s,zoneID=%s,actID=%s,errStateActID=%s,dbState=%s" % (actName, zoneID, actID, errStateActID, dbState))
                    PlayerDBGSEvent.SetDBGSTrig_ByKey(PlayerDBGSEvent.Def_ActFlowStateError % (actName, zoneID), 0)
                    errStateActID = 0
                flowStateIndex, flowState, flowStatePre = GetActTimeFlowState(actFlowID, actStartDataTime, curDateTime)
                # 非第一个流程状态变更的时候,要验证流程是否正确,如果异常,则流程照走,标记异常,具体异常的处理由各活动自行处理
                if flowStateIndex > 0 and flowState != dbState and flowStatePre != dbState and not errStateActID:
                    GameWorld.ErrLog("按流程走的活动流程已异常! %s,zoneID=%s,actID=%s,flowStatePre=%s,dbState=%s" % (actName, zoneID, actID, flowStatePre, dbState))
                    PlayerDBGSEvent.SetDBGSTrig_ByKey(PlayerDBGSEvent.Def_ActFlowStateError % (actName, zoneID), actID)
                    errStateActID = actID
                state = flowState
                
            # 全服广播提示信息
            if curDateTime in notifyDict:
                serverIDRangeList = actInfoDict.get(ShareDefine.ActKey_ServerIDRangeList)
            if curDateTime in notifyDict and not flowState and not errStateActID:
                if serverIDRangeList != None:
                    notifyKey, paramList = notifyDict[curDateTime]
                    country = 0
@@ -427,49 +655,190 @@
                    crossNotifyList = []
                    crossNotifyList.append([ShareDefine.CrossNotify_CrossAct, [country, notifyKey, paramList], serverIDRangeList])
                    PlayerControl.CrossNotifyEx(serverGroupIDList, crossNotifyList)
            dbInfo = actInfoDict.get(ShareDefine.ActKey_DBInfo, {})
            dbState = dbInfo.get(ShareDefine.ActKey_State, 0)
            dbActID = dbInfo.get(ShareDefine.ActKey_ID, 0)
            dbTemplateID = dbInfo.get(ShareDefine.ActKey_TemplateID, 0)
            actID = actInfoDict.get(ShareDefine.ActKey_ID, 0)
            templateID = actInfoDict.get(ShareDefine.ActKey_TemplateID, 0)
            if not isReload and dbState == state and dbActID == actID:
            if not isReload and dbState == state and dbStateJoin == stateJoin and dbActID == actID and not forceReset:
                #已经是这个状态了
                continue
            GameWorld.Log("跨服运营活动变更: actName=%s,cfgID=%s,dbState=%s -> state=%s, dbActID=%s -> actID=%s"
                          % (actName, cfgID, dbState, state, dbActID, actID))
            GameWorld.Log("跨服运营活动状态: actName=%s,cfgID=%s,groupName=%s,zoneID=%s,dbState=%s -> state=%s,isEnd=%s, dbActID=%s -> actID=%s,forceReset=%s, dbStateJoin=%s -> stateJoin=%s"
                          % (actName, cfgID, groupName, zoneID, dbState, state, isEnd, dbActID, actID, forceReset, dbStateJoin, stateJoin))
            
            if dbActID != actID:
                GameWorld.Log("    活动ID变更: actName=%s,cfgID=%s,dbActID=%s -> actID=%s,dbTemplateID=%s"
                              % (actName, cfgID, dbActID, actID, dbTemplateID))
                if actName == ShareDefine.CrossActName_CTGBillboard:
                    CrossActCTGBillboard.OnActIDChange(cfgID, dbTemplateID, state)
            if dbState != state:
                pass
            # 更新状态
            actInfoDict[ShareDefine.ActKey_State] = state
            actInfoDict[ShareDefine.ActKey_DBInfo] = {ShareDefine.ActKey_ID:actID, ShareDefine.ActKey_State:state, ShareDefine.ActKey_TemplateID:templateID}
            GameWorld.Log("    活动状态同步信息: actName=%s,cfgID=%s,actInfoDict=%s" % (actName, cfgID, actInfoDict))
            actInfoDict[ShareDefine.ActKey_StateJoin] = stateJoin
            dbInfo = {ShareDefine.ActKey_ID:actID, ShareDefine.ActKey_State:state, ShareDefine.ActKey_TemplateID:templateID,
                      ShareDefine.ActKey_CfgID:cfgID, ShareDefine.ActKey_ServerIDRangeList:serverIDRangeList,
                      ShareDefine.ActKey_StateJoin:stateJoin}
            if errStateActID:
                actInfoDict[ShareDefine.ActKey_StateError] = errStateActID
            actInfoDict[ShareDefine.ActKey_DBInfo] = dbInfo
            #GameWorld.Log("    活动状态同步信息: actName=%s,cfgID=%s,groupName=%s,zoneID=%s,actInfoDict=%s" % (actName, cfgID, groupName, zoneID, actInfoDict))
            if actName not in sysnCrossActInfoDict:
                sysnCrossActInfoDict[actName] = {}
            sysnCrossActInfoDict[actName][cfgID] = actInfoDict
            
            if dbActID != actID or forceReset:
                GameWorld.Log("    活动ID变更: actName=%s,cfgID=%s,groupName=%s,zoneID=%s,dbActID=%s -> actID=%s,forceReset=%s,dbTemplateID=%s"
                              % (actName, cfgID, groupName, zoneID, dbActID, actID, forceReset, dbTemplateID))
                if errStateActID:
                    flowStateErrorResetList.append((actName, zoneID))
                if actName == ShareDefine.CrossActName_CTGBillboard:
                    CrossActCTGBillboard.OnActIDChange(cfgID, dbTemplateID, state)
                elif actName == ShareDefine.CrossActName_BossTrial:
                    PlayerActBossTrial.OnCrossActIDChange(cfgID, zoneID, ipyData, state)
                elif actName == ShareDefine.CrossActName_XianXiaMJ:
                    PlayerActXianXiaMJ.OnCrossActIDChange(cfgID, zoneID, ipyData, state)
                elif actName == ShareDefine.CrossActName_Gubao:
                    PlayerActGubao.OnCrossActIDChange(cfgID, zoneID, ipyData, state)
                elif actName == ShareDefine.CrossActName_HorsePetTrain:
                    PlayerActHorsePetTrain.OnCrossActIDChange(cfgID, zoneID, ipyData, state)
                elif actName == ShareDefine.CrossActName_Lianqi:
                    PlayerActLianqi.OnCrossActIDChange(cfgID, zoneID, ipyData, state)
                elif actName == ShareDefine.CrossActName_FamilyGCZ:
                    CrossFamilyGCZ.OnCrossActIDChange(cfgID, zoneID, ipyData, state)
                else:
                    actChangeList.append([actName, ipyData, state, cfgID, groupName, zoneID, dbActID, actID, forceReset, dbTemplateID])
                # 活动ID变更强制视为状态变更,防止维护前后状态一样,但其实活动ID已经不同的情况会导致无法触发状态变更
                actIDChange = True
                actStateChangeList.append([actName, ipyData, dbState, state, cfgID, groupName, zoneID, actIDChange, actID, dbTemplateID])
            elif dbState != state:
                actIDChange = False
                GameWorld.Log("    活动状态变更: actName=%s,cfgID=%s,groupName=%s,zoneID=%s,dbState=%s -> state=%s,actIDChange=%s,dbTemplateID=%s"
                              % (actName, cfgID, groupName, zoneID, dbState, state, actIDChange, dbTemplateID))
                actStateChangeList.append([actName, ipyData, dbState, state, cfgID, groupName, zoneID, actIDChange, actID, dbTemplateID])
            # 活动中刷新,每次都需要刷新的逻辑,包含重读配置等
            if state:
                if actName == ShareDefine.CrossActName_BossTrial:
                    PlayerActBossTrial.OnCrossActInStateRefresh(cfgID, zoneID, ipyData)
                elif actName == ShareDefine.CrossActName_XianXiaMJ:
                    PlayerActXianXiaMJ.OnCrossActInStateRefresh(cfgID, zoneID, ipyData)
                elif actName == ShareDefine.CrossActName_Gubao:
                    PlayerActGubao.OnCrossActInStateRefresh(cfgID, zoneID, ipyData)
                elif actName == ShareDefine.CrossActName_HorsePetTrain:
                    PlayerActHorsePetTrain.OnCrossActInStateRefresh(cfgID, zoneID, ipyData)
                elif actName == ShareDefine.CrossActName_Lianqi:
                    PlayerActLianqi.OnCrossActInStateRefresh(cfgID, zoneID, ipyData)
            # 仅活动有配置参与时间段的会触发
            if actID and dbActID == actID and dbStateJoin != stateJoin:
                GameWorld.Log("    参与状态变更: dbStateJoin=%s,stateJoin=%s" % (dbStateJoin, stateJoin))
                # 参与开始
                if stateJoin == ShareDefine.ActStateJoin_Start:
                    pass
                # 参与结束
                elif stateJoin == ShareDefine.ActStateJoin_End:
                    if actName == ShareDefine.CrossActName_BossTrial:
                        PlayerActBossTrial.OnCrossActJoinEnd(cfgID, zoneID, ipyData)
                    elif actName == ShareDefine.CrossActName_XianXiaMJ:
                        PlayerActXianXiaMJ.OnCrossActJoinEnd(cfgID, zoneID, ipyData)
                    elif actName == ShareDefine.CrossActName_Gubao:
                        PlayerActGubao.OnCrossActJoinEnd(cfgID, zoneID, ipyData)
                    elif actName == ShareDefine.CrossActName_HorsePetTrain:
                        PlayerActHorsePetTrain.OnCrossActJoinEnd(cfgID, zoneID, ipyData)
                    elif actName == ShareDefine.CrossActName_Lianqi:
                        PlayerActLianqi.OnCrossActJoinEnd(cfgID, zoneID, ipyData)
            GameWorld.SendMapServerMsgEx(ShareDefine.Def_Notify_WorldKey_CrossActInfo % actName, crossActInfoDict[actName])
            # 非活动中的处理完关闭后,最后删除
            if not state:
            if not state and isEnd:
                del crossActInfoDict[actName][cfgID]
                if not crossActInfoDict[actName]:
                    del crossActInfoDict[actName]
                GameWorld.DebugLog("    删除结束的活动: actName=%s,cfgID=%s,crossActInfoDict=%s" % (actName, cfgID, crossActInfoDict))
                GameWorld.Log("    移除结束的活动: actName=%s,cfgID=%s,crossActInfoDict=%s" % (actName, cfgID, crossActInfoDict))
                
    # 同步子服务器
    serverGroupIDList = []
    CrossRealmMsg.SendMsgToClientServer(ShareDefine.CrossServerMsg_CrossActInfo, sysnCrossActInfoDict, serverGroupIDList)
    if sysnCrossActInfoDict:
        serverGroupIDList = []
        CrossRealmMsg.SendMsgToClientServer(ShareDefine.CrossServerMsg_CrossActInfo, sysnCrossActInfoDict, serverGroupIDList)
    # 需要等活动等同步到子服后才处理以下逻辑,不然可能导致子服没有活动时间明细引起活动异常
    for changeInfo in actChangeList:
        actName, ipyData, state, cfgID, groupName, zoneID, dbActID, actID, forceReset, dbTemplateID = changeInfo
        GameWorld.Log("    活动ID变更: actName=%s,cfgID=%s,groupName=%s,zoneID=%s,dbActID=%s -> actID=%s,forceReset=%s,dbTemplateID=%s"
                      % (actName, cfgID, groupName, zoneID, dbActID, actID, forceReset, dbTemplateID))
        if actName == ShareDefine.CrossActName_AllRecharge:
            import CrossActAllRecharge
            CrossActAllRecharge.OnActIDChange(ipyData, state)
    for changeInfo in actStateChangeList:
        actName, ipyData, dbState, state, cfgID, groupName, zoneID, actIDChange, actID, dbTemplateID = changeInfo
        GameWorld.Log("    活动状态变更: actName=%s,cfgID=%s,groupName=%s,zoneID=%s,dbState=%s -> state=%s,actIDChange=%s,dbTemplateID=%s"
                      % (actName, cfgID, groupName, zoneID, dbState, state, actIDChange, dbTemplateID))
        if actName == ShareDefine.CrossActName_LuckyCloudBuy:
            import CrossLuckyCloudBuy
            CrossLuckyCloudBuy.OnLuckyCloudBuyStateChange(ipyData, actIDChange, state)
        elif actName == ShareDefine.CrossActName_FamilyGCZ:
            CrossFamilyGCZ.OnCrossActStateChange(ipyData, actID, dbState, state)
    for actName, zoneID in flowStateErrorResetList:
        GameWorld.Log("活动结束重置按流程走的活动流程异常状态! %s,zoneID=%s" % (actName, zoneID))
        PlayerDBGSEvent.SetDBGSTrig_ByKey(PlayerDBGSEvent.Def_ActFlowStateError % (actName, zoneID), 0)
    return
def IsActFlowStateError(actName, zoneID):
    ## 流程状态是否已异常
    errStateActID = PlayerDBGSEvent.GetDBGSTrig_ByKey(PlayerDBGSEvent.Def_ActFlowStateError % (actName, zoneID))
    if errStateActID:
        GameWorld.ErrLog("活动流程状态已异常! %s,zoneID=%s,errStateActID=%s" % (actName, zoneID, errStateActID))
        return True
    return False
def GetActTimeFlowState(actFlowID, actStartDataTime, curDateTime):
    ## 获取活动流程ID对应当前状态
    ipyDataList = IpyGameDataPY.GetIpyGameDataList("ActTimeFlow", actFlowID)
    if not ipyDataList:
        return 0
    flowStatePre = 0
    flowState = 0
    flowStateIndex = -1
    for index, timeIpyData in enumerate(ipyDataList):
        #dataID = timeIpyData.GetID()
        startDay, startHour, startMinute = timeIpyData.GetStartDay(), timeIpyData.GetStartHour(), timeIpyData.GetStartMinute()
        endDay, endHour, endMinute = timeIpyData.GetEndDay(), timeIpyData.GetEndHour(), timeIpyData.GetEndMinute()
        startSeconds = ((startDay - 1) * 24 + startHour) * 3600 + startMinute * 60
        endSeconds = ((endDay - 1) * 24 + endHour) * 3600 + endMinute * 60
        startDateTime = actStartDataTime + datetime.timedelta(seconds=startSeconds)
        endDateTime = actStartDataTime + datetime.timedelta(seconds=endSeconds)
        if curDateTime < startDateTime or curDateTime > endDateTime:
            flowStatePre = timeIpyData.GetStateValue()
            continue
        flowState = timeIpyData.GetStateValue()
        flowStateIndex = index
        #notifyInfoDict = timeIpyData.GetNotifyInfo()
        #if not stateError and notifyInfoDict:
        #    diffDateTime = curDateTime - startDateTime
        #    diffMinute = (diffDateTime.days * 24 * 3600 + diffDateTime.seconds) / 60 # 当前时间与开始时间相差分钟数
        #    GameWorld.DebugLog("    广播判断: curDateTime=%s,startDateTime=%s,diffDays=%s,diffSeconds=%s,diffMinute=%s"
        #                       % (curDateTime, startDateTime, diffDateTime.days, diffDateTime.seconds, diffMinute))
        #    if diffMinute in notifyInfoDict:
        #        notifyKey, paramList = notifyInfoDict[diffMinute]
        #        PlayerControl.WorldNotifyCross(serverGroupIDList, 0, notifyKey, paramList)
        break
    if not flowState:
        flowStatePre = 0
    return flowStateIndex, flowState, flowStatePre
def Sync_CrossActInfoToClientServer(serverGroupID=0):
    ''' 同步跨服运营活动信息到子服务器
@@ -493,13 +862,26 @@
    ## 收到跨服服务器同步的跨服运营活动状态
    
    GameWorld.Log("===== 收到跨服服务器同步的跨服运营活动状态: %s" % sysnCrossActInfoDict)
    if PyGameData.g_crossActInfoDict == None:
    if PyGameData.g_crossActInfoDict == None or not sysnCrossActInfoDict:
        PyGameData.g_crossActInfoDict = {}
    PyGameData.g_crossActInfoDict.update(sysnCrossActInfoDict)
    for actName, actInfoDict in sysnCrossActInfoDict.items():
        GameWorld.SendMapServerMsgEx(ShareDefine.Def_Notify_WorldKey_CrossActInfo % actName, actInfoDict)
        
    for actName, syncActInfoDict in sysnCrossActInfoDict.items():
        for cfgID, syncActInfo in syncActInfoDict.items():
            if actName not in PyGameData.g_crossActInfoDict:
                PyGameData.g_crossActInfoDict[actName] = {}
            actInfoDict = PyGameData.g_crossActInfoDict[actName]
            actInfoDict[cfgID] = syncActInfo
        if actName == ShareDefine.CrossActName_LuckyCloudBuy:
            import CrossLuckyCloudBuy
            CrossLuckyCloudBuy.Sync_LuckyCloudBuyRoundInfo(None)
        GameWorld.SendMapServerMsgEx(ShareDefine.Def_Notify_WorldKey_CrossActInfo % actName, syncActInfoDict)
        # 以下需要等活动信息同步给地图后才处理
        if actName == ShareDefine.CrossActName_FamilyGCZ:
            CrossFamilyGCZ.ClientServer_CrossActInfo()
    # 删除非活动中的
    for actName, actInfoDict in PyGameData.g_crossActInfoDict.items():
        for cfgID, actInfo in actInfoDict.items():
@@ -507,6 +889,28 @@
                del PyGameData.g_crossActInfoDict[actName][cfgID]
                
    return
def GetPlayerCrossActInfo(curPlayer, actName):
    ## 获取跨服玩家对应的跨服活动信息
    if PyGameData.g_crossActInfoDict == None:
        return {}
    actInfoDict = PyGameData.g_crossActInfoDict.get(actName, {})
    if not actInfoDict:
        return {}
    playerServerID = GameWorld.GetPlayerServerID(curPlayer)
    for actInfo in actInfoDict.values():
        if not actInfo.get(ShareDefine.ActKey_State, 0):
            continue
        if ShareDefine.ActKey_ServerIDRangeList not in actInfo:
            continue
        serverIDRangeList = actInfo[ShareDefine.ActKey_ServerIDRangeList]
        if not serverIDRangeList:
            # 全服开启
            return actInfo
        for serverIDA, serverIDB in serverIDRangeList:
            if serverIDA <= playerServerID <= serverIDB:
                return actInfo
    return {}
def SendMapServerCrossActionState():
    # 地图启动成功时通知跨服活动相关状态  - 本服地图,跨服地图不需要通知
@@ -521,3 +925,214 @@
        
    return
## ================================================================================================
def __GetTodayCrossDailyActionInfo():
    # 获取本日待处理的日常活动信息
    key = "TodayCrossDailyActionInfo"
    curTime = int(time.time())
    curDateStr = GameWorld.ChangeTimeNumToStr(curTime, ChConfig.TYPE_Time_YmdFormat) # 当天日期
    loadSign = curDateStr
    TodayDailyActionInfo = IpyGameDataPY.GetConfigEx(key)
    if TodayDailyActionInfo and TodayDailyActionInfo[0] == loadSign:
        GameWorld.DebugLog("已经加载过本日跨服日常活动处理信息!loadSign=%s" % loadSign)
        return TodayDailyActionInfo[1]
    todayActionInfo = []
    dayTime = GameWorld.GetServerTime()
    weekDay = str(dayTime.weekday() + 1) # 格式为json, 当前星期几, 1代表星期1
    GameWorld.Log("===== 加载今天跨服日常活动信息 =====")
    GameWorld.Log("当前星期%s" % weekDay)
    dailyTimeInfoList = []
    ipyDataMgr = IpyGameDataPY.IPY_Data()
    for i in xrange(ipyDataMgr.GetCrossDailyActionCount()):
        dailyIpyData = ipyDataMgr.GetCrossDailyActionByIndex(i)
        dailyID = dailyIpyData.GetDailyID()
        openTimeDict = dailyIpyData.GetOpenTimeDict()
        # 没有时间控制的,代表永久开放
        if not openTimeDict:
            todayActionInfo.append([dailyID])
            GameWorld.Log("    增加本日常开跨服日常活动信息: dailyID=%s" % dailyID)
            continue
        #如果星期key中存在 "0" 代表每日都开启
        if "0" not in openTimeDict and weekDay not in openTimeDict:
            GameWorld.Log("    不是跨服日常活动开启星期: dailyID=%s,openWeekLimit=%s" % (dailyID, openTimeDict.keys()))
            continue
        openTimeList = openTimeDict["0"] if "0" in openTimeDict else openTimeDict[weekDay]
        dailyTimeInfoList.append([openTimeList, dailyIpyData])
    GameWorld.Log("    -----------------------")
    for openTimeList, ipyData in dailyTimeInfoList:
        dailyID = ipyData.GetDailyID()
        notifyInfoDict = ipyData.GetNotifyInfo()
        openList = [] # [(时,分), ...]
        overList = [] # [(时,分), ...]
        goonStateDict = {} # {״̬:[(aDateTime, bDateTime)], ...}
        notifyDict = {} # {(时,分):[notifyKey, [参数]], ...}
        OpenState = 1 # 定义开启状态为1
        for hour, minute in openTimeList:
            openTimeStr = "%s %02d:%02d:%02d" % (curDateStr, hour, minute, 0)
            # 精确开启时间
            openDateTime = datetime.datetime.strptime(openTimeStr, ChConfig.TYPE_Time_Format)
            openList.append((openDateTime.hour, openDateTime.minute))
            # 精确关闭时间
            overDateTime = openDateTime + datetime.timedelta(minutes=ipyData.GetDuration())
            overList.append((overDateTime.hour, overDateTime.minute))
            # goon 开启状态
            openStateTimeList = goonStateDict.get(OpenState, [])
            openStateTimeList.append((openDateTime, overDateTime))
            goonStateDict[OpenState] = openStateTimeList
            # goon 其他状态,待扩展
            # ...
            # 广播
            for notifyMinute, notifyInfo in notifyInfoDict.items():
                notifyDateTime = openDateTime + datetime.timedelta(minutes=notifyMinute)
                notifyDict[(notifyDateTime.hour, notifyDateTime.minute)] = notifyInfo
        todayActionInfo.append([dailyID, openList, overList, goonStateDict, notifyDict])
        GameWorld.Log("    增加本日跨服日常活动信息: dailyID=%s,openList=%s,overList=%s,goonStateDict=%s,notifyDict=%s"
                      % (dailyID, openList, overList, goonStateDict, notifyDict))
    TodayDailyActionInfo = IpyGameDataPY.SetConfigEx(key, [loadSign, todayActionInfo])
    GameWorld.Log("本日跨服日常活动信息加载完毕! loadSign=%s" % loadSign)
    GameWorld.Log("=============================================================")
    return TodayDailyActionInfo[1]
def Dispose_CrossDailyActionState():
    # 跨服日常活动状态变更检查处理
    todayDailyActionInfo = __GetTodayCrossDailyActionInfo()
    if not todayDailyActionInfo:
        return
    gameWorld = GameWorld.GetGameWorld()
    dayTime = GameWorld.GetServerTime()
    curHourMinute = (dayTime.hour, dayTime.minute)
    sysnCrossDailyActionStateDict = {}
    for actionInfo in todayDailyActionInfo:
        dailyActionID = actionInfo[0]
        state = 0 # 默认关闭
        # 长度为1的代表常开的活动
        if len(actionInfo) == 1:
            state = 1
        else:
            #openList = [] # [(时,分), ...]
            #overList = [] # [(时,分), ...]
            #goonStateDict = {} # {״̬:[(aDateTime, bDateTime)], ...}
            #notifyDict = {} # {(时,分):[notifyKey, [参数]], ...}
            openList, overList, goonStateDict, notifyDict = actionInfo[1:]
            # 精确匹配开启
            if curHourMinute in openList:
                state = 1
            # 精确匹配关闭
            elif curHourMinute in overList:
                state = 0
            # goon ״̬
            else:
                for goonState, openStateTimeList in goonStateDict.items():
                    for dateTimeInfo in openStateTimeList:
                        if dateTimeInfo[0] < dayTime < dateTimeInfo[1]:
                            state = goonState
                            break
            # 全服广播提示信息
            if curHourMinute in notifyDict:
                notifyKey, paramList = notifyDict[curHourMinute]
                serverGroupIDList = []
                PlayerControl.WorldNotifyCross(serverGroupIDList, 0, notifyKey, paramList)
        dictName = ShareDefine.Def_Notify_WorldKey_CrossDailyActionState % dailyActionID
        beforeState = gameWorld.GetDictByKey(dictName)
        if beforeState == state:
            #已经是这个状态了
            continue
        if state:
            if dailyActionID in ChConfig.Def_CrossDailyMap:
                # 开启对应日常地图分区线路
                __openCrossDailyMap(ChConfig.Def_CrossDailyMap[dailyActionID])
            if dailyActionID == ShareDefine.CrossDailyActionID_YaomoBoss:
                GameWorld.SendMapServerMsgEx(ShareDefine.Def_Notify_WorldKey_ActionBossRebornSign % dailyActionID, int(time.time()))
        sysnCrossDailyActionStateDict[dailyActionID] = state
        #通知Mapserver,设置字典
        GameWorld.SendMapServerMsgEx(dictName, state)
        #更新字典值
        gameWorld.SetDict(dictName, state)
        GameWorld.Log("跨服日常活动状态变更: dailyActionID=%s,state=%s,dictName=%s" % (dailyActionID, state, dictName))
    # 同步子服务器
    if sysnCrossDailyActionStateDict:
        serverGroupIDList = []
        CrossRealmMsg.SendMsgToClientServer(ShareDefine.CrossServerMsg_CrossDailyActionState, sysnCrossDailyActionStateDict, serverGroupIDList)
    return
def __openCrossDailyMap(mapID):
    if mapID not in ChConfig.Def_CrossZoneMapTableName:
        return
    zoneTypeName = ChConfig.Def_CrossZoneMapTableName[mapID]
    ipyDataMgr = IpyGameDataPY.IPY_Data()
    if zoneTypeName and hasattr(ipyDataMgr, "Get%sCount" % zoneTypeName):
        realMapInfo = {}
        for index in range(getattr(ipyDataMgr, "Get%sCount" % zoneTypeName)()):
            ipyData = getattr(ipyDataMgr, "Get%sByIndex" % zoneTypeName)(index)
            zoneID = ipyData.GetZoneID()
            realMapID = ipyData.GetMapID()
            copyMapID = ipyData.GetCopyMapID()
            if realMapID not in realMapInfo:
                realMapInfo[realMapID] = []
            copyPropertyList = realMapInfo[realMapID]
            copyPropertyList.append([copyMapID, zoneID])
        for realMapID, copyPropertyList in realMapInfo.items():
            PlayerFB.SendMapOpenFBEx(realMapID, copyPropertyList)
    return
def SendMapServerCrossDailyActionState():
    # 地图启动成功时通知本日进行中的日常活动状态
    todayDailyActionInfo = __GetTodayCrossDailyActionInfo()
    if not todayDailyActionInfo:
        return
    gameWorld = GameWorld.GetGameWorld()
    for actionInfo in todayDailyActionInfo:
        dailyActionID = actionInfo[0]
        dictName = ShareDefine.Def_Notify_WorldKey_CrossDailyActionState % dailyActionID
        state = gameWorld.GetDictByKey(dictName)
        if state:
            GameWorld.SendMapServerMsgEx(dictName, state)
    return
def CrossServerMsg_CrossDailyActionState(msgData):
    gameWorld = GameWorld.GetGameWorld()
    for dailyActionID, state in msgData.items():
        dictName = ShareDefine.Def_Notify_WorldKey_CrossDailyActionState % dailyActionID
        #通知Mapserver,设置字典
        GameWorld.SendMapServerMsgEx(dictName, state)
        #更新字典值
        gameWorld.SetDict(dictName, state)
        GameWorld.Log("收到跨服日常活动状态变更: dailyActionID=%s,state=%s,dictName=%s" % (dailyActionID, state, dictName))
    return