using Fantasy.Async; using Fantasy.DataStructure.Collection; using Fantasy.Entitas.Interface; using Fantasy.Helper; namespace Fantasy; public class MailBoxManageComponentDestroySystem : DestroySystem { protected override void Destroy(MailBoxManageComponent self) { if (self.TimerId != 0) { self.Scene.TimerComponent.Net.Remove(ref self.TimerId); } foreach (var (_, mailBox) in self.MailBoxes) { mailBox.Dispose(); } self.MinTime = 0; self.MailsByAccount.Clear(); self.MailsByMailBoxType.Clear(); self.Timers.Clear(); self.TimeOutQueue.Clear(); } } public static class MailBoxManageComponentSystem { public static async FTask Init(this MailBoxManageComponent self) { // 获取数据库中所有的没有处理完成的MailBox var mailBoxes = await self.Scene.World.DataBase.Query(d => true); foreach (var mailBox in mailBoxes) { self.MailBoxes.Add(mailBox.Id, mailBox); switch (mailBox.MailBoxType) { case MailBoxType.Specify: { foreach (var accountId in mailBox.AccountId) { self.MailsByAccount.Add(accountId, mailBox); } break; } case MailBoxType.All: case MailBoxType.AllToDate: { self.MailsByMailBoxType.Add((int)mailBox.MailBoxType, mailBox); break; } } } self.TimerId = self.Scene.TimerComponent.Net.RepeatedTimer(MailBoxManageComponent.MailCheckTIme, self.Timeout); } private static void Timeout(this MailBoxManageComponent self) { var currentTime = TimeHelper.Now; if (currentTime < self.MinTime) { return; } // 检查当然时候有过期的邮件箱需要处理 foreach (var (timeKey, _) in self.Timers) { if (timeKey > currentTime) { self.MinTime = timeKey; break; } self.TimeOutQueue.Enqueue(timeKey); } while (self.TimeOutQueue.TryDequeue(out var timeKey)) { foreach (var mailBoxId in self.Timers[timeKey]) { Log.Info($"MailBox:{mailBoxId} 过期了!"); self.Remove(mailBoxId).Coroutine(); } self.Timers.RemoveKey(timeKey); } } public static async FTask Remove(this MailBoxManageComponent self, long mailBoxId) { if (!self.MailBoxes.Remove(mailBoxId, out var mailBox)) { return; } // 先删除按照分类存储的邮箱 self.MailsByMailBoxType.RemoveValue((int)mailBox.MailBoxType, mailBox); // 删除个人邮件的邮件箱 self.MailsByAccount.RemoveValue(mailBoxId, mailBox); // 在数据库中删除这个邮件 await self.Scene.World.DataBase.Remove(mailBoxId); // 销毁这个MailBox mailBox.Dispose(); } public static async FTask GetHaveMail(this MailBoxManageComponent self, MailUnit mailUnit, bool sync) { var now = TimeHelper.Now; var worldDataBase = self.Scene.World.DataBase; var mailComponent = mailUnit.GetComponent(); // 玩家领取范围邮件的逻辑处理 foreach (var (mailBoxType, mailBoxList) in self.MailsByMailBoxType) { using var removeMailBox = ListPool.Create(); switch ((MailBoxType)mailBoxType) { // 发送给所有人的邮件 case MailBoxType.All: { foreach (var mailBox in mailBoxList) { if (!mailBox.Received.Contains(mailUnit.Id)) { // 如果是没有领取过这个邮件,首先要把自己添加到领取过的名单中。 mailBox.Received.Add(mailUnit.Id); // 发送给自己的邮件列表里添加邮件。 await mailUnit.GetComponent().Add(MailFactory.Serializer.Clone(mailBox.Mail), true); } if (mailBox.ExpireTime <= now) { // 邮件已经过期了,要进行清理这个邮件的操作了 removeMailBox.Add(mailBox); continue; } // 保存邮件箱状态到数据库中。 await worldDataBase.Save(mailBox); } foreach (var mailBox in removeMailBox) { await self.Remove(mailBox.Id); } // 这里有一个小的细节要处理,这里大家课下自己实现一下。 break; } case MailBoxType.AllToDate: { foreach (var mailBox in mailBoxList) { Log.Debug($"mailBox.CreateTime >= mailUnit.CreateTime {mailBox.CreateTime} >= {mailUnit.CreateTime}"); if (mailBox.CreateTime >= mailUnit.CreateTime && !mailBox.Received.Contains(mailUnit.Id)) { // 如果是没有领取过这个邮件,首先要把自己添加到领取过的名单中。 mailBox.Received.Add(mailUnit.Id); // 发送给自己的邮件列表里添加邮件。 await mailUnit.GetComponent().Add(MailFactory.Serializer.Clone(mailBox.Mail), true); } if (mailBox.ExpireTime <= now) { // 邮件已经过期了,要进行清理这个邮件的操作了 removeMailBox.Add(mailBox); continue; } // 保存邮件箱状态到数据库中。 await worldDataBase.Save(mailBox); } foreach (var mailBox in removeMailBox) { await self.Remove(mailBox.Id); } break; } } } if (self.MailsByAccount.TryGetValue(mailUnit.AccountId, out var mailBoxes)) { using var removeMailBox = ListPool.Create(); foreach (var mailBox in mailBoxes) { var cloneMail = MailFactory.Serializer.Clone(mailBox.Mail); await mailComponent.Add(cloneMail, sync); mailBox.AccountId.Remove(mailUnit.AccountId); Log.Debug($"领取了一个离线邮件 MailId:{cloneMail.Id}"); if (mailBox.AccountId.Count <= 0) { // 当邮件箱里没有要发送的玩家了,就表示这个邮件箱已经没有用处,可以删除了。 removeMailBox.Add(mailBox); } } foreach (var mailBox in removeMailBox) { await self.Remove(mailBox.Id); } if (mailBoxes.Count <= 0) { // 如果MailsByAccount里的邮件箱已经没有邮件了,就删除这个邮件箱的缓存。 self.MailsByAccount.RemoveByKey(mailUnit.AccountId); } } } }