ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerCompensation.py
@@ -28,12 +28,16 @@
import NetPackCommon
import CommFunc
import ChPyNetSendPack
import PyGameDataStruct
import CrossRealmMsg
import DataRecordPack
import ReadChConfig
import PlayerDBOper
import EventReport
import IpyGameDataPY
import PlayerControl
import PyDataManager
import PyGameData
import datetime
import uuid
import math
@@ -68,6 +72,216 @@
Def_RequestState = "CompensationRequestState"
#==================================================================================================
class CrossPersonalCompensationManager(object):
    ## 跨服邮件管理,注意该类只处理数据逻辑,功能相关逻辑不要写在该类,不然重读脚本不会生效
    def __init__(self):
        self.playerMailDict = {} # 玩家补偿列表 {playerID:{GUID:tagDBCrossPersonalCompensation, ...}, ...}
        return
    # 保存数据 存数据库和realtimebackup
    def GetSaveData(self):
        savaData = ""
        cntData = ""
        cnt = 0
        for mailDict in self.playerMailDict.values():
            for mailObj in mailDict.values():
                cnt += 1
                savaData += mailObj.getBuffer()
        GameWorld.Log("Save DBCrossPersonalCompensation count :%s, len=%s" % (cnt, len(savaData)))
        return CommFunc.WriteDWORD(cntData, cnt) + savaData
    # 从数据库载入数据
    def LoadPyGameData(self, datas, pos, dataslen):
        cnt, pos = CommFunc.ReadDWORD(datas, pos)
        GameWorld.Log("Load DBCrossPersonalCompensation count :%s" % cnt)
        for _ in xrange(cnt):
            mailObj = PyGameDataStruct.tagDBCrossPersonalCompensation()
            mailObj.clear()
            pos += mailObj.readData(datas, pos, dataslen)
            playerID = mailObj.PlayerID
            guid = mailObj.GUID
            if playerID not in self.playerMailDict:
                self.playerMailDict[playerID] = {}
            mailDict = self.playerMailDict[playerID]
            mailDict[guid] = mailObj
        return pos
def Sync_CrossMailPlayerIDToClientServer(serverGroupID=0):
    ''' 同步有跨服邮件的玩家ID到子服
    @param serverGroupID: 为0时同步所有子服
    '''
    crossMailMgr = PyDataManager.GetCrossPersonalCompensationManager()
    addMailPlayerIDList = crossMailMgr.playerMailDict.keys()
    if not addMailPlayerIDList:
        return
    # 同步子服务器
    serverGroupIDList = [serverGroupID] if serverGroupID else []
    dataMsg = {"IDType":"Add", "PlayerIDList":addMailPlayerIDList}
    CrossRealmMsg.SendMsgToClientServer(ShareDefine.CrossServerMsg_MailPlayerIDList, dataMsg, serverGroupIDList)
    return
def CrossServerMsg_MailPlayerIDList(dataMsg):
    ## 收到跨服服务器同步有跨服邮件的玩家ID列表
    idType = dataMsg["IDType"]
    playerIDList = dataMsg["PlayerIDList"]
    for playerID in playerIDList:
        if idType == "Del":
            if playerID in PyGameData.g_crossMailPlayerDict:
                PyGameData.g_crossMailPlayerDict.pop(playerID)
            continue
        if idType == "Add":
            if playerID in PyGameData.g_crossMailPlayerDict:
                continue
            PyGameData.g_crossMailPlayerDict[playerID] = 0
            player = GameWorld.GetPlayerManager().FindPlayerByID(playerID)
            if not player or not player.GetInitOK():
                continue
            RequestToGetCrossMail(player)
    return
def RequestToGetCrossMail(curPlayer):
    ## 请求同步跨服邮件内容
    playerID = curPlayer.GetPlayerID()
    if playerID not in PyGameData.g_crossMailPlayerDict:
        return
    lastTick = PyGameData.g_crossMailPlayerDict[playerID]
    tick = GameWorld.GetGameWorld().GetTick()
    if tick - lastTick <= 30000:
        return
    PyGameData.g_crossMailPlayerDict[playerID] = tick
    dataMsg = {"CMD":"Get", "PlayerID":playerID}
    CrossRealmMsg.SendMsgToCrossServer(ShareDefine.ClientServerMsg_MailContent, dataMsg)
    return
