From eb2b495812782c219d963559e840d1be46c5c846 Mon Sep 17 00:00:00 2001
From: hxp <ale99527@vip.qq.com>
Date: 星期三, 14 五月 2025 11:46:47 +0800
Subject: [PATCH] 16 卡牌服务端(邮件功能;)
---
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ShareDefine.py | 11
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetPack.py | 64 +
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetSendPack.py | 369 ++++++++++
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/DB/StructData/DBFamily.py | 5
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerMail.py | 515 +++++++++++++++
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/DB/DBDataMgr.py | 20
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/PyNetPack.ini | 12
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/DataRecordPack.py | 24
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/ChPlayer.py | 2
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorld.py | 8
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/DB/StructData/DBMail.py | 418 ++++++++++++
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorldLogic/GameWorldProcess.py | 2
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerEventCounter.py | 4
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/DB/DBStruct.py | 402 +++++++++++
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GM/Commands/Mail.py | 158 ++++
15 files changed, 2,003 insertions(+), 11 deletions(-)
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/PyNetPack.ini b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/PyNetPack.ini
index e8d28a9..572a9ab 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/PyNetPack.ini
+++ b/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
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetPack.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetPack.py
index 763fff9..fa57fb5 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetPack.py
+++ b/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):
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetSendPack.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetSendPack.py
index 693db8a..aa30ab6 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetSendPack.py
+++ b/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):
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/DB/DBDataMgr.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/DB/DBDataMgr.py
index 977f92f..47ff107 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/DB/DBDataMgr.py
+++ b/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
+
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/DB/DBStruct.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/DB/DBStruct.py
index 8fce029..c258a1a 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/DB/DBStruct.py
+++ b/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]
+
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/DB/StructData/DBFamily.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/DB/StructData/DBFamily.py
index d688586..44d3fd7 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/DB/StructData/DBFamily.py
+++ b/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)
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/DB/StructData/DBMail.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/DB/StructData/DBMail.py
new file mode 100644
index 0000000..bd9a051
--- /dev/null
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/DB/StructData/DBMail.py
@@ -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
+
+
\ No newline at end of file
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/DataRecordPack.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/DataRecordPack.py
index 593dd42..9a24612 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/DataRecordPack.py
+++ b/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
\ No newline at end of file
+ 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
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GM/Commands/Mail.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GM/Commands/Mail.py
new file mode 100644
index 0000000..ab5ab3f
--- /dev/null
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GM/Commands/Mail.py
@@ -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
+
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorld.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorld.py
index c71d18d..6092f9c 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorld.py
+++ b/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=""):
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorldLogic/GameWorldProcess.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorldLogic/GameWorldProcess.py
index 77e539c..fa6d995 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorldLogic/GameWorldProcess.py
+++ b/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)
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/ChPlayer.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/ChPlayer.py
index 1c4fbf6..d205783 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/ChPlayer.py
+++ b/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)
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerEventCounter.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerEventCounter.py
index 0e9b165..6846c02 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerEventCounter.py
+++ b/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()
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerMail.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerMail.py
new file mode 100644
index 0000000..cdcf8db
--- /dev/null
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerMail.py
@@ -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
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ShareDefine.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ShareDefine.py
index c6b2c9a..e0d4613 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ShareDefine.py
+++ b/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 = (
--
Gitblit v1.8.0