hxp
2025-05-14 eb2b495812782c219d963559e840d1be46c5c846
16 卡牌服务端(邮件功能;)
12个文件已修改
3个文件已添加
2014 ■■■■■ 已修改文件
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/PyNetPack.ini 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetPack.py 64 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetSendPack.py 369 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/DB/DBDataMgr.py 20 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/DB/DBStruct.py 402 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/DB/StructData/DBFamily.py 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/DB/StructData/DBMail.py 418 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/DataRecordPack.py 24 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GM/Commands/Mail.py 158 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorld.py 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorldLogic/GameWorldProcess.py 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/ChPlayer.py 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerEventCounter.py 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerMail.py 515 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ShareDefine.py 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/PyNetPack.ini
@@ -34,6 +34,18 @@
PacketSubCMD_6=0x08
PacketCallFunc_6=OnItemTimeout
;邮件
[PlayerMail]
ScriptName = Player\PlayerMail.py
Writer = hxp
Releaser = hxp
RegType = 0
RegisterPackCount = 1
PacketCMD_1=0xA5
PacketSubCMD_1=0x37
PacketCallFunc_1=OnRequestMail
;法器
[PlayerFaQi]
ScriptName = Player\PlayerFaQi.py
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetPack.py
@@ -14125,6 +14125,70 @@
#------------------------------------------------------
# A5 37 请求邮件操作 #tagCMRequestMail
class  tagCMRequestMail(Structure):
    Head = tagHead()
    GUID = ""    #(char GUID[36])//邮件GUID,可传空,默认针对个人邮件的批量处理,如批量领取、批量删除已领邮件等;全服邮件暂时限制只能单封邮件处理
    ReqType = 0    #(BYTE ReqType)//0-设置已读,1-领取邮件,2-删除邮件
    data = None
    def __init__(self):
        self.Clear()
        self.Head.Cmd = 0xA5
        self.Head.SubCmd = 0x37
        return
    def ReadData(self, _lpData, _pos=0, _Len=0):
        self.Clear()
        _pos = self.Head.ReadData(_lpData, _pos)
        self.GUID,_pos = CommFunc.ReadString(_lpData, _pos,36)
        self.ReqType,_pos = CommFunc.ReadBYTE(_lpData, _pos)
        return _pos
    def Clear(self):
        self.Head = tagHead()
        self.Head.Clear()
        self.Head.Cmd = 0xA5
        self.Head.SubCmd = 0x37
        self.GUID = ""
        self.ReqType = 0
        return
    def GetLength(self):
        length = 0
        length += self.Head.GetLength()
        length += 36
        length += 1
        return length
    def GetBuffer(self):
        data = ''
        data = CommFunc.WriteString(data, self.Head.GetLength(), self.Head.GetBuffer())
        data = CommFunc.WriteString(data, 36, self.GUID)
        data = CommFunc.WriteBYTE(data, self.ReqType)
        return data
    def OutputString(self):
        DumpString = '''
                                Head:%s,
                                GUID:%s,
                                ReqType:%d
                                '''\
                                %(
                                self.Head.OutputString(),
                                self.GUID,
                                self.ReqType
                                )
        return DumpString
m_NAtagCMRequestMail=tagCMRequestMail()
ChNetPackDict[eval("0x%02x%02x"%(m_NAtagCMRequestMail.Head.Cmd,m_NAtagCMRequestMail.Head.SubCmd))] = m_NAtagCMRequestMail
#------------------------------------------------------
# A5 68 请求寻宝 #tagCMRequestTreasure
class  tagCMRequestTreasure(Structure):
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetSendPack.py
@@ -27626,6 +27626,375 @@
#------------------------------------------------------
# A3 62 邮件列表 #tagMCMailList
class  tagMCMailItem(Structure):
    ItemID = 0    #(DWORD ItemID)//物品ID
    Count = 0    #(DWORD Count)//数量
    IsBind = 0    #(BYTE IsBind)//是否绑定
    UserDataLen = 0    #(WORD UserDataLen)
    UserData = ""    #(String UserData)//自定义数据
    data = None
    def __init__(self):
        self.Clear()
        return
    def ReadData(self, _lpData, _pos=0, _Len=0):
        self.Clear()
        self.ItemID,_pos = CommFunc.ReadDWORD(_lpData, _pos)
        self.Count,_pos = CommFunc.ReadDWORD(_lpData, _pos)
        self.IsBind,_pos = CommFunc.ReadBYTE(_lpData, _pos)
        self.UserDataLen,_pos = CommFunc.ReadWORD(_lpData, _pos)
        self.UserData,_pos = CommFunc.ReadString(_lpData, _pos,self.UserDataLen)
        return _pos
    def Clear(self):
        self.ItemID = 0
        self.Count = 0
        self.IsBind = 0
        self.UserDataLen = 0
        self.UserData = ""
        return
    def GetLength(self):
        length = 0
        length += 4
        length += 4
        length += 1
        length += 2
        length += len(self.UserData)
        return length
    def GetBuffer(self):
        data = ''
        data = CommFunc.WriteDWORD(data, self.ItemID)
        data = CommFunc.WriteDWORD(data, self.Count)
        data = CommFunc.WriteBYTE(data, self.IsBind)
        data = CommFunc.WriteWORD(data, self.UserDataLen)
        data = CommFunc.WriteString(data, self.UserDataLen, self.UserData)
        return data
    def OutputString(self):
        DumpString = '''
                                ItemID:%d,
                                Count:%d,
                                IsBind:%d,
                                UserDataLen:%d,
                                UserData:%s
                                '''\
                                %(
                                self.ItemID,
                                self.Count,
                                self.IsBind,
                                self.UserDataLen,
                                self.UserData
                                )
        return DumpString
class  tagMCMail(Structure):
    GUID = ""    #(char GUID[36])//邮件GUID
    Type = 0    #(BYTE Type)//邮件类型,暂时默认0
    CreateTime = ""    #(char CreateTime[30])//创建时间
    LimitDays = 0    #(BYTE LimitDays)//有效天数
    TitleLen = 0    #(BYTE TitleLen)
    Title = ""    #(String Title)//标题
    TextLen = 0    #(WORD TextLen)
    Text = ""    #(String Text)//内容
    MailState = 0    #(BYTE MailState)//邮件状态: 0-未知;1-未读;2-已读;3-已领;
    Count = 0    #(BYTE Count)//物品数
    Items = list()    #(vector<tagMCMailItem> Items)//物品信息
    data = None
    def __init__(self):
        self.Clear()
        return
    def ReadData(self, _lpData, _pos=0, _Len=0):
        self.Clear()
        self.GUID,_pos = CommFunc.ReadString(_lpData, _pos,36)
        self.Type,_pos = CommFunc.ReadBYTE(_lpData, _pos)
        self.CreateTime,_pos = CommFunc.ReadString(_lpData, _pos,30)
        self.LimitDays,_pos = CommFunc.ReadBYTE(_lpData, _pos)
        self.TitleLen,_pos = CommFunc.ReadBYTE(_lpData, _pos)
        self.Title,_pos = CommFunc.ReadString(_lpData, _pos,self.TitleLen)
        self.TextLen,_pos = CommFunc.ReadWORD(_lpData, _pos)
        self.Text,_pos = CommFunc.ReadString(_lpData, _pos,self.TextLen)
        self.MailState,_pos = CommFunc.ReadBYTE(_lpData, _pos)
        self.Count,_pos = CommFunc.ReadBYTE(_lpData, _pos)
        for i in range(self.Count):
            temItems = tagMCMailItem()
            _pos = temItems.ReadData(_lpData, _pos)
            self.Items.append(temItems)
        return _pos
    def Clear(self):
        self.GUID = ""
        self.Type = 0
        self.CreateTime = ""
        self.LimitDays = 0
        self.TitleLen = 0
        self.Title = ""
        self.TextLen = 0
        self.Text = ""
        self.MailState = 0
        self.Count = 0
        self.Items = list()
        return
    def GetLength(self):
        length = 0
        length += 36
        length += 1
        length += 30
        length += 1
        length += 1
        length += len(self.Title)
        length += 2
        length += len(self.Text)
        length += 1
        length += 1
        for i in range(self.Count):
            length += self.Items[i].GetLength()
        return length
    def GetBuffer(self):
        data = ''
        data = CommFunc.WriteString(data, 36, self.GUID)
        data = CommFunc.WriteBYTE(data, self.Type)
        data = CommFunc.WriteString(data, 30, self.CreateTime)
        data = CommFunc.WriteBYTE(data, self.LimitDays)
        data = CommFunc.WriteBYTE(data, self.TitleLen)
        data = CommFunc.WriteString(data, self.TitleLen, self.Title)
        data = CommFunc.WriteWORD(data, self.TextLen)
        data = CommFunc.WriteString(data, self.TextLen, self.Text)
        data = CommFunc.WriteBYTE(data, self.MailState)
        data = CommFunc.WriteBYTE(data, self.Count)
        for i in range(self.Count):
            data = CommFunc.WriteString(data, self.Items[i].GetLength(), self.Items[i].GetBuffer())
        return data
    def OutputString(self):
        DumpString = '''
                                GUID:%s,
                                Type:%d,
                                CreateTime:%s,
                                LimitDays:%d,
                                TitleLen:%d,
                                Title:%s,
                                TextLen:%d,
                                Text:%s,
                                MailState:%d,
                                Count:%d,
                                Items:%s
                                '''\
                                %(
                                self.GUID,
                                self.Type,
                                self.CreateTime,
                                self.LimitDays,
                                self.TitleLen,
                                self.Title,
                                self.TextLen,
                                self.Text,
                                self.MailState,
                                self.Count,
                                "..."
                                )
        return DumpString
