From 44bcd51874e364012946b5f34dd7bb166d86edfb Mon Sep 17 00:00:00 2001
From: hxp <ale99527@vip.qq.com>
Date: 星期六, 31 八月 2024 00:16:46 +0800
Subject: [PATCH] 10130 【后端】福地争夺资源功能(剩余时间为0报错防范;)

---
 ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerFamilyRedPacket.py | 1696 ++++++++++++++++++++++++++++++++++++++++------------------
 1 files changed, 1,169 insertions(+), 527 deletions(-)

diff --git a/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerFamilyRedPacket.py b/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerFamilyRedPacket.py
index 80e0bc0..d2dca9f 100644
--- a/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerFamilyRedPacket.py
+++ b/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerFamilyRedPacket.py
@@ -18,72 +18,977 @@
 #---------------------------------------------------------------------
 
 import GameWorld
-import ChPyNetSendPack
-import NetPackCommon
 import ShareDefine
+import NetPackCommon
 import IpyGameDataPY
-import PlayerDBGSEvent
-import PlayerUniversalGameRec
-import PlayerControl
-import ChConfig
+import ChPyNetSendPack
 import PlayerCompensation
+import PlayerDBGSEvent
+import PlayerControl
 import PlayerFamily
+import PyGameData
+import ChConfig
 
-import time
+import datetime
 import random
-
-#Def_UniversalGameRecType_FamilyRedPacketAllRecord
-#value1    红包唯一ID
-#value2    家族ID
-#value3    总额度*10+金钱类型
-#value4    状态
-#value5    时间,用来判断是否过期删除的
-#strValue1 创建者ID|创建者名字|创建者职业|获得途径
-#strValue2 可抢总个数
-#strValue3 祝福语
-
-#Def_UniversalGameRecType_FamilyRedPacketGrabRecord
-#value1    红包唯一ID
-#value2    playerID
-#value3    job
-#value4    moneyType
-#value5    getMoney
-#strValue1 名字
+import time
 
 (
-State_NoSend,   #未发
-State_NoGot,    #未领取
-State_HasGot,   #已领取
-State_HasAllGot,#全部领完
-)=range(4)
+State_NoSend, #未发
+State_NoGot, #未领取
+State_HasGot, #已领取
+State_HasAllGot, #全部领完
+) = range(4)
 
-g_allRecordDict = {} #{红包ID:recData, ...}
-g_grabDataDict = {} #{红包ID:{playerid:[抢到的钱,名字,job]}, ...}
-g_osRedCnt = 0 #开服红包个数
-## 玩家登录
-#  @param None
-#  @return None
-def OnPlayerLogin(curPlayer):
-    NotifyRedPacketInfo(curPlayer)
-    return
+DBKey_RedPacketSend = "RedPacketSend_%s" # 系统定时红包是否已发放, 参数红包ID
+DBKey_RedPacketSystemDayCount = "RedPacketSystemDayCount" # 全服系统红包已发放个数
 
-
-## 隔天更新
-#  @param None
-#  @return None
-def DoOnDay():
-    __CheckGrabRecData()
+def __SaveRedpacketRecData(recData, redPacketObj):
+    ''' 红包暂定有效期24小时,过天清除过期的红包,如果是玩家发放的返还未领取的货币
+            上线同步所有红包信息,红包变化实时广播全服在线玩家
+    '''
+    #红包数据 Def_UniversalGameRecType_FamilyRedPacketAllRecord
+    #Time      创建红包时间,非红包实际开放领取时间,如果红包表有配置系统发放时间,则该时间存配表时间,没有的话存创建时的服务器时间
+    #value1    红包唯一ID,该ID为实例ID,非配表的红包ID
+    #value2    家族ID,0代表全服红包
+    #value3    总额度*10+金钱类型
+    #value4    状态
+    #value5    时间,用来判断是否过期删除的,实际开放该红包领取的时间
+    #strValue1 创建者ID|创建者名字|创建者职业|获得途径(红包类型)
+    #strValue2 可抢总个数|是否匿名(默认不匿名兼容老数据)
+    #strValue3 祝福语,玩家自己编辑的内容
     
+    recData.SetTime(redPacketObj.createTime)
+    recData.SetValue1(redPacketObj.redPacketID)
+    recData.SetValue2(redPacketObj.familyID)
+    recData.SetValue3(redPacketObj.moneyType + redPacketObj.moneyValue * 10)
+    recData.SetValue4(redPacketObj.state)
+    recData.SetValue5(redPacketObj.calcTime)
+    strValue1 = '%s|%s|%s|%s' % (redPacketObj.playerID, redPacketObj.playerName, redPacketObj.playerJob, redPacketObj.getWay)
+    recData.SetStrValue1(strValue1)
+    recData.SetStrValue2('%s|%s' % (redPacketObj.packetCnt, int(redPacketObj.isAnonymous)))
+    recData.SetStrValue3(redPacketObj.wish)
     return
 