def ClientServerMsg_MailContent(serverGroupID, msgData, tick):
    ## 收到子服玩家请求同步跨服邮件
    GameWorld.Log("收到子服玩家同步个人邮件命令: serverGroupID=%s, %s" % (serverGroupID, msgData))
    reqCMD = msgData["CMD"]
    playerID = msgData["PlayerID"]
    guidList = msgData.get("GuidList", [])
    crossMailMgr = PyDataManager.GetCrossPersonalCompensationManager()
    if playerID not in crossMailMgr.playerMailDict:
        return
    playerMailDict = crossMailMgr.playerMailDict[playerID]
    if reqCMD == "Get":
        SyncTickAttrKey = "SyncTick"
        getMailList = []
        for guid, mailObj in playerMailDict.items():
            if hasattr(mailObj, SyncTickAttrKey):
                getTick = getattr(mailObj, SyncTickAttrKey)
                if tick - getTick <= 30000:
                    GameWorld.DebugLog("短时间内重复请求领取的邮件不同步,防止重复发放! GUID=%s" % guid)
                    continue
            setattr(mailObj, SyncTickAttrKey, tick)
            crossMailDict = {"PlayerID":mailObj.PlayerID, "GUID":mailObj.GUID, "LimitTime":mailObj.LimitTime,
                             "Text":mailObj.Text, "ItemInfo":mailObj.ItemInfo, "Detail":mailObj.Detail,
                             "Gold":mailObj.Gold, "GoldPaper":mailObj.GoldPaper, "Silver":mailObj.Silver,
                             "MoneySource":mailObj.MoneySource
                             }
            getMailList.append(crossMailDict)
        if getMailList:
            CrossRealmMsg.SendMsgToClientServer(ShareDefine.CrossServerMsg_MailContent, getMailList, [serverGroupID])
    elif reqCMD == "GetOK":
        for guid in guidList:
            playerMailDict.pop(guid, None)
            DataRecordPack.DR_GiveCompensationSuccess(playerID, guid)
        if not playerMailDict:
            crossMailMgr.playerMailDict.pop(playerID, None)
            dataMsg = {"IDType":"Del", "PlayerIDList":[playerID]}
            CrossRealmMsg.SendMsgToClientServer(ShareDefine.CrossServerMsg_MailPlayerIDList, dataMsg, [serverGroupID])
    return
def CrossServerMsg_MailContent(getMailList):
    ## 收到跨服服务器同步的待发送邮件内容
    playerGetGUIDInfo = {}
    for mailDict in getMailList:
        GUID = mailDict.get("GUID", "")
        playerID = mailDict.get("PlayerID", 0)
        if not GUID or not playerID:
            continue
        GameWorld.Log("收到跨服个人邮件内容:%s" % mailDict, playerID)
        addItemDictList = eval(mailDict.get("ItemInfo", "[]"))
        LimitTime = mailDict.get("LimitTime", "")
        Text = mailDict.get("Text", "")
        gold = GameWorld.ToIntDef(mailDict.get("Gold"))
        goldPaper = GameWorld.ToIntDef(mailDict.get("GoldPaper"))
        silver = GameWorld.ToIntDef(mailDict.get("Silver"))
        moneySource = GameWorld.ToIntDef(mailDict.get("MoneySource"), ChConfig.Def_GiveMoney_Mail)
        detail = mailDict.get("Detail", "")
        AddPersonalItem(GUID, addItemDictList, [playerID], LimitTime, Text, gold, goldPaper, silver, detail, moneySource)
        if playerID not in playerGetGUIDInfo:
            playerGetGUIDInfo[playerID] = []
        guidList = playerGetGUIDInfo[playerID]
        guidList.append(GUID)
    for playerID, guidList in playerGetGUIDInfo.items():
        dataMsg = {"CMD":"GetOK", "PlayerID":playerID, "GuidList":guidList}
        CrossRealmMsg.SendMsgToCrossServer(ShareDefine.ClientServerMsg_MailContent, dataMsg)
    return