class  tagMCMailList(Structure):
    Head = tagHead()
    IsServerMail = 0    #(BYTE IsServerMail)//是否全服邮件,如公告、维护、更新、补偿等重要邮件
    Count = 0    #(WORD Count)
    MailList = list()    #(vector<tagMCMail> MailList)//邮件列表
    data = None
    def __init__(self):
        self.Clear()
        self.Head.Cmd = 0xA3
        self.Head.SubCmd = 0x62
        return
    def ReadData(self, _lpData, _pos=0, _Len=0):
        self.Clear()
        _pos = self.Head.ReadData(_lpData, _pos)
        self.IsServerMail,_pos = CommFunc.ReadBYTE(_lpData, _pos)
        self.Count,_pos = CommFunc.ReadWORD(_lpData, _pos)
        for i in range(self.Count):
            temMailList = tagMCMail()
            _pos = temMailList.ReadData(_lpData, _pos)
            self.MailList.append(temMailList)
        return _pos
    def Clear(self):
        self.Head = tagHead()
        self.Head.Clear()
        self.Head.Cmd = 0xA3
        self.Head.SubCmd = 0x62
        self.IsServerMail = 0
        self.Count = 0
        self.MailList = list()
        return
    def GetLength(self):
        length = 0
        length += self.Head.GetLength()
        length += 1
        length += 2
        for i in range(self.Count):
            length += self.MailList[i].GetLength()
        return length
    def GetBuffer(self):
        data = ''
        data = CommFunc.WriteString(data, self.Head.GetLength(), self.Head.GetBuffer())
        data = CommFunc.WriteBYTE(data, self.IsServerMail)
        data = CommFunc.WriteWORD(data, self.Count)
        for i in range(self.Count):
            data = CommFunc.WriteString(data, self.MailList[i].GetLength(), self.MailList[i].GetBuffer())
        return data
    def OutputString(self):
        DumpString = '''
                                Head:%s,
                                IsServerMail:%d,
                                Count:%d,
                                MailList:%s
                                '''\
                                %(
                                self.Head.OutputString(),
                                self.IsServerMail,
                                self.Count,
                                "..."
                                )
        return DumpString
m_NAtagMCMailList=tagMCMailList()
ChNetPackDict[eval("0x%02x%02x"%(m_NAtagMCMailList.Head.Cmd,m_NAtagMCMailList.Head.SubCmd))] = m_NAtagMCMailList
#------------------------------------------------------
# A3 63 邮件状态变更 #tagMCMailStateChange
class  tagMCMailState(Structure):
    GUID = ""    #(char GUID[36])//邮件GUID
    MailState = 0    #(BYTE MailState)//邮件状态: 0-未知;1-未读;2-已读;3-已领;4-已删
    data = None
    def __init__(self):
        self.Clear()
        return
    def ReadData(self, _lpData, _pos=0, _Len=0):
        self.Clear()
        self.GUID,_pos = CommFunc.ReadString(_lpData, _pos,36)
        self.MailState,_pos = CommFunc.ReadBYTE(_lpData, _pos)
        return _pos
    def Clear(self):
        self.GUID = ""
        self.MailState = 0
        return
    def GetLength(self):
        length = 0
        length += 36
        length += 1
        return length
    def GetBuffer(self):
        data = ''
        data = CommFunc.WriteString(data, 36, self.GUID)
        data = CommFunc.WriteBYTE(data, self.MailState)
        return data
    def OutputString(self):
        DumpString = '''
                                GUID:%s,
                                MailState:%d
                                '''\
                                %(
                                self.GUID,
                                self.MailState
                                )
        return DumpString
class  tagMCMailStateChange(Structure):
    Head = tagHead()
    Count = 0    #(WORD Count)
    MailList = list()    #(vector<tagMCMailState> MailList)//邮件列表
    data = None
    def __init__(self):
        self.Clear()
        self.Head.Cmd = 0xA3
        self.Head.SubCmd = 0x63
        return
    def ReadData(self, _lpData, _pos=0, _Len=0):
        self.Clear()
        _pos = self.Head.ReadData(_lpData, _pos)
        self.Count,_pos = CommFunc.ReadWORD(_lpData, _pos)
        for i in range(self.Count):
            temMailList = tagMCMailState()
            _pos = temMailList.ReadData(_lpData, _pos)
            self.MailList.append(temMailList)
        return _pos
    def Clear(self):
        self.Head = tagHead()
        self.Head.Clear()
        self.Head.Cmd = 0xA3
        self.Head.SubCmd = 0x63
        self.Count = 0
        self.MailList = list()
        return
    def GetLength(self):
        length = 0
        length += self.Head.GetLength()
        length += 2
        for i in range(self.Count):
            length += self.MailList[i].GetLength()
        return length
    def GetBuffer(self):
        data = ''
        data = CommFunc.WriteString(data, self.Head.GetLength(), self.Head.GetBuffer())
        data = CommFunc.WriteWORD(data, self.Count)
        for i in range(self.Count):
            data = CommFunc.WriteString(data, self.MailList[i].GetLength(), self.MailList[i].GetBuffer())
        return data
    def OutputString(self):
        DumpString = '''
                                Head:%s,
                                Count:%d,
                                MailList:%s
                                '''\
                                %(
                                self.Head.OutputString(),
                                self.Count,
                                "..."
                                )
        return DumpString
m_NAtagMCMailStateChange=tagMCMailStateChange()
ChNetPackDict[eval("0x%02x%02x"%(m_NAtagMCMailStateChange.Head.Cmd,m_NAtagMCMailStateChange.Head.SubCmd))] = m_NAtagMCMailStateChange
#------------------------------------------------------
# A3 46 大师经验信息 #tagMCGreatMasterExp
class  tagMCGreatMasterExp(Structure):
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/DB/DBDataMgr.py
@@ -19,6 +19,7 @@
import PyGameData
import DBPlayerViewCache
import DBFamily
import DBMail
import binascii
import time
@@ -43,9 +44,13 @@
def OnServerClose():
    return
def OnMinute(curMinute):
def OnMinute(curTime):
    curMinute = curTime.minute
    ServerDataBackup()
    DBFamily.OnMinute(curMinute)
    return
def OnDayEx():
    return
#------------------------------------------- 备档 ---------------------------------------------------
@@ -160,17 +165,21 @@
    def __init__(self):
        self.PlayerViewCacheMgr = DBPlayerViewCache.PlayerViewCacheMgr()
        self.FamilyMgr = DBFamily.FamilyMgr()
        self.MailMgr = DBMail.MailMgr()
        return
    
    def GetSaveData(self):
        buff = ""
        buff += self.PlayerViewCacheMgr.GetSaveData()
        buff += self.FamilyMgr.GetSaveData()
        buff += self.MailMgr.GetSaveData()
        return buff
    
    def LoadGameData(self, gameBuffer, pos):
        pos = self.PlayerViewCacheMgr.LoadPyGameData(gameBuffer, pos, len(gameBuffer))
        pos = self.FamilyMgr.LoadPyGameData(gameBuffer, pos, len(gameBuffer))
        dataslen = len(gameBuffer)
        pos = self.PlayerViewCacheMgr.LoadPyGameData(gameBuffer, pos, dataslen)
        pos = self.FamilyMgr.LoadPyGameData(gameBuffer, pos, dataslen)
        pos = self.MailMgr.LoadPyGameData(gameBuffer, pos, dataslen)
        return pos
    
def GetDBDataMgr():
@@ -195,3 +204,8 @@
    ## 家族Action数据管理器
    return GetFamilyMgr().GetFamilyActionMgr()
def GetMailMgr():
    ## 邮件数据管理器
    dbDataMgr = GetDBDataMgr()
    return dbDataMgr.MailMgr
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/DB/DBStruct.py
@@ -1236,3 +1236,405 @@
        else:
            self.FamilyName = Str[:33]
            
# 邮件个人邮件表 #tagDBMailPersonal
class tagDBMailPersonal(Structure):
    _pack_ = 1
    _fields_ = [
        ('PlayerID', ctypes.c_ulong),
        ('GUID', ctypes.c_char * 36),
        ('Type', ctypes.c_ubyte),
        ('CreateTime', ctypes.c_char * 30),
        ('LimitDays', ctypes.c_ubyte),
        ('TitleLen', ctypes.c_ubyte),
        ('Title', ctypes.c_char_p),
        ('TextLen', ctypes.c_ushort),
        ('Text', ctypes.c_char_p),
        ('MailState', ctypes.c_ubyte),
        ('ADOResult', ctypes.c_ulong),
    ]
    def __init__(self):
        Structure.__init__(self)
        self.clear()
    def clear(self):
        self.PlayerID = 0
        self.GUID = ''
        self.Type = 0
        self.CreateTime = ''
        self.LimitDays = 0
        self.TitleLen = 0
        self.Title = ''
        self.TextLen = 0
        self.Text = ''
        self.MailState = 0
    def readData(self, buf, pos = 0, length = 0):
        if not pos <= length:
            return -1
        if len(buf) < pos + self.getLength():
            return -1
        self.clear()
        self.PlayerID, pos = CommFunc.ReadDWORD(buf, pos)
        self.GUID, pos = CommFunc.ReadString(buf, pos, 36)
        self.Type, pos = CommFunc.ReadBYTE(buf, pos)
        self.CreateTime, pos = CommFunc.ReadString(buf, pos, 30)
        self.LimitDays, pos = CommFunc.ReadBYTE(buf, pos)
        self.TitleLen, pos = CommFunc.ReadBYTE(buf, pos)
        tmp, pos = CommFunc.ReadString(buf, pos, self.TitleLen)
        self.Title = ctypes.c_char_p(tmp)
        self.TextLen, pos = CommFunc.ReadWORD(buf, pos)
        tmp, pos = CommFunc.ReadString(buf, pos, self.TextLen)
        self.Text = ctypes.c_char_p(tmp)
        self.MailState, pos = CommFunc.ReadBYTE(buf, pos)
        return self.getLength()
    def getBuffer(self):
        buf = ''
        buf = CommFunc.WriteDWORD(buf, self.PlayerID)
        buf = CommFunc.WriteString(buf, sizeof(ctypes.c_char) * 36, self.GUID)
        buf = CommFunc.WriteBYTE(buf, self.Type)
        buf = CommFunc.WriteString(buf, sizeof(ctypes.c_char) * 30, self.CreateTime)
        buf = CommFunc.WriteBYTE(buf, self.LimitDays)
        buf = CommFunc.WriteBYTE(buf, self.TitleLen)
        buf = CommFunc.WriteString(buf, self.TitleLen, self.Title)
        buf = CommFunc.WriteWORD(buf, self.TextLen)
        buf = CommFunc.WriteString(buf, self.TextLen, self.Text)
        buf = CommFunc.WriteBYTE(buf, self.MailState)
        return buf
    def getLength(self):
        length = 0
        length += sizeof(ctypes.c_ulong)
        length += sizeof(ctypes.c_char) * 36
        length += sizeof(ctypes.c_ubyte)
        length += sizeof(ctypes.c_char) * 30
        length += sizeof(ctypes.c_ubyte)
        length += sizeof(ctypes.c_ubyte)
        length += self.TitleLen
        length += sizeof(ctypes.c_ushort)
        length += self.TextLen
        length += sizeof(ctypes.c_ubyte)
        return length
    def outputString(self):
        output = '''// 邮件个人邮件表 #tagDBMailPersonal:
            PlayerID = %s,
            GUID = %s,
            Type = %s,
            CreateTime = %s,
            LimitDays = %s,
            TitleLen = %s,
            Title = %s,
            TextLen = %s,
            Text = %s,
            MailState = %s,
            ADOResult = %s,
            '''%(
                self.PlayerID,
                self.GUID,
                self.Type,
                self.CreateTime,
                self.LimitDays,
                self.TitleLen,
                self.Title,
                self.TextLen,
                self.Text,
                self.MailState,
                self.ADOResult,
            )
        return output
    #Char数组类型Set接口,使用该接口对此类型数据赋值,防止赋值的数据过长报错
    def SetGUID(self,Str):
        if len(Str)<=36:
            self.GUID = Str
        else:
            self.GUID = Str[:36]
    def SetCreateTime(self,Str):
        if len(Str)<=30:
            self.CreateTime = Str
        else:
            self.CreateTime = Str[:30]