+def __SaveRedpacketRecGrabData(recData, grabObj):
+    #抢红包记录 Def_UniversalGameRecType_FamilyRedPacketGrabRecord
+    #value1    红包唯一ID
+    #value2    playerID
+    #value3    job
+    #value4    moneyType
+    #value5    getMoney
+    #strValue1 名字
+    
+    recData.SetValue1(grabObj.redPacketID)
+    recData.SetValue2(grabObj.playerID)
+    recData.SetValue3(grabObj.playerJob)
+    recData.SetValue4(grabObj.moneyType)
+    recData.SetValue5(grabObj.getMoney)
+    recData.SetStrValue1(grabObj.playerName)
+    return
+
+class RedPacketGrab():
+    ## 红包抢记录数据
+    
+    def __init__(self, redPacketID, playerID):
+        self.redPacketID = redPacketID
+        self.playerID = playerID
+        self.playerJob = 0
+        self.playerName = ""
+        self.moneyType = 0
+        self.getMoney = 0
+        return
+
+class RedPacketData():
+    ## 红包数据
+    
+    def __init__(self, redPacketID):
+        self.redPacketID = redPacketID
+        self.familyID = 0
+        self.moneyType = 0
+        self.moneyValue = 0
+        self.state = 0
+        self.createTime = 0
+        self.calcTime = 0
+        self.playerID = 0
+        self.playerName = ""
+        self.playerJob = 0
+        self.getWay = 0
+        self.packetCnt = 0
+        self.isAnonymous = 0 # 是否匿名
+        self.wish = ""
+        
+        self.grabDict = {} # 抢红包记录 {playerID:RedPacketGrab, ...}
+        return
+    
+class RedPacketMgr():
+    ''' 红包缓存管理等
+    通知玩家红包逻辑:
+    由于刚开服时红包大概率会比较多,红包的交互及交叉通知也相对比较密集,所以做些优化,不对所有红包处理
+    将红包分为红包总库及通知给玩家的部分红包,假设当前所有红包总数为500个,标记为 T 个
+    可配置限制通知给玩家可操作的红包个数如只通知20个,标记为 M 个,可视为热红包,当 M 消化完后可附加通知  N 个
+    
+    通知玩家的红包组成: 
+    非仙盟红包: 归属玩家的未开放红包A + 不限制通知个数的红包B + 限制通知个数的红包C;  不包含其他玩家未开放的
+        仙盟红包: 所有玩家未领取过的且未全部领完的红包,包含其他玩家未开放的
+        
+    如果 (A + B) >= M 了,则不需要再附加通知 C 
+    '''
+    def __init__(self):
+        self.allRedPacketDict = {} # 所有红包信息  {红包ID:RedPacketData, ...}
+        
+        self.familyRedPacketDict = {} # 仙盟红包信息,全部同步  {familyID:[红包ID, ...], ...}
+        
+        # --- 以下仅针对非仙盟红包 --- 
+        # 针对红包量比较大的红包类型,有限制同步个数,按类型分组,每组按规则独立同步;如 开服成就红包、节日成就红包、全服红包
+        # 同步规则:
+        # 比如先同步20个,然后减一个则再从已开放的库中补充;
+        # 新增一个开放领取的红包时,如果玩家有可领取的则不需要同步,没有可领取的则需要同步给他
+        # 注: 全服红包中,未开放的红包仅玩家自己可见
+        self.playerNosendRedPacketIDInfo = {} # 玩家未开放的红包ID信息,针对有同步个数限制的类型 {playerID:{红包类型:[红包ID, ...], ...}, ...}
+        
+        # playerCanGetRedPacketIDInfo 的playerID包含所有在线玩家,不含脱机挂
+        self.playerCanGetRedPacketIDInfo = {} # 玩家可领取的红包ID信息,针对有同步个数限制的类型 {playerID:{红包类型:[红包ID, ...], ...}, ...}
+        self.activeRedPacketIDInfo = {} # 已开放领取的红包ID列表,针对有同步个数限制的类型 {红包类型:[红包ID, ...], ...}
+        
+        # 其他全服红包,一般量比较少的,相对固定的,全部同步,如节日定时发送的红包
+        self.notifyAllServerRedPacketIDList = [] # 其他没有限制下发同步个数的全服红包ID [红包ID, ...]
+        return
+    
+    def GetRedPacketObj(self, redPacketID, createNew):
+        ## 获取红包实例
+        redPacketObj = None
+        if redPacketID in self.allRedPacketDict:
+            redPacketObj = self.allRedPacketDict[redPacketID]
+        elif createNew:
+                redPacketObj = RedPacketData(redPacketID)
+                self.allRedPacketDict[redPacketID] = redPacketObj
+        return redPacketObj
+    
+    def AddFamilyRedPacketID(self, familyID, redPacketID):
+        ## 添加红包ID进入仙盟红包ID缓存
+        if familyID not in self.familyRedPacketDict:
+            self.familyRedPacketDict[familyID] = []
+        familyRedpacketIDList = self.familyRedPacketDict[familyID]
+        if redPacketID not in familyRedpacketIDList:
+            familyRedpacketIDList.append(redPacketID)
+        return
+    
+    def DelFamilyRedPacketID(self, familyID, redPacketID):
+        ## 删除仙盟红包ID缓存
+        if familyID not in self.familyRedPacketDict:
+            return
+        familyRedpacketIDList = self.familyRedPacketDict[familyID]
+        if redPacketID not in familyRedpacketIDList:
+            return
+        familyRedpacketIDList.remove(redPacketID)
+        return True
+        
+    def AddPlayerNosendRedPacketID(self, playerID, getWay, redPacketID):
+        ## 添加玩家未开放的红包ID缓存
+        if playerID not in self.playerNosendRedPacketIDInfo:
+            self.playerNosendRedPacketIDInfo[playerID] = {}
+        playerNosendRedPacketTypeIDInfo = self.playerNosendRedPacketIDInfo[playerID]
+        if getWay not in playerNosendRedPacketTypeIDInfo:
+            playerNosendRedPacketTypeIDInfo[getWay] = []
+        playerNosendRedPacketTypeIDList = playerNosendRedPacketTypeIDInfo[getWay]
+        if redPacketID not in playerNosendRedPacketTypeIDList:
+            playerNosendRedPacketTypeIDList.append(redPacketID)
+        return
+    
+    def DelPlayerNosendRedPacketID(self, playerID, getWay, redPacketID):
+        ## 删除玩家未开放的红包ID缓存
+        if playerID not in self.playerNosendRedPacketIDInfo:
+            return
+        playerNosendRedPacketTypeIDInfo = self.playerNosendRedPacketIDInfo[playerID]
+        if getWay not in playerNosendRedPacketTypeIDInfo:
+            return
+        playerNosendRedPacketTypeIDList = playerNosendRedPacketTypeIDInfo[getWay]
+        if redPacketID not in playerNosendRedPacketTypeIDList:
+            return
+        playerNosendRedPacketTypeIDList.remove(redPacketID)
+        return True
+            
+    def AddActiveRedPacketID(self, getWay, redPacketID):
+        ## 添加已开放的全服红包ID缓存
+        if getWay not in self.activeRedPacketIDInfo:
+            self.activeRedPacketIDInfo[getWay] = []
+        redPacketIDList = self.activeRedPacketIDInfo[getWay]
+        if redPacketID not in redPacketIDList:
+            redPacketIDList.append(redPacketID)
+        return
+    
+    def DelActiveRedPacketID(self, getWay, redPacketID):
+        ## 删除已开放的全服红包ID缓存
+        if getWay not in self.activeRedPacketIDInfo:
+            return
+        redPacketIDList = self.activeRedPacketIDInfo[getWay]
+        if redPacketID not in redPacketIDList:
+            return
+        redPacketIDList.remove(redPacketID)
+        return True
+        
+    def AddPlayerCanGetRedPacketID(self, playerID, getWay, redPacketID):
+        ## 添加玩家可领取的红包ID缓存
+        if not playerID:
+            return
+        if playerID not in self.playerCanGetRedPacketIDInfo:
+            self.playerCanGetRedPacketIDInfo[playerID] = {}
+        redPacketTypeIDInfo = self.playerCanGetRedPacketIDInfo[playerID]
+        if getWay not in redPacketTypeIDInfo:
+            redPacketTypeIDInfo[getWay] = []
+        redPacketIDList = redPacketTypeIDInfo[getWay]
+        if redPacketID not in redPacketIDList:
+            redPacketIDList.append(redPacketID)
+            return redPacketIDList
+        return
+    
+    def DelPlayerCanGetRedPacketID(self, playerID, getWay, redPacketID):
+        ## 删除玩家可领取的红包ID缓存
+        if playerID not in self.playerCanGetRedPacketIDInfo:
+            return
+        redPacketTypeIDInfo = self.playerCanGetRedPacketIDInfo[playerID]
+        if getWay not in redPacketTypeIDInfo:
+            return
+        redPacketIDList = redPacketTypeIDInfo[getWay]
+        if redPacketID not in redPacketIDList:
+            return
+        redPacketIDList.remove(redPacketID)
+        # 返回当前类型可用红包ID列表
+        return redPacketIDList
+    
+def PrintRedPacketData(sign=""):
+    redPacketMgr = GetRedpacketMgr()
+    if sign:
+        GameWorld.DebugLog("    === %s ===" % sign)
+    GameWorld.DebugLog("    所有红包:count=%s,=%s" % (len(redPacketMgr.allRedPacketDict), redPacketMgr.allRedPacketDict.keys()))
+    for familyID, redIDList in redPacketMgr.familyRedPacketDict.items():
+        GameWorld.DebugLog("    仙盟红包:familyID=%s,count=%s,%s" % (familyID, len(redIDList), redIDList))
+    GameWorld.DebugLog("    全服全部下发红包=%s" % redPacketMgr.notifyAllServerRedPacketIDList)
+    for getWay, redIDList in redPacketMgr.activeRedPacketIDInfo.items():
+        GameWorld.DebugLog("    全服公共活跃红包:getWay=%s,count=%s,%s" % (getWay, len(redIDList), redIDList))
+    for playerID, redIDInfo in redPacketMgr.playerNosendRedPacketIDInfo.items():
+        for getWay, redIDList in redIDInfo.items():
+            GameWorld.DebugLog("    全服个人未开放红包:playerID=%s,getWay=%s,count=%s,%s" % (playerID, getWay, len(redIDList), redIDList))
+    for playerID, redIDInfo in redPacketMgr.playerCanGetRedPacketIDInfo.items():
+        for getWay, redIDList in redIDInfo.items():
+            GameWorld.DebugLog("    全服个人可领取红包:playerID=%s,getWay=%s,count=%s,%s" % (playerID, getWay, len(redIDList), redIDList))
+    return
+    
+def GetRedpacketMgr():
+    redPacketMgr = PyGameData.g_redPacketMgr
+    if redPacketMgr == None:
+        redPacketMgr = RedPacketMgr()
+        PyGameData.g_redPacketMgr = redPacketMgr
+    return redPacketMgr
+
+def OnServerStart():
+    redPacketMgr = GetRedpacketMgr()
+    
+    universalRecMgr = GameWorld.GetUniversalRecMgr()
+        
+    # 红包数据
+    notifyLimitTypeList = IpyGameDataPY.GetFuncEvalCfg("RedPacketSys", 1)
+    recordList = universalRecMgr.GetTypeList(ShareDefine.Def_UniversalGameRecType_FamilyRedPacketAllRecord)
+    GameWorld.Log("加载红包信息通用记录: count=%s" % recordList.Count())
+    for index in xrange(recordList.Count()):
+        recData = recordList.At(index)
+        state = recData.GetValue4()
+        if state == State_HasAllGot:
+            # 已全部领完的不处理
+            continue
+        redPacketID = recData.GetValue1()
+        familyID = recData.GetValue2()
+        
+        redPacketObj = redPacketMgr.GetRedPacketObj(redPacketID, True)
+        redPacketObj.familyID = familyID
+        redPacketObj.createTime = recData.GetTime()
+        redPacketObj.moneyType = recData.GetValue3() % 10
+        redPacketObj.moneyValue = recData.GetValue3() / 10
+        redPacketObj.state = recData.GetValue4()
+        redPacketObj.calcTime = recData.GetValue5()
+        
+        strValue1List = recData.GetStrValue1().split('|')
+        playerID, playerName, job, getWay = strValue1List
+        redPacketObj.playerID = GameWorld.ToIntDef(playerID)
+        redPacketObj.playerName = playerName
+        redPacketObj.playerJob = GameWorld.ToIntDef(job)
+        redPacketObj.getWay = GameWorld.ToIntDef(getWay)
+        
+        strValue2List = recData.GetStrValue2().split('|')
+        redPacketObj.packetCnt = GameWorld.ToIntDef(strValue2List[0])
+        redPacketObj.isAnonymous = GameWorld.ToIntDef(strValue2List[1]) if len(strValue2List) > 1 else 0
+        
+        redPacketObj.wish = recData.GetStrValue3()
+        
+        playerID = redPacketObj.playerID
+        getWay = redPacketObj.getWay
+        
+        # 1. 仙盟的红包
+        if familyID:
+            redPacketMgr.AddFamilyRedPacketID(familyID, redPacketID)
+            continue
+        
+        # 以下是面向全服的红包
+        # 2. 全服未开放红包
+        if state == State_NoSend:
+            # 未发放的添加进ID缓存
+            redPacketMgr.AddPlayerNosendRedPacketID(playerID, getWay, redPacketID)
+            continue
+        
+        # 3. 全服不限制下发个数的
+        if getWay not in notifyLimitTypeList:
+            redPacketMgr.notifyAllServerRedPacketIDList.append(redPacketID)
+            continue
+        
+        # 4. 有限制通知个数的
+        if state == State_NoGot:
+            redPacketMgr.AddActiveRedPacketID(getWay, redPacketID)
+            
+    # 抢红包记录
+    grabRecordList = universalRecMgr.GetTypeList(ShareDefine.Def_UniversalGameRecType_FamilyRedPacketGrabRecord)
+    GameWorld.Log("加载红包抢记录信息通用记录: count=%s" % grabRecordList.Count())
+    for index in xrange(grabRecordList.Count()):
+        recData = grabRecordList.At(index)
+        redPacketID = recData.GetValue1()
+        playerID = recData.GetValue2()
+        redPacketObj = redPacketMgr.GetRedPacketObj(redPacketID, False)
+        if not redPacketObj:
+            continue
+        
+        grabObj = RedPacketGrab(redPacketID, playerID)
+        grabObj.playerJob = recData.GetValue3()
+        grabObj.playerName = recData.GetStrValue1()
+        grabObj.moneyType = recData.GetValue4()
+        grabObj.getMoney = recData.GetValue5()
+        
+        redPacketObj.grabDict[playerID] = grabObj
+        
+    #PrintRedPacketData("OnServerStart")
+    return
+
+def OnServerClose():
+    
+    redPacketMgr = GetRedpacketMgr()
+    
+    recMgr = GameWorld.GetUniversalRecMgr()
+    recMgr.Delete(ShareDefine.Def_UniversalGameRecType_FamilyRedPacketAllRecord)
+    recDataList = recMgr.GetTypeList(ShareDefine.Def_UniversalGameRecType_FamilyRedPacketAllRecord)
+    
+    recMgr.Delete(ShareDefine.Def_UniversalGameRecType_FamilyRedPacketGrabRecord)
+    grabRecDataList = recMgr.GetTypeList(ShareDefine.Def_UniversalGameRecType_FamilyRedPacketGrabRecord)
+    
+    redPacketCount = 0
+    grabRecCount = 0
+    for redPacketObj in redPacketMgr.allRedPacketDict.values():
+        if redPacketObj.state == State_HasAllGot:
+            # 已全部抢完的不保存
+            continue
+        recData = recDataList.AddRec()
+        __SaveRedpacketRecData(recData, redPacketObj)
+        redPacketCount += 1
+        
+        for grabObj in redPacketObj.grabDict.values():
+            grabRecData = grabRecDataList.AddRec()
+            __SaveRedpacketRecGrabData(grabRecData, grabObj)
+            grabRecCount += 1
+        
+    GameWorld.Log("保存红包信息通用记录: count=%s" % redPacketCount)
+    GameWorld.Log("保存红包抢记录信息通用记录: count=%s" % grabRecCount)
+    return
+
+def OnPlayerLogin(curPlayer):
+    
+    if not PlayerControl.GetIsTJG(curPlayer):
+        
+        redPacketMgr = GetRedpacketMgr()
+        playerID = curPlayer.GetPlayerID()
+        redPacketMgr.playerCanGetRedPacketIDInfo[playerID] = {}
+        
+        notifyLimitTypeList = IpyGameDataPY.GetFuncEvalCfg("RedPacketSys", 1)
+        maxNotifyCount = IpyGameDataPY.GetFuncCfg("RedPacketSys", 2)
+        
+        for getWay in notifyLimitTypeList:
+            redPacketMgr.playerCanGetRedPacketIDInfo[playerID][getWay] = [] # 确保 getWay key 一定存在
+            
+            nowActiveRedPacketIDList = redPacketMgr.activeRedPacketIDInfo.get(getWay, []) # 当前此类型还可用的公共已开放红包列表
+            if not nowActiveRedPacketIDList:
+                continue
+            nosendIDList = redPacketMgr.playerNosendRedPacketIDInfo.get(playerID, {}).get(getWay, [])
+            addCount = maxNotifyCount - len(nosendIDList)
+            if addCount <= 0:
+                continue
+            
+            playerCanGetIDList = []
+            for redPacketID in nowActiveRedPacketIDList:
+                redPacketObj = redPacketMgr.GetRedPacketObj(redPacketID, False)
+                if not redPacketObj:
+                    continue
+                if playerID in redPacketObj.grabDict:
+                    continue
+                playerCanGetIDList.append(redPacketID)
+                addCount -= 1
+                if addCount <= 0:
+                    break
+            redPacketMgr.playerCanGetRedPacketIDInfo[playerID][getWay] = playerCanGetIDList
+            
+        #PrintRedPacketData("OnPlayerLogin %s" % playerID)
+        
+    NotifyRedPacketInfo(curPlayer, isLogin=True)
+    return
+
+def OnLeaveServer(curPlayer):
+    playerID = curPlayer.GetPlayerID()
+    redPacketMgr = GetRedpacketMgr()
+    redPacketMgr.playerCanGetRedPacketIDInfo.pop(playerID, None)
+    return
+    
+## 隔天更新
+def DoOnDay():
+    PlayerDBGSEvent.SetDBGSTrig_ByKey(DBKey_RedPacketSystemDayCount, 0) # 重置每日全服系统红包发放个数
+    RandTodayServerSystemRedPacketSendTime()
+    return
+
+def GetRedPackGetWayType(getWay):
+    ## 获取红包getWay所属红包分类
+    getWayTypeDict = IpyGameDataPY.GetFuncEvalCfg("RedPacketClassify", 1, {})
+    for getWayType, getWayList in getWayTypeDict.items():
+        if getWay in getWayList:
+            return getWayType
+    return ShareDefine.RedPackWayType_Family
+
+def CheckDelRedpacketData():
+    ## 检查红包删除红包,5分钟一次: 1-删除过期红包,2-删除已全部抢完的红包
+    
+    curTimeNum = int(time.time())
+    rangeTime = IpyGameDataPY.GetFuncCfg("RedPacketSys", 3) * 3600
+    
+    backMoneyDict = {}
+    delRedPacketIDList = [] # 删除的全服红包 [红包ID, ...]
+    delFamilyRedPacketInfo = {} # 删除的仙盟红包 {familyID:[红包ID, ...], ...}
+    delNosendRedPacketInfo = {} # 要通知给玩家删除的红包 {playerID:[红包ID, ...], ...}
+    
+    redPacketMgr = GetRedpacketMgr()
+    
+    for redPacketObj in redPacketMgr.allRedPacketDict.values():
+        
+        state = redPacketObj.state
+        if state == State_HasAllGot:
+            pass
+        elif curTimeNum - redPacketObj.calcTime < rangeTime:
+            continue
+        
+        redPacketID = redPacketObj.redPacketID
+        playerID = redPacketObj.playerID
+        familyID = redPacketObj.familyID
+        getWay = redPacketObj.getWay
+        
+        if redPacketID in redPacketMgr.allRedPacketDict:
+            redPacketMgr.allRedPacketDict.pop(redPacketID)
+            
+        # 返还未领完的玩家主动发放的仙玉红包
+        if state != State_HasAllGot and playerID and getWay == ShareDefine.RedPackType_GoldPacket:
+            outNum = sum([grabObj.getMoney for grabObj in redPacketObj.grabDict.values()]) #已被抢的钱
+            moneyType = redPacketObj.moneyType
+            totalMoney = redPacketObj.moneyValue
+            remainMoney = totalMoney - outNum #剩余的钱
+            if moneyType == 1 and remainMoney:
+                backMoneyDict[playerID] = backMoneyDict.get(playerID, 0) + remainMoney
+                
+        # 1. 仙盟红包 
+        if familyID:
+            redPacketMgr.DelFamilyRedPacketID(familyID, redPacketID)
+            
+            if familyID not in delFamilyRedPacketInfo:
+                delFamilyRedPacketInfo[familyID] = []
+            defFamilyRedPacketIDList = delFamilyRedPacketInfo[familyID]
+            defFamilyRedPacketIDList.append(redPacketID)
+            continue
+        
+        # 2. 全服红包 
+        
+        #     2.1 是否玩家私有未开放的全服红包
+        if state == State_NoSend:
+            redPacketMgr.DelPlayerNosendRedPacketID(playerID, getWay, redPacketID)
+            
+            if playerID not in delNosendRedPacketInfo:
+                delNosendRedPacketInfo[playerID] = []
+            playerNosendRedPacketIDList = delNosendRedPacketInfo[playerID]
+            playerNosendRedPacketIDList.append(redPacketID)
+            continue
+        
+        #     2.2 已开放的全服红包
+        redPacketMgr.DelActiveRedPacketID(getWay, redPacketID)
+        
+        if redPacketID in redPacketMgr.notifyAllServerRedPacketIDList:
+            redPacketMgr.notifyAllServerRedPacketIDList.remove(redPacketID)
+            
+        # 这个玩家可领取的可能包含非玩家自己发的红包
+        for typeIDDict in redPacketMgr.playerCanGetRedPacketIDInfo.values():
+            if getWay not in typeIDDict:
+                continue
+            redpacketIDList = typeIDDict[getWay]
+            if redPacketID not in redpacketIDList:
+                continue
+            redpacketIDList.remove(redPacketID)
+            
+        delRedPacketIDList.append(redPacketID)
+                
+    #返回玩家未被领取的仙玉
+    if backMoneyDict:
+        for playerID, moneyNum in backMoneyDict.items():
+            PlayerCompensation.SendMailByKey('RedPackBack', [playerID], [], [], moneyNum)
+            
+    playerManager = GameWorld.GetPlayerManager()
+    
+    # 同步删除的仙盟红包
+    #GameWorld.DebugLog("同步删除的仙盟红包: %s" % delFamilyRedPacketInfo)
+    for familyID, delIDList in delFamilyRedPacketInfo.items():
+        family = GameWorld.GetFamilyManager().FindFamily(familyID)
+        if not family:
+            return
+        
+        sendPack = ChPyNetSendPack.tagGCRedPacketDel()
+        sendPack.DelRedPacketID = delIDList
+        sendPack.Cnt = len(delIDList)
+        
+        for i in xrange(family.GetCount()):
+            notifyMember = family.GetAt(i)
+            curPlayer = playerManager.FindPlayerByID(notifyMember.GetPlayerID())
+            if curPlayer == None or not curPlayer.GetInitOK() or PlayerControl.GetIsTJG(curPlayer):
+                continue
+            NetPackCommon.SendFakePack(curPlayer, sendPack)
+            
+    # 同步删除个人未开放的全服红包
+    #GameWorld.DebugLog("同步删除个人未开放的全服红包: %s" % delNosendRedPacketInfo)
+    for playerID, nosendIDList in delNosendRedPacketInfo.items():
+        curPlayer = playerManager.FindPlayerByID(playerID)
+        if curPlayer == None or not curPlayer.GetInitOK() or PlayerControl.GetIsTJG(curPlayer):
+            continue
+        sendPack = ChPyNetSendPack.tagGCRedPacketDel()
+        sendPack.DelRedPacketID = nosendIDList
+        sendPack.Cnt = len(nosendIDList)
+        NetPackCommon.SendFakePack(curPlayer, sendPack)
+        
+    # 同步删除已开放的全服红包
+    #GameWorld.DebugLog("同步删除已开放的全服红包: %s" % delRedPacketIDList)
+    if delRedPacketIDList:
+        sendPack = ChPyNetSendPack.tagGCRedPacketDel()
+        sendPack.Clear()
+        sendPack.DelRedPacketID = delRedPacketIDList
+        sendPack.Cnt = len(delRedPacketIDList)
+        for i in xrange(playerManager.GetActivePlayerCount()):
+            curPlayer = playerManager.GetActivePlayerAt(i)
+            if curPlayer == None or not curPlayer.GetInitOK() or PlayerControl.GetIsTJG(curPlayer):
+                continue
+            NetPackCommon.SendFakePack(curPlayer, sendPack)
+            
+    return
+
+def OnChangeRedPacketState(family, redPacketObj, beforeState=None):
+    ## 红包状态变更处理
+    state = redPacketObj.state
+    if state == beforeState:
+        return
+    
+    redPacketMgr = GetRedpacketMgr()
+    redPacketID = redPacketObj.redPacketID
+    familyID = redPacketObj.familyID
+    ownerID = redPacketObj.playerID
+    getWay = redPacketObj.getWay
+    
+    GameWorld.DebugLog("红包状态变更处理: redPacketID=%s,ownerID=%s,familyID=%s,beforeState=%s,state=%s" 
+                       % (redPacketID, ownerID, familyID, beforeState, state))
+    
+    notifyPlayerDict = {ownerID:[redPacketID]} # 通知给指定玩家的信息,每个玩家可能不一样
+    
+    # 1. 仙盟红包直接通知该仙盟所有成员
+    if family:
+        if state in [State_NoSend, State_NoGot]:
+            redPacketMgr.AddFamilyRedPacketID(family.GetID(), redPacketID)
+        elif state == State_HasAllGot:
+            redPacketMgr.DelFamilyRedPacketID(familyID, redPacketID)
+    
+    # 除仙盟红包外,以下是全服红包的相关处理
+    
+    # 2. 全服未开放红包默认只发给个人
+    elif state == State_NoSend:
+        if not ownerID:
+            return
+        if beforeState == None:
+            redPacketMgr.AddPlayerNosendRedPacketID(ownerID, getWay, redPacketID)
+            
+    # 3. 全服不限制下发个数的同步全服玩家
+    elif getWay not in IpyGameDataPY.GetFuncEvalCfg("RedPacketSys", 1):
+        notifyPlayerDict = None
+        if state == State_HasAllGot:
+            if redPacketID in redPacketMgr.notifyAllServerRedPacketIDList:
+                redPacketMgr.notifyAllServerRedPacketIDList.remove(redPacketID)
+        else:
+            if redPacketID not in redPacketMgr.notifyAllServerRedPacketIDList:
+                redPacketMgr.notifyAllServerRedPacketIDList.append(redPacketID)
+                
+    # 4. 其他的要限制下发个数的检查需要同步的玩家即可
+    #     4.1 变为  开放领取状态
+    elif state == State_NoGot:
+        if beforeState != State_NoGot:
+            redPacketMgr.DelPlayerNosendRedPacketID(ownerID, getWay, redPacketID) # 移出拥有者私有未开放红包队列
+            redPacketMgr.AddPlayerCanGetRedPacketID(ownerID, getWay, redPacketID) # 添加拥有者私有已开放红包队列
+            redPacketMgr.AddActiveRedPacketID(getWay, redPacketID) # 添加公共已开放红包队列
+            
+            maxNotifyCount = IpyGameDataPY.GetFuncCfg("RedPacketSys", 2)
+            # 检查追加该红包记录的玩家
+            for playerID, typeRedIDDict in redPacketMgr.playerCanGetRedPacketIDInfo.items():
+                if playerID == ownerID:
+                    continue
+                redIDList = typeRedIDDict.get(getWay, [])
+                if redPacketID in redIDList:
+                    continue
+                nosendTypeRedIDDict = redPacketMgr.playerNosendRedPacketIDInfo.get(playerID, {})
+                nosendRedIDList = nosendTypeRedIDDict.get(getWay, [])
+                totalCount = len(nosendRedIDList) + len(redIDList) # 玩家当前还可操作领取的红包数
+                if totalCount >= maxNotifyCount:
+                    continue
+                redPacketMgr.AddPlayerCanGetRedPacketID(playerID, getWay, redPacketID) # 添加目标玩家私有已开放红包队列
+                notifyPlayerDict[playerID] = [redPacketID]
+    
+    #     4.1 变为  全部领取完毕
+    elif state == State_HasAllGot:
+        if beforeState != State_HasAllGot:
+            redPacketMgr.DelActiveRedPacketID(getWay, redPacketID) # 移除公共已开放红包队列
+            
+            nowActiveRedPacketIDList = redPacketMgr.activeRedPacketIDInfo.get(getWay, []) # 当前此类型还可用的公共已开放红包列表
+            
+            # 检查需要补充红包记录的玩家,采用 减去1  补充1 的模式
+            for playerID in redPacketMgr.playerCanGetRedPacketIDInfo.keys():
+                notifyRedIDList = DoPlayerReductCanGetRedPacket(playerID, redPacketObj, nowActiveRedPacketIDList)
+                if notifyRedIDList:
+                    notifyPlayerDict[playerID] = notifyRedIDList
+    else:
+        return
+    
+    #PrintRedPacketData("StateChange")
+    
+    syncRedPacketList = [redPacketID]
+    playerManager = GameWorld.GetPlayerManager()
+    
+    # 仙盟的直接同步该仙盟所有玩家
+    if family:
+        for i in xrange(family.GetCount()):
+            notifyMember = family.GetAt(i)
+            player = playerManager.FindPlayerByID(notifyMember.GetPlayerID())
+            if player == None or not player.GetInitOK() or PlayerControl.GetIsTJG(player):
+                continue
+            NotifyRedPacketInfo(player, syncRedPacketList)
+            
+    # 没有指定玩家,则通知全服玩家
+    elif notifyPlayerDict == None:
+        for i in xrange(playerManager.GetActivePlayerCount()):
+            player = playerManager.GetActivePlayerAt(i)
+            if player == None or not player.GetInitOK() or PlayerControl.GetIsTJG(player):
+                continue
+            NotifyRedPacketInfo(player, syncRedPacketList)
+            
+    # 通知指定玩家
+    else:
+        for playerID, syncRedPacketList in notifyPlayerDict.items():
+            if not playerID:
+                continue
+            player = playerManager.FindPlayerByID(playerID)
+            if player == None or not player.GetInitOK() or PlayerControl.GetIsTJG(player):
+                continue
+            NotifyRedPacketInfo(player, syncRedPacketList)
+    return
+
+def DoPlayerReductCanGetRedPacket(playerID, redPacketObj, nowActiveRedPacketIDList=None):
+    ## 玩家减少全服限制下发红包可领取个数处理
+    ## @return: 需要通知的红包ID列表
+    
+    getWay = redPacketObj.getWay
+    redPacketID = redPacketObj.redPacketID
+    
+    redPacketMgr = GetRedpacketMgr()
+    if nowActiveRedPacketIDList == None:
+        nowActiveRedPacketIDList = redPacketMgr.activeRedPacketIDInfo.get(getWay, []) # 当前此类型还可用的公共已开放红包列表
+    
+    # 检查需要补充红包记录的玩家,采用 减去1  补充1 的模式
+    canGetIDList = redPacketMgr.DelPlayerCanGetRedPacketID(playerID, getWay, redPacketID) # 移出私有已开放红包队列
+    if canGetIDList == None:
+        return
+    
+    lastCanGetID = 0 if not canGetIDList else canGetIDList[-1]
+    checkIndex = nowActiveRedPacketIDList.index(lastCanGetID) if lastCanGetID in nowActiveRedPacketIDList else 0
+    for i in xrange(checkIndex + 1, len(nowActiveRedPacketIDList)):
+        newCanGetRedID = nowActiveRedPacketIDList[i]
+        newRedPacketObj = redPacketMgr.GetRedPacketObj(newCanGetRedID, False)
+        if not newRedPacketObj:
+            continue
+        if playerID in newRedPacketObj.grabDict:
+            continue
+        if newCanGetRedID not in canGetIDList:
+            if redPacketMgr.AddPlayerCanGetRedPacketID(playerID, getWay, newCanGetRedID): # 添加目标玩家私有已开放红包队列
+                return [redPacketID, newCanGetRedID]
+    return [redPacketID]
+
+def DelRedPackByFamilyID(delfamilyID):
+    ## 删除仙盟的时候才需要删除红包,所以这里不做通知,重新加入仙盟时会重新同步一次 isAll 的情况
+    
+    familyID = delfamilyID
+    redPacketMgr = GetRedpacketMgr()
+    if familyID not in redPacketMgr.familyRedPacketDict:
+        return
+    familyRedpacketIDList = redPacketMgr.familyRedPacketDict.pop(familyID)
+    
+    for redPacketID in familyRedpacketIDList:
+        if redPacketID in redPacketMgr.allRedPacketDict:
+            redPacketMgr.allRedPacketDict.pop(redPacketID)
+            
+    GameWorld.DebugLog("解散仙盟删除仙盟红包! familyID=%s, %s" % (familyID, familyRedpacketIDList))
+    return
+
+##---------------------------------------- 节日红包 -----------------------------------------------
+
+def OnResetFeastRedPacket(ipyData, dayIndex):
+    ## 重置节日红包状态
+    
+    if not ipyData:
+        return
+    
+    dayRedPackIDList = ipyData.GetRedPacketIDList()
+    GameWorld.Log("重置节日红包发放状态: dayRedPackIDList=%s, dayIndex=%s" % (dayRedPackIDList, dayIndex))
+    if dayIndex < 0 or dayIndex >= len(dayRedPackIDList):
+        GameWorld.ErrLog("当前节日天索引没有配配置系统红包ID! dayRedPackIDList=%s, dayIndex=%s" % (dayRedPackIDList, dayIndex))
+        return
+    
+    for redPackID in dayRedPackIDList[dayIndex]:
+        GameWorld.Log("    重置节日红包发放状态: redPackID=%s" % redPackID)
+        if PlayerDBGSEvent.GetDBGSTrig_ByKey(DBKey_RedPacketSend % redPackID):
+            PlayerDBGSEvent.SetDBGSTrig_ByKey(DBKey_RedPacketSend % redPackID, 0)
+            
+    return
+
+def __GetTodayRedPacketByTimeList():
+    key = "TodayRedPacketByTime"
+    openServerDay = PlayerDBGSEvent.GetDBGSTrig_ByKey(PlayerDBGSEvent.Def_ServerDay) + 1
+    TodayRedPacketByTimeInfo = IpyGameDataPY.GetConfigEx(key)
+    if TodayRedPacketByTimeInfo and TodayRedPacketByTimeInfo[0] == openServerDay:
+        #GameWorld.DebugLog("已经加载过本日系统定时发放的红包! openServerDay=%s" % openServerDay)
+        return TodayRedPacketByTimeInfo[1]
+    
+    redPacketByTimeList = []
+    serverTime = GameWorld.GetServerTime()
+    
+    GameWorld.Log("===== 加载今天系统定时发放红包信息 ===== openServerDay=%s" % openServerDay)
+    
+    ipyDataMgr = IpyGameDataPY.IPY_Data()
+    for index in xrange(ipyDataMgr.GetFamilyRedPackCount()):
+        ipyData = ipyDataMgr.GetFamilyRedPackByIndex(index)
+        redPackID = ipyData.GetID()
+        openTimeStr = ipyData.GetPacketOpenTime()
+        if not openTimeStr:
+            #GameWorld.DebugLog("非定时发放的红包!redPackID=%s" % (redPackID))
+            continue
+        
+        openDateTime = datetime.datetime.strptime("%s:00" % openTimeStr, ChConfig.TYPE_Time_Format)
+        if openDateTime.year != serverTime.year or openDateTime.month != serverTime.month or openDateTime.day != serverTime.day:
+            #GameWorld.DebugLog("非今日定时发放的红包!redPackID=%s" % (redPackID))
+            continue
+        
+        endDateTime = None
+        validMinutes = ipyData.GetValidMinutes()
+        if validMinutes:
+            endDateTime = openDateTime + +datetime.timedelta(minutes=validMinutes)
+            
+        redPacketByTimeList.append([redPackID, openDateTime, endDateTime])
+        
+        GameWorld.Log("    增加本日定时发放系统红包信息: redPackID=%s, %s" % (redPackID, openTimeStr))
+        
+    TodayRedPacketByTimeInfo = IpyGameDataPY.SetConfigEx(key, [openServerDay, redPacketByTimeList])
+    GameWorld.Log("本日系统定时发放的红包加载完毕!")
+    GameWorld.Log("=============================================================")
+    return TodayRedPacketByTimeInfo[1]
+
+def OnRedPacketMinuteProcess():
+    ## 每分钟处理,定时发放系统红包
+    
+    CheckSendServerSystemRedPacket()
+    
+    todayRedPacketByTimeList = __GetTodayRedPacketByTimeList()
+    if not todayRedPacketByTimeList:
+        return
+    
+    serverTime = GameWorld.GetServerTime()
+    
+    for redPacketOpenInfo in todayRedPacketByTimeList:
+        redPackID, openDateTime, endDateTime = redPacketOpenInfo
+        
+        if serverTime < openDateTime or (endDateTime and serverTime >= endDateTime):
+            #GameWorld.DebugLog("非红包发放时段!  redPackID=%s, openDateTime=%s, endDateTime=%s" % (redPackID, openDateTime, endDateTime))
+            continue
+        
+        if PlayerDBGSEvent.GetDBGSTrig_ByKey(DBKey_RedPacketSend % redPackID):
+            #GameWorld.DebugLog("红包已发放过! redPackID=%s" % (redPackID))
+            continue
+        CreateSystemRedPacket(redPackID)
+        
+    return
+
+def Sync_FeastRedPacket(ipyData, curPlayer=None):
+    ## 同步节日红包活动信息
+    
+    if not ipyData:
+        return
+    
+    startDateStr, endDateStr = GameWorld.GetOperationActionDateStr(ipyData)
+    feastPack = ChPyNetSendPack.tagGCFeastRedPacketInfo()
+    feastPack.StartDate = startDateStr
+    feastPack.EndtDate = endDateStr
+    feastPack.LimitLV = ipyData.GetLVLimit()
+    feastPack.ResetType = ipyData.GetResetType()
+    feastPack.RedPacketDayList = []
+    for redPacketIDList in ipyData.GetRedPacketIDList():
+        dayInfo = ChPyNetSendPack.tagGCFeastRedPacketDay()
+        dayInfo.RedPacketIDList = redPacketIDList
+        dayInfo.RedPacketCount = len(dayInfo.RedPacketIDList)
+        feastPack.RedPacketDayList.append(dayInfo)
+    feastPack.RedPacketDays = len(feastPack.RedPacketDayList)
+    
+    if not curPlayer:
+        # 全服广播在线玩家
+        playerManager = GameWorld.GetPlayerManager()
+        for i in xrange(playerManager.GetActivePlayerCount()):
+            curPlayer = playerManager.GetActivePlayerAt(i)
+            if curPlayer == None or not curPlayer.GetInitOK():
+                continue
+            NetPackCommon.SendFakePack(curPlayer, feastPack)
+    else:
+        NetPackCommon.SendFakePack(curPlayer, feastPack)
+    return
+
+##--------------------------------------------------------------------------------------------------
+##---------------------------------------- 全服系统红包  ---------------------------------------------
+
+def RandTodayServerSystemRedPacketSendTime():
+    ## 随机生成今日全服系统红包发放时间点
+    sendTimeList = []
+    sysRedPackketSendCountToday = PlayerDBGSEvent.GetDBGSTrig_ByKey(DBKey_RedPacketSystemDayCount) 
+    maxCount = IpyGameDataPY.GetFuncCfg("ServerSysRedPacket", 1)
+    if not maxCount:
+        return
+    needSendCount = max(0, maxCount - sysRedPackketSendCountToday)
+    
+    GameWorld.Log("随机生成发放全服系统红包时间! maxCount=%s,sysRedPackketSendCountToday=%s,needSendCount=%s" 
+                  % (maxCount, sysRedPackketSendCountToday, needSendCount))
+    if needSendCount > 0:
+        startHour, endHour = IpyGameDataPY.GetFuncEvalCfg("ServerSysRedPacket", 3)
+        serverTime = GameWorld.GetServerTime()
+        year, month, day = serverTime.year, serverTime.month, serverTime.day
+        startDateTime = datetime.datetime(year, month, day, startHour)
+        if endHour == 0:
+            endDateTime = datetime.datetime(year, month, day) + datetime.timedelta(days=1)
+        else:
+            endDateTime = datetime.datetime(year, month, day, endHour)
+            
+        totalSeconds = (endDateTime - startDateTime).seconds # 可处理的总秒数
+        aveSeconds = totalSeconds / maxCount # 平均间隔
+        GameWorld.Log("    startDateTime=%s" % startDateTime)
+        GameWorld.Log("    endDateTime=%s" % endDateTime)
+        GameWorld.Log("    totalSeconds=%s,aveSeconds=%s" % (totalSeconds, aveSeconds))
+        
+        nextStartDateTime = startDateTime
+        for _ in xrange(maxCount):
+            randSeconds = random.randint(60, aveSeconds - 60) # 前后扣掉1分钟,防止随机到同分钟
+            randSendDateTime = nextStartDateTime + datetime.timedelta(seconds=randSeconds)
+            if randSendDateTime > serverTime:
+                sendTimeList.append(randSendDateTime)
+            GameWorld.Log("    随机起始时间=%s,randSeconds=%s,随机发放时间=%s" % (nextStartDateTime, randSeconds, randSendDateTime))
+            
+            nextStartDateTime += datetime.timedelta(seconds=aveSeconds)
+            
+    GameWorld.Log("    sendTimeList=%s" % sendTimeList)
+    IpyGameDataPY.SetConfigEx("ServerSystemRedPacketSendTime", sendTimeList)
+    return sendTimeList
+
+def CheckSendServerSystemRedPacket():
+    ## 检查发送今日全服系统红包
+    
+    sendTimeList = IpyGameDataPY.GetConfigEx("ServerSystemRedPacketSendTime")
+    if sendTimeList == None:
+        sendTimeList = RandTodayServerSystemRedPacketSendTime()
+        
+    if not sendTimeList:
+        #GameWorld.DebugLog("没有随机发放系统红包时间了!")
+        return
+    
+    serverTime = GameWorld.GetServerTime()
+    nextSendTime = sendTimeList[0]
+    if serverTime.hour == nextSendTime.hour and serverTime.minute == nextSendTime.minute:
+        sendTimeList.pop(0)
+        
+        randSysRedPacketList = IpyGameDataPY.GetFuncEvalCfg("ServerSysRedPacket", 2)
+        redPackID = GameWorld.GetResultByRandomList(randSysRedPacketList)
+        if not redPackID:
+            return
+        
+        CreateSystemRedPacket(redPackID)
+        
+        sysRedPackketSendCountToday = PlayerDBGSEvent.GetDBGSTrig_ByKey(DBKey_RedPacketSystemDayCount) + 1
+        PlayerDBGSEvent.SetDBGSTrig_ByKey(DBKey_RedPacketSystemDayCount, sysRedPackketSendCountToday)
+        GameWorld.Log("发放全服系统红包: redPackID=%s, sysRedPackketSendCountToday=%s" % (redPackID, sysRedPackketSendCountToday))
+        
+        maxCount = IpyGameDataPY.GetFuncCfg("ServerSysRedPacket", 1)
+        if sysRedPackketSendCountToday >= maxCount:
+            IpyGameDataPY.SetConfigEx("ServerSystemRedPacketSendTime", [])
+            GameWorld.Log("    今日全服系统红包已经全部发完了! maxCount=%s" % maxCount)
+            
+    elif nextSendTime < serverTime:
+        sendTimeList.pop(0)
+        #GameWorld.DebugLog("发放系统红包时间过期了!serverTime=%s, nextSendTime=%s" % (serverTime, nextSendTime))
+    #else:
+    #    GameWorld.DebugLog("非发放系统红包时间!serverTime=%s, nextSendTime=%s" % (serverTime, nextSendTime))
+        
+    return
+
+##--------------------------------------------------------------------------------------------------
+
+def CreateSystemRedPacket(redPackID):
+    ## 发放系统红包
+    ipyData = IpyGameDataPY.GetIpyGameData('FamilyRedPack', redPackID)
+    if not ipyData:
+        return
+    getType = ipyData.GetGetType()
+    moneyType = ipyData.GetMoneyType()
+    outputNum = ipyData.GetMoneyNum()
+    packetCnt = ipyData.GetPacketCnt()
+    openTime = ipyData.GetPacketOpenTime() # 如果有指定发放时间的
+    sysCreateTime = GameWorld.ChangeTimeStrToNum("%s:00" % openTime) if openTime else None
+    
+    isAnonymous = 0
+    state = State_NoGot # 暂直接设定已发放
+    if ipyData.GetPacketOpenTime():
+        PlayerDBGSEvent.SetDBGSTrig_ByKey(DBKey_RedPacketSend % redPackID, 1)
+        GameWorld.DebugLog("定时发放的红包,设置已发放! redPackID=%s" % redPackID)
+        
+    getWayType = GetRedPackGetWayType(getType)
+    if getWayType == ShareDefine.RedPackWayType_Server:
+        isAnonymous = 1
+        
+    job = 0
+    jobRank = 0
+    playerName = ""
+    playerID = 0
+    family = None
+    
+    __SaveNewRedRecord(family, playerID, playerName, job, jobRank, getType, moneyType, outputNum, packetCnt, state, sysCreateTime=sysCreateTime, isAnonymous=isAnonymous)
+    return
 
 ## 生成新红包
