226 lines
8.0 KiB
C#
226 lines
8.0 KiB
C#
using Fantasy.Async;
|
||
using Fantasy.DataStructure.Collection;
|
||
using Fantasy.Entitas.Interface;
|
||
using Fantasy.Helper;
|
||
#pragma warning disable CS8619 // Nullability of reference types in value doesn't match target type.
|
||
|
||
namespace Fantasy;
|
||
|
||
public class MailComponentDestroySystem : DestroySystem<MailComponent>
|
||
{
|
||
protected override void Destroy(MailComponent self)
|
||
{
|
||
foreach (var (_, mail) in self.Mails)
|
||
{
|
||
mail.Dispose();
|
||
}
|
||
|
||
self.Mails.Clear();
|
||
self.Timer.Clear();
|
||
}
|
||
}
|
||
|
||
public class MailComponentDeserializeSystem : DeserializeSystem<MailComponent>
|
||
{
|
||
protected override void Deserialize(MailComponent self)
|
||
{
|
||
self.Timer.Clear();
|
||
foreach (var (_, mail) in self.Mails)
|
||
{
|
||
self.Timer.Add(mail.ExpireTime, mail.Id);
|
||
}
|
||
}
|
||
}
|
||
|
||
public static class MailComponentSystem
|
||
{
|
||
public static async FTask Add(this MailComponent self, Mail mail, bool sync)
|
||
{
|
||
mail.CreateTime = TimeHelper.Now;
|
||
mail.ExpireTime = mail.CreateTime + MailComponent.MailExpireTime;
|
||
|
||
// 如果身上的邮件数量,大于了设置的最大数量怎么办?
|
||
// 先不用考虑,稍后咱们再解决问题。
|
||
if (self.Mails.Count >= MailComponent.MaxMailCount)
|
||
{
|
||
// 删除最老的邮件。
|
||
var (_, value) = self.Timer.First();
|
||
var removeId = value[0];
|
||
await self.Remove(removeId, MailRemoveActionType.Overtop, sync);
|
||
}
|
||
|
||
self.Mails.Add(mail.Id, mail);
|
||
self.Timer.Add(mail.ExpireTime, mail.Id);
|
||
|
||
if (sync)
|
||
{
|
||
// 同步邮件状态给客户端。
|
||
self.Scene.NetworkMessagingComponent.SendInnerRoute(self.GetParent<MailUnit>().GateRouteId, new Mail2C_HaveMail()
|
||
{
|
||
Mail = mail.ToMailSimplifyInfo()
|
||
});
|
||
}
|
||
|
||
// 这里的保存,也可以不用,这里看情况而定。
|
||
await self.Scene.World.DataBase.Save(self);
|
||
Log.Info($"MailComponentSystem Add {mail.Id} Count:{self.Mails.Count}");
|
||
}
|
||
|
||
public static async FTask<uint> Remove(this MailComponent self, long mailId, MailRemoveActionType mailRemoveActionType ,bool sync)
|
||
{
|
||
if (!self.Mails.Remove(mailId, out var mail))
|
||
{
|
||
// 这里的1代表的没有找到对应邮件。
|
||
return 1;
|
||
}
|
||
|
||
self.Timer.RemoveValue(mail.ExpireTime, mail.Id);
|
||
mail.Dispose();
|
||
|
||
if (sync)
|
||
{
|
||
// 同步给客户端,邮件删除的消息。
|
||
self.Scene.NetworkMessagingComponent.SendInnerRoute(self.GetParent<MailUnit>().GateRouteId,
|
||
new Mail2C_MailState()
|
||
{
|
||
MailState = (int)mailRemoveActionType, MailId = mailId
|
||
});
|
||
}
|
||
|
||
// 保存下数据库。
|
||
await self.Scene.World.DataBase.Save(self);
|
||
Log.Info($"MailComponentSystem Remove {mailId} mailRemoveActionType:{mailRemoveActionType} Count:{self.Mails.Count}");
|
||
return 0;
|
||
}
|
||
|
||
public static async FTask CheckTimeOut(this MailComponent self)
|
||
{
|
||
var now = TimeHelper.Now;
|
||
using var listPool = ListPool<long>.Create();
|
||
|
||
foreach (var (_, mail) in self.Mails)
|
||
{
|
||
if (mail.ExpireTime > now)
|
||
{
|
||
continue;
|
||
}
|
||
|
||
listPool.Add(mail.Id);
|
||
}
|
||
|
||
foreach (var mailId in listPool)
|
||
{
|
||
await self.Remove(mailId, MailRemoveActionType.ExpireTimeRemove,false);
|
||
}
|
||
|
||
Log.Info($"MailComponentSystem CheckTimeOut Count:{listPool.Count}");
|
||
}
|
||
|
||
public static async FTask<(uint ErrorCode, Mail mail)> OpenMail(this MailComponent self, long mailId)
|
||
{
|
||
if (!self.Mails.TryGetValue(mailId, out var mail))
|
||
{
|
||
// 这个1代表的是没有找到对应邮件
|
||
return (1, null);
|
||
}
|
||
|
||
if (mail.ExpireTime < TimeHelper.Now)
|
||
{
|
||
// 如果邮件已经过期了,需要清楚这个邮件。
|
||
await self.Remove(mailId, MailRemoveActionType.ExpireTimeRemove, true);
|
||
// 这里2代表的是邮件已经过期。
|
||
return (2, null);
|
||
}
|
||
|
||
mail.MailState = MailState.HaveRead;
|
||
// 这个保存数据库不是必须要保存的,因为一个邮件的查看状态并不能影响游戏的逻辑。
|
||
// 这里的话,大家看自己的需求而定。
|
||
await self.Scene.World.DataBase.Save(self);
|
||
return (0, mail);
|
||
}
|
||
|
||
public static void GetMailSimplifyInfos(this MailComponent self, ICollection<MailSimplifyInfo> mailSimplifyInfos)
|
||
{
|
||
foreach (var (_, mail) in self.Mails)
|
||
{
|
||
mailSimplifyInfos.Add(mail.ToMailSimplifyInfo());
|
||
}
|
||
}
|
||
|
||
public static void GetMailSimplifyInfos(this MailComponent self, ICollection<MailSimplifyInfo> mailSimplifyInfos, int pageIndex, int pageSize)
|
||
{
|
||
foreach (var (_, mail) in self.Mails.Skip((pageIndex -1) * pageSize).Take(pageSize))
|
||
{
|
||
mailSimplifyInfos.Add(mail.ToMailSimplifyInfo());
|
||
}
|
||
}
|
||
|
||
public static async FTask<uint> Receive(this MailComponent self, long mailId, bool money, List<long> item, bool sync)
|
||
{
|
||
if (!self.Mails.TryGetValue(mailId, out var mail))
|
||
{
|
||
// 这里的1代表是没有找到该邮件。
|
||
return 1;
|
||
}
|
||
|
||
var needSave = false;
|
||
|
||
if (money && mail.Money > 0)
|
||
{
|
||
// 领取金钱一般都是在玩家身上,但现在咱们所在的服务器是Mail服务器,玩家并不在这个服务器.
|
||
// 所以一般金钱的操作会有一个专用的接口来操作。这个接口无论在什么服务器上,都会正确的发送到用户所在的服务器上进行金钱操作。
|
||
// 假设下面的增加金钱的一个异步接口。
|
||
// var resposne = await MoneyHelper.Add(self.Scene, mail.Money, sync);
|
||
// if (resposne.ErrorCode != 0)
|
||
// {
|
||
// // 这里的2代表的是金钱添加失败。
|
||
// return 2;
|
||
// }
|
||
// 再假设增加金钱是成功的,那么咱们就要处理邮件相关信息了。
|
||
mail.Money = 0;
|
||
needSave = true;
|
||
}
|
||
|
||
if (item != null && item.Count > 0)
|
||
{
|
||
using var listItem = ListPool<Item>.Create();
|
||
foreach (var itemId in item)
|
||
{
|
||
var rItem = mail.Items.FirstOrDefault(d => d.Id == itemId);
|
||
if (rItem == null)
|
||
{
|
||
continue;
|
||
}
|
||
listItem.Add(rItem);
|
||
}
|
||
|
||
// 假设背包在其他服务器,需要调用某一个接口来添加物品到目标服务器的背包身上。
|
||
// var response = await BagHelper.Add(self.Scene, listItem, sync);
|
||
// if (response.ErrorCode != 0)
|
||
// {
|
||
// return 2;
|
||
// }
|
||
// 还有一种情况,就是背包里的空间只有一个空余位置了,也就是只能放进一个物品了,但是邮件领取的是2个物品.
|
||
// 会有下面2中情况,当然这个情况是要策划来决定怎么处理:
|
||
// 1、只领取一个物品到背包中,另外一个不领取,然后提示用户背包已满。
|
||
// 2、一个都不领取,直接提示用户背包已满。
|
||
// 如果是是第一种情况下,把BagHelper.Add接口,就需要返回添加成功的物品ID,方便邮件来处理。
|
||
// 假设全部物品都领取成功了,就可以执行下面的逻辑了。
|
||
|
||
foreach (var item1 in listItem)
|
||
{
|
||
mail.Items.Remove(item1);
|
||
item1.Dispose();
|
||
}
|
||
|
||
needSave = true;
|
||
}
|
||
|
||
if (needSave)
|
||
{
|
||
await self.Scene.World.DataBase.Save(self);
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
} |