# 邮件全服邮件表 #tagDBMailServer
class tagDBMailServer(Structure):
    _pack_ = 1
    _fields_ = [
        ('GUID', ctypes.c_char * 36),
        ('Type', ctypes.c_ubyte),
        ('CreateTime', ctypes.c_char * 30),
        ('LimitDays', ctypes.c_ubyte),
        ('TitleLen', ctypes.c_ubyte),
        ('Title', ctypes.c_char_p),
        ('TextLen', ctypes.c_ushort),
        ('Text', ctypes.c_char_p),
        ('LimitLV', ctypes.c_ushort),
        ('LimitLVType', ctypes.c_ubyte),
        ('CheckState', ctypes.c_ubyte),
        ('ADOResult', ctypes.c_ulong),
    ]
    def __init__(self):
        Structure.__init__(self)
        self.clear()
    def clear(self):
        self.GUID = ''
        self.Type = 0
        self.CreateTime = ''
        self.LimitDays = 0
        self.TitleLen = 0
        self.Title = ''
        self.TextLen = 0
        self.Text = ''
        self.LimitLV = 0
        self.LimitLVType = 0
        self.CheckState = 0
    def readData(self, buf, pos = 0, length = 0):
        if not pos <= length:
            return -1
        if len(buf) < pos + self.getLength():
            return -1
        self.clear()
        self.GUID, pos = CommFunc.ReadString(buf, pos, 36)
        self.Type, pos = CommFunc.ReadBYTE(buf, pos)
        self.CreateTime, pos = CommFunc.ReadString(buf, pos, 30)
        self.LimitDays, pos = CommFunc.ReadBYTE(buf, pos)
        self.TitleLen, pos = CommFunc.ReadBYTE(buf, pos)
        tmp, pos = CommFunc.ReadString(buf, pos, self.TitleLen)
        self.Title = ctypes.c_char_p(tmp)
        self.TextLen, pos = CommFunc.ReadWORD(buf, pos)
        tmp, pos = CommFunc.ReadString(buf, pos, self.TextLen)
        self.Text = ctypes.c_char_p(tmp)
        self.LimitLV, pos = CommFunc.ReadWORD(buf, pos)
        self.LimitLVType, pos = CommFunc.ReadBYTE(buf, pos)
        self.CheckState, pos = CommFunc.ReadBYTE(buf, pos)
        return self.getLength()
    def getBuffer(self):
        buf = ''
        buf = CommFunc.WriteString(buf, sizeof(ctypes.c_char) * 36, self.GUID)
        buf = CommFunc.WriteBYTE(buf, self.Type)
        buf = CommFunc.WriteString(buf, sizeof(ctypes.c_char) * 30, self.CreateTime)
        buf = CommFunc.WriteBYTE(buf, self.LimitDays)
        buf = CommFunc.WriteBYTE(buf, self.TitleLen)
        buf = CommFunc.WriteString(buf, self.TitleLen, self.Title)
        buf = CommFunc.WriteWORD(buf, self.TextLen)
        buf = CommFunc.WriteString(buf, self.TextLen, self.Text)
        buf = CommFunc.WriteWORD(buf, self.LimitLV)
        buf = CommFunc.WriteBYTE(buf, self.LimitLVType)
        buf = CommFunc.WriteBYTE(buf, self.CheckState)
        return buf
    def getLength(self):
        length = 0
        length += sizeof(ctypes.c_char) * 36
        length += sizeof(ctypes.c_ubyte)
        length += sizeof(ctypes.c_char) * 30
        length += sizeof(ctypes.c_ubyte)
        length += sizeof(ctypes.c_ubyte)
        length += self.TitleLen
        length += sizeof(ctypes.c_ushort)
        length += self.TextLen
        length += sizeof(ctypes.c_ushort)
        length += sizeof(ctypes.c_ubyte)
        length += sizeof(ctypes.c_ubyte)
        return length
    def outputString(self):
        output = '''// 邮件全服邮件表 #tagDBMailServer:
            GUID = %s,
            Type = %s,
            CreateTime = %s,
            LimitDays = %s,
            TitleLen = %s,
            Title = %s,
            TextLen = %s,
            Text = %s,
            LimitLV = %s,
            LimitLVType = %s,
            CheckState = %s,
            ADOResult = %s,
            '''%(
                self.GUID,
                self.Type,
                self.CreateTime,
                self.LimitDays,
                self.TitleLen,
                self.Title,
                self.TextLen,
                self.Text,
                self.LimitLV,
                self.LimitLVType,
                self.CheckState,
                self.ADOResult,
            )
        return output
    #Char数组类型Set接口,使用该接口对此类型数据赋值,防止赋值的数据过长报错
    def SetGUID(self,Str):
        if len(Str)<=36:
            self.GUID = Str
        else:
            self.GUID = Str[:36]
    def SetCreateTime(self,Str):
        if len(Str)<=30:
            self.CreateTime = Str
        else:
            self.CreateTime = Str[:30]
# 邮件物品表 #tagDBMailItem
class tagDBMailItem(Structure):
    _pack_ = 1
    _fields_ = [
        ('GUID', ctypes.c_char * 36),
        ('ItemID', ctypes.c_ulong),
        ('Count', ctypes.c_ulong),
        ('IsBind', ctypes.c_ubyte),
        ('UserDataLen', ctypes.c_ushort),
        ('UserData', ctypes.c_char_p),
        ('ADOResult', ctypes.c_ulong),
    ]
    def __init__(self):
        Structure.__init__(self)
        self.clear()
    def clear(self):
        self.GUID = ''
        self.ItemID = 0
        self.Count = 0
        self.IsBind = 0
        self.UserDataLen = 0
        self.UserData = ''
    def readData(self, buf, pos = 0, length = 0):
        if not pos <= length:
            return -1
        if len(buf) < pos + self.getLength():
            return -1
        self.clear()
        self.GUID, pos = CommFunc.ReadString(buf, pos, 36)
        self.ItemID, pos = CommFunc.ReadDWORD(buf, pos)
        self.Count, pos = CommFunc.ReadDWORD(buf, pos)
        self.IsBind, pos = CommFunc.ReadBYTE(buf, pos)
        self.UserDataLen, pos = CommFunc.ReadWORD(buf, pos)
        tmp, pos = CommFunc.ReadString(buf, pos, self.UserDataLen)
        self.UserData = ctypes.c_char_p(tmp)
        return self.getLength()
    def getBuffer(self):
        buf = ''
        buf = CommFunc.WriteString(buf, sizeof(ctypes.c_char) * 36, self.GUID)
        buf = CommFunc.WriteDWORD(buf, self.ItemID)
        buf = CommFunc.WriteDWORD(buf, self.Count)
        buf = CommFunc.WriteBYTE(buf, self.IsBind)
        buf = CommFunc.WriteWORD(buf, self.UserDataLen)
        buf = CommFunc.WriteString(buf, self.UserDataLen, self.UserData)
        return buf
    def getLength(self):
        length = 0
        length += sizeof(ctypes.c_char) * 36
        length += sizeof(ctypes.c_ulong)
        length += sizeof(ctypes.c_ulong)
        length += sizeof(ctypes.c_ubyte)
        length += sizeof(ctypes.c_ushort)
        length += self.UserDataLen
        return length
    def outputString(self):
        output = '''// 邮件物品表 #tagDBMailItem:
            GUID = %s,
            ItemID = %s,
            Count = %s,
            IsBind = %s,
            UserDataLen = %s,
            UserData = %s,
            ADOResult = %s,
            '''%(
                self.GUID,
                self.ItemID,
                self.Count,
                self.IsBind,
                self.UserDataLen,
                self.UserData,
                self.ADOResult,
            )
        return output
    #Char数组类型Set接口,使用该接口对此类型数据赋值,防止赋值的数据过长报错
    def SetGUID(self,Str):
        if len(Str)<=36:
            self.GUID = Str
        else:
            self.GUID = Str[:36]