-def CreatFamilyRedPacket(msgList):
-    playerID, getType, packetCnt, moneyType, outputNum, wishStr, state, data = msgList
+def MapServer_CreatRedPacket(msgList):
+    playerID, getType, packetCnt, moneyType, outputNum, wishStr, state, data, isFamilyRedPacket = msgList
     curPlayer = GameWorld.GetPlayerManager().FindPlayerByID(playerID)
     if not curPlayer:
         return
-    if getType == IpyGameDataPY.GetFuncCfg('OpenServerRedPacketType'):
+    if not isFamilyRedPacket:
         familyID = 0
         family = None
     else:
@@ -91,30 +996,14 @@
         family = GameWorld.GetFamilyManager().FindFamily(familyID)
         if not family:
             return
-        packetCnt = min(packetCnt, family.GetCount())
-#    if getType != 0:
-#        commonCntLimit = IpyGameDataPY.GetFuncCfg('FamilyRedPacketCnt')
-#        packetCnt = max(packetCnt, commonCntLimit)
-    
+        
     if outputNum < packetCnt:
-        GameWorld.DebugLog("    生成新仙盟红包 红包额度不能低于红包个数!outputNum=%s,redCnt=%s" % (outputNum, packetCnt))
+        GameWorld.DebugLog("    生成新仙盟红包 红包额度不能低该红包个数!outputNum=%s,redCnt=%s" % (outputNum, packetCnt))
         return
     job = curPlayer.GetJob()
