From e9ec5c336b25726e16385e290227e2e8677cebb7 Mon Sep 17 00:00:00 2001
From: hxp <ale99527@vip.qq.com>
Date: 星期五, 23 四月 2021 18:13:23 +0800
Subject: [PATCH] 8901 【BT2】【后端】全服红包(优化红包系统 1.全服红包去除总上限个数,改为限制下发数量,并在领取红包后补充相应的红包数量; 2.全服未开放可领的红包仅个人可见; 3.红包超时间隔改为5分钟检查一次 4.修改封包)

---
 ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerFamilyRedPacket.py | 1355 ++++++++++++++++++++++++++++++++++++----------------------
 1 files changed, 843 insertions(+), 512 deletions(-)

diff --git a/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerFamilyRedPacket.py b/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerFamilyRedPacket.py
index 7c07e9a..ad6da7b 100644
--- a/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerFamilyRedPacket.py
+++ b/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerFamilyRedPacket.py
@@ -18,50 +18,27 @@
 #---------------------------------------------------------------------
 
 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 random
 import datetime
-
-'''
-红包暂定有效期24小时,过天清除过期的红包,如果是玩家发放的返还未领取的货币
-上线同步所有红包信息,红包变化实时广播全服在线玩家
-'''
-#Def_UniversalGameRecType_FamilyRedPacketAllRecord
-#Time      创建红包时间,非红包实际开放领取时间,如果红包表有配置系统发放时间,则该时间存配表时间,没有的话存创建时的服务器时间
-#value1    红包唯一ID,该ID为实例ID,非配表的红包ID
-#value2    家族ID,0代表全服红包
-#value3    总额度*10+金钱类型
-#value4    状态
-#value5    时间,用来判断是否过期删除的,实际开放该红包领取的时间
-#strValue1 创建者ID|创建者名字|创建者职业|获得途径(红包类型)
-#strValue2 可抢总个数|是否匿名(默认不匿名兼容老数据)
-#strValue3 祝福语,玩家自己编辑的内容
-
-#Def_UniversalGameRecType_FamilyRedPacketGrabRecord
-#value1    红包唯一ID
-#value2    playerID
-#value3    job
-#value4    moneyType
-#value5    getMoney
-#strValue1 名字
+import random
+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]}, ...}
@@ -70,21 +47,663 @@
 DBKey_RedPacketSend = "RedPacketSend_%s" # 系统定时红包是否已发放, 参数红包ID
 DBKey_RedPacketSystemDayCount = "RedPacketSystemDayCount" # 全服系统红包已发放个数
 