# 邮件全服记录表 #tagDBMailPlayerRec
class tagDBMailPlayerRec(Structure):
    _pack_ = 1
    _fields_ = [
        ('PlayerID', ctypes.c_ulong),
        ('GUID', ctypes.c_char * 36),
        ('MailState', ctypes.c_ubyte),
        ('ADOResult', ctypes.c_ulong),
    ]
    def __init__(self):
        Structure.__init__(self)
        self.clear()
    def clear(self):
        memset(addressof(self), 0, self.getLength())
    def readData(self, buf, pos = 0, length = 0):
        if not pos <= length:
            return -1
        if len(buf) < pos + self.getLength():
            return -1
        self.clear()
        self.PlayerID, pos = CommFunc.ReadDWORD(buf, pos)
        self.GUID, pos = CommFunc.ReadString(buf, pos, 36)
        self.MailState, pos = CommFunc.ReadBYTE(buf, pos)
        return self.getLength()
    def getBuffer(self):
        buf = create_string_buffer(self.getLength())
        memmove(addressof(buf), addressof(self), self.getLength())
        return string_at(addressof(buf), self.getLength())
    def getLength(self):
        return sizeof(tagDBMailPlayerRec)
    def outputString(self):
        output = '''// 邮件全服记录表 #tagDBMailPlayerRec:
            PlayerID = %s,
            GUID = %s,
            MailState = %s,
            ADOResult = %s,
            '''%(
                self.PlayerID,
                self.GUID,
                self.MailState,
                self.ADOResult,
            )
        return output
    #Char数组类型Set接口,使用该接口对此类型数据赋值,防止赋值的数据过长报错
    def SetGUID(self,Str):
        if len(Str)<=36:
            self.GUID = Str
        else:
            self.GUID = Str[:36]
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/DB/StructData/DBFamily.py
@@ -352,7 +352,7 @@
    def RefrshFightPowerTotal(self, checkChange=False):
        ## 刷新总战力
        if checkChange and self.__memFightPowerChange == False: # 默认None,首次必刷新
            GameWorld.DebugLog("没有成员战力变化可不刷新仙盟总战力! familyID=%s" % self.GetID())
            #GameWorld.DebugLog("没有成员战力变化可不刷新仙盟总战力! familyID=%s" % self.GetID())
            return
        familyFightPowerTotal = 0
        for index in range(self.GetCount()):
@@ -604,8 +604,7 @@
            family = self.FindFamily(familyID)
            if not family:
                continue
            member = family.InitMemberInstance(dbData)
            GameWorld.Log("    member:%s,familyID=%s" % (member.GetPlayerID(), familyID))
            family.InitMemberInstance(dbData)
            
        # 行为
        cnt, pos = CommFunc.ReadDWORD(datas, pos)
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/DB/StructData/DBMail.py
New file
@@ -0,0 +1,418 @@
#!/usr/bin/python
# -*- coding: GBK -*-
#-------------------------------------------------------------------------------
#
##@package DB.StructData.DBMail
#
# @todo:DB邮件
# @author hxp
# @date 2025-05-14
# @version 1.0
#
# 详细描述: DB邮件
#
#-------------------------------------------------------------------------------
#"""Version = 2025-05-14 12:00"""
#-------------------------------------------------------------------------------
import DBStruct
import CommFunc
import ShareDefine
import GameWorld
class MailItem():
    ## 邮件物品 - 个人、全服邮件通用
    def __init__(self, dbData=None):
        self.__dbData = DBStruct.tagDBMailItem() if not dbData else dbData
        return
    def GetGUID(self): return self.__dbData.GUID
    def GetItemID(self): return self.__dbData.ItemID
    def GetCount(self): return self.__dbData.Count
    def GetIsBind(self): return self.__dbData.IsBind
    def GetUserData(self): return self.__dbData.UserData
    def GetBuffer(self): return self.__dbData.getBuffer()
class ServerMail():
    ## 全服邮件
    def __init__(self, dbData=None):
        self.__dbData = DBStruct.tagDBMailServer() if not dbData else dbData
        return
    def GetGUID(self): return self.__dbData.GUID
    def GetType(self): return self.__dbData.Type
    def GetCreateTime(self): return self.__dbData.CreateTime
    def GetLimitDays(self): return self.__dbData.LimitDays
    def GetTitle(self): return self.__dbData.Title
    def GetText(self): return self.__dbData.Text
    def GetLimitLV(self): return self.__dbData.LimitLV # 限制可领的最低玩家等级
    def SetLimitLV(self, limitLV): self.__dbData.LimitLV = limitLV
    def GetLimitLVType(self): return self.__dbData.LimitLVType # 升级达到等级条件后是否可领;0-不可,1-可以
    def SetLimitLVType(self, limitLVType): self.__dbData.LimitLVType = limitLVType
    def GetCheckState(self): return self.__dbData.CheckState # 需要审核状态:0-已审核;1-未审核
    def SetCheckState(self, checkState): self.__dbData.CheckState = checkState
    def GetBuffer(self): return self.__dbData.getBuffer()
class PersonalMail():
    ## 个人邮件
    def __init__(self, dbData=None):
        self.__dbData = DBStruct.tagDBMailPersonal() if not dbData else dbData
        return
    def GetPlayerID(self): return self.__dbData.PlayerID
    def GetGUID(self): return self.__dbData.GUID
    def GetType(self): return self.__dbData.Type
    def GetCreateTime(self): return self.__dbData.CreateTime
    def GetLimitDays(self): return self.__dbData.LimitDays
    def GetTitle(self): return self.__dbData.Title
    def GetText(self): return self.__dbData.Text
    def GetMailState(self): return self.__dbData.MailState
    def SetMailState(self, mailState): self.__dbData.MailState = mailState
    def GetBuffer(self): return self.__dbData.getBuffer()