-    jobRank = PlayerControl.GetJobRank(curPlayer)
+    jobRank = 0
     playerName = curPlayer.GetName()
-    redPacketRecData = __SaveNewRedRecord(familyID, playerID, playerName, job, jobRank, getType, moneyType, outputNum, packetCnt, state, wishStr)
-    #通知
-    if redPacketRecData:
-        __NotifyFamilyRedPacketInfo(family, redPacketRecData, [])
-        if not familyID:
-            if not PlayerDBGSEvent.GetDBGSTrig_ByKey(PlayerDBGSEvent.Def_OSRedPacket):
-                PlayerControl.WorldNotify(0, 'OpenRedBag2', [playerName, data, outputNum])
-                PlayerDBGSEvent.SetDBGSTrig_ByKey(PlayerDBGSEvent.Def_OSRedPacket, 1)
-            elif data in IpyGameDataPY.GetFuncEvalCfg('OSRSuccess'):
-                PlayerControl.WorldNotify(0, 'OpenRedBag3', [playerName, data, outputNum])
-            #大于200额度的红包
-            if outputNum >= IpyGameDataPY.GetFuncCfg('OpenServerRedPacketRain'):
-                PlayerControl.WorldNotify(0, 'OSRedpackSfx')
+    __SaveNewRedRecord(family, playerID, playerName, job, jobRank, getType, moneyType, outputNum, packetCnt, state, wishStr, data=data)
     return
 
 def CreatNewFamilyRedPacket(family, playerID, redPackID):