-## 玩家登录
-#  @param None
-#  @return None
-def OnPlayerLogin(curPlayer):
-    NotifyRedPacketInfo(curPlayer)
+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 PrintData(self, sign=""):
+        if sign:
+            GameWorld.DebugLog("    === %s ===" % sign)
+        GameWorld.DebugLog("    所有红包=%s" % self.allRedPacketDict.keys())
+        GameWorld.DebugLog("    仙盟红包=%s" % self.familyRedPacketDict)
+        GameWorld.DebugLog("    全服同步全部红包=%s" % self.notifyAllServerRedPacketIDList)
+        GameWorld.DebugLog("    全服同步活跃红包=%s" % self.activeRedPacketIDInfo)
+        GameWorld.DebugLog("    全服个人未开放红包=%s" % self.playerNosendRedPacketIDInfo)
+        GameWorld.DebugLog("    全服个人可领取红包=%s" % self.playerCanGetRedPacketIDInfo)
+        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 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
+    
+    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 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
+        
+    redPacketMgr.PrintData("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] = {}
+        redPacketMgr.PrintData("OnPlayerLogin %s" % 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 playerID in redPacketObj.grabDict:
+                    continue
+                playerCanGetIDList.append(redPacketID)
+                addCount -= 1
+                if addCount <= 0:
+                    break
+            redPacketMgr.playerCanGetRedPacketIDInfo[playerID][getWay] = playerCanGetIDList
+            
+        redPacketMgr.PrintData("loginOK")
+        
+    NotifyRedPacketInfo(curPlayer, isLogin=True)
+    return
+
+def OnLeaveServer(curPlayer):
+    playerID = curPlayer.GetPlayerID()
+    redPacketMgr = GetRedpacketMgr()
+    redPacketMgr.playerCanGetRedPacketIDInfo.pop(playerID, None)
+    return
+    
 ## 隔天更新
-#  @param None
-#  @return None
 def DoOnDay():
-    __CheckGrabRecData()
     PlayerDBGSEvent.SetDBGSTrig_ByKey(DBKey_RedPacketSystemDayCount, 0) # 重置每日全服系统红包发放个数
     RandTodayServerSystemRedPacketSendTime()
+    return
+
+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))
+    redPacketMgr.PrintData("a")
+    
+    notifyPlayerDict = {ownerID:[redPacketID]} # 通知给指定玩家的信息,每个玩家可能不一样
+    
+    # 1. 仙盟红包直接通知该仙盟所有成员
+    if family:
+        if state in [State_NoSend, State_NoGot]:
+            redPacketMgr.AddFamilyRedPacketID(family.GetID(), 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, typeRedIDDict in redPacketMgr.playerCanGetRedPacketIDInfo.items():
+                
+                canGetIDList = redPacketMgr.DelPlayerCanGetRedPacketID(playerID, getWay, redPacketID) # 移出私有已开放红包队列
+                if canGetIDList == None:
+                    continue
+                
+                lastCanGetID = 0 if not canGetIDList else canGetIDList[-1]
+                checkIndex = nowActiveRedPacketIDList.index(lastCanGetID) if lastCanGetID in nowActiveRedPacketIDList else 0
+                for i in xrange(checkIndex, len(nowActiveRedPacketIDList)):
+                    newCanGetRedID = nowActiveRedPacketIDList[i]
+                    if newCanGetRedID not in canGetIDList:
+                        if redPacketMgr.AddPlayerCanGetRedPacketID(playerID, getWay, newCanGetRedID): # 添加目标玩家私有已开放红包队列
+                            notifyPlayerDict[playerID] = [redPacketID, newCanGetRedID]                      
+                            break
+    else:
+        return
+    
+    redPacketMgr.PrintData("b")
+    
+    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():
+            player = playerManager.FindPlayerByID(playerID)
+            if player == None or not player.GetInitOK() or PlayerControl.GetIsTJG(player):
+                continue
+            NotifyRedPacketInfo(player, syncRedPacketList)
+    return
+
+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
 
 ##---------------------------------------- 节日红包 -----------------------------------------------
@@ -138,7 +757,7 @@
         endDateTime = None
         validMinutes = ipyData.GetValidMinutes()
         if validMinutes:
-            endDateTime = openDateTime +  + datetime.timedelta(minutes=validMinutes)
+            endDateTime = openDateTime + +datetime.timedelta(minutes=validMinutes)
             
         redPacketByTimeList.append([redPackID, openDateTime, endDateTime])
         
@@ -211,12 +830,13 @@
 
 def RandTodayServerSystemRedPacketSendTime():
     ## 随机生成今日全服系统红包发放时间点
-    
     sendTimeList = []
     sysRedPackketSendCountToday = PlayerDBGSEvent.GetDBGSTrig_ByKey(DBKey_RedPacketSystemDayCount) 
     maxCount = IpyGameDataPY.GetFuncCfg("ServerSysRedPacket", 1)
+    if maxCount:
+        return
     needSendCount = max(0, maxCount - sysRedPackketSendCountToday)
-            
+    
     GameWorld.Log("随机生成发放全服系统红包时间! maxCount=%s,sysRedPackketSendCountToday=%s,needSendCount=%s" 
                   % (maxCount, sysRedPackketSendCountToday, needSendCount))
     if needSendCount > 0:
@@ -374,23 +994,7 @@
     return
 
 ## 记录新红包数据
-def __SaveNewRedRecord(family, ownerid, playerName, job, jobRank, getType, moneyType, outputNum, packetCnt,state=State_NoSend, wishStr='', sysCreateTime=None, data=0, isAnonymous=0):
-    global g_allRecordDict
-    global g_redPackCountDict
-    recordType = ShareDefine.Def_UniversalGameRecType_FamilyRedPacketAllRecord
-    universalRecMgr = GameWorld.GetUniversalRecMgr()
-    recordList = universalRecMgr.GetTypeList(recordType)
-    for maxCountKeyNum, getTypeList in ShareDefine.RedPackMaxCountDict.items():
-        if getType in getTypeList:
-            if not __CheckOSRedPacketCnt(recordList, maxCountKeyNum, getTypeList):
-                return
-            g_redPackCountDict[maxCountKeyNum] = g_redPackCountDict.get(maxCountKeyNum, 0) + 1
-            GameWorld.DebugLog("当前红包数: g_redPackCountDict=%s" % g_redPackCountDict)
-            break
-        
-    familyID = family.GetID() if family else 0
-    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
@@ -400,21 +1004,33 @@
         redPacketID = 1
     PlayerDBGSEvent.SetDBGSTrig_ByKey(DB_RedPacketID, redPacketID)
     
+    familyID = family.GetID() if family else 0
+    
     curTimeNum = int(time.time())
-    recData.SetTime(sysCreateTime if sysCreateTime else 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('%s|%s' % (packetCnt, int(isAnonymous)))#可抢总个数|是否匿名
-    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))
+    
+    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))
     
     #通知