class MailMgr():
    def __init__(self):
        self.__personalMailDict = {} # 个人邮件 {playerID:{GUID:PersonalMail, ...}, ...}
        self.__mailItemDict = {} # 邮件物品 {GUID:[MailItem, ...], ...}
        self.__serverMailDict = {} # 全服邮件 {GUID:ServerMail, ...}
        self.__serverMailPlayerStateDict = {} # 全服邮件玩家状态 {GUID:{playerID:mailState, ...}, ...}
        return
    def __InitPersonalMailInstance(self, dbData):
        '''初始化功能数据实例,创建或加载数据时通用,功能一般不调用
        @param dbData: 实例对应绑定的dbData
        @return: 成功返回实例对象,失败返回None
        '''
        mailObj = PersonalMail(dbData)
        playerID = mailObj.GetPlayerID()
        if playerID not in self.__personalMailDict:
            self.__personalMailDict[playerID] = {}
        mailDict = self.__personalMailDict[playerID]
        mailDict[mailObj.GetGUID()] = mailObj
        return mailObj
    def __InitServerMailInstance(self, dbData):
        '''初始化功能数据实例,创建或加载数据时通用,功能一般不调用
        @param dbData: 实例对应绑定的dbData
        @return: 成功返回实例对象,失败返回None
        '''
        mailObj = ServerMail(dbData)
        guid = mailObj.GetGUID()
        self.__serverMailDict[guid] = mailObj
        return mailObj
    def __InitMailItemInstance(self, dbData):
        '''初始化功能数据实例,创建或加载数据时通用,功能一般不调用
        @param dbData: 实例对应绑定的dbData
        @return: 成功返回实例对象,失败返回None
        '''
        mailItem = MailItem(dbData)
        guid = mailItem.GetGUID()
        if guid not in self.__mailItemDict:
            self.__mailItemDict[guid] = []
        mailItemList = self.__mailItemDict[guid]
        mailItemList.append(mailItem)
        return mailItem
    def __AddMailItem(self, guid, itemList):
        '''添加邮件物品,全服、个人邮件通用,邮件物品只关联guid,功能使用层级单封邮件物品上限不限,但是邮件系统单封有内置上限
        @param itemList: 元素支持字典{k:v, ...} 或列表 [itemID, itemCount, 可选是否拍品, 物品UserData]
        '''
        if not itemList:
            return
        self.__mailItemDict.pop(guid, None) # 防止重复添加邮件物品,先移除
        # 检查整合合并物品,并确保物品顺序
        itemRankList = []
        itemDict = {}
        for itemInfo in itemList:
            if isinstance(itemInfo, dict):
                itemID = itemInfo.get("ItemID", 0)
                itemCount = itemInfo.get("Count", 0)
                isBind = itemInfo.get("IsBind", 0)
                userData = itemInfo.get("UserData", "")
            elif (isinstance(itemInfo, list) or isinstance(itemInfo, tuple)) and len(itemInfo) >= 2:
                itemID, itemCount = itemInfo[:2]
                isBind = itemInfo[2] if len(itemInfo) > 2 else 0
                userData = itemInfo[3] if len(itemInfo) > 3 else ""
            else:
                continue
            itemID = min(GameWorld.ToIntDef(itemID, 0), ShareDefine.Def_UpperLimit_DWord)
            itemCount = min(GameWorld.ToIntDef(itemCount, 0), ShareDefine.Def_UpperLimit_DWord)
            isBind = 1 if isBind else 0
            if not itemID or not itemCount:
                continue
            if userData:
                itemRankList.append([itemID, itemCount, isBind, userData])
            else:
                key = (itemID, isBind)
                if key not in itemDict:
                    itemDict[key] = 0
                    itemRankList.append(key)
                itemDict[key] = itemDict[key] + itemCount
        mailItemCount = 0
        for itemInfo in itemRankList:
            if len(itemInfo) == 4:
                itemID, itemCount, isBind, userData = itemInfo
            else:
                userData = ""
                itemID, isBind = itemInfo
                itemCount = itemDict.get(itemInfo, 0)
            dbData = DBStruct.tagDBMailItem()
            dbData.GUID = guid
            dbData.ItemID = itemID
            dbData.Count = itemCount
            dbData.IsBind = isBind
            dbData.UserData = userData
            dbData.UserDataLen = len(dbData.UserData)
            self.__InitMailItemInstance(dbData)
            mailItemCount += 1
            if mailItemCount >= 20:
                #防范某些异常情况,内置单封邮件物品上限,做下限制,并做后台邮件警告
                GameWorld.SendGameErrorEx("MailItemMultiError", "%s|%s" % (guid, itemList))
                break
        return
    def AddPersonalMail(self, playerID, title, text, itemList, limitDays=7, mailType=0):
        '''添加个人邮件
        @param itemList: 元素支持字典{k:v, ...} 或列表 [itemID, itemCount, 可选是否拍品, 物品UserData]
        '''
        guid = GameWorld.GetGUID()
        dbData = DBStruct.tagDBMailPersonal()
        dbData.PlayerID = playerID
        dbData.GUID = guid
        dbData.Type = mailType
        dbData.CreateTime = GameWorld.GetCurrentDataTimeStr()
        dbData.LimitDays = limitDays
        dbData.Title = title
        dbData.TitleLen = len(dbData.Title)
        dbData.Text = text
        dbData.TextLen = len(dbData.Text)
        dbData.MailState = ShareDefine.MailState_UnRead # 个人邮件默认未读
        self.__AddMailItem(guid, itemList)
        mailObj = self.__InitPersonalMailInstance(dbData)
        return mailObj
    def GetAllPersonalMailDict(self): return self.__personalMailDict
    def GetPersonalMailCount(self, playerID):
        ## 获取玩家个人邮件总数
        if playerID not in self.__personalMailDict:
            return 0
        return len(self.__personalMailDict[playerID])
    def GetPersonalMailGuids(self, playerID):
        ## 获取玩家所有个人邮件guid列表
        if playerID not in self.__personalMailDict:
            return []
        mailDict = self.__personalMailDict[playerID]
        return mailDict.keys()
    def GetPersonalMails(self, playerID):
        ## 获取玩家所有个人邮件实例列表
        if playerID not in self.__personalMailDict:
            return []
        mailDict = self.__personalMailDict[playerID]
        return mailDict.values()
    def GetPersonalMail(self, playerID, guid):
        ## 获取玩家个人邮件
        mailObj = None
        if playerID not in self.__personalMailDict:
            self.__personalMailDict[playerID] = {}
        mailDict = self.__personalMailDict[playerID]
        if guid in mailDict:
            mailObj = mailDict[guid]
        elif False:
            mailObj = PersonalMail()
        return mailObj
    def GetMailItemCount(self, guid):
        ## 获取邮件物品个数,全服邮件、个人邮件通用
        if guid not in self.__mailItemDict:
            return 0
        return len(self.__mailItemDict[guid])
    def GetMailItemAt(self, guid, index):
        ## 获取邮件某个物品
        itemObj = None
        if guid in self.__mailItemDict:
            itemObjList = self.__mailItemDict[guid]
            if 0 <= index < len(itemObjList):
                itemObj = itemObjList[index]
        if not itemObj and False:
            itemObj = MailItem()
        return itemObj
    def AddServerMail(self, guid, title, text, itemList, limitDays=7, mailType=0):
        '''添加个人邮件
        @param guid: 指定的邮件guid,为空时自动生成新guid
        @param itemList: 元素支持字典{k:v, ...} 或列表 [itemID, itemCount, 可选是否拍品, 物品UserData]
        '''
        if not guid:
            guid = GameWorld.GetGUID()
        dbData = DBStruct.tagDBMailServer()
        dbData.GUID = guid
        dbData.Type = mailType
        dbData.CreateTime = GameWorld.GetCurrentDataTimeStr()
        dbData.LimitDays = limitDays
        dbData.Title = title
        dbData.TitleLen = len(dbData.Title)
        dbData.Text = text
        dbData.TextLen = len(dbData.Text)
        self.__AddMailItem(guid, itemList)
        mailObj = self.__InitServerMailInstance(dbData)
        return mailObj
    def GetServerMail(self, guid):
        ## 获取全服邮件
        mailObj = None
        if guid in self.__serverMailDict:
            mailObj = self.__serverMailDict[guid]
        elif False:
            mailObj = ServerMail()
        return mailObj
    def GetServerMailGuids(self):
        ## 获取所有全服邮件guid列表
        return self.__serverMailDict.keys()
    def GetPlayerMailState(self, guid, playerID):
        ## 获取玩家某个邮件状态,个人、全服邮件通用
        personalMail = self.GetPersonalMail(playerID, guid)
        if personalMail:
            return personalMail.GetMailState()
        if guid not in self.__serverMailPlayerStateDict:
            return ShareDefine.MailState_Unknown
        playerStateDict = self.__serverMailPlayerStateDict[guid]
        if playerID not in playerStateDict:
            return ShareDefine.MailState_Unknown
        return playerStateDict[playerID]
    def SetPlayerMailState(self, guid, playerID, mailState):
        ## 设置玩家某个邮件状态,个人、全服邮件通用
        #  @return: 返回设置的邮件状态
        personalMail = self.GetPersonalMail(playerID, guid)
        if personalMail:
            if mailState >= ShareDefine.MailState_Del:
                self.DelPersonalMail(playerID, guid)
                return ShareDefine.MailState_Del
            personalMail.SetMailState(mailState)
            return mailState
        if guid not in self.__serverMailPlayerStateDict:
            self.__serverMailPlayerStateDict[guid] = {}
        playerStateDict = self.__serverMailPlayerStateDict[guid]
        playerStateDict[playerID] = mailState
        return mailState
    def DelPersonalMail(self, playerID, guid):
        ## 删除个人邮件
        self.__mailItemDict.pop(guid, None)
        if playerID in self.__personalMailDict:
            mailDict = self.__personalMailDict[playerID]
            mailDict.pop(guid, None)
        return
    def DelServerMail(self, guid):
        ## 删除某个全服邮件
        self.__mailItemDict.pop(guid, None)
        self.__serverMailDict.pop(guid, None)
        playerStateDict = self.__serverMailPlayerStateDict.pop(guid, {})
        return playerStateDict
    # 保存数据 存数据库和realtimebackup
    def GetSaveData(self):
        saveData = ""
        # 全服邮件
        serverMailCnt, serverMailSavaData = 0, ""
        for mailObj in self.__serverMailDict.values():
            serverMailCnt += 1
            serverMailSavaData += mailObj.GetBuffer()
        saveData += CommFunc.WriteDWORD("", serverMailCnt) + serverMailSavaData
        GameWorld.Log("Save DBMailServer count :%s len=%s" % (serverMailCnt, len(serverMailSavaData)))
        # 全服邮件玩家状态
        dbData = DBStruct.tagDBMailPlayerRec()
        playerStateCnt, playerStateSaveData = 0, ""
        for guid, playerStateDict in self.__serverMailPlayerStateDict.items():
            for playerID, mailState in playerStateDict.items():
                dbData.clear()
                dbData.GUID = guid
                dbData.PlayerID = playerID
                dbData.MailState = mailState
                playerStateCnt += 1
                playerStateSaveData += dbData.getBuffer()
        saveData += CommFunc.WriteDWORD("", playerStateCnt) + playerStateSaveData
        GameWorld.Log("Save DBMailPlayerRec count :%s len=%s" % (playerStateCnt, len(playerStateSaveData)))
        # 个人邮件
        personalMailCnt, personalMailSavaData = 0, ""
        for mailDict in self.__personalMailDict.values():
            for mailObj in mailDict.values():
                personalMailCnt += 1
                personalMailSavaData += mailObj.GetBuffer()
        saveData += CommFunc.WriteDWORD("", personalMailCnt) + personalMailSavaData
        GameWorld.Log("Save DBMailPersonal count :%s len=%s" % (personalMailCnt, len(personalMailSavaData)))
        # 邮件物品
        mailItemCnt, mailItemSavaData = 0, ""
        for itemList in self.__mailItemDict.values():
            for itemObj in itemList:
                mailItemCnt += 1
                mailItemSavaData += itemObj.GetBuffer()
        saveData += CommFunc.WriteDWORD("", mailItemCnt) + mailItemSavaData
        GameWorld.Log("Save DBMailItem count :%s len=%s" % (mailItemCnt, len(mailItemSavaData)))
        return saveData
    # 从数据库载入数据
    def LoadPyGameData(self, datas, pos, dataslen):
        if pos >= dataslen:
            return
        # 全服邮件
        cnt, pos = CommFunc.ReadDWORD(datas, pos)
        GameWorld.Log("Load DBMailServer count :%s" % cnt)
        for _ in xrange(cnt):
            dbData = DBStruct.tagDBMailServer()
            pos += dbData.readData(datas, pos, dataslen)
            self.__InitServerMailInstance(dbData)
        # 全服邮件玩家状态
        cnt, pos = CommFunc.ReadDWORD(datas, pos)
        GameWorld.Log("Load DBMailPlayerRec count :%s" % cnt)
        dbData = DBStruct.tagDBMailPlayerRec()
        for _ in xrange(cnt):
            dbData.clear()
            pos += dbData.readData(datas, pos, dataslen)
            self.SetServerMailPlayerState(dbData.GUID, dbData.PlayerID, dbData.MailState)
        # 个人邮件
        cnt, pos = CommFunc.ReadDWORD(datas, pos)
        GameWorld.Log("Load DBMailPersonal count :%s" % cnt)
        for _ in xrange(cnt):
            dbData = DBStruct.tagDBMailPersonal()
            pos += dbData.readData(datas, pos, dataslen)
            self.__InitPersonalMailInstance(dbData)
        # 邮件物品
        cnt, pos = CommFunc.ReadDWORD(datas, pos)
        GameWorld.Log("Load DBMailItem count :%s" % cnt)
        for _ in xrange(cnt):
            dbData = DBStruct.tagDBMailItem()
            pos += dbData.readData(datas, pos, dataslen)
            self.__InitMailItemInstance(dbData)
        return pos
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/DataRecordPack.py
@@ -1565,4 +1565,26 @@
                'AccID':curPlayer.GetAccID(), 'dayIndex':dayIndex, 'point':point}
    #发送封包
    SendEventPack("FeastWeekPartyPoint", dataDict, curPlayer)
    return
    return
def DR_MailSend(playerID, GUID, addDict={}):
    ## 邮件发送流向
    dataDict = {'PlayerID':playerID, 'GUID':GUID}
    dataDict.update(addDict)
    #发送封包
    SendEventPack("MailSend", dataDict)
    return
def DR_MailGiveSuccess(playerID, GUID):
    ## 邮件领取流向
    dataDict = {'PlayerID':playerID, 'GUID':GUID}
    #发送封包
    SendEventPack("MailGiveSuccess", dataDict)
    return