@@ -138,27 +1027,11 @@
     jobRank = 0
     playerName = member.GetName()
     
-    redPacketRecData = __SaveNewRedRecord(familyID, playerID, playerName, job, jobRank, getType, moneyType, outputNum, 0)
-    #通知
-    __NotifyFamilyRedPacketInfo(family, redPacketRecData, [])
+    __SaveNewRedRecord(family, playerID, playerName, job, jobRank, getType, moneyType, outputNum, 0)
     return
 
 ## 记录新红包数据
-def __SaveNewRedRecord(familyID, ownerid, playerName, job, jobRank, getType, moneyType, outputNum, packetCnt,state=State_NoSend, wishStr=''):
-    global g_allRecordDict
-    global g_osRedCnt
-    job = job + jobRank * 10   #个位是job 十位百位是jobrank
-    recordType = ShareDefine.Def_UniversalGameRecType_FamilyRedPacketAllRecord
-    universalRecMgr = GameWorld.GetUniversalRecMgr()
-    recordList = universalRecMgr.GetTypeList(recordType)
-    if getType == IpyGameDataPY.GetFuncCfg('OpenServerRedPacketType'):
-        if not __CheckOSRedPacketCnt(recordList):
-            return
-        if g_osRedCnt:
-            g_osRedCnt += 1
-    
-    recData = recordList.AddRec()
-    
+def __SaveNewRedRecord(family, ownerID, playerName, job, jobRank, getType, moneyType, outputNum, packetCnt, state=State_NoSend, wishStr='', sysCreateTime=None, data=0, isAnonymous=0):
     
     #红包唯一ID 从1开始累计 超过20亿则重新开始
     # 红包唯一ID
@@ -168,129 +1041,58 @@
         redPacketID = 1
     PlayerDBGSEvent.SetDBGSTrig_ByKey(DB_RedPacketID, redPacketID)
     
+    familyID = family.GetID() if family else 0
+    
     curTimeNum = int(time.time())
