hxp
2025-05-28 a6fe9b060edf315f6abde7443e48db5dea439f47
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
#!/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
                
        giveItemList = []
        for itemInfo in itemRankList:
            if len(itemInfo) == 4:
                itemID, itemCount, isBind, userData = itemInfo
            else:
                userData = ""
                itemID, isBind = itemInfo
                itemCount = itemDict.get(itemInfo, 0)
            giveItemList.append([itemID, itemCount, isBind, userData])
            
        Max_MailItem = 20
        if len(giveItemList) > Max_MailItem:
            GameWorld.SendGameErrorEx("MailItemMultiError", "%s|%s|%s|%s" % (guid, len(giveItemList), itemList, giveItemList))
            #giveItemList = giveItemList[:Max_MailItem] ÔÝʱ»¹ÊÇÈ÷¢£¬ÏÈ×öϺǫ́Óʼþ¾¯¸æ¼´¿É
            
        for itemID, itemCount, isBind, userData in giveItemList:                
            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)
            
        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):
        ## »ñÈ¡Óʼþij¸öÎïÆ·
        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):
        ## »ñÈ¡Íæ¼Òij¸öÓʼþ״̬£¬¸öÈË¡¢È«·þÓʼþͨÓÃ
        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):
        ## ÉèÖÃÍæ¼Òij¸öÓʼþ״̬£¬¸öÈË¡¢È«·þÓʼþͨÓÃ
        #  @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):
        ## É¾³ýij¸öÈ«·þÓʼþ
        self.__mailItemDict.pop(guid, None)
        self.__serverMailDict.pop(guid, None)
        playerStateDict = self.__serverMailPlayerStateDict.pop(guid, {})
        return playerStateDict
    
    def DelAllMail(self):
        self.__personalMailDict = {}
        self.__mailItemDict = {}
        self.__serverMailDict = {}
        self.__serverMailPlayerStateDict = {}
        return
    
    # ±£´æÊý¾Ý ´æÊý¾Ý¿âºÍ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.SetPlayerMailState(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