def __AddPlayerCrossMail(addItemDictList, PlayerIDList, LimitTime, Text, gold, goldPaper, silver, detail, moneySource):
    ## 添加跨服玩家个人补偿邮件
    addMailPlayerIDList = []
    crossMailMgr = PyDataManager.GetCrossPersonalCompensationManager()
    for playerID in PlayerIDList:
        GUID = str(uuid.uuid1()) # 由于跨服邮件由每个玩家独自同步个人邮件,所以插入时每个人的邮件单独GUID,防止批量发送同内容邮件时重复插入奖励物品
        mailObj = PyGameDataStruct.tagDBCrossPersonalCompensation()
        mailObj.PlayerID = playerID
        mailObj.GUID = GUID
        mailObj.LimitTime = LimitTime
        mailObj.Text = Text
        mailObj.TextLen = len(mailObj.Text)
        mailObj.Gold = gold
        mailObj.GoldPaper = goldPaper
        mailObj.Silver = silver
        mailObj.ItemInfo = json.dumps(addItemDictList, ensure_ascii=False)
        mailObj.ItemLen = len(mailObj.ItemInfo)
        mailObj.Detail = detail
        mailObj.DetailLen = len(mailObj.Detail)
        mailObj.MoneySource = moneySource
        if playerID not in crossMailMgr.playerMailDict:
            crossMailMgr.playerMailDict[playerID] = {}
            addMailPlayerIDList.append(playerID)
        playerMailDict = crossMailMgr.playerMailDict[playerID]
        playerMailDict[GUID] = mailObj
        #添加流向
        addDict = {"LimitTime":LimitTime, "Text":Text, "Gold":gold, "GoldPaper":goldPaper, "Silver":silver,
                   "ItemListLen":len(addItemDictList), "Detail":detail, "MoneySource":moneySource, "CrossMail":True}
        DataRecordPack.DR_AddPersonalCompensation(PlayerIDList, GUID, addItemDictList, addDict)
    if addMailPlayerIDList:
        dataMsg = {"IDType":"Add", "PlayerIDList":addMailPlayerIDList}
        CrossRealmMsg.SendMsgToClientServer(ShareDefine.CrossServerMsg_MailPlayerIDList, dataMsg)
    return
#==================================================================================================
## 根据物品信息字典,生成补偿物品实例,用于GM工具添加补偿
#  @param curItemDict 
#  @return IpyCompensationItem
@@ -76,24 +290,24 @@
    #curItemData.GUID = curItemDict['GUID']
    curItemData.ItemID = curItemDict['ItemID']
    curItemData.Count = curItemDict['Count']
    curItemData.IsBind = curItemDict.get('IsBind',0)
    #curItemData.IsBind = curItemDict.get('IsBind',0)
    curItemData.IsBind = curItemDict.get('IsAuctionItem',0)
    curItemData.UserData = curItemDict.get('UserData', '')
    return curItemData
#  此处货币playerIDList发放统一,如根据玩家不同而变,则应需修改
## 功能发放物品补偿/奖励邮件
#  @param addItemList [(itemID, itemCnt, isBind), {或物品信息字典}, ...]
#  @param addItemList [(itemID, itemCnt, 是否拍品), {或物品信息字典}, ...]
#  @return GUID
def SendPersonalItemMailEx(title, content, getDays, playerIDList, addItemList,
                           gold = 0, goldPaper = 0, silver = 0, sourceType = ChConfig.Mail_Type_Default, detail=""):
def SendPersonalItemMailEx(title, content, getDays, playerIDList, addItemList, gold = 0, goldPaper = 0, silver = 0,
                           detail="", moneySource=ChConfig.Def_GiveMoney_Mail, crossMail=False):
    limitTime = str(GameWorld.GetDatetimeByDiffDays(getDays))
    limitTime = limitTime.split(".")[0]
    return SendPersonalItemMail(title, content, limitTime, playerIDList, addItemList,
                                gold, goldPaper, silver, sourceType, detail=detail)
    return SendPersonalItemMail(title, content, limitTime, playerIDList, addItemList, gold, goldPaper, silver, detail, moneySource, crossMail)
    
def SendPersonalItemMailBatch(batchMailInfoList):
    ## 批量发送邮件
    mailTypeKey, batchPlayerIDList, batchAddItemList, batchParamList, batchGold, batchGoldPaper, batchSilver, batchDetail = batchMailInfoList
    mailTypeKey, batchPlayerIDList, batchAddItemList, batchParamList, batchGold, batchGoldPaper, batchSilver, batchDetail, moneySource = batchMailInfoList
    
    lenPlayerID = len(batchPlayerIDList)
    lenItem = len(batchAddItemList)
@@ -109,6 +323,8 @@
    limitTime = limitTime.split(".")[0]
    
    for i, playerIDList in enumerate(batchPlayerIDList):
        if not playerIDList:
            continue
        addItemList = batchAddItemList[i] if lenItem == lenPlayerID else []
        paramList = batchParamList[i] if lenParam == lenPlayerID else []
        gold = batchGold[i] if lenGold == lenPlayerID else 0