-    recData.SetTime(curTimeNum)
-    recData.SetValue1(redPacketID) #红包唯一ID
-    recData.SetValue2(familyID)  #家族ID   
-    recData.SetValue3(moneyType + outputNum * 10) #总额度*10+金钱类型
-    recData.SetValue4(state) #是否已发
-    recData.SetValue5(curTimeNum) 
-    recData.SetStrValue1('%s|%s|%s|%s'%(ownerid,playerName,job,getType)) #创建者ID|创建者名字|创建者职业|途径
-    recData.SetStrValue2(str(packetCnt))#可抢总个数
-    recData.SetStrValue3(wishStr)#祝福语
-    g_allRecordDict[redPacketID] = recData
-    GameWorld.Log("    生成新的红包familyID=%s, redPacketID =%s!ownerid=%s, ownername=%s,getType=%s,moneyType=%s,outputNum=%s,packetCnt=%s" % (familyID, redPacketID, ownerid, playerName, getType, moneyType, outputNum, packetCnt))
-    return recData
-
-
-def __CheckOSRedPacketCnt(recordList):
-    global g_grabDataDict
-    global g_allRecordDict
-    global g_osRedCnt
-    ##开服红包个数是否达上限
-    openServerRedPacketCnt = IpyGameDataPY.GetFuncCfg('OpenServerRedPacketCnt')
-    if g_osRedCnt and g_osRedCnt < openServerRedPacketCnt + 10:
-        return True
-    OpenServerRedPacketType = IpyGameDataPY.GetFuncCfg('OpenServerRedPacketType')
-    allCnt = recordList.Count()
-
-    curCnt = 0
-    delRedPacketIDList = []
-    for index in xrange(allCnt):
-        universalRecData = recordList.At(index)
-        strValue1 = universalRecData.GetStrValue1()
-        strValue1List = strValue1.split('|')
-        getWay = int(strValue1List[3])
-        if getWay != OpenServerRedPacketType:
-            continue
-        redPacketID = universalRecData.GetValue1()
-        curCnt += 1
-        if len(delRedPacketIDList) < 10:
-            delRedPacketIDList.append(redPacketID)
-        elif g_osRedCnt:
-            break
-    if not delRedPacketIDList:
-        return True
-    if not g_osRedCnt:
-        g_osRedCnt = curCnt
-
-    if g_osRedCnt < openServerRedPacketCnt + 10:
-        return True
-
-    delCnt = 0
-    for index in xrange(recordList.Count()):
-        dataIndex = index - delCnt
-        universalRecData = recordList.At(dataIndex)
-        delRedPacketID = universalRecData.GetValue1()
-        if delRedPacketID in delRedPacketIDList:
-            recordList.Delete(dataIndex)
-            delCnt +=1
-            g_grabDataDict.pop(delRedPacketID, 0)
-            g_allRecordDict.pop(delRedPacketID, 0)
-    g_osRedCnt -= delCnt
     
-        
-    recordType = ShareDefine.Def_UniversalGameRecType_FamilyRedPacketGrabRecord
-    universalRecMgr = GameWorld.GetUniversalRecMgr()
-    recordList = universalRecMgr.GetTypeList(recordType)
-    delCnt = 0
-    for index in xrange(recordList.Count()):
-        dataIndex = index - delCnt
-        universalRecData = recordList.At(dataIndex)
-        if universalRecData.GetValue1() in delRedPacketIDList:
-            recordList.Delete(dataIndex)
-            delCnt +=1
-            
+    redPacketMgr = GetRedpacketMgr()
+    redPacketObj = redPacketMgr.GetRedPacketObj(redPacketID, True)
+    redPacketObj.redPacketID = redPacketID
+    redPacketObj.familyID = familyID
+    redPacketObj.moneyType = moneyType
+    redPacketObj.moneyValue = outputNum
+    redPacketObj.state = state
+    redPacketObj.createTime = sysCreateTime if sysCreateTime else curTimeNum
+    redPacketObj.calcTime = curTimeNum
+    redPacketObj.playerID = ownerID
+    redPacketObj.playerName = playerName
+    redPacketObj.playerJob = job
+    redPacketObj.getWay = getType
+    redPacketObj.packetCnt = packetCnt
+    redPacketObj.isAnonymous = isAnonymous # 是否匿名
+    redPacketObj.wish = wishStr
+    redPacketObj.grabDict = {}
+    
+    GameWorld.Log("生成新的红包: familyID=%s,redPacketID=%s,ownerID=%s,getType=%s,moneyType=%s,outputNum=%s,packetCnt=%s,state=%s,isAnonymous=%s" 
+                  % (familyID, redPacketID, ownerID, getType, moneyType, outputNum, packetCnt, state, isAnonymous))
+    
     #通知
-    NotifyDelRedPacketInfo(delRedPacketIDList)
-    return True
-
-def __DelGrabRecord():
-    #删除多余抢信息
-    universalRecMgr = GameWorld.GetUniversalRecMgr()
-    allRecordList = universalRecMgr.GetTypeList(ShareDefine.Def_UniversalGameRecType_FamilyRedPacketAllRecord)
-    allCnt = allRecordList.Count()
-    redPacketIDList = []
-    for index in xrange(allCnt):
-        universalRecData = allRecordList.At(index)
-        redPacketID = universalRecData.GetValue1()
-        redPacketIDList.append(redPacketID)
+    OnChangeRedPacketState(family, redPacketObj, None)
     
-    recordType = ShareDefine.Def_UniversalGameRecType_FamilyRedPacketGrabRecord
-    recordList = universalRecMgr.GetTypeList(recordType)
-    delCnt = 0
-    for index in xrange(recordList.Count()):
-        dataIndex = index - delCnt
-        universalRecData = recordList.At(dataIndex)
-        if universalRecData.GetValue1() not in redPacketIDList:
-            recordList.Delete(dataIndex)
-            delCnt +=1
-    GameWorld.Log('    删除多余抢红包信息 delCnt=%s'%delCnt)
-    return
-
-isdel = False
-if not isdel:
-    __DelGrabRecord()
-    isdel = True
-    
-
+    if not familyID:
+        #大于200额度的红包
+        getTypeRainDict = IpyGameDataPY.GetFuncEvalCfg('OpenServerRedPacketRain', 2, {})
+        if str(getType) in getTypeRainDict:
+            PlayerControl.WorldNotify(0, getTypeRainDict[str(getType)])
+        elif outputNum >= IpyGameDataPY.GetFuncCfg('OpenServerRedPacketRain'):
+            PlayerControl.WorldNotify(0, 'OSRedpackSfx', [getType])
+            
+    return redPacketObj
 
 def SendFamilyRedPacket(msgList):
-    '''发系统赠送的红包'''
-    playerID, redPacketID, packetCnt = msgList
+    '''开放红包可领取,该红包已存在,只是状态未发放,由归属玩家自由选择发放时机'''
+    playerID, redPacketID, packetCnt, isAnonymous = msgList
     curPlayer = GameWorld.GetPlayerManager().FindPlayerByID(playerID)
     if not curPlayer:
         return
     
-    recDataList = __FindGrabRecData(ShareDefine.Def_UniversalGameRecType_FamilyRedPacketAllRecord,redPacketID)
-    
-    if not recDataList:
+    redPacketMgr = GetRedpacketMgr()
+    redPacketObj = redPacketMgr.GetRedPacketObj(redPacketID, False)
+    if not redPacketObj:
         return
-    recData=recDataList[0]
-    strValue1 = recData.GetStrValue1()
-    strValue1List = strValue1.split('|')
-    ownID = int(strValue1List[0])
-    getWay = int(strValue1List[3])
+    
+    ownID = redPacketObj.playerID
+    getWay = redPacketObj.getWay
     
     ipyData = IpyGameDataPY.GetIpyGameDataByCondition('FamilyRedPack', {'GetType':getWay})
     if not ipyData:
@@ -300,107 +1102,123 @@
             GameWorld.DebugLog('    发系统赠送的红包 权限不足!', playerID)
             return
         if playerID != ownID:
-            strValue1List[0] = str(playerID)
-            StrValue1 = '|'.join(strValue1List)
-            recData.SetStrValue1(StrValue1)
+            redPacketObj.playerID = playerID
             
     elif playerID != ownID:
         GameWorld.DebugLog('    发系统赠送的红包 不是本人!', playerID)
         return
     
-    recData.SetValue4(State_NoGot)
-    recData.SetStrValue2(str(packetCnt))
-    #更新时间
-    curTimeNum = int(time.time())
-    recData.SetValue5(curTimeNum)
-    if recData.GetValue2() == 0:
+    beforeState = redPacketObj.state
+    redPacketObj.state = State_NoGot
+    redPacketObj.packetCnt = packetCnt
+    redPacketObj.isAnonymous = int(isAnonymous)
+    redPacketObj.calcTime = int(time.time())
+    
+    if redPacketObj.familyID == 0:
         family = None
     else:
         family = curPlayer.GetFamily()
         if family == None:
             return
-    __NotifyFamilyRedPacketInfo(family, recData, [])
+        
+    OnChangeRedPacketState(family, redPacketObj, beforeState)
     return
 
-
-## 抢红包
 def DoGrabFamilyRedPacket(curPlayer, msgList):
-    global g_grabDataDict
-    redPacketID, OSCanGrabCnt = msgList
+    ## 抢红包
+    redPacketID, reqGetWay, canGrabCnt = msgList
     
-    playerID= curPlayer.GetPlayerID()
-    job = curPlayer.GetJob()
-    jobRank = PlayerControl.GetJobRank(curPlayer)
-    job = jobRank * 10 + job
-    playerName = curPlayer.GetName()
-    
-    
-    recDataList = __FindGrabRecData(ShareDefine.Def_UniversalGameRecType_FamilyRedPacketAllRecord, redPacketID)
-    if not recDataList:
-        GameWorld.Log('    未找到该仙盟红包记录redPacketID=%s'%redPacketID)
+    redPacketMgr = GetRedpacketMgr()
+    redPacketObj = redPacketMgr.GetRedPacketObj(redPacketID, False)
+    if not redPacketObj:
+        GameWorld.ErrLog("红包不存在!")
         return
-    redPacketRecData = recDataList[0]
-    state = redPacketRecData.GetValue4()
+    
+    playerID = curPlayer.GetPlayerID()
+    
+    state = redPacketObj.state
+    beforeState = state
     if state in [State_NoSend]:
-        GameWorld.DebugLog("    该仙盟红包还未发送!",playerID)
+        GameWorld.DebugLog("    该红包还未发送!", playerID)
         return
-    familyID = redPacketRecData.GetValue2()
+    
+    familyID = redPacketObj.familyID
     if familyID:
         curFamily = curPlayer.GetFamily()
         if curFamily == None:
             return
     else:
         curFamily = None
-    
-    value3 = redPacketRecData.GetValue3()
-    moneyType, totalMoney =value3%10, value3/10
-    packetCnt = int(redPacketRecData.GetStrValue2())
+        
+    moneyType = redPacketObj.moneyType
+    totalMoney = redPacketObj.moneyValue
+    packetCnt = redPacketObj.packetCnt
     
     #找该红包的抢信息
-    grabRecordDict = __GetGrabRecord(redPacketID)
-    if playerID in grabRecordDict or len(grabRecordDict) >= packetCnt:
-        GameWorld.DebugLog("    该玩家已抢过此红包!",playerID)
+    grabRecordDict = redPacketObj.grabDict
+    if playerID in grabRecordDict:
+        GameWorld.DebugLog("    该玩家已抢过此红包!", playerID)
         __NotifyGrabRedPacketInfo(curPlayer, redPacketID, grabRecordDict)
         return
     
-    outNum = sum([a[0] for a in grabRecordDict.values()]) #已被抢的钱
+    outNum = sum([grabObj.getMoney for grabObj in grabRecordDict.values()]) #已被抢的钱
     remainNum = totalMoney - outNum #剩余的钱