-    __NotifyFamilyRedPacketInfo(family, recData, [])
+    OnChangeRedPacketState(family, redPacketObj, None)
     if getType == ShareDefine.RedPackType_OpenServer:
         if not PlayerDBGSEvent.GetDBGSTrig_ByKey(PlayerDBGSEvent.Def_OSRedPacket):
             PlayerControl.WorldNotify(0, 'OpenRedBag2', [playerName, data, outputNum])
@@ -431,100 +1047,7 @@
             and getType not in [ShareDefine.RedPackType_Server]:
             PlayerControl.WorldNotify(0, 'OSRedpackSfx', [getType])   
             
-    return recData
-
-
-def __CheckOSRedPacketCnt(recordList, maxCountKeyNum, getTypeList):
-    global g_grabDataDict
-    global g_allRecordDict
-    global g_redPackCountDict
-    ##开服红包个数是否达上限
-    curRedCnt = g_redPackCountDict.get(maxCountKeyNum, 0)
-    openServerRedPacketCnt = IpyGameDataPY.GetFuncCfg('OpenServerRedPacketCnt', 1) # 直接用开服红包这个配置作为通用配置
-    if curRedCnt and curRedCnt < openServerRedPacketCnt + 10:
-        return True
-    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 not in getTypeList:
-            continue
-        redPacketID = universalRecData.GetValue1()
-        curCnt += 1
-        if len(delRedPacketIDList) < 10:
-            delRedPacketIDList.append(redPacketID)
-        elif curRedCnt:
-            break
-    if not delRedPacketIDList:
-        return True
-    if not curRedCnt:
-        curRedCnt = curCnt
-
-    if curRedCnt < 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)
-    curRedCnt -= 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
-            
-    #通知
-    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)
-    
-    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
-    
-
+    return redPacketObj
 
 def SendFamilyRedPacket(msgList):
     '''发系统赠送的红包,该红包已存在,只是状态未发放,由归属玩家自由选择发放时机'''
@@ -533,15 +1056,13 @@
     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:
@@ -551,88 +1072,81 @@
             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('%s|%s' % (packetCnt, int(isAnonymous)))
-    #更新时间
-    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, reqGetWay, canGrabCnt = msgList
     
-    playerID= curPlayer.GetPlayerID()
-    job = curPlayer.GetJob()
-    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:
+        PlayerControl.NotifyCode(curPlayer, "该红包不存在!")
         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
-    strValue2 = redPacketRecData.GetStrValue2()
-    strValue2List = strValue2.split('|')
-    packetCnt = int(strValue2List[0])
+        
+    moneyType = redPacketObj.moneyType
+    totalMoney = redPacketObj.moneyValue
+    packetCnt = redPacketObj.packetCnt
     
     #找该红包的抢信息