@@ -116,26 +332,36 @@
        silver = batchSilver[i] if lenSilver == lenPlayerID else 0
        detail = batchDetail[i] if lenDetail == lenPlayerID else ""
        content = "<MailTemplate>%s</MailTemplate>%s" % (mailTypeKey, str(paramList))
        SendPersonalItemMail(title, content, limitTime, playerIDList, addItemList, gold, goldPaper, silver, detail=detail)
        SendPersonalItemMail(title, content, limitTime, playerIDList, addItemList, gold, goldPaper, silver, detail=detail, moneySource=moneySource)
        
    return
def SendMailByKey(mailTypeKey, playerIDList, addItemList, paramList=[], gold=0, goldPaper=0, silver=0, detail=""):
def SendMailByKey(mailTypeKey, playerIDList, addItemList, paramList=[], gold=0, goldPaper=0, silver=0,
                  detail="", moneySource=ChConfig.Def_GiveMoney_Mail, crossMail=False):
    if not mailTypeKey:
        mailTypeKey = ShareDefine.DefaultLackSpaceMailType
    GameWorld.DebugLog("SendMailByKey %s, playerIDList=%s, addItemList=%s, paramList=%s, gold=%s, goldPaper=%s, silver=%s"
                       % (mailTypeKey, playerIDList, addItemList, paramList, gold, goldPaper, silver))
    GameWorld.DebugLog("SendMailByKey %s, playerIDList=%s, addItemList=%s, paramList=%s, gold=%s, goldPaper=%s, silver=%s, moneySource=%s"
                       % (mailTypeKey, playerIDList, addItemList, paramList, gold, goldPaper, silver, moneySource))
    title = ""
    content = "<MailTemplate>%s</MailTemplate>%s" % (mailTypeKey, json.dumps(paramList, ensure_ascii=False))
    return SendPersonalItemMailEx(title, content, 30, playerIDList, addItemList, gold, goldPaper, silver, detail=detail)
    return SendPersonalItemMailEx(title, content, 30, playerIDList, addItemList, gold, goldPaper, silver, detail, moneySource, crossMail)
def CrossServerMsg_SendMail(msgData):
    ## 收到跨服服务器同步的发送邮件
    mailTypeKey = msgData["MailTypeKey"]
    playerIDList = msgData["Player"]
    addItemList = msgData.get("Item", [])
    paramList = msgData.get("Param", [])
    SendMailByKey(mailTypeKey, playerIDList, addItemList, paramList)
    return
#  此处货币playerIDList发放统一,如根据玩家不同而变,则应需修改
## 功能发放物品补偿/奖励邮件
#  @param addItemList [(itemID, itemCnt, isBind), {或物品信息字典}, ...]
#  @param addItemList [(itemID, itemCnt, 是否拍品), {或物品信息字典}, ...]
#  @return GUID
#  @remarks addItemList支持append字典
def SendPersonalItemMail(title, content, limitTime, playerIDList, addItemList,
                         gold = 0, goldPaper = 0, silver = 0, sourceType = ChConfig.Mail_Type_Default, detail=""):
def SendPersonalItemMail(title, content, limitTime, playerIDList, addItemList, gold = 0, goldPaper = 0, silver = 0,
                         detail="", moneySource=ChConfig.Def_GiveMoney_Mail, crossMail=False):
    if not playerIDList:
        return ""
    
@@ -156,36 +382,37 @@
        
        
        if len(itemInfo) == 3:
            itemID, itemCnt, isBind = itemInfo
            itemID, itemCnt, isAuctionItem = itemInfo
        else:
            continue
            
        addItemDict = {}
        addItemDict['ItemID'] = itemID
        addItemDict['Count'] = itemCnt
        addItemDict['IsBind'] = isBind
        addItemDict['IsAuctionItem'] = isAuctionItem
        addItemDictList.append(addItemDict)
        
    perMailItemCnt = IpyGameDataPY.GetFuncCfg("MailMaxItemCnt")
    mailCnt = max(1, int(math.ceil(len(addItemDictList)/float(perMailItemCnt)))) # 一封邮件最多5个物品
    for i in xrange(mailCnt):
        if i != 0:
            gold, goldPaper, silver = 0, 0, 0 # 拆分后非第一封的邮件货币归零,防止重复给货币奖励
        startIndex = i*perMailItemCnt
        GUID = str(uuid.uuid1())
        AddPersonalItem(GUID, addItemDictList[startIndex:startIndex + perMailItemCnt], playerIDList, 
                                           limitTime, "%s<$_$>%s<$_$>%s" % (ChConfig.Def_Mail_SenderSys, title, content),
                                           gold, goldPaper, silver, sourceType, detail)
                                           gold, goldPaper, silver, detail, moneySource, crossMail)
    return GUID