-    remainPacketCnt = packetCnt-len(grabRecordDict)
-    if remainNum < remainPacketCnt:
-        GameWorld.Log(' 该红包剩余的钱不够发 packetCnt =%s,totalMoney=%s,outNum=%s,remainMoney=%s,grabRecordDict=%s'%(packetCnt, totalMoney,outNum,remainNum, grabRecordDict))
+    
+    if len(grabRecordDict) >= packetCnt or remainNum <= 0:
+        GameWorld.DebugLog("    红包已被抢完!", playerID)
+        if state != State_HasAllGot:
+            redPacketObj.state = State_HasAllGot
+            #GameWorld.DebugLog("    纠正红包已抢完状态! state=%s,updState=%s" % (state, State_HasAllGot))
+            OnChangeRedPacketState(curFamily, redPacketObj, beforeState)
+        __NotifyGrabRedPacketInfo(curPlayer, redPacketID, grabRecordDict)
         return
-    strValue1 = redPacketRecData.GetStrValue1()
-    strValue1List = strValue1.split('|')
-    getWay = int(strValue1List[3])
-    owerID = int(strValue1List[0])
+    
+    remainPacketCnt = packetCnt - len(grabRecordDict)
+    
+    getWay = redPacketObj.getWay
+    owerID = redPacketObj.playerID
     isSelf = owerID == playerID
-    if getWay == IpyGameDataPY.GetFuncCfg('OpenServerRedPacketType'):
-        #开服红包需要判断次数
-        if not isSelf and OSCanGrabCnt <= 0:
-            GameWorld.DebugLog('    抢开服红包,次数不足!!')
-            return
+    if not isSelf and canGrabCnt != -1 and canGrabCnt <= 0:
+        GameWorld.DebugLog('    抢开服红包,次数不足!!')
+        return
+    if reqGetWay != getWay:
+        GameWorld.ErrLog("领取的红包类型不一致,无法领取! reqGetWay=%s,getWay=%s" % (reqGetWay, getWay))
+        return
+    
+    getWayType = GetRedPackGetWayType(getWay)
+    if getWayType == ShareDefine.RedPackWayType_Server:
         getNumformula = IpyGameDataPY.GetFuncCompileCfg('OpenRedRacketOutNum')
+    elif getWayType == ShareDefine.RedPackWayType_Feast:
+        getNumformula = IpyGameDataPY.GetFuncCompileCfg('FeastRedPacket', 2)
     else:
         getNumformula = IpyGameDataPY.GetFuncCompileCfg('FamilyRedRacketOutNum')
-    
-    getMoney = eval(getNumformula) if remainPacketCnt > 1 else remainNum
-    GameWorld.DebugLog("    该玩家抢到红包=%s!"%getMoney, playerID)
-    grabRecordDict[playerID] = [getMoney, playerName, job]
-    #新增一条抢的记录
-    recType = ShareDefine.Def_UniversalGameRecType_FamilyRedPacketGrabRecord
-    valueList = [redPacketID, playerID, job, moneyType, getMoney]
-    strValueList = [playerName]
-    PlayerUniversalGameRec.MapServer_UniversalGameRec(None, recType, valueList, strValueList)
-    #{playerid:[抢到的钱,名字,job]}
-    g_grabDataDict[redPacketID] = grabRecordDict
-    
-    if len(grabRecordDict) == packetCnt:
-        redPacketRecData.SetValue4(State_HasAllGot)
         
-        #通知该玩家红包抢结果
-        __NotifyFamilyRedPacketInfo(curFamily, redPacketRecData, grabRecordDict.keys())
+    getMoney = eval(getNumformula) if remainPacketCnt > 1 else remainNum
+    getMoney = min(getMoney, remainNum)
+    remainNum -= getMoney
+    GameWorld.DebugLog("    该玩家抢到红包: redPacketID=%s,getWay=%s,getMoney=%s,remainNum=%s" 
+                       % (redPacketID, getWay, getMoney, remainNum), playerID)
+    
+    # 新增抢的记录
+    grabObj = RedPacketGrab(redPacketID, playerID)
+    grabObj.playerJob = curPlayer.GetJob()
+    grabObj.playerName = curPlayer.GetName()
+    grabObj.moneyType = moneyType
+    grabObj.getMoney = getMoney
+    grabRecordDict[playerID] = grabObj
+    
+    if len(grabRecordDict) >= packetCnt or remainNum <= 0:
+        redPacketObj.state = State_HasAllGot
+        OnChangeRedPacketState(curFamily, redPacketObj, beforeState)
     else:
-        NotifyRedPacketInfo(curPlayer, [redPacketRecData, grabRecordDict.keys()])
+        if getWay in IpyGameDataPY.GetFuncEvalCfg("RedPacketSys", 1):
+            #PrintRedPacketData("GrabBefore")
+            notifyRedIDList = DoPlayerReductCanGetRedPacket(playerID, redPacketObj)
+            if notifyRedIDList:
+                NotifyRedPacketInfo(curPlayer, notifyRedIDList)
+            #PrintRedPacketData("GrabAfter")
+        else:
+            NotifyRedPacketInfo(curPlayer, [redPacketID])
         
     __NotifyGrabRedPacketInfo(curPlayer, redPacketID, grabRecordDict)
     
@@ -409,279 +1227,103 @@
     curPlayer.MapServer_QueryPlayerResult(0, 0, "GrabFamilyRedPacketResult", result, len(result))
     return getMoney
 
-    
-    
-## 获取抢红包记录
-def __GetGrabRecord(redPacketID):
-    if redPacketID in g_grabDataDict:
-        return g_grabDataDict[redPacketID]
-    
-    recDataList = __FindGrabRecData(ShareDefine.Def_UniversalGameRecType_FamilyRedPacketGrabRecord, redPacketID)
-    if not recDataList:
-        return {}
-    grabRecordDict = {}
-    for recData in recDataList: #{playerid:[抢到的钱,名字,job]}
-        grabRecordDict[recData.GetValue2()] = [recData.GetValue5(), recData.GetStrValue1(), recData.GetValue3()]
-    
-    return grabRecordDict
-
-def __FindGrabRecData(recordType, redPacketID):
-    global g_allRecordDict
-    if recordType == ShareDefine.Def_UniversalGameRecType_FamilyRedPacketAllRecord:
-        if redPacketID in g_allRecordDict:
-            frecData = g_allRecordDict[redPacketID]
-            if frecData:
-                return [frecData]
-            
-    
-    recDataList = []
-    universalRecMgr = GameWorld.GetUniversalRecMgr()
-    allRecordList = universalRecMgr.GetTypeList(recordType)
-    allCnt = allRecordList.Count()
-    for index in xrange(allCnt):
-        recData = allRecordList.At(index)
-        if recData.GetValue1() == redPacketID:
-            recDataList.append(recData)
-            if recordType == ShareDefine.Def_UniversalGameRecType_FamilyRedPacketAllRecord:
-                g_allRecordDict[redPacketID] = recData
-                break
-    return recDataList
-
-## 检查红包是否过期
-def __CheckGrabRecData():
-    global g_grabDataDict
-    global g_allRecordDict
-    global g_osRedCnt
-    g_osRedCnt = 0
-    universalRecMgr = GameWorld.GetUniversalRecMgr()
-    allRecordList = universalRecMgr.GetTypeList(ShareDefine.Def_UniversalGameRecType_FamilyRedPacketAllRecord)
-    allCnt = allRecordList.Count()
-    curTimeNum = int(time.time())
-    
-    rangeTime = 24*60*60
-    backMoneyDict = {}
-    delRedPacketIDList = []
-    familyIDList = []
-    delCnt = 0
-    for index in xrange(allCnt):
-        dataIndex = index - delCnt
-        universalRecData = allRecordList.At(dataIndex)
-        saveTime = universalRecData.GetValue5()
-        GameWorld.DebugLog("    检查红包是否过期 curTime=%s,saveTime=%s,rangeTime=%s,redPacketID=%s"%(curTimeNum, saveTime, curTimeNum -saveTime,universalRecData.GetValue1()))
-        if curTimeNum -saveTime > rangeTime:#过期
-            redPacketID = universalRecData.GetValue1()
-            
-            strValue1 = universalRecData.GetStrValue1()
-            strValue1List = strValue1.split('|')
-            playerID = strValue1List[0]
-            if playerID:
-                playerID = int(playerID)
-                grabRecordDict = __GetGrabRecord(redPacketID)
-                outNum = sum([a[0] for a in grabRecordDict.values()]) #已被抢的钱
-                value3 = universalRecData.GetValue3()
-                moneyType, totalMoney =value3%10, value3/10
-                remainMoney = totalMoney - outNum #剩余的钱
-                #GameWorld.DebugLog('    outNum=%s,remainMoney=%s,moneyType=%s'%(outNum,remainMoney,moneyType))
-                if moneyType ==1 and remainMoney:
-                    backMoneyDict[playerID] = backMoneyDict.get(playerID, 0) + remainMoney
-            
-            delRedPacketIDList.append(redPacketID)
-            familyID=universalRecData.GetValue2()
-            if familyID not in familyIDList:
-                familyIDList.append(familyID)
-            
-            allRecordList.Delete(dataIndex)
-            delCnt +=1
-            
-    if not delRedPacketIDList:
-        return
-    for redID in delRedPacketIDList:
-        g_grabDataDict.pop(redID, 0)
-        g_allRecordDict.pop(redID, 0)
-    recordType = ShareDefine.Def_UniversalGameRecType_FamilyRedPacketGrabRecord
-    recordList = universalRecMgr.GetTypeList(recordType)
-
-    delCnt = 0
-    for index in xrange(recordList.Count()):
-        dataIndex = index - delCnt
-        universalRecData = recordList.At(dataIndex)
-        if universalRecData.GetValue1() in delRedPacketIDList:
-            recordList.Delete(dataIndex)
-            delCnt +=1
-            
-
-    NotifyDelRedPacketInfo(delRedPacketIDList)
-
-        
-    #返回玩家未被领取的仙玉
-    if backMoneyDict:
-        for playerID, moneyNum in backMoneyDict.items():
-            PlayerCompensation.SendMailByKey('RedPackBack', [playerID], [], [], moneyNum)
-    
-    return
-def DelRedPackByFamilyID(delfamilyID):
-    global g_grabDataDict
-    global g_allRecordDict
-    #删除某个家族的红包记录
-    universalRecMgr = GameWorld.GetUniversalRecMgr()
-    allRecordList = universalRecMgr.GetTypeList(ShareDefine.Def_UniversalGameRecType_FamilyRedPacketAllRecord)
-    allCnt = allRecordList.Count()
-    delRedPacketIDList = []
-    delCnt = 0
-    for index in xrange(allCnt):
-        dataIndex = index - delCnt
-        universalRecData = allRecordList.At(dataIndex)
-        familyID=universalRecData.GetValue2()
-        if delfamilyID != familyID:
-            continue
-        redPacketID = universalRecData.GetValue1()
-        delRedPacketIDList.append(redPacketID)
-        allRecordList.Delete(dataIndex)
-        delCnt +=1
-    if not delRedPacketIDList:
-        return
-    for redID in delRedPacketIDList:
-        g_grabDataDict.pop(redID, 0)
-        g_allRecordDict.pop(redID, 0)
-    recordList = universalRecMgr.GetTypeList(ShareDefine.Def_UniversalGameRecType_FamilyRedPacketGrabRecord)
-    delCnt = 0
-    for index in xrange(recordList.Count()):
-        dataIndex = index - delCnt
-        universalRecData = recordList.At(dataIndex)
-        if universalRecData.GetValue1() in delRedPacketIDList:
-            recordList.Delete(dataIndex)
-            delCnt +=1
-    #NotifyDelRedPacketInfo(delRedPacketIDList)
-    return
-
-## 红包变更通知单个红包给对应战盟所有成员
-def __NotifyFamilyRedPacketInfo(family, redPacketRecData, grabHeroIDList):
-    syncPacketDataList = [redPacketRecData, grabHeroIDList]
-#    recordType = ShareDefine.Def_UniversalGameRecType_FamilyRedPacketAllRecord
-#    universalRecMgr = GameWorld.GetUniversalRecMgr()
-#    recordList = universalRecMgr.GetTypeList(recordType)
-#    for index in xrange(recordList.Count()):
-#        recData = recordList.At(index)
-#        familyID = recData.GetValue2()
-#        if familyID and family and family.GetID() != familyID:
-#            continue
-#        if redPacketID:
-#            if recData.GetValue1() == redPacketID:
-#                syncPacketDataList = [recData, grabHeroIDList]
-#                break
-#        else:
-#            syncPacketDataList.append(recData)
-    if not syncPacketDataList:
-        return
-    playerManager = GameWorld.GetPlayerManager()
-    if not family:
-        for i in xrange(0, playerManager.GetActivePlayerCount()):
-            curPlayer = playerManager.GetActivePlayerAt(i)
-            if curPlayer == None or not curPlayer.GetInitOK():
-                continue
-            NotifyRedPacketInfo(curPlayer, syncPacketDataList)
-    else:
-        for i in xrange(0, family.GetCount()):
-            notifyMember = family.GetAt(i)
-            notifyPlayer = playerManager.FindPlayerByID(notifyMember.GetPlayerID())
-            if notifyPlayer == None:
-                continue
-            NotifyRedPacketInfo(notifyPlayer, syncPacketDataList)
-    return
-
-## 通知红包信息
-# 通知玩家本战盟所有红包或单个红包
-def NotifyRedPacketInfo(curPlayer, packetDataList=[]):
-    if PlayerControl.GetIsTJG(curPlayer):
-        return
-    if not packetDataList:
-        syncPacketDataList = []
-        recordType = ShareDefine.Def_UniversalGameRecType_FamilyRedPacketAllRecord
-        universalRecMgr = GameWorld.GetUniversalRecMgr()
-        recordList = universalRecMgr.GetTypeList(recordType)
-        for index in xrange(recordList.Count()):
-            recData = recordList.At(index)
-            familyID = recData.GetValue2()
-            if familyID and curPlayer.GetFamilyID() != familyID:
-                continue
-            grabRecordDict = __GetGrabRecord(recData.GetValue1())
-            syncPacketDataList.append([recData, grabRecordDict.keys()])
-    else:
-        syncPacketDataList = [packetDataList]
-    if not syncPacketDataList:
-        return
-    joinFamilyTime = PlayerFamily.GetPlayerJoinFamilyTime(curPlayer)
-    sendPack = ChPyNetSendPack.tagGCFamilyRedPacketInfo()
-    sendPack.Clear()
-    sendPack.IsAll = int(packetDataList==[])
-    sendPack.RedPacketInfo = []
-    
-    for packetData, grabHeroIDList in syncPacketDataList:
-        #仙盟红包只通知玩家进入仙盟后生成的红包
-        #GameWorld.Log('1111packetData.GetValue2()=%s,joinFamilyTime=%s,packetData.GetValue5()=%s'%(packetData.GetValue2(),joinFamilyTime,packetData.GetValue5()))
-        if packetData.GetValue2() and joinFamilyTime and packetData.GetValue5() < joinFamilyTime:
-            continue
-        
-        packetInfo = ChPyNetSendPack.tagFRedPacketInfo()
-        packetInfo.Clear()
-        packetInfo.RedPacketID = packetData.GetValue1()
-        strValue1 = packetData.GetStrValue1()
-        strValue1List = strValue1.split('|')
-        if len(strValue1List) != 4:
-            return
-        playerID, playerName, job, getWay = strValue1List
-        packetInfo.PlayerID = int(playerID)
-        packetInfo.Name = playerName
-        packetInfo.Time = packetData.GetTime()
-        packetInfo.PlayeJob = int(job)
-        value3 = packetData.GetValue3()
-        packetInfo.MoneyType = value3 % 10
-        packetInfo.MoneyNum = value3 / 10
-        packetInfo.GetWay = int(getWay)
-        state = packetData.GetValue4()
-
-        if curPlayer.GetPlayerID() in grabHeroIDList:
-            state = State_HasGot
-        packetInfo.State = state
-        packetInfo.PacketCnt = int(packetData.GetStrValue2())
-        
-        packetInfo.Wish = packetData.GetStrValue3()
-        sendPack.RedPacketInfo.append(packetInfo)
-    
-    sendPack.Count = len(sendPack.RedPacketInfo)
-    NetPackCommon.SendFakePack(curPlayer, sendPack)
-    #GameWorld.Log('仙盟红包通知 IsAll=%s,Count=%s,syncPacketDataList=%s,redPacketID=%s'%(sendPack.IsAll,sendPack.Count,syncPacketDataList,redPacketID))
-    return 
-
-
 def __NotifyGrabRedPacketInfo(curPlayer, redPacketID, grabRecordDict):
     '''通知抢红包信息'''
     sendPack = ChPyNetSendPack.tagGCFamilyRedPacketGrabInfo()
     sendPack.Clear()
     sendPack.RedPacketID = redPacketID
