hxp
2025-06-30 388823edfe6308cba6f76ca6dc4f20022c5cb2be
ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/CrossActionControl.py
@@ -22,10 +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
@@ -57,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, "")
@@ -67,8 +76,9 @@
            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
@@ -112,14 +122,55 @@
    GameWorld.DebugLog("找不到服务器组ID对应跨服活动分区! actName=%s, serverGroupID=%s" % (actName, serverGroupID))
    return
def GetCrossActInfoByCfgID(actName, cfgID):
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
    return curActInfoDict[cfgID]
    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:
@@ -137,6 +188,7 @@
            state = recData.GetValue2()
            actID = recData.GetValue3()
            templateID = recData.GetValue4()
            stateJoin = recData.GetValue5()
            if not state:
                continue
            if actName not in PyGameData.g_crossActInfoDict:
@@ -144,7 +196,8 @@
            actInfoDict = PyGameData.g_crossActInfoDict[actName]
            # 活动ID、状态、模板信息单独存储,重置活动判断用
            dbInfo = {ShareDefine.ActKey_ID:actID, ShareDefine.ActKey_State:state, ShareDefine.ActKey_TemplateID:templateID, 
                      ShareDefine.ActKey_CfgID:cfgID, ShareDefine.ActKey_ServerIDRangeList:serverIDRangeList}
                      ShareDefine.ActKey_CfgID:cfgID, ShareDefine.ActKey_ServerIDRangeList:serverIDRangeList,
                      ShareDefine.ActKey_StateJoin:stateJoin}
            actInfo = {}
            actInfo.update(dbInfo)
            actInfo[ShareDefine.ActKey_DBInfo] = dbInfo
@@ -281,6 +334,13 @@
                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()
                endHMStrList = ipyData.GetEndTimeList()
@@ -296,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)
@@ -353,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]
                # 广播 - 相对实际开始时间
@@ -391,7 +463,7 @@
                
            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]
@@ -405,10 +477,11 @@
            
            # 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)
            
@@ -444,7 +517,6 @@
                    
                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)
@@ -492,6 +564,7 @@
    actChangeList = []
    actStateChangeList = []
    sysnCrossActInfoDict = {}
    flowStateErrorResetList = []
    for actName in ShareDefine.CrossActNameList:
        if actName not in actTimeInfoDict or actName not in crossActInfoDict or actName not in actCfgIDInfoDict:
            continue
@@ -503,13 +576,16 @@
        for cfgID in cfgIDList:
            if cfgID not in timeInfoDict:
                continue
            ipyData, startList, endList, notifyDict = timeInfoDict[cfgID]
            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] = {}
@@ -521,23 +597,29 @@
                    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)
            # 全服广播提示信息
            if curDateTime in notifyDict:
                if serverIDRangeList != None:
                    notifyKey, paramList = notifyDict[curDateTime]
                    country = 0
                    serverGroupIDList = []
                    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)
            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)
@@ -547,18 +629,48 @@
            if dbCfgID == cfgID and dbServerIDRangeList != serverIDRangeList:
                forceReset = True
                
            actID = actInfoDict.get(ShareDefine.ActKey_ID, 0)
            templateID = actInfoDict.get(ShareDefine.ActKey_TemplateID, 0)
            if not isReload and dbState == state and dbActID == actID and not forceReset:
            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 and not flowState and not errStateActID:
                if serverIDRangeList != None:
                    notifyKey, paramList = notifyDict[curDateTime]
                    country = 0
                    serverGroupIDList = []
                    crossNotifyList = []
                    crossNotifyList.append([ShareDefine.CrossNotify_CrossAct, [country, notifyKey, paramList], serverIDRangeList])
                    PlayerControl.CrossNotifyEx(serverGroupIDList, crossNotifyList)
            if not isReload and dbState == state and dbStateJoin == stateJoin and dbActID == actID and not forceReset:
                #已经是这个状态了
                continue
            GameWorld.Log("跨服运营活动状态: actName=%s,cfgID=%s,groupName=%s,zoneID=%s,dbState=%s -> state=%s,isEnd=%s, dbActID=%s -> actID=%s,forceReset=%s"
                          % (actName, cfgID, groupName, zoneID, dbState, state, isEnd, dbActID, actID, forceReset))
            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))
            
            # 更新状态
            actInfoDict[ShareDefine.ActKey_State] = state
            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_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:
@@ -569,22 +681,80 @@
                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, dbTemplateID])
                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, 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 and isEnd:
                del crossActInfoDict[actName][cfgID]
@@ -608,15 +778,67 @@
            CrossActAllRecharge.OnActIDChange(ipyData, state)
            
    for changeInfo in actStateChangeList:
        actName, ipyData, dbState, state, cfgID, groupName, zoneID, actIDChange, dbTemplateID = changeInfo
        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):
    ''' 同步跨服运营活动信息到子服务器
@@ -656,6 +878,10 @@
            
        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():