## 发送纯文字个人补偿
#  @param limitTime 可以传空
#  @param sourceType 查看 Mail_Type_Default 相关定义
#  @return None
def SendPersonalAsTextMail(PlayerID, title, content, limitTime, sourceType = ChConfig.Mail_Type_Default):
def SendPersonalAsTextMail(PlayerID, title, content, limitTime):
    if GameWorld.IsCrossServer():
        return
    GUID = str(uuid.uuid1())
    PyAddPersonalCompensation(GUID, PlayerID, GameWorld.GetCurrentDataTimeStr(), limitTime, 
                              "%s<$_$>%s<$_$>%s" % (ChConfig.Def_Mail_SenderSys,title, content), sourceType)
                              "%s<$_$>%s<$_$>%s" % (ChConfig.Def_Mail_SenderSys,title, content))
    return
def GetEntireCompensationInfo(checkState, limitLVType, limitLV):
@@ -196,8 +423,51 @@
    limitLVType = (mailInfo - checkState * 1000000) / 100000
    return checkState, limitLVType, limitLV
def QueryCompensationPersonalInfo(playerID):
    '''个人补偿邮件查询
    '''
    retList = []
    compensationMgr = GameWorld.GetCompensationMgr()
    tempSign = "<MailTemplate>"
    tempSignEnd = "</MailTemplate>"
    curPersonalCount = compensationMgr.GetPersonalCompensationCount(playerID)
    GameWorld.DebugLog("QueryCompensationPersonalInfo %s" % curPersonalCount)
    for i in xrange(curPersonalCount):
        compensation = compensationMgr.PersonalCompensationAt(playerID, i)
        contentList = compensation.Text.split("<$_$>")
        if len(contentList) != 3:
            continue
        sender, title, content = contentList
        if tempSign in content and tempSignEnd in content:
            title = content[content.index(tempSign) + len(tempSign):content.index(tempSignEnd)]
            content = ""
        GUID = compensation.GUID
        itemList = []
        curGUIDItemCount = compensationMgr.FindItemCount(GUID)
        for i in xrange(curGUIDItemCount):
            curItem = compensationMgr.FindItemAt(GUID, i)
            itemID = curItem.ItemID
            if not itemID:
                continue
            itemList.append([itemID, curItem.Count, curItem.IsBind, curItem.UserData])
        recState = compensationMgr.FindPlayerRecState(playerID, GUID)
        infoDict = {"GUID":GUID, "Gold":compensation.Gold, "GoldPaper":compensation.GoldPaper, "Silver":compensation.Silver,
                    "Sender":sender, "Title":title, "Content":content, "RecState":recState,
                    "CreateTime":compensation.CreateTime, "LimitTime":compensation.LimitTime, "ItemList":itemList}
        retList.append(infoDict)
    return retList