-    grabRecordDict = __GetGrabRecord(redPacketID)
+    grabRecordDict = redPacketObj.grabDict
     if playerID in grabRecordDict:
         GameWorld.DebugLog("    该玩家已抢过此红包!", playerID)
         __NotifyGrabRedPacketInfo(curPlayer, redPacketID, grabRecordDict)
         return
     
-    if len(grabRecordDict) >= packetCnt:
+    outNum = sum([grabObj.getMoney for grabObj in grabRecordDict.values()]) #已被抢的钱
+    remainNum = totalMoney - outNum #剩余的钱
+    
+    if len(grabRecordDict) >= packetCnt or remainNum <= 0:
         GameWorld.DebugLog("    红包已被抢完!", playerID)
         if state != State_HasAllGot:
-            redPacketRecData.SetValue4(State_HasAllGot)
+            redPacketObj.state = State_HasAllGot
             #GameWorld.DebugLog("    纠正红包已抢完状态! state=%s,updState=%s" % (state, State_HasAllGot))
-            __NotifyFamilyRedPacketInfo(curFamily, redPacketRecData, grabRecordDict.keys())
+            OnChangeRedPacketState(curFamily, redPacketObj, beforeState)
         __NotifyGrabRedPacketInfo(curPlayer, redPacketID, grabRecordDict)
         return
     
-    outNum = sum([a[0] for a 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))
-        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 not isSelf and canGrabCnt != -1 and canGrabCnt <= 0:
         GameWorld.DebugLog('    抢开服红包,次数不足!!')
@@ -640,6 +1154,7 @@
     if reqGetWay != getWay:
         GameWorld.ErrLog("领取的红包类型不一致,无法领取! reqGetWay=%s,getWay=%s" % (reqGetWay, getWay))
         return
+    
     if getWay in [ShareDefine.RedPackType_OpenServer, ShareDefine.RedPackType_Server]:
         getNumformula = IpyGameDataPY.GetFuncCompileCfg('OpenRedRacketOutNum')
     elif getWay in ShareDefine.FeastRedPackType:
@@ -648,23 +1163,25 @@
         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
+    getMoney = min(getMoney, remainNum)
+    remainNum -= getMoney
+    GameWorld.DebugLog("    该玩家抢到红包=%s!" % getMoney, playerID)
     
-    if len(grabRecordDict) >= packetCnt:
-        redPacketRecData.SetValue4(State_HasAllGot)
-        
-        #通知该玩家红包抢结果
-        __NotifyFamilyRedPacketInfo(curFamily, redPacketRecData, grabRecordDict.keys())
+    # 新增抢的记录
+    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):
+            redPacketMgr.DelPlayerCanGetRedPacketID(playerID, getWay, redPacketID)
+        NotifyRedPacketInfo(curPlayer, [redPacketID])
         
     __NotifyGrabRedPacketInfo(curPlayer, redPacketID, grabRecordDict)
     
@@ -673,289 +1190,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_redPackCountDict
-    g_redPackCountDict = {}
-    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]
-            getWay = int(strValue1List[3])
-            if playerID and getWay is ShareDefine.RedPackType_GoldPacket:
-                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
-        if sendPack.IsAll and state in [State_HasGot, State_HasAllGot]:
-            #GameWorld.DebugLog("已抢或抢完的不发: RedPacketID=%s,state=%s" % (packetInfo.RedPacketID, state))
-            continue
-        packetInfo.State = state
-        strValue2 = packetData.GetStrValue2()
-        strValue2List = strValue2.split('|')
-        packetInfo.PacketCnt = int(strValue2List[0])
-        packetInfo.IsAnonymous = int(strValue2List[1]) if len(strValue2List) > 1 else 0
-        
-        packetInfo.Wish = packetData.GetStrValue3()
-        sendPack.RedPacketInfo.append(packetInfo)
-        if len(sendPack.RedPacketInfo) > 250:
-            #GameWorld.DebugLog("红包太多了!")
-            break
-    
-    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