def DR_MailDel(playerID, GUID, eventName):
    ## 邮件删除流向
    dataDict = {'PlayerID':playerID, 'GUID':GUID, 'eventName':eventName}
    #发送封包
    SendEventPack("MailDel", dataDict)
    return
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GM/Commands/Mail.py
New file
@@ -0,0 +1,158 @@
#!/usr/bin/python
# -*- coding: GBK -*-
#-------------------------------------------------------------------------------
#
##@package GM.Commands.Mail
#
# @todo:邮件
# @author hxp
# @date 2025-05-14
# @version 1.0
#
# 详细描述: 邮件
#
#-------------------------------------------------------------------------------
#"""Version = 2025-05-14 12:00"""
#-------------------------------------------------------------------------------
import GameWorld
import PlayerMail
import ShareDefine
import DataRecordPack
import DBDataMgr
import random
## 执行逻辑
#  @param curPlayer 当前玩家
#  @param gmList []
#  @return None
def OnExec(curPlayer, gmList):
    if not gmList:
        GameWorld.DebugAnswer(curPlayer, "清空邮件: Mail 0")
        GameWorld.DebugAnswer(curPlayer, "发送邮件: Mail 几封 物品数 [模板key 参数1 ...]")
        GameWorld.DebugAnswer(curPlayer, "输出邮件: Mail p")
        return
    value = gmList[0]
    if value == 0:
        ClearMail(curPlayer)
        return
    if value == "p":
        PrintPlayerMail(curPlayer)
        return
    if value > 0:
        SendPlayerMail(curPlayer, gmList)
        return
    return
def SendPlayerMail(curPlayer, gmList):
    playerID = curPlayer.GetPlayerID()
    sendCnt = gmList[0]
    mailItemCnt = gmList[1] if len(gmList) > 1 else 5
    mailTypeKey = gmList[2] if len(gmList) > 2 else ""
    paramList = gmList[3:]
    itemIDList = range(3501, 3530 + 1)
    moneyIDList = [20, 30]
    mailMgr = DBDataMgr.GetMailMgr()
    mailCntBef = mailMgr.GetPersonalMailCount(playerID)
    isBind = 0
    for _ in range(sendCnt):
        itemList = []
        if mailItemCnt:
            for moneyID in moneyIDList:
                itemCount = random.choice([100, 1000, 10000, 20000, 50000, 100000, 200000, 300000, 500000])
                itemList.append([moneyID, itemCount, isBind])
                if len(itemList) >= mailItemCnt:
                    break
            random.shuffle(itemIDList)
            for i in range(mailItemCnt):
                itemID = itemIDList[i]
                itemCount = random.randint(1, 100000)
                itemList.append([itemID, itemCount, isBind])
                if len(itemList) >= mailItemCnt:
                    break
        PlayerMail.SendMailByKey(mailTypeKey, playerID, itemList, paramList)
    mailCntAft = mailMgr.GetPersonalMailCount(playerID)
    GameWorld.DebugAnswer(curPlayer, "发送个人邮件OK:%s, %s~%s" % (sendCnt, mailCntBef, mailCntAft))
    return
def ClearMail(curPlayer):
    notifyGUIDState = {}
    playerID = curPlayer.GetPlayerID()
    mailMgr = DBDataMgr.GetMailMgr()
    guidList = mailMgr.GetPersonalMailGuids(playerID)
    for guid in guidList:
        mailMgr.DelPersonalMail(playerID, guid)
        DataRecordPack.DR_MailDel(playerID, guid, "GMDel")
        notifyGUIDState[guid] = ShareDefine.MailState_Del
    GameWorld.DebugAnswer(curPlayer, "删除个人邮件:%s" % len(guidList))
    guidList = mailMgr.GetServerMailGuids()
    for guid in guidList:
        playerStateDict = mailMgr.DelServerMail(guid)
        if playerID in playerStateDict and playerStateDict[playerID] < ShareDefine.MailState_Del:
            notifyGUIDState[guid] = ShareDefine.MailState_Del
    if len(guidList):
        GameWorld.DebugAnswer(curPlayer, "删除全服邮件:%s" % len(guidList))
    PlayerMail.Sync_PlayerMailState(curPlayer, notifyGUIDState)
    return
def PrintPlayerMail(curPlayer):
    playerID = curPlayer.GetPlayerID()
    mailMgr = DBDataMgr.GetMailMgr()
    guidList = mailMgr.GetPersonalMailGuids(playerID)
    GameWorld.DebugAnswer(curPlayer, "个人邮件数:%s" % len(guidList))
    for num, guid in enumerate(guidList, 1):
        mailObj = mailMgr.GetPersonalMail(playerID, guid)
        __printMailLog(curPlayer, mailMgr, mailObj, num, False)
    guidList = mailMgr.GetServerMailGuids()
    GameWorld.DebugAnswer(curPlayer, "全服邮件数:%s" % len(guidList))
    for num, guid in enumerate(guidList, 1):
        mailObj = mailMgr.GetServerMail(guid)
        __printMailLog(curPlayer, mailMgr, mailObj, num, True)
    GameWorld.DebugAnswer(curPlayer, "邮件明细详见地图日志")
    return
def __printMailLog(curPlayer, mailMgr, mailObj, num, isServerMail):
    playerID = curPlayer.GetPlayerID()
    GUID = mailObj.GetGUID()
    Title = mailObj.GetTitle()
    Text = mailObj.GetText()
    CreateTime = mailObj.GetCreateTime()
    LimitDays = mailObj.GetLimitDays()
    mailState = mailMgr.GetPlayerMailState(GUID, playerID)
    mailItemCount = mailMgr.GetMailItemCount(GUID)
    GameWorld.DebugLog("%s,%s,mailState=%s,mailItemCount=%s" % (num, GUID, mailState, mailItemCount), playerID)
    GameWorld.DebugLog("    CreateTime=%s,LimitDays=%s,Title=%s,Text=%s" % (CreateTime, LimitDays, Title, Text), playerID)
    if isServerMail:
        LimitLV = mailObj.GetLimitLV()
        LimitLVType = mailObj.GetLimitLVType()
        CheckState = mailObj.GetCheckState()
        GameWorld.DebugLog("    LimitLV=%s,升级可领=%s,需要审核=%s" % (LimitLV, LimitLVType, CheckState), playerID)
    itemList = []
    for index in range(mailItemCount):
        mailItem = mailMgr.GetMailItemAt(GUID, index)
        itemID = mailItem.GetItemID()
        itemCount = mailItem.GetCount()
        isBind = mailItem.GetIsBind()
        userData = mailItem.GetUserData()
        itemList.append([itemID, itemCount, isBind, userData])
    if itemList:
        GameWorld.DebugLog("    %s,itemList=%s" % (mailItemCount, itemList), playerID)
    return
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorld.py
@@ -56,6 +56,7 @@
import PyGameData
import urllib
import md5
import uuid
#---------------------------------------------------------------------
#设置允许的最大迭代数目, 默认1000
#在NPCAI中, 可能超过1000, 所以要设定为2000
@@ -1475,6 +1476,8 @@
    ChannelCodeDict = ReadChConfig.GetEvalChConfig("ChannelCode")
    return ChannelCodeDict.get(codeNum, "")
def GetGUID(): return str(uuid.uuid1())
#---------------------------------------------------------------------
##大额度金钱记录
# @param tradeGold 物品售价金子
@@ -2365,7 +2368,7 @@
    #    return
    #===========================================================================
    
    DebugLog(text)
    DebugLog(text, curPlayer.GetPlayerID())
    text = text.decode(ShareDefine.Def_Game_Character_Encoding).encode(GetCharacterEncoding())
    curPlayer.DebugAnswer(text)
    return
@@ -2381,10 +2384,9 @@
def SendGameErrorEx(errType, msgInfo="", playerID=0):
    ErrLog("SendGameErrorEx: %s -> %s" % (errType, msgInfo), playerID)
    SendGameError(errType, msgInfo)
    if GetGameWorld().GetDebugLevel():
        raise Exception("%s -> %s" % (errType, msgInfo))
    else:
        SendGameError(errType, msgInfo)
    return
def SendGameError(errType, msgInfo=""):
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorldLogic/GameWorldProcess.py
@@ -782,7 +782,7 @@
    if curMinute == PyGameData.g_mapLastProcess_Minute:
        return
    if PyGameData.g_initGame:
        DBDataMgr.OnMinute(curMinute)
        DBDataMgr.OnMinute(curTime)
    PyGameData.g_mapLastProcess_Minute = curMinute
    PlayerTeam.OnCheckTeamPlayerDisconnectTimeout(tick)
    
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/ChPlayer.py
@@ -172,6 +172,7 @@
import PlayerActFamilyGCZ
import PlayerActYunshi
import PlayerActTask
import PlayerMail
import datetime
import time
@@ -1007,6 +1008,7 @@
        pass
    
    else:
        PlayerMail.OnPlayerLogin(curPlayer)
        PlayerChatBox.OnPlayerLogin(curPlayer)
        PlayerFace.OnPlayerLogin(curPlayer)
        PlayerXiangong.OnPlayerLogin(curPlayer)
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerEventCounter.py
@@ -142,6 +142,8 @@
import PlayerXiangong
import PlayerFuncTeam
import PlayerMineArea
import PlayerMail
import DBDataMgr
import datetime
import time
@@ -222,6 +224,8 @@
def __Func_GameServer_OnDayEx(tick):
    GameWorld.Log("MapServer -> OnDayEx!")
    
    DBDataMgr.OnDayEx()
    PlayerMail.OnDayEx()
    PlayerControl.RemoveTimeoutLeaveServerPlayerInfo(tick)
    
    playerManager = GameWorld.GetPlayerManager()
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerMail.py
New file
@@ -0,0 +1,515 @@
#!/usr/bin/python
# -*- coding: GBK -*-
#-------------------------------------------------------------------------------
#
##@package Player.PlayerMail
#
# @todo:邮件
# @author hxp
# @date 2025-05-14
# @version 1.0
#
# 详细描述: 邮件
#
#-------------------------------------------------------------------------------
#"""Version = 2025-05-14 12:00"""
#-------------------------------------------------------------------------------
import GameWorld
import ItemCommon
import PlayerControl
import IPY_GameWorld
import DataRecordPack
import ChPyNetSendPack
import IpyGameDataPY
import ItemControler
import NetPackCommon
import ShareDefine
import DBDataMgr
import ChConfig
import json
import time
def OnPlayerLogin(curPlayer):
    Sync_PlayerServerMail(curPlayer)
    Sync_PersonalMail(curPlayer)
    return