def QueryCompensationInfo(fromDate, toDate, guid, searchTitle, searchContent, searchState=None, maxCount=10):
    '''补偿邮件查询
    '''全服补偿邮件查询
    '''
    
    compensationMgr = GameWorld.GetCompensationMgr()
@@ -264,7 +534,7 @@
        
    compensationDict = {"GUID":GUID, "CheckState":checkState, "LimitLVType":limitLVType, "LimitLV":limitLV,
                        "Gold":compensation.Gold, "GoldPaper":compensation.GoldPaper, "Silver":compensation.Silver,
                        "PlayerJob":compensation.PlayerJob, "Sender":sender, "Title":title, "Content":content,
                        "PlayerJob":compensation.PlayerJob, "Sender":sender, "Title":title, "Content":content, "OnlyServerID":compensation.ServerID,
                        "CreateTime":compensation.CreateTime, "LimitTime":compensation.LimitTime, "ItemList":itemList}
    return compensationDict
@@ -326,6 +596,54 @@
            
    return successGUIDList
def SendEntireMail(mailTypeKey, getDays, limitLV, limitLVType, addItemList=[], paramList=[], \
                   gold=0, goldPaper=0, silver=0, detail="", moneySource=ChConfig.Def_GiveMoney_Mail, GUID=""):
    ''' 发送全服邮件
    @param mailTypeKey: 邮件模板key
    @param getDays: 有效天数
    @param limitLV: 领取最低等级限制
    @param limitLVType: 等级不足的升级后是否可领 0-不可,1-可以
    '''
    if not mailTypeKey or getDays <= 0:
        return
    addItemDictList = []
    for itemInfo in addItemList:
        if isinstance(itemInfo, dict):
            addItemDictList.append(itemInfo)
            continue
        if len(itemInfo) == 3:
            itemID, itemCnt, isAuctionItem = itemInfo
        else:
            continue
        addItemDict = {}
        addItemDict['ItemID'] = itemID
        addItemDict['Count'] = itemCnt
        addItemDict['IsAuctionItem'] = isAuctionItem
        addItemDictList.append(addItemDict)
    if not GUID:
        GUID = str(uuid.uuid1())
    limitTime = str(GameWorld.GetDatetimeByDiffDays(getDays))
    limitTime = limitTime.split(".")[0]
    sender = ChConfig.Def_Mail_SenderSys
    title = ""
    content = "<MailTemplate>%s</MailTemplate>%s" % (mailTypeKey, json.dumps(paramList, ensure_ascii=False))
    checkState = 0 # 邮件审核状态,为兼容老邮件,默认0-已审核,1-未审核
    mailInfo = GetEntireCompensationInfo(checkState, limitLVType, limitLV)
    PlayerJob = 127 # 默认全职业可领
    serverID = 0 # 默认所有服务器ID
    AddEntireItem(GUID, addItemDictList, limitTime, mailInfo, PlayerJob, "%s<$_$>%s<$_$>%s" % (sender, title, content),
                  gold, goldPaper, silver, detail, serverID)
    return
## 添加全服补偿
#  @param addItemDictList, LimitTime, mailInfo, PlayerJob,  Text 
#  @return None
@@ -378,38 +696,33 @@
# 检查邮件是否已达到保存上限,如超过则先删除旧邮件
# @param LimitTime 参数可传空,个人邮件不限制领取期限,只限制保存数量, 
def PyAddPersonalCompensation(GUID, PlayerID, CreateTime, LimitTime, Text, sourceType,
                              gold = 0, goldPaper = 0, silver = 0):
def PyAddPersonalCompensation(GUID, PlayerID, CreateTime, LimitTime, Text, gold = 0, goldPaper = 0, silver = 0, moneySource=ChConfig.Def_GiveMoney_Mail):
    curPlayer = GameWorld.GetPlayerManager().FindPlayerByID(PlayerID)
    cnt = GameWorld.GetCompensationMgr().GetPersonalCompensationCountByType(PlayerID, sourceType)
    totalCount = GameWorld.GetCompensationMgr().GetPersonalCompensationCount(PlayerID)
    #待支持py读表
    tmpDict = {ChConfig.Mail_Type_Default:IpyGameDataPY.GetFuncCfg("MailDefaultCount"),
               ChConfig.Mail_Type_Market:IpyGameDataPY.GetFuncCfg("MailMarketCount")}
    delcnt = cnt - tmpDict[sourceType] + 1
    #GameWorld.DebugLog("PyAddPersonalCompensation typecnt = %s-%s"%(cnt, delcnt))
    if delcnt > 0:
    maxMailCount = IpyGameDataPY.GetFuncCfg("MailDefaultCount")
    delCount = totalCount - maxMailCount + 1
    GameWorld.DebugLog("新增个人邮件: totalCount=%s,maxMailCount=%s" % (totalCount, maxMailCount), PlayerID)
    if delCount > 0:
        GameWorld.Log("个人邮件达到上限,需要删除!delCount=%s" % (delCount), PlayerID)
        #先取得要删除的GUID
        delGUIDs = []
        for i in xrange(delcnt):
            tmpGuid = GameWorld.GetCompensationMgr().AtGUIDInPersonalTypesByType(PlayerID, sourceType, i)
            if not tmpGuid:
                #GameWorld.DebugLog("PyAddPersonalCompensation not GUID = %s"%tmpGuid)
                continue
            delGUIDs.append(tmpGuid)
        for guid in delGUIDs:
        for i in xrange(delCount):
            curIpyPersonalData = GameWorld.GetCompensationMgr().PersonalCompensationAt(PlayerID, i)
            delGUIDs.append(curIpyPersonalData.GUID)
        for guid in delGUIDs:
            ClearPersonalCompensation(PlayerID, guid)
            #GameWorld.DebugLog("PyAddPersonalCompensation DeletePersonalCompensation GUID = %s"%guid)
            GameWorld.Log("    DeletePersonalCompensation GUID = %s" % guid, PlayerID)
            
            if curPlayer:
                NotifyCompensationResult(curPlayer, guid, 1)
            #未补流向
    #GameWorld.DebugLog("PyAddPersonalCompensation CreateTime %s"%CreateTime)
    #此处没有下发通知
    mailType = moneySource - ChConfig.Def_GiveMoney_Unknown # type类型为byte,存值时需要处理下
    GameWorld.GetCompensationMgr().AddPersonalCompensation(GUID, PlayerID, CreateTime,
                                                           LimitTime, Text, sourceType, gold, goldPaper, silver)
                                                           LimitTime, Text, mailType, gold, goldPaper, silver)
    return
@@ -417,9 +730,11 @@
## 添加个人补偿
#  @param addItemDict, PlayerIDList, LimitTime, Text 
#  @return None
def AddPersonalItem(GUID, addItemDictList, PlayerIDList, LimitTime, Text,
                    gold = 0, goldPaper = 0, silver = 0, sourceType = ChConfig.Mail_Type_Default, detail=""):
def AddPersonalItem(GUID, addItemDictList, PlayerIDList, LimitTime, Text, gold = 0, goldPaper = 0, silver = 0,
                    detail="", moneySource=ChConfig.Def_GiveMoney_Mail, crossMail=False):
    if GameWorld.IsCrossServer():
        if crossMail:
            __AddPlayerCrossMail(addItemDictList, PlayerIDList, LimitTime, Text, gold, goldPaper, silver, detail, moneySource)
        return
    GameWorld.DebugLog("Compensation### AddPersonalItem GUID:%s ItemDict:\n%s "%(GUID, addItemDictList))
    
@@ -433,8 +748,7 @@
    #批量添加玩家个人补偿领取表
    createTime = GameWorld.GetCurrentDataTimeStr()
    for PlayerID in PlayerIDList:
        PyAddPersonalCompensation(GUID, PlayerID, createTime, LimitTime,
                                  Text, sourceType, gold, goldPaper, silver)
        PyAddPersonalCompensation(GUID, PlayerID, createTime, LimitTime, Text, gold, goldPaper, silver, moneySource)
        # 针对个人补偿,如果是在线玩家,则立即推送给客户端
        curPlayer = GameWorld.GetPlayerManager().FindPlayerByID(PlayerID)
        if curPlayer:
@@ -454,7 +768,7 @@
    
    #添加流向
    addDict = {"LimitTime":LimitTime, "Text":Text, "Gold":gold, "GoldPaper":goldPaper, "Silver":silver, 
               "ItemListLen":len(addItemDictList), "Detail":detail}
               "ItemListLen":len(addItemDictList), "Detail":detail, "MoneySource":moneySource}
    DataRecordPack.DR_AddPersonalCompensation(PlayerIDList, GUID, addItemDictList, addDict)
    return
@@ -538,6 +852,7 @@
# 提取接收邮件下发
def NotifyPlayerCompensation(curPlayer):
    RequestToGetCrossMail(curPlayer)
    notifyList = SeekPlayerCompensation(curPlayer)
    SyncQueryCompensationResult(curPlayer, notifyList)
    return
@@ -615,6 +930,11 @@
                SetPrizeState(curPlayerID, curRequire.GUID, Disable_State, readState)
                continue
            
        if curRequire.ServerID and curRequire.ServerID != GameWorld.GetPlayerServerID(curPlayer):
            # 指定服务器邮件
            SetPrizeState(curPlayerID, curRequire.GUID, Disable_State, readState)
            continue
        #可以用的奖励
        if Enable_State != curState:
            SetPrizeState(curPlayerID, curRequire.GUID, Enable_State, readState)
@@ -680,7 +1000,6 @@
        curPlayer.SetDict(Def_RequestState, 0)#解锁
        GameWorld.DebugLog("Compensation### OnMGRequestCompensation no found")
        return
    Text, gold, goldPaper, silver = curEntireRequire.Text, curEntireRequire.Gold, curEntireRequire.GoldPaper, curEntireRequire.Silver
    #校验背包剩余空间是否足够
    #===========================================================================
    # curCUIDItemCount = GameWorld.GetCompensationMgr().FindItemCount(GUID)
@@ -690,7 +1009,7 @@
    #    return
    #===========================================================================
    #发送到MapServer给予奖励
    SendGMRequestCompensationResult(routeIndex, mapID, curPlayer, GUID, compensationType, Text, gold, goldPaper, silver)
    SendGMRequestCompensationResult(routeIndex, mapID, curPlayer, GUID, compensationType, curEntireRequire)
    GameWorld.DebugLog("Compensation### OnMGRequestCompensation out")
    
##请求领取物品
@@ -766,17 +1085,24 @@
##发送封包 03 02 玩家领取补偿结果#tagGMRequestCompensationResult
#  @param routeIndex, mapID, curPlayer, curItem
#  @return None
def SendGMRequestCompensationResult(routeIndex, mapID, curPlayer, GUID, compensationType, Text,
                                    gold, goldPaper, silver):
def SendGMRequestCompensationResult(routeIndex, mapID, curPlayer, GUID, compensationType, curEntireRequire):
    Text, gold, goldPaper, silver, createTime = curEntireRequire.Text, curEntireRequire.Gold, \
        curEntireRequire.GoldPaper, curEntireRequire.Silver, curEntireRequire.CreateTime
    # 全服邮件没有 Type 字段
    moneySource = curEntireRequire.Type if compensationType == Personal_CompensationType else 0
    sendPack = ChGameToMapPyPack.tagGMRequestCompensationResult() 
    sendPack.PlayerID = curPlayer.GetID()
    sendPack.CompensationType = compensationType
    sendPack.GUID = GUID
    sendPack.CreateTime = createTime
    sendPack.Text = Text
    sendPack.TextLen = len(Text)
    sendPack.Gold = gold
    sendPack.GoldPaper = goldPaper
    sendPack.Silver = silver
    sendPack.MoneySource = moneySource
    curGUIDItemCount = GameWorld.GetCompensationMgr().FindItemCount(GUID)
    
    for i in xrange(curGUIDItemCount):
@@ -857,11 +1183,35 @@
    return
##清理超时30天的个人邮件, 否则流失玩家在不断合服情况下数据会累积
# 个人邮件暂无过期时间设定,只有30天清理逻辑,以创建时间为准
#  @param None
#  @return None
def ClearUpPersonalCompensation():
    #校验过期补偿
    curTime = datetime.datetime.today()
    needClearGUIDList = []
    allCnt = GameWorld.GetCompensationMgr().GetAllPersonalCompensationCount()
    for i in xrange(allCnt):
        curMail = GameWorld.GetCompensationMgr().AtAllPersonalCompensation(i)
        # 超过接收邮件30天则完全删除此邮件
        limitTime = datetime.datetime.strptime(curMail.CreateTime, ChConfig.TYPE_Time_Format) + datetime.timedelta(days = 30)
        if limitTime < curTime:
            needClearGUIDList.append([curMail.PlayerID, curMail.GUID])
    GameWorld.Log("ClearUpPersonalCompensation count=%s"%len(needClearGUIDList))
    #删除过期补偿信息, 没有主动通知在线玩家
    for playerID, GUID in needClearGUIDList:
        ClearPersonalCompensation(playerID, GUID)
    return
## 清理超时补偿, 个人邮件在超过上限后才会自动删除
#  @param None
#  @return None
def ClearUpTimeOutCompensation():
    
    ClearUpPersonalCompensation()
    ClearUpEntireCompensation()
    return
@@ -917,6 +1267,11 @@
    #在个人补偿中
    curPersonalCompensation = GameWorld.GetCompensationMgr().FindPersonalCompensation(curPlayerID, GUID)
    if curPersonalCompensation.PlayerID == curPlayerID:
        if not CheckCanDelCompensation(curPersonalCompensation, GUID):
            #有附件不可删除
            NotifyCompensationResult(curPlayer, GUID, 0)
            return
        ClearPersonalCompensation(curPlayerID, GUID)
        NotifyCompensationResult(curPlayer, GUID, 1)
        #GameWorld.DebugLog("个人补偿中OnDelCompensation:%s"%GUID)
@@ -932,12 +1287,28 @@
    #全服邮件
    curEntireRequire = GameWorld.GetCompensationMgr().FindEntireCompensation(GUID)
    if curEntireRequire.GUID == GUID:
        if not CheckCanDelCompensation(curEntireRequire, GUID):
            #有附件不可删除
            NotifyCompensationResult(curPlayer, GUID, 0)
            return
        SetPrizeState(curPlayerID, GUID, Disable_State, GameWorld.GetCompensationMgr().FindPlayerRecState(curPlayerID, GUID)/10)
        NotifyCompensationResult(curPlayer, GUID, 1)
        #GameWorld.DebugLog("全服邮件OnDelCompensation:%s"%GUID)
        return
    NotifyCompensationResult(curPlayer, GUID, 0)
# 有附件的情况玩家不可主动删除邮件,避免误操作;系统可删除不用调用此接口
def CheckCanDelCompensation(mailObj, GUID):
    if mailObj.Gold or mailObj.GoldPaper or mailObj.Silver:
        # 有附加货币不可删除
        return False
    if GameWorld.GetCompensationMgr().FindItemCount(GUID):
        # 有附件物品不可删除
        return False
    return True
        
# 邮件删除情况   
def NotifyCompensationResult(curPlayer, GUID, result):