-    #grabRecordDict = __GetGrabRecord(redPacketID) #{playerid:[抢到的钱,名字,job]}
-    sendPack.Count = len(grabRecordDict)
     sendPack.GrabInfo = []
-    for playerID, info in grabRecordDict.items():
-        money, name, job = info
+    for grabObj in grabRecordDict.values():
         grabInfo = ChPyNetSendPack.tagFGrabRedPacketInfo()
-        grabInfo.Name = name
-        grabInfo.PlayeJob = job
-        grabInfo.MoneyNum = money
+        grabInfo.Name = grabObj.playerName
+        grabInfo.NameLen = len(grabInfo.Name)
+        grabInfo.PlayeJob = grabObj.playerJob
+        grabInfo.MoneyNum = grabObj.getMoney
         sendPack.GrabInfo.append(grabInfo)
+    sendPack.Count = len(sendPack.GrabInfo)
     NetPackCommon.SendFakePack(curPlayer, sendPack)
     return
 
-def NotifyDelRedPacketInfo(delRedPacketIDList):
-    ##通知红包删除信息
-    sendPack = ChPyNetSendPack.tagGCRedPacketDel()
-    sendPack.Clear()
-    sendPack.DelRedPacketID = delRedPacketIDList
-    sendPack.Cnt = len(delRedPacketIDList)
-    playerManager = GameWorld.GetPlayerManager()
-    for i in xrange(0, playerManager.GetActivePlayerCount()):
-        curPlayer = playerManager.GetActivePlayerAt(i)
-        if curPlayer == None or not curPlayer.GetInitOK():
+def NotifyRedPacketInfo(curPlayer, syncRedPacketIDList=None, isLogin=False):
+    ## 通知红包信息
+    if PlayerControl.GetIsTJG(curPlayer):
+        return
+    
+    redPacketMgr = GetRedpacketMgr()
+    isAll = int(syncRedPacketIDList == None)
+    if syncRedPacketIDList == None:
+        syncRedPacketIDList = []
+        
+        playerID = curPlayer.GetPlayerID()
+        family = curPlayer.GetFamily()
+        familyID = family.GetID() if family else 0
+        
+        syncRedPacketIDList += redPacketMgr.familyRedPacketDict.get(familyID, []) # 1. 仙盟所有(含未开放的)
+        
+        syncRedPacketIDList += redPacketMgr.notifyAllServerRedPacketIDList # 2. 全服不限制下发个数
+        
+        # 3. 全服私有未开放
+        for redIDList in redPacketMgr.playerNosendRedPacketIDInfo.get(playerID, {}).values():
+            syncRedPacketIDList += redIDList
+            
+        # 4. 全服限制下发个数分配给个人可领取的红包
+        for redIDList in redPacketMgr.playerCanGetRedPacketIDInfo.get(playerID, {}).values():
+            syncRedPacketIDList += redIDList
+            
+    if not syncRedPacketIDList and isLogin:
+        return
+    
+    redPacketInfo = []
+    playerID = curPlayer.GetPlayerID()
+    joinFamilyTime = PlayerFamily.GetPlayerJoinFamilyTime(curPlayer)
+    #GameWorld.DebugLog("通知红包信息: isLogin=%s,isAll=%s,syncRedPacketIDList=%s" % (isLogin, isAll, syncRedPacketIDList), playerID)
+    
+    for redPacketID in syncRedPacketIDList:
+        redPacketObj = redPacketMgr.GetRedPacketObj(redPacketID, False)
+        if not redPacketObj:
             continue
-        NetPackCommon.SendFakePack(curPlayer, sendPack)
-    return
\ No newline at end of file
+        
+        #仙盟红包只通知玩家进入仙盟后生成的红包
+        if redPacketObj.familyID:
+            if joinFamilyTime and redPacketObj.calcTime < joinFamilyTime:
+                #GameWorld.DebugLog("    加入仙盟之前的红包不发: redPacketID=%s,joinFamilyTime=%s > %s" % (redPacketID, joinFamilyTime, redPacketObj.calcTime))
+                continue
+            
+        state = redPacketObj.state
+        if playerID in redPacketObj.grabDict:
+            state = State_HasGot
+        if isAll and state in [State_HasGot, State_HasAllGot]:
+            #GameWorld.DebugLog("    已抢或抢完的不发: redPacketID=%s,state=%s" % (redPacketID, state))
+            continue
+        
+        packetInfo = ChPyNetSendPack.tagFRedPacketInfo()
+        packetInfo.Clear()
+        packetInfo.RedPacketID = redPacketObj.redPacketID
+        packetInfo.PlayerID = redPacketObj.playerID
+        packetInfo.Name = "" if redPacketObj.isAnonymous else redPacketObj.playerName
+        packetInfo.NameLen = len(packetInfo.Name)
+        packetInfo.Time = redPacketObj.createTime
+        packetInfo.PlayeJob = redPacketObj.playerJob
+        packetInfo.MoneyType = redPacketObj.moneyType
+        packetInfo.MoneyNum = redPacketObj.moneyValue
+        packetInfo.GetWay = redPacketObj.getWay
+        packetInfo.State = state
+        packetInfo.PacketCnt = redPacketObj.packetCnt
+        packetInfo.IsAnonymous = int(redPacketObj.isAnonymous)
+        packetInfo.Wish = redPacketObj.wish
+        packetInfo.WishLen = len(packetInfo.Wish)
+        redPacketInfo.append(packetInfo)
+        if len(redPacketInfo) > 250:
+            #GameWorld.DebugLog("红包太多了!")
+            break
+        
+    if not redPacketInfo:
+        return
+    
+    sendPack = ChPyNetSendPack.tagGCFamilyRedPacketInfo()
+    sendPack.Clear()
+    sendPack.IsAll = isAll
+    sendPack.RedPacketInfo = redPacketInfo
+    sendPack.Count = len(sendPack.RedPacketInfo)
+    NetPackCommon.SendFakePack(curPlayer, sendPack)
+    return 

--
Gitblit v1.8.0