def OnDayEx():
    curTime = int(time.time())
    DelTimeoutServerMail(curTime)
    DelTimeoutPersonalMail(curTime)
    return
def DelTimeoutServerMail(curTime):
    ## 清理超时全服邮件, 全服邮件分两部处理:1. 邮件接收的有效时间,后台设置,2. 邮件删除时间为接收有效时间再延长30天
    mailMgr = DBDataMgr.GetMailMgr()
    serverMailGuids = mailMgr.GetServerMailGuids()
    for guid in serverMailGuids:
        mailObj = mailMgr.GetServerMail(guid)
        if not mailObj:
            continue
        createTime = GameWorld.ChangeTimeStrToNum(mailObj.GetCreateTime())
        limitTime = createTime + (mailObj.GetLimitDays() + 7) * 3600 * 24
        if curTime < limitTime:
            #GameWorld.DebugLog("全服邮件未超时,不删除! %s,createTime=%s,limitTime=%s" % (guid, mailObj.GetCreateTime(), GameWorld.ChangeTimeNumToStr(limitTime)))
            continue
        DelServerMail(guid)
    return
def DelServerMail(guid):
    mailMgr = DBDataMgr.GetMailMgr()
    playerStateDict = mailMgr.DelServerMail(guid)
    if not playerStateDict:
        return
    playerMgr = GameWorld.GetPlayerManager()
    clientPack = __packMailStateChange({guid:ShareDefine.MailState_Del})
    for playerID, mailState in playerStateDict.items():
        if mailState >= ShareDefine.MailState_Del:
            continue
        curPlayer = playerMgr.FindPlayerByID(playerID)
        if curPlayer:
            NetPackCommon.SendFakePack(curPlayer, clientPack)
    return
def DelTimeoutPersonalMail(curTime):
    ## 清理超时个人邮件
    mailMgr = DBDataMgr.GetMailMgr()
    personalMailDict = mailMgr.GetAllPersonalMailDict()
    for playerID, mailDict in personalMailDict.items():
        notifyGUIDState = {}
        for guid, mailObj in mailDict.items():
            createTime = GameWorld.ChangeTimeStrToNum(mailObj.GetCreateTime())
            limitTime = createTime + (mailObj.GetLimitDays() + 0) * 3600 * 24
            if curTime < limitTime:
                #GameWorld.DebugLog("个人邮件未超时,不删除! %s,createTime=%s,limitTime=%s" % (guid, mailObj.GetCreateTime(), GameWorld.ChangeTimeNumToStr(limitTime)), playerID)
                continue
            mailState = mailObj.GetMailState()
            mailItemCount = mailMgr.GetMailItemCount(guid)
            if mailItemCount and mailState != ShareDefine.MailState_Got:
                #GameWorld.DebugLog("个人邮件有物品邮件未领取不删除! %s" % guid, playerID)
                continue
            mailMgr.DelPersonalMail(playerID, guid)
            DataRecordPack.DR_MailDel(playerID, guid, "Timeout")
            notifyGUIDState[guid] = ShareDefine.MailState_Del
        if not notifyGUIDState:
            continue
        curPlayer = GameWorld.GetPlayerManager().FindPlayerByID(playerID)
        if curPlayer:
            Sync_PlayerMailState(curPlayer, notifyGUIDState)
    return
def SendMailByKey(mailTypeKey, playerID, itemList, paramList=[], limitDays=7):
    ## 发送个人邮件魔板
    if not mailTypeKey:
        mailTypeKey = ShareDefine.DefaultLackSpaceMailType
    title = "<T>%s</T>" % mailTypeKey
    text = "%s" % json.dumps(paramList, ensure_ascii=False)
    SendMail(playerID, title, text, itemList, limitDays)
    return
def SendMail(playerID, title, text, itemList=None, limitDays=7, mailType=0):
    ## 发送个人邮件
    if itemList == None:
        itemList = []
    mailMgr = DBDataMgr.GetMailMgr()
    mailMax = IpyGameDataPY.GetFuncCfg("PersonalMail", 1)
    mailCnt = mailMgr.GetPersonalMailCount(playerID)
    if mailCnt >= mailMax:
        mailList = mailMgr.GetPersonalMails(playerID)
        mailList.sort(key=lambda m: (-m.GetMailState(), m.GetCreateTime())) # 按邮件状态倒序、创建时间升序排
        oneDelCnt = max(1, mailMax / 10) # 一次性删除最大数量的1/10封邮件
        isStop = False
        delCnt = 0
        notifyGUIDState = {}
        while delCnt < oneDelCnt and mailList and not isStop:
            mailObj = mailList.pop(0) # 该列表是copy,可直接pop
            if not mailObj:
                continue
            guid = mailObj.GetGUID()
            mailState = mailObj.GetMailState()
            # 已经删到未读或未领取的邮件,则强制停止,不再删除
            if mailState == ShareDefine.MailState_UnRead or (mailState == ShareDefine.MailState_Read and mailMgr.GetMailItemCount(guid)):
                isStop = True
                if delCnt > 0:
                    # 已经有删过了本封可不删
                    break
            #至少要删1封
            delCnt += 1
            GameWorld.DebugLog("系统自动删除邮件: playerID=%s,guid=%s,mailState=%s,isStop=%s" % (playerID, guid, mailState, isStop))
            mailMgr.DelPersonalMail(playerID, guid)
            DataRecordPack.DR_MailDel(playerID, guid, "MaxCountLimiit")
            notifyGUIDState[guid] = ShareDefine.MailState_Del
        if notifyGUIDState:
            curPlayer = GameWorld.GetPlayerManager().FindPlayerByID(playerID)
            if curPlayer:
                Sync_PlayerMailState(curPlayer, notifyGUIDState)
    mailObj = mailMgr.AddPersonalMail(playerID, title, text, itemList, limitDays, mailType)
    CreateTime = mailObj.GetCreateTime()
    GUID = mailObj.GetGUID()
    #添加流向
    addDict = {"CreateTime":CreateTime, "Title":title, "Text":text, "LimitDays":limitDays,
               "ItemList":itemList, "ItemListLen":len(itemList)}
    DataRecordPack.DR_MailSend(playerID, GUID, addDict)
    curPlayer = GameWorld.GetPlayerManager().FindPlayerByID(playerID)
    if curPlayer:
        Sync_PersonalMail(curPlayer, [mailObj.GetGUID()])
    return
def SendSeverMail(guid, title, text, itemList=None, limitDays=7, mailType=0, limitLV=0, limitLVType=0, checkState=0):
    '''发送全服邮件
    @param limitLV: 限制可领的最低等级
    @param limitLVType: 等级达到后是否可领,默认不可
    @param checkState: 是否需要审核,默认不需要
    '''
    mailMgr = DBDataMgr.GetMailMgr()
    mailObj = mailMgr.AddServerMail(guid, title, text, itemList, limitDays, mailType)
    mailObj.SetLimitLV(limitLV)
    mailObj.SetLimitLVType(limitLVType)
    mailObj.SetCheckState(checkState)
    if not checkState:
        Sync_ServerMail(mailObj.GetGUID())
    return
def CheckServerMailResult(guid, isOK):
    ## 审核全服邮件结果
    # @param isOK: 是否通过审核
    mailMgr = DBDataMgr.GetMailMgr()
    mailObj = mailMgr.GetServerMail(guid)
    if not mailObj:
        return
    if not isOK:
        return
    mailObj.SetCheckState(0) # 设置为0,不需要审核了,即通过
    Sync_ServerMail(guid)
    return
#// A5 37 请求邮件操作 #tagCMRequestMail
#
#struct    tagCMRequestMail
#{
#    tagHead        Head;
#    char        GUID[36];    //邮件GUID,可传空,默认针对个人邮件的批量处理,如批量领取、批量删除已领邮件等;全服邮件暂时限制只能单封邮件处理
#    BYTE        ReqType;        //0-设置已读,1-领取邮件,2-删除邮件
#};
def OnRequestMail(index, curPackData, tick):
    curPlayer = GameWorld.GetPlayerManager().GetPlayerByIndex(index)
    guid = curPackData.GUID
    reqType = curPackData.ReqType
    if reqType == 2:
        doMailDel(curPlayer, guid)
    elif reqType == 1:
        doMailGetAward(curPlayer, guid)
    else:
        doMailRead(curPlayer, guid)
    return
def doMailRead(curPlayer, guid):
    ## 执行邮件已读
    if not guid:
        return
    playerID = curPlayer.GetPlayerID()
    mailMgr = DBDataMgr.GetMailMgr()
    mailState = mailMgr.GetPlayerMailState(guid, playerID)
    if mailState == ShareDefine.MailState_UnRead:
        mailState = mailMgr.SetPlayerMailState(guid, playerID, ShareDefine.MailState_Read)
    Sync_PlayerMailState(curPlayer, {guid:mailState})
    return
def doMailGetAward(curPlayer, guid):
    ## 执行邮件领取,支持批量
    playerID = curPlayer.GetPlayerID()
    mailMgr = DBDataMgr.GetMailMgr()
    # 批量处理,仅针对个人邮件
    if not guid:
        guidList = mailMgr.GetPersonalMailGuids(playerID)
    else:
        guidList = [guid]
    statItemList = []
    statItemDict = {} # 统计累计
    isPackSpaceEnough = True
    notifyGUIDState = {}
    for guid in guidList:
        mailState = mailMgr.GetPlayerMailState(guid, playerID)
        if mailState == ShareDefine.MailState_Unknown or mailState >= ShareDefine.MailState_Got:
            GameWorld.DebugLog("邮件状态已领取或不能领取! mailState=%s,%s" % (mailState, guid), playerID)
            continue
        mailItemCount = mailMgr.GetMailItemCount(guid)
        if not mailItemCount:
            GameWorld.DebugLog("邮件没有物品可领取! %s" % (guid), playerID)
            continue
        needPackSpaceDict = {}
        for index in range(mailItemCount):
            mailItem = mailMgr.GetMailItemAt(guid, index)
            itemID = mailItem.GetItemID()
            itemCount = mailItem.GetCount()
            isBind = mailItem.GetIsBind()
            userData = mailItem.GetUserData()
            curItemData = GameWorld.GetGameData().GetItemByTypeID(itemID)
            if not curItemData:
                continue
            packType = ChConfig.GetItemPackType(curItemData)
            if userData:
                statItemList.append([itemID, itemCount, isBind, userData])
                needSpace = 1
            else:
                key = (itemID, isBind)
                if key not in statItemDict:
                    statItemDict[key] = 0
                    statItemList.append(key)
                statItemDict[key] = statItemDict[key] + itemCount
                needSpace = ItemControler.GetItemNeedPackCount(packType, curItemData, itemCount, isBind)
            needPackSpaceDict[packType] = needPackSpaceDict.get(packType, 0) + needSpace
        GameWorld.DebugLog("    guid=%s,needPackSpaceDict=%s" % (guid, needPackSpaceDict))
        for packType, needSpace in needPackSpaceDict.items():
            if needSpace > ItemCommon.GetItemPackSpace(curPlayer, packType, needSpace):
                PlayerControl.NotifyCode(curPlayer, "GeRen_chenxin_676165", [packType])
                isPackSpaceEnough = False
                break
        if not isPackSpaceEnough:
            break
        notifyGUIDState[guid] = mailMgr.SetPlayerMailState(guid, playerID, ShareDefine.MailState_Got)
        for index in range(mailItemCount):
            mailItem = mailMgr.GetMailItemAt(guid, index)
            itemID = mailItem.GetItemID()
            itemCount = mailItem.GetCount()
            isBind = mailItem.GetIsBind()
            userData = mailItem.GetUserData()
            #setAttrDict = {} if not userData else eval(userData) 之后扩展有指定属性的,可参考砍树版本
            if not ItemControler.GivePlayerItem(curPlayer, itemID, itemCount, isBind, [IPY_GameWorld.rptItem],
                                                event=[ChConfig.ItemGive_Mail, False, {"MailGUID":guid}]):
                continue
        DataRecordPack.DR_MailGiveSuccess(playerID, guid)
    giveItemInfo = []
    for statItem in statItemList:
        if len(statItem) == 2:
            itemID, isBind = statItem
            itemCount = statItemDict.get(statItem, 0)
            giveItemInfo.append([itemID, itemCount, isBind])
        else:
            giveItemInfo.append(statItem)
    if giveItemInfo:
        ItemControler.NotifyGiveAwardInfo(curPlayer, giveItemInfo, "Mail")
    Sync_PlayerMailState(curPlayer, notifyGUIDState)
    return
def doMailDel(curPlayer, guid, isGM=False):
    ## 执行邮件删除
    # @param isGM: 是否GM删除,无视物品是否已领取,强制删除
    playerID = curPlayer.GetPlayerID()
    mailMgr = DBDataMgr.GetMailMgr()
    # 批量处理,仅针对个人邮件
    if not guid:
        guidList = mailMgr.GetPersonalMailGuids(playerID)
    else:
        guidList = [guid]
    notifyGUIDState = {}
    for guid in guidList:
        mailState = mailMgr.GetPlayerMailState(guid, playerID)
        if mailState >= ShareDefine.MailState_Del:
            continue
        if not isGM:
            mailItemCount = mailMgr.GetMailItemCount(guid)
            if mailItemCount and mailState != ShareDefine.MailState_Got:
                GameWorld.DebugLog("有物品邮件未领取不能删除! %s" % guid, playerID)
                continue
            if not mailItemCount and mailState != ShareDefine.MailState_Read:
                GameWorld.DebugLog("无物品邮件未读不能删除! %s" % guid, playerID)
                continue
        notifyGUIDState[guid] = mailMgr.SetPlayerMailState(guid, playerID, ShareDefine.MailState_Del)
        if isGM:
            DataRecordPack.DR_MailDel(playerID, guid, "GMDel")
        # 这里玩家主动删除的可不记录流向,因为未读未领取不允许主动删除,已领取的已有领取记录,所以可不记录
    Sync_PlayerMailState(curPlayer, notifyGUIDState)
    return
def Sync_ServerMail(guid):
    ## 通知全服邮件
    mailMgr = DBDataMgr.GetMailMgr()
    serverMail = mailMgr.GetServerMail(guid)
    if not serverMail:
        return
    packMail = __packMailObj(serverMail)
    clientPack = ChPyNetSendPack.tagMCMailList()
    clientPack.IsServerMail = 1
    clientPack.MailList = [packMail]
    clientPack.Count = len(clientPack.MailList)
    playerManager = GameWorld.GetPlayerManager()
    for i in range(playerManager.OnlineCount()):
        curPlayer = playerManager.OnlineAt(i)
        if not GameWorld.IsNormalPlayer(curPlayer):
            continue
        mailState = CheckPlayerServerMailState(curPlayer, serverMail)
        if mailState == ShareDefine.MailState_Unknown or mailState >= ShareDefine.MailState_Del:
            continue
        packMail.MailState = mailState
        NetPackCommon.SendFakePack(curPlayer, clientPack)
    return
def Sync_PlayerServerMail(curPlayer):
    ## 通知玩家相关的全服邮件
    mailMgr = DBDataMgr.GetMailMgr()
    guidList = mailMgr.GetServerMailGuids()
    if not guidList:
        return
    mailList = []
    for guid in guidList:
        mailObj = mailMgr.GetServerMail(guid)
        if not mailObj:
            continue
        mailState = CheckPlayerServerMailState(curPlayer, mailObj)
        if mailState == ShareDefine.MailState_Unknown or mailState >= ShareDefine.MailState_Del:
            continue
        mail = __packMailObj(mailObj)
        mail.MailState = mailState
        mailList.append(mail)
    if not mailList:
        return
    clientPack = ChPyNetSendPack.tagMCMailList()
    clientPack.MailList = mailList
    clientPack.Count = len(clientPack.MailList)
    NetPackCommon.SendFakePack(curPlayer, clientPack)
    return
def CheckPlayerServerMailState(curPlayer, serverMail):
    ## 检查处理玩家全服邮件状态
    # @return: 玩家该全服邮件的状态
    if not serverMail or serverMail.GetCheckState():
        # 需要审核的,直接返回
        return ShareDefine.MailState_Unknown
    playerID = curPlayer.GetPlayerID()
    guid = serverMail.GetGUID()
    mailMgr = DBDataMgr.GetMailMgr()
    mailState = mailMgr.GetPlayerMailState(guid, playerID)
    if mailState != ShareDefine.MailState_Unknown:
        return mailState
    mailState = ShareDefine.MailState_Unknown
    limitLV = serverMail.GetLimitLV()
    limitLVType = serverMail.GetLimitLVType()
    playerLV = curPlayer.GetLV()
    if playerLV < limitLV:
        if not limitLVType:
            return mailMgr.SetPlayerMailState(guid, playerID, ShareDefine.MailState_Limit)
        return ShareDefine.MailState_Unknown
    return mailMgr.SetPlayerMailState(guid, playerID, ShareDefine.MailState_UnRead)
def Sync_PersonalMail(curPlayer, guidList=None):
    ## 通知玩家个人邮件
    playerID = curPlayer.GetPlayerID()
    mailMgr = DBDataMgr.GetMailMgr()
    if not guidList:
        guidList = mailMgr.GetPersonalMailGuids(playerID)
    if not guidList:
        return
    clientPack = ChPyNetSendPack.tagMCMailList()
    clientPack.MailList = []
    for guid in guidList:
        mailObj = mailMgr.GetPersonalMail(playerID, guid)
        if not mailObj:
            continue
        mail = __packMailObj(mailObj)
        mail.MailState = mailObj.GetMailState()
        clientPack.MailList.append(mail)
    clientPack.Count = len(clientPack.MailList)
    NetPackCommon.SendFakePack(curPlayer, clientPack)
    return
def __packMailObj(mailObj):
    ## 打包通知的邮件
    guid = mailObj.GetGUID()
    mail = ChPyNetSendPack.tagMCMail()
    mail.GUID = guid
    mail.Type = mailObj.GetType()
    mail.CreateTime = mailObj.GetCreateTime()
    mail.LimitDays = mailObj.GetLimitDays()
    mail.Title = mailObj.GetTitle()
    mail.TitleLen = len(mail.Title)
    mail.Text = mailObj.GetText()
    mail.TextLen = len(mail.Text)
    mailMgr = DBDataMgr.GetMailMgr()
    mailItemCount = mailMgr.GetMailItemCount(guid)
    for index in range(mailItemCount):
        mailItem = mailMgr.GetMailItemAt(guid, index)
        if not mailItem:
            continue
        item = ChPyNetSendPack.tagMCMailItem()
        item.ItemID = mailItem.GetItemID()
        item.Count = mailItem.GetCount()
        item.IsBind = mailItem.GetIsBind()
        item.UserData = mailItem.GetUserData()
        item.UserDataLen = len(item.UserData)
        mail.Items.append(item)
    mail.Count = len(mail.Items)
    return mail
def __packMailStateChange(notifyGUIDState):
    clientPack = ChPyNetSendPack.tagMCMailStateChange()
    clientPack.MailList = []
    for guid, mailState in notifyGUIDState.items():
        mail = ChPyNetSendPack.tagMCMailState()
        mail.GUID = guid
        mail.MailState = mailState
        clientPack.MailList.append(mail)
    clientPack.Count = len(clientPack.MailList)
    return clientPack
def Sync_PlayerMailState(curPlayer, notifyGUIDState):
    ## 通知邮件状态变更
    if not notifyGUIDState:
        return
    NetPackCommon.SendFakePack(curPlayer, __packMailStateChange(notifyGUIDState))
    return
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ShareDefine.py
@@ -2261,6 +2261,17 @@
DefaultLackSpaceMailType = "DefaultLackSpace" # 背包空间不足时发放物品的默认邮件模板
Def_Space = "<Space=1>" # <Space=空格数>
# 邮件状态定义,每封邮件只能有一种状态,状态只升不降
MailStateList = (
MailState_Unknown, # δ֪ 0
MailState_UnRead, # 未读 1
MailState_Read, # 已读 2
MailState_Got, # 已领取 3
MailState_Del, # 已删除,全服邮件会用到 4
MailState_Limit, # 限制接收邮件,全服邮件会用到 5
) = range(6)
# 手游不使用C++定义 enum            RoleEquipType
# 装备位定义
RoleEquipType = (