提交修改
This commit is contained in:
74
Hotfix/Game/Item/Helper/ItemUseHelper.cs
Normal file
74
Hotfix/Game/Item/Helper/ItemUseHelper.cs
Normal file
@@ -0,0 +1,74 @@
|
||||
namespace NB.Game;
|
||||
|
||||
public static class ItemUseHelper
|
||||
{
|
||||
// public static uint UseBagItem(Account account, long itemId, int count)
|
||||
// {
|
||||
// return UseItem(account, ContainerType.Bag, itemId, count);
|
||||
// }
|
||||
//
|
||||
// public static uint CanUseBagItem(Account account, long itemId, int count, out Container container, out ItemConfig itemConfig, out ItemUseComponent itemUseComponent)
|
||||
// {
|
||||
// return CanUseItem(account, ContainerType.Bag, itemId, count, out container, out itemConfig, out itemUseComponent);
|
||||
// }
|
||||
//
|
||||
// public static uint UseItem(Account account, ContainerType containerType, long itemId, int count)
|
||||
// {
|
||||
// var errorCode = CanUseItem(account, containerType, itemId, count, out var container, out var itemConfig, out var itemUseComponent);
|
||||
//
|
||||
// if (errorCode != 0)
|
||||
// {
|
||||
// return errorCode;
|
||||
// }
|
||||
//
|
||||
// errorCode = container.RemoveItem(itemId, count, ItemReason.ItemUse, true);
|
||||
//
|
||||
// if (errorCode != 0)
|
||||
// {
|
||||
// return errorCode;
|
||||
// }
|
||||
//
|
||||
// itemUseComponent.Use(account, itemConfig, ref count);
|
||||
// return 0;
|
||||
// }
|
||||
//
|
||||
|
||||
// public static uint CanUseItem(Player account, long itemId, int count, out cfg.Item itemConfig,
|
||||
// out ItemUseComponent itemUseComponent)
|
||||
// {
|
||||
// itemConfig = null;
|
||||
// itemUseComponent = null;
|
||||
// var errorCode = ContainerHelper.TryGetContainer(account, containerType, out container);
|
||||
//
|
||||
// if (errorCode != 0)
|
||||
// {
|
||||
// return errorCode;
|
||||
// }
|
||||
//
|
||||
// if (!container.GetItemById(itemId, out var item))
|
||||
// {
|
||||
// // 这里是找不到该物品的错误码。
|
||||
// return 1;
|
||||
// }
|
||||
//
|
||||
// if (item.Count < count)
|
||||
// {
|
||||
// // 这里是物品数量不足的错误码。
|
||||
// return 2;
|
||||
// }
|
||||
//
|
||||
// itemConfig = item.Config;
|
||||
//
|
||||
// if (itemConfig.Params.Length <= 0)
|
||||
// {
|
||||
// // 这里是物品没有配置参数的错误码。
|
||||
// return 3;
|
||||
// }
|
||||
//
|
||||
// // 这里还可以增加一些其他的判定,比如物品是否过期,物品是否被锁定等。
|
||||
// // 甚至还有物品使用的CD。
|
||||
// // 使用物品效果来判定
|
||||
// itemUseComponent = account.Scene.GetComponent<ItemUseComponent>();
|
||||
// return itemUseComponent.CanUse(account, item.Config, ref count);
|
||||
// }
|
||||
}
|
||||
51
Hotfix/Game/Item/UseEffect/ItemUse_Drug_AddAttr.cs
Normal file
51
Hotfix/Game/Item/UseEffect/ItemUse_Drug_AddAttr.cs
Normal file
@@ -0,0 +1,51 @@
|
||||
using Fantasy;
|
||||
|
||||
namespace NB.Game;
|
||||
|
||||
[ItemUse(ItemUseEffect.AddAttr)]
|
||||
public class ItemUse_Drug_AddAttr : IItemUse
|
||||
{
|
||||
// public uint CanUse(Account account, ItemConfig config, ref int count)
|
||||
// {
|
||||
// if (config.Params.Length < 2)
|
||||
// {
|
||||
// Log.Error($"configId:{config.Id} config.Params.Length({config.Params.Length}) < 2");
|
||||
// return 1;
|
||||
// }
|
||||
//
|
||||
// Log.Debug($"CanUse 使用了药品增加属性 configId:{config.Id} count:{count}");
|
||||
// return 0;
|
||||
// }
|
||||
//
|
||||
// public void Use(Account account, ItemConfig config, ref int count)
|
||||
// {
|
||||
// for (int i = 0; i < config.Params.Length; i += 2)
|
||||
// {
|
||||
// var attrKey = config.Params[i];
|
||||
// var attrValue = config.Params[i + 1];
|
||||
// Log.Debug($"Use 使用了药品增加属性 configId:{config.Id} attrKey:{attrKey} attrValue:{attrValue}");
|
||||
// }
|
||||
// }
|
||||
public uint CanUse(Player player, cfg.Item config, ref int count)
|
||||
{
|
||||
// if (config.Params.Length < 2)
|
||||
// {
|
||||
// Log.Error($"configId:{config.Id} config.Params.Length({config.Params.Length}) < 2");
|
||||
// return 1;
|
||||
// }
|
||||
//
|
||||
Log.Debug($"CanUse 使用了药品增加属性 configId:{config.Id} count:{count}");
|
||||
return 0;
|
||||
}
|
||||
|
||||
public void Use(Player player, cfg.Item config, ref int count)
|
||||
{
|
||||
// for (int i = 0; i < config.Params.Length; i += 2)
|
||||
// {
|
||||
// var attrKey = config.Params[i];
|
||||
// var attrValue = config.Params[i + 1];
|
||||
// Log.Debug($"Use 使用了药品增加属性 configId:{config.Id} attrKey:{attrKey} attrValue:{attrValue}");
|
||||
// }
|
||||
Log.Debug($"Use 使用了药品增加属性 configId:{config.Id} count:{count}");
|
||||
}
|
||||
}
|
||||
18
Hotfix/Game/Item/UseEffect/ItemUse_Equip_Equip.cs
Normal file
18
Hotfix/Game/Item/UseEffect/ItemUse_Equip_Equip.cs
Normal file
@@ -0,0 +1,18 @@
|
||||
using Fantasy;
|
||||
|
||||
namespace NB.Game;
|
||||
|
||||
[ItemUse(ItemUseEffect.Equip)]
|
||||
public class ItemUse_Equip_Equip : IItemUse
|
||||
{
|
||||
public uint CanUse(Player player, cfg.Item config, ref int count)
|
||||
{
|
||||
Log.Debug($"CanUse 使用了装备装备到身上 configId:{config.Id} count:{count}");
|
||||
return 0;
|
||||
}
|
||||
|
||||
public void Use(Player player, cfg.Item config, ref int count)
|
||||
{
|
||||
Log.Debug($"Use 使用了装备装备到身上 configId:{config.Id} count:{count}");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
using Fantasy;
|
||||
using Fantasy.Async;
|
||||
using Fantasy.Network.Interface;
|
||||
using NBF;
|
||||
|
||||
namespace NB;
|
||||
|
||||
public class Other2Mail_SendRequestHandler : AddressRPC<Scene, Other2Mail_SendMailRequest, Mail2Other_SendMailResponse>
|
||||
{
|
||||
protected override async FTask Run(Scene scene, Other2Mail_SendMailRequest request, Mail2Other_SendMailResponse response, Action reply)
|
||||
{
|
||||
await MailHelper.Send(scene, request.MailBox);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
using Fantasy;
|
||||
using Fantasy.Async;
|
||||
using Fantasy.Network.Interface;
|
||||
using NB.Game;
|
||||
using NBF;
|
||||
|
||||
// ReSharper disable ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract
|
||||
|
||||
namespace NB;
|
||||
|
||||
public sealed class C2Mail_GetHaveMailRequestHandler : AddressRPC<Player, C2Mail_GetHaveMailRequest, Mail2C_GetHaveMailResposne>
|
||||
{
|
||||
protected override async FTask Run(Player mailUnit, C2Mail_GetHaveMailRequest request, Mail2C_GetHaveMailResposne response, Action reply)
|
||||
{
|
||||
var mailComponent = mailUnit.GetComponent<MailComponent>();
|
||||
|
||||
// 这个mailComponent是不是可能会为空?答案是可能的。
|
||||
// 那如果是空的怎么办呢,这样情况只能是别人恶意发包了。
|
||||
|
||||
if (mailComponent == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
// 检查是否有超时的邮件。如果有那就清楚掉
|
||||
await mailComponent.CheckTimeOut();
|
||||
// 领取当前的邮件
|
||||
mailComponent.GetMailSimplifyInfos(response.Mails);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
using Fantasy.Async;
|
||||
using Fantasy.Network.Interface;
|
||||
using NB;
|
||||
using NB.Game;
|
||||
using NBF;
|
||||
|
||||
namespace Fantasy;
|
||||
|
||||
public class C2Mail_OpenMailRequestHandler : AddressRPC<Player, C2Mail_OpenMailRequest, Mail2C_OpenMailResposne>
|
||||
{
|
||||
protected override async FTask Run(Player mailUnit, C2Mail_OpenMailRequest request, Mail2C_OpenMailResposne response, Action reply)
|
||||
{
|
||||
if (request.MailId <= 0)
|
||||
{
|
||||
response.ErrorCode = 100;
|
||||
return;
|
||||
}
|
||||
|
||||
// 根据这个MailId来拿到邮件的详细信息
|
||||
var (errorCode, mail) = await mailUnit.GetComponent<MailComponent>().OpenMail(request.MailId);
|
||||
|
||||
if (errorCode != 0)
|
||||
{
|
||||
response.ErrorCode = errorCode;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!request.ReturnMailInfo)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
response.MailInfo = mail.ToMailInfo();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
using Fantasy.Async;
|
||||
using Fantasy.Network.Interface;
|
||||
using NB;
|
||||
using NB.Game;
|
||||
using NBF;
|
||||
|
||||
namespace Fantasy;
|
||||
|
||||
public class C2Mail_ReceiveMailRequestHandler : AddressRPC<Player, C2Mail_ReceiveMailRequest, Mail2C_ReceiveMailResponse>
|
||||
{
|
||||
protected override async FTask Run(Player mailUnit, C2Mail_ReceiveMailRequest request, Mail2C_ReceiveMailResponse response, Action reply)
|
||||
{
|
||||
if (request.MailId <= 0)
|
||||
{
|
||||
response.ErrorCode = 100;
|
||||
return;
|
||||
}
|
||||
|
||||
response.ErrorCode = await mailUnit.GetComponent<MailComponent>()
|
||||
.Receive(request.MailId, request.Money, request.ItemId, true);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
using Fantasy.Async;
|
||||
using Fantasy.Network.Interface;
|
||||
using NB;
|
||||
using NB.Game;
|
||||
using NBF;
|
||||
|
||||
namespace Fantasy;
|
||||
|
||||
public class C2Mail_RemoveMailRequestHandler : AddressRPC<Player,C2Mail_RemoveMailRequest, Mail2C_RemoveMailResponse>
|
||||
{
|
||||
protected override async FTask Run(Player mailUnit, C2Mail_RemoveMailRequest request, Mail2C_RemoveMailResponse response, Action reply)
|
||||
{
|
||||
if (request.MailId <= 0)
|
||||
{
|
||||
// 这里的1代表MailId不正确。
|
||||
response.ErrorCode = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
response.ErrorCode = await mailUnit.GetComponent<MailComponent>()
|
||||
.Remove(request.MailId, MailRemoveActionType.Remove, true);
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
using Fantasy.Async;
|
||||
using Fantasy.DataStructure.Collection;
|
||||
using Fantasy.Network.Interface;
|
||||
using NB;
|
||||
using NB.Game;
|
||||
using NBF;
|
||||
|
||||
namespace Fantasy;
|
||||
|
||||
public class C2Mail_SendMailRequestHandler : AddressRPC<Player, C2Mail_SendMailRequest, Mail2C_SendMailResponse>
|
||||
{
|
||||
protected override async FTask Run(Player mailUnit, C2Mail_SendMailRequest request,
|
||||
Mail2C_SendMailResponse response, Action reply)
|
||||
{
|
||||
if (request.UserId < 1)
|
||||
{
|
||||
// 这里的1代表的是发送的接收玩家名字不正确。
|
||||
response.ErrorCode = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(request.Title) || string.IsNullOrEmpty(request.Content))
|
||||
{
|
||||
// 这里的2代表的是发送的邮件标题或者内容不正确。
|
||||
response.ErrorCode = 2;
|
||||
return;
|
||||
}
|
||||
|
||||
if (request.ItemId.Count > 10)
|
||||
{
|
||||
// 这里的3代表的是发送的邮件附件超出了最大范围。
|
||||
response.ErrorCode = 3;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!mailUnit.Scene.GetComponent<PlayerManageComponent>().TryGet(request.UserId, out var receiveMailUnit))
|
||||
{
|
||||
// 这里的4代表的是没有该玩家。
|
||||
response.ErrorCode = 4;
|
||||
return;
|
||||
}
|
||||
|
||||
if (request.Money > 0)
|
||||
{
|
||||
// 如果大于0,就要调用某一个接口去货币所在的服务器上面去扣除玩家的钱。
|
||||
// var moneyResposne = await MoneyHelper.Cost(mailUnit.Scene, request.Money);
|
||||
// if (moneyResposne.ErrorCode != 0)
|
||||
// {
|
||||
// response.ErrorCode = moneyResposne.ErrorCode;
|
||||
// return;
|
||||
// }
|
||||
}
|
||||
|
||||
using var mailItems = ListPool<Item>.Create();
|
||||
if (request.ItemId.Count > 0)
|
||||
{
|
||||
// var itemResposne = await BagHelper.Get(mailUnit.Scene, request.ItemId);
|
||||
// if (itemResposne.ErrorCode != 0)
|
||||
// {
|
||||
// response.ErrorCode = itemResposne.ErrorCode;
|
||||
// return;
|
||||
// }
|
||||
// mailItems.AddRange(itemResposne.Items);
|
||||
}
|
||||
|
||||
var accountId = ListPool<long>.Create(receiveMailUnit.Id);
|
||||
var mail = MailFactory.Create(mailUnit.Scene, MailType.User, request.Title, request.Content, request.Money,
|
||||
mailItems);
|
||||
var mailBox = MailBoxFactory.Create(mailUnit.Scene, MailBoxType.Specify, mailUnit.Id, mail,
|
||||
1000 * 60 * 60, accountId);
|
||||
await MailHelper.Send(mailUnit.Scene, mailBox);
|
||||
}
|
||||
}
|
||||
22
Hotfix/Game/Mail/Handler/Outer/C2Mail_TestRequestHandler.cs
Normal file
22
Hotfix/Game/Mail/Handler/Outer/C2Mail_TestRequestHandler.cs
Normal file
@@ -0,0 +1,22 @@
|
||||
using Fantasy.Async;
|
||||
using Fantasy.DataStructure.Collection;
|
||||
using Fantasy.Network.Interface;
|
||||
using NB;
|
||||
using NB.Game;
|
||||
using NBF;
|
||||
|
||||
namespace Fantasy;
|
||||
|
||||
public class C2Mail_TestRequestHandler : AddressRPC<Player, C2Mail_TestRequest, Mail2C_TestResponse>
|
||||
{
|
||||
protected override async FTask Run(Player mailUnit, C2Mail_TestRequest request, Mail2C_TestResponse response, Action reply)
|
||||
{
|
||||
Log.Debug($"这是一个测试的自定义消息协议 Tag:{mailUnit.Id}");
|
||||
response.Tag = "666";
|
||||
// using var accountId = ListPool<long>.Create(65491190472245249);
|
||||
var mail = MailFactory.Create(mailUnit.Scene, MailType.System, "测试所有人指定日期玩家邮件", "测试所有人指定日期玩家邮件内容", 9991);
|
||||
var mailBox = MailBoxFactory.Create(mailUnit.Scene, MailBoxType.AllToDate, mailUnit.Id, mail,
|
||||
1000 * 60 * 60);
|
||||
await MailHelper.Send(mailUnit.Scene, mailBox);
|
||||
}
|
||||
}
|
||||
65
Hotfix/Game/Mail/Helper/MailBoxFactory.cs
Normal file
65
Hotfix/Game/Mail/Helper/MailBoxFactory.cs
Normal file
@@ -0,0 +1,65 @@
|
||||
using Fantasy;
|
||||
using Fantasy.Entitas;
|
||||
using Fantasy.Helper;
|
||||
using NB;
|
||||
using NB.Game;
|
||||
|
||||
namespace NBF;
|
||||
|
||||
public static class MailBoxFactory
|
||||
{
|
||||
/// <summary>
|
||||
/// 创建一个邮件箱
|
||||
/// </summary>
|
||||
/// <param name="scene"></param>
|
||||
/// <param name="mailBoxType"></param>
|
||||
/// <param name="sendAccountId"></param>
|
||||
/// <param name="mail"></param>
|
||||
/// <param name="expireTime"></param>
|
||||
/// <param name="accountId"></param>
|
||||
/// <returns></returns>
|
||||
public static MailBox Create(Scene scene, MailBoxType mailBoxType, long sendAccountId, Mail mail, int expireTime,
|
||||
List<long> accountId = null)
|
||||
{
|
||||
var mailBox = Entity.Create<MailBox>(scene, true, true);
|
||||
mailBox.SendAccountId = sendAccountId;
|
||||
mailBox.Mail = mail;
|
||||
mailBox.MailBoxType = mailBoxType;
|
||||
mailBox.CreateTime = TimeHelper.Now;
|
||||
mailBox.ExpireTime = mailBox.CreateTime + expireTime;
|
||||
|
||||
if (accountId == null || accountId.Count <= 0)
|
||||
{
|
||||
return mailBox;
|
||||
}
|
||||
|
||||
foreach (var raId in accountId)
|
||||
{
|
||||
mailBox.AccountId.Add(raId);
|
||||
}
|
||||
|
||||
return mailBox;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建一个邮件箱
|
||||
/// </summary>
|
||||
/// <param name="scene"></param>
|
||||
/// <param name="mailType"></param>
|
||||
/// <param name="mailBoxType"></param>
|
||||
/// <param name="title"></param>
|
||||
/// <param name="content"></param>
|
||||
/// <param name="money"></param>
|
||||
/// <param name="items"></param>
|
||||
/// <param name="sendAccountId"></param>
|
||||
/// <param name="expireTime"></param>
|
||||
/// <param name="accountId"></param>
|
||||
/// <returns></returns>
|
||||
public static MailBox Create(Scene scene, MailType mailType, MailBoxType mailBoxType, string title, string content,
|
||||
int money, List<Item> items,
|
||||
long sendAccountId, int expireTime, List<long> accountId = null)
|
||||
{
|
||||
var mail = MailFactory.Create(scene, mailType, title, content, money, items);
|
||||
return Create(scene, mailBoxType, sendAccountId, mail, expireTime, accountId);
|
||||
}
|
||||
}
|
||||
45
Hotfix/Game/Mail/Helper/MailFactory.cs
Normal file
45
Hotfix/Game/Mail/Helper/MailFactory.cs
Normal file
@@ -0,0 +1,45 @@
|
||||
using Fantasy;
|
||||
using Fantasy.Entitas;
|
||||
using Fantasy.Serialize;
|
||||
using NB;
|
||||
using NB.Game;
|
||||
|
||||
namespace NBF;
|
||||
|
||||
public static class MailFactory
|
||||
{
|
||||
/// <summary>
|
||||
/// 创建一个基础的邮件
|
||||
/// </summary>
|
||||
/// <param name="scene"></param>
|
||||
/// <param name="title"></param>
|
||||
/// <param name="content"></param>
|
||||
/// <param name="money"></param>
|
||||
/// <param name="items"></param>
|
||||
/// <param name="mailType"></param>
|
||||
/// <returns></returns>
|
||||
public static Mail Create(Scene scene, MailType mailType, string title, string content, int money = 0,
|
||||
List<Item> items = null)
|
||||
{
|
||||
var mail = Entity.Create<Mail>(scene, true, true);
|
||||
mail.Title = title;
|
||||
mail.Content = content;
|
||||
mail.Money = money;
|
||||
mail.MailType = mailType;
|
||||
mail.MailState = MailState.Unread;
|
||||
|
||||
|
||||
if (items != null && items.Count > 0)
|
||||
{
|
||||
foreach (var item in items)
|
||||
{
|
||||
// 最好的是要个这个Item给克隆出一份来。
|
||||
// 这样就可以保证,无论外面怎么改变也不会影响这个邮件的东西了。
|
||||
var cloneItem = SerializerManager.BsonPack.CloneEntity(item);
|
||||
mail.Items.Add(cloneItem);
|
||||
}
|
||||
}
|
||||
|
||||
return mail;
|
||||
}
|
||||
}
|
||||
205
Hotfix/Game/Mail/Helper/MailHelper.cs
Normal file
205
Hotfix/Game/Mail/Helper/MailHelper.cs
Normal file
@@ -0,0 +1,205 @@
|
||||
using Fantasy;
|
||||
using Fantasy.Async;
|
||||
using Fantasy.DataStructure.Collection;
|
||||
using Fantasy.Platform.Net;
|
||||
using Fantasy.Serialize;
|
||||
using NB;
|
||||
using NB.Game;
|
||||
|
||||
namespace NBF;
|
||||
|
||||
/// <summary>
|
||||
/// 发送邮件的唯一接口
|
||||
/// 如果不是通过这个接口发送的邮件、出现任何问题,后果自负
|
||||
/// </summary>
|
||||
public static class MailHelper
|
||||
{
|
||||
/// <summary>
|
||||
/// 发送邮件
|
||||
/// </summary>
|
||||
/// <param name="scene"></param>
|
||||
/// <param name="mailBox">发送完成后,记着一定要销毁这个MailBox,不然会有GC。</param>
|
||||
public static async FTask Send(Scene scene, MailBox mailBox)
|
||||
{
|
||||
if (scene.SceneType == SceneType.Game)
|
||||
{
|
||||
await InnerSend(scene, mailBox);
|
||||
return;
|
||||
}
|
||||
|
||||
// 如果不在同一个Scene下,就需要发送内部的网络消息给这个Scene了
|
||||
var mailSceneConfig = SceneConfigData.Instance.GetSceneBySceneType(SceneType.Game)[0];
|
||||
// await scene.NetworkMessagingComponent.CallInnerRoute(mailSceneConfig.RouteId, new Other2Mail_SendMailRequest()
|
||||
// {
|
||||
// MailBox = mailBox
|
||||
// });
|
||||
scene.NetworkMessagingComponent.Send(mailSceneConfig.Address, new Other2Mail_SendMailRequest()
|
||||
{
|
||||
MailBox = mailBox
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 发送邮件
|
||||
/// </summary>
|
||||
/// <param name="scene"></param>
|
||||
/// <param name="mailBox"></param>
|
||||
/// <returns></returns>
|
||||
private static async FTask InnerSend(Scene scene, MailBox mailBox)
|
||||
{
|
||||
// 现在的情况,这个接口只能是在Mail这个服务器下可以操作
|
||||
// 但是真实的情况,其他同时开发的逻辑,调用这个接口一般都是在其他的服务器。
|
||||
// 这个问题其实很好解决,只需要判定当前Scene不是Mail、那就做一个协议,自动发送到这个MailScene就可以了。
|
||||
|
||||
if (mailBox.MailBoxType == MailBoxType.None)
|
||||
{
|
||||
Log.Error("MailBoxType MailBoxType.None not support!");
|
||||
return;
|
||||
}
|
||||
|
||||
var playerManageComponent = scene.GetComponent<PlayerManageComponent>();
|
||||
var mailBoxManageComponent = scene.GetComponent<MailBoxManageComponent>();
|
||||
mailBoxManageComponent.MailBoxes.Add(mailBox.Id, mailBox);
|
||||
|
||||
switch (mailBox.MailBoxType)
|
||||
{
|
||||
case MailBoxType.Specify:
|
||||
{
|
||||
if (mailBox.AccountId.Count <= 0)
|
||||
{
|
||||
Log.Error($"{mailBox.Id} AccountId is 0!");
|
||||
return;
|
||||
}
|
||||
|
||||
// 这里可能有几种情况
|
||||
// 1、AccountId里面可能只有一个人。
|
||||
// 2、AccountId里面有多个人。
|
||||
|
||||
using var sendAccountIds = ListPool<long>.Create();
|
||||
|
||||
foreach (var accountId in mailBox.AccountId)
|
||||
{
|
||||
if (!playerManageComponent.TryGet(accountId, out var mailUnit))
|
||||
{
|
||||
// 如果没有的话,代表这个用户根本不存在。
|
||||
// 那这样的情况就不需要做任何处理。
|
||||
continue;
|
||||
}
|
||||
|
||||
// 如果有的话,那么就给这个用户发送邮件。
|
||||
// 这个玩家是否在线?
|
||||
var mailComponent = mailUnit.GetComponent<MailComponent>();
|
||||
// 在线的话,就直接发送邮件给这个玩家就可以了。
|
||||
if (mailComponent != null)
|
||||
{
|
||||
await mailComponent.Add(SerializerManager.BsonPack.CloneEntity(mailBox.Mail), true);
|
||||
sendAccountIds.Add(accountId);
|
||||
}
|
||||
else
|
||||
{
|
||||
// 不在线
|
||||
// 首先
|
||||
// 1、如果玩家不在线,那就把这个邮件在数据库中拿出来,然后把邮件插入到玩家的邮件列表里。然后再保存
|
||||
// 这样的做法是不推荐的,因为咱们游戏所有的东西都是有状态的,但是你拿出来的邮件是没有状态的。这样可能会导致一些问题的出现。
|
||||
// 正确的做做法:
|
||||
// 把这个邮件方法一个地方,比如是一个处理中心,当玩家上线的时候,主动去这个中心领取这个邮件。
|
||||
// 快递驿站、菜鸟、
|
||||
mailBoxManageComponent.MailsByAccount.Add(accountId, mailBox);
|
||||
Log.Debug("发送离线邮件成功,用户上线第一时间会领取这个邮件。");
|
||||
}
|
||||
}
|
||||
|
||||
// 移除掉发送成功的账号。
|
||||
|
||||
foreach (var sendAccountId in sendAccountIds)
|
||||
{
|
||||
mailBox.AccountId.Remove(sendAccountId);
|
||||
}
|
||||
|
||||
// 如果没有任何收件人了、就可以把这个邮箱给删除了。
|
||||
|
||||
if (mailBox.AccountId.Count <= 0)
|
||||
{
|
||||
mailBox.Dispose();
|
||||
}
|
||||
else
|
||||
{
|
||||
// 当这个邮件箱还有没有接收的玩家时候,要保存到数据库中,方便下次停服维护再重新启动的时候,加载这个邮件箱。
|
||||
await scene.World.Database.Save(mailBox);
|
||||
Log.Debug("保存离线邮件成功");
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case MailBoxType.Online:
|
||||
{
|
||||
// // 这里有个问题,如何知道在线的人呢?
|
||||
// foreach (var (_, mailUnit) in mailUnitManageComponent.UnitByAccountId)
|
||||
// {
|
||||
// var mailComponent = mailUnit.GetComponent<MailComponent>();
|
||||
// if (mailComponent == null)
|
||||
// {
|
||||
// continue;
|
||||
// }
|
||||
// // 能指定到这里的都是在线的玩家。
|
||||
// await mailComponent.Add(MailFactory.Serializer.Clone(mailBox.Mail), true);
|
||||
// }
|
||||
try
|
||||
{
|
||||
foreach (var (_, mailUnit) in playerManageComponent.Players)
|
||||
{
|
||||
await mailUnit.GetComponent<MailComponent>()
|
||||
.Add(SerializerManager.BsonPack.CloneEntity(mailBox.Mail), true);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
mailBox.Dispose();
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case MailBoxType.All:
|
||||
{
|
||||
// 要保证这个邮件一定要有一个生命周期。并且这个周期一定要短,如果是想要实现永久的,可以比如30天发送一次。
|
||||
mailBoxManageComponent.MailsByMailBoxType.Add((int)MailBoxType.All, mailBox);
|
||||
// 首先给所有在线的玩家发送。
|
||||
foreach (var (_, mailUnit) in playerManageComponent.Players)
|
||||
{
|
||||
await mailUnit.GetComponent<MailComponent>()
|
||||
.Add(SerializerManager.BsonPack.CloneEntity(mailBox.Mail), true);
|
||||
// 在邮件盒子中记录下玩家领取的记录,避免重复领取。
|
||||
mailBox.Received.Add(mailUnit.Id);
|
||||
}
|
||||
|
||||
// 保存邮件箱到数据库。
|
||||
await scene.World.Database.Save(mailBox);
|
||||
break;
|
||||
}
|
||||
case MailBoxType.AllToDate:
|
||||
{
|
||||
mailBoxManageComponent.MailsByMailBoxType.Add((int)MailBoxType.AllToDate, mailBox);
|
||||
foreach (var (_, player) in playerManageComponent.Players)
|
||||
{
|
||||
if (player.CreateTime > mailBox.CreateTime)
|
||||
{
|
||||
// 如果执行到这里,表示这里用户是这个邮件创建之后的用户。这个就不要发送了
|
||||
continue;
|
||||
}
|
||||
|
||||
// 所以这个邮件类型的逻辑就是,给当前邮件创建时间之前的玩家发送。
|
||||
await player.GetComponent<MailComponent>()
|
||||
.Add(SerializerManager.BsonPack.CloneEntity(mailBox.Mail), true);
|
||||
// 在邮件盒子中记录下玩家领取的记录,避免重复领取。
|
||||
mailBox.Received.Add(player.Id);
|
||||
}
|
||||
|
||||
// 保存邮件箱到数据库。
|
||||
await scene.World.Database.Save(mailBox);
|
||||
break;
|
||||
}
|
||||
// 根据玩家等级、等等这样的邮件箱类型,都可以自行扩展了
|
||||
// 课下作业、自己实现一个起来类型的邮箱。
|
||||
}
|
||||
}
|
||||
}
|
||||
230
Hotfix/Game/Mail/System/MailBoxManageComponentSystem.cs
Normal file
230
Hotfix/Game/Mail/System/MailBoxManageComponentSystem.cs
Normal file
@@ -0,0 +1,230 @@
|
||||
using Fantasy;
|
||||
using Fantasy.Async;
|
||||
using Fantasy.DataStructure.Collection;
|
||||
using Fantasy.Entitas.Interface;
|
||||
using Fantasy.Helper;
|
||||
using Fantasy.Serialize;
|
||||
using NB;
|
||||
using NB.Game;
|
||||
|
||||
namespace NBF;
|
||||
|
||||
|
||||
public class MailBoxManageComponentDestroySystem : DestroySystem<MailBoxManageComponent>
|
||||
{
|
||||
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<MailBox>(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<MailBox>(mailBoxId);
|
||||
// 销毁这个MailBox
|
||||
mailBox.Dispose();
|
||||
}
|
||||
|
||||
public static async FTask GetHaveMail(this MailBoxManageComponent self, Player mailUnit, bool sync)
|
||||
{
|
||||
var now = TimeHelper.Now;
|
||||
var worldDataBase = self.Scene.World.Database;
|
||||
var mailComponent = mailUnit.GetComponent<MailComponent>();
|
||||
|
||||
// 玩家领取范围邮件的逻辑处理
|
||||
|
||||
foreach (var (mailBoxType, mailBoxList) in self.MailsByMailBoxType)
|
||||
{
|
||||
using var removeMailBox = ListPool<MailBox>.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<MailComponent>().Add(SerializerManager.BsonPack.CloneEntity(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<MailComponent>().Add(SerializerManager.BsonPack.CloneEntity(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.Id, out var mailBoxes))
|
||||
{
|
||||
using var removeMailBox = ListPool<MailBox>.Create();
|
||||
foreach (var mailBox in mailBoxes)
|
||||
{
|
||||
var cloneMail = SerializerManager.BsonPack.CloneEntity(mailBox.Mail);
|
||||
await mailComponent.Add(cloneMail, sync);
|
||||
mailBox.AccountId.Remove(mailUnit.Id);
|
||||
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.Remove(mailUnit.Id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,8 @@
|
||||
using Fantasy.Entitas.Interface;
|
||||
using Fantasy;
|
||||
using Fantasy.Entitas.Interface;
|
||||
using NB;
|
||||
|
||||
namespace NB.Chat;
|
||||
namespace NBF;
|
||||
|
||||
public class MailBoxDestroySystem : DestroySystem<MailBox>
|
||||
{
|
||||
@@ -12,7 +14,7 @@ public class MailBoxDestroySystem : DestroySystem<MailBox>
|
||||
self.Mail = null;
|
||||
}
|
||||
|
||||
self.BoxType = MailBoxType.None;
|
||||
self.MailBoxType = MailBoxType.None;
|
||||
self.CreateTime = 0;
|
||||
self.ExpireTime = 0;
|
||||
self.SendAccountId = 0;
|
||||
234
Hotfix/Game/Mail/System/MailComponentSystem.cs
Normal file
234
Hotfix/Game/Mail/System/MailComponentSystem.cs
Normal file
@@ -0,0 +1,234 @@
|
||||
using Fantasy;
|
||||
using Fantasy.Async;
|
||||
using Fantasy.DataStructure.Collection;
|
||||
using Fantasy.Entitas.Interface;
|
||||
using Fantasy.Helper;
|
||||
using NB;
|
||||
using NB.Game;
|
||||
|
||||
namespace NBF;
|
||||
|
||||
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.Send(self.GetParent<Player>().SessionRunTimeId,
|
||||
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.Send(self.GetParent<Player>().SessionRunTimeId,
|
||||
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;
|
||||
}
|
||||
}
|
||||
77
Hotfix/Game/Mail/System/MailSystem.cs
Normal file
77
Hotfix/Game/Mail/System/MailSystem.cs
Normal file
@@ -0,0 +1,77 @@
|
||||
using Fantasy;
|
||||
using Fantasy.Entitas.Interface;
|
||||
using NB;
|
||||
|
||||
namespace NBF;
|
||||
|
||||
|
||||
public sealed class MailDestroySystem : DestroySystem<Mail>
|
||||
{
|
||||
protected override void Destroy(Mail self)
|
||||
{
|
||||
self.OwnerId = 0;
|
||||
self.Title = null;
|
||||
self.Content = null;
|
||||
self.CreateTime = 0;
|
||||
self.ExpireTime = 0;
|
||||
self.Money = 0;
|
||||
self.MailState = MailState.None;
|
||||
self.MailType = MailType.None;
|
||||
|
||||
foreach (var selfItem in self.Items)
|
||||
{
|
||||
selfItem.Dispose();
|
||||
}
|
||||
|
||||
self.Items.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
public static class MailSystem
|
||||
{
|
||||
public static MailSimplifyInfo ToMailSimplifyInfo(this Mail self)
|
||||
{
|
||||
return new MailSimplifyInfo()
|
||||
{
|
||||
MailId = self.Id,
|
||||
OwnerId = self.OwnerId,
|
||||
Title = self.Title,
|
||||
Content = self.Content,
|
||||
CreateTime = self.CreateTime,
|
||||
ExpireTime = self.ExpireTime,
|
||||
MailState = (int)self.MailState,
|
||||
MailType = (int)self.MailType
|
||||
};
|
||||
}
|
||||
|
||||
public static MailInfo ToMailInfo(this Mail self)
|
||||
{
|
||||
var mailInfo = new MailInfo()
|
||||
{
|
||||
MailId = self.Id,
|
||||
OwnerId = self.OwnerId,
|
||||
Title = self.Title,
|
||||
Content = self.Content,
|
||||
CreateTime = self.CreateTime,
|
||||
ExpireTime = self.ExpireTime,
|
||||
Money = self.Money,
|
||||
MailState = (int)self.MailState,
|
||||
MailType = (int)self.MailType
|
||||
};
|
||||
|
||||
foreach (var selfItem in self.Items)
|
||||
{
|
||||
mailInfo.Items.Add(new ItemInfo()
|
||||
{
|
||||
Id = selfItem.Id,
|
||||
ConfigId = selfItem.ConfigId,
|
||||
Count = selfItem.Count,
|
||||
ExpirationTime = selfItem.ExpirationTime,
|
||||
GetTime = selfItem.GetTime,
|
||||
Abrasion = selfItem.Abrasion
|
||||
});
|
||||
}
|
||||
|
||||
return mailInfo;
|
||||
}
|
||||
}
|
||||
@@ -42,7 +42,6 @@ public static class RoomManageComponentSystem
|
||||
return null;
|
||||
}
|
||||
|
||||
// roomManageComponent.on
|
||||
var room = Entity.Create<MapRoom>(self.Scene, true, true);
|
||||
room.Owner = ownerId;
|
||||
room.RoomId = roomId;
|
||||
|
||||
@@ -91,7 +91,7 @@ public static class PlayerManageComponentSystem
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// account.Statistics.LoginTime = TimeHelper.Now;
|
||||
// account.SetTestData();
|
||||
|
||||
@@ -157,6 +157,7 @@ public static class PlayerManageComponentSystem
|
||||
player.Country = "cn";
|
||||
player.Exp = 999;
|
||||
player.Head = "xxx.png";
|
||||
player.CreateTime = TimeHelper.Now;
|
||||
|
||||
// var list = InitConfig.GetList();
|
||||
var list = Configs.Tables.TbInitItemConfig.DataList;
|
||||
|
||||
@@ -5,6 +5,7 @@ using Fantasy.Async;
|
||||
using Fantasy.Entitas;
|
||||
using Fantasy.Entitas.Interface;
|
||||
using Fantasy.Helper;
|
||||
using NB.Chat;
|
||||
|
||||
#pragma warning disable CS8625 // 无法将 null 字面量转换为非 null 的引用类型。
|
||||
|
||||
@@ -31,6 +32,16 @@ public sealed class PlayerDestroySystem : DestroySystem<Player>
|
||||
// self.Statistics.Dispose();
|
||||
// self.Statistics = null;
|
||||
|
||||
// 退出当前ChatUnit拥有的所有频道
|
||||
foreach (var (_, chatChannelComponent) in self.Channels)
|
||||
{
|
||||
chatChannelComponent.ExitChannel(self.Id, false);
|
||||
}
|
||||
|
||||
// 理论情况下,这个self.Channels不会存在因为数据的,因为上面已经给清空掉了。
|
||||
// 但是self.Channels.Clear();还是加上吧,防止以后忘记了。
|
||||
self.Channels.Clear();
|
||||
|
||||
self.SessionRunTimeId = 0;
|
||||
}
|
||||
}
|
||||
@@ -47,7 +58,6 @@ public static class PlayerSystem
|
||||
/// <param name="items"></param>
|
||||
public static async FTask AddItems(this Player self, Dictionary<int, int> items)
|
||||
{
|
||||
|
||||
var itemContainer = self.GetComponent<PlayerItemContainerComponent>();
|
||||
HashSet<ItemBasicType> addType = new HashSet<ItemBasicType>();
|
||||
foreach (var (key, value) in items)
|
||||
@@ -64,7 +74,7 @@ public static class PlayerSystem
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
public static MapUnitInfo ToMapUnitInfo(this Player self)
|
||||
{
|
||||
var ret = new MapUnitInfo()
|
||||
@@ -79,11 +89,11 @@ public static class PlayerSystem
|
||||
ret.Position.x = mapUnit.Position.x;
|
||||
ret.Position.y = mapUnit.Position.y;
|
||||
ret.Position.z = mapUnit.Position.z;
|
||||
|
||||
|
||||
ret.Rotation.x = mapUnit.Rotation.x;
|
||||
ret.Rotation.y = mapUnit.Rotation.y;
|
||||
ret.Rotation.z = mapUnit.Rotation.z;
|
||||
|
||||
|
||||
// ret.Gears
|
||||
|
||||
return ret;
|
||||
|
||||
@@ -1,46 +0,0 @@
|
||||
using System;
|
||||
using Fantasy;
|
||||
using Fantasy.Async;
|
||||
using Fantasy.Network.Interface;
|
||||
using NB.Game;
|
||||
|
||||
namespace NB.Chat;
|
||||
|
||||
public class C2Game_DeleteMailRequestHandler : AddressRPC<Player, C2Game_DeleteMailRequest, Game2C_DeleteMailResponse>
|
||||
{
|
||||
protected override async FTask Run(Player entity, C2Game_DeleteMailRequest request,
|
||||
Game2C_DeleteMailResponse response, Action reply)
|
||||
{
|
||||
if (request.Id < 1)
|
||||
{
|
||||
response.ErrorCode = ErrorCode.ErrArgs;
|
||||
return;
|
||||
}
|
||||
|
||||
var mailManageComponent = entity.Scene.GetComponent<MailManageComponent>();
|
||||
if (mailManageComponent == null)
|
||||
{
|
||||
Log.Error("组件不存在 MailManageComponent");
|
||||
response.ErrorCode = ErrorCode.ErrServer;
|
||||
return;
|
||||
}
|
||||
|
||||
var conversation = await mailManageComponent.GetConversation(entity.Id, request.Id);
|
||||
if (conversation == null)
|
||||
{
|
||||
response.ErrorCode = ErrorCode.ErrArgs;
|
||||
return;
|
||||
}
|
||||
|
||||
conversation.RemoveId.Add(entity.Id);
|
||||
if (conversation.RemoveId.Count > 1)
|
||||
{
|
||||
//都删除了,则吧会话直接移除掉
|
||||
await mailManageComponent.DeleteConversation(entity.Id, request.Id);
|
||||
}
|
||||
else
|
||||
{
|
||||
await conversation.Save();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using Fantasy;
|
||||
using Fantasy.Async;
|
||||
using Fantasy.Network.Interface;
|
||||
using NB.Game;
|
||||
|
||||
namespace NB.Chat;
|
||||
|
||||
public class
|
||||
C2Game_GetConversationsRequestHandler : AddressRPC<Player, C2Game_GetConversationsRequest, Game2C_GetConversationsResponse>
|
||||
{
|
||||
protected override async FTask Run(Player entity, C2Game_GetConversationsRequest request,
|
||||
Game2C_GetConversationsResponse response, Action reply)
|
||||
{
|
||||
Stopwatch stopwatch = new Stopwatch();
|
||||
stopwatch.Start();
|
||||
var mailManageComponent = entity.Scene.GetComponent<MailManageComponent>();
|
||||
var list = await mailManageComponent.GetConversations(entity.Id);
|
||||
response.List = await list.ToInfo(entity.Scene, entity.Id);
|
||||
stopwatch.Stop();
|
||||
Log.Info($"查询会话列表耗时={stopwatch.ElapsedMilliseconds}");
|
||||
}
|
||||
}
|
||||
@@ -1,70 +0,0 @@
|
||||
using System;
|
||||
using Fantasy;
|
||||
using Fantasy.Async;
|
||||
using Fantasy.Network.Interface;
|
||||
using NB.Game;
|
||||
|
||||
namespace NB.Chat;
|
||||
|
||||
public class C2Game_SendMailRequestHandler : AddressRPC<Player, C2Game_SendMailRequest, Game2C_SendMailResponse>
|
||||
{
|
||||
protected override async FTask Run(Player entity, C2Game_SendMailRequest request, Game2C_SendMailResponse response,
|
||||
Action reply)
|
||||
{
|
||||
if (request.Target < 1)
|
||||
{
|
||||
response.ErrorCode = ErrorCode.ErrArgs;
|
||||
return;
|
||||
}
|
||||
|
||||
var mailManageComponent = entity.Scene.GetComponent<MailManageComponent>();
|
||||
if (mailManageComponent == null)
|
||||
{
|
||||
Log.Error("组件不存在 MailManageComponent");
|
||||
response.ErrorCode = ErrorCode.ErrServer;
|
||||
return;
|
||||
}
|
||||
|
||||
var chatUnitManage = entity.Scene.GetComponent<PlayerManageComponent>();
|
||||
if (chatUnitManage == null)
|
||||
{
|
||||
Log.Error("组件不存在 SocialUnitManageComponent");
|
||||
response.ErrorCode = ErrorCode.ErrServer;
|
||||
return;
|
||||
}
|
||||
|
||||
var conversation = await mailManageComponent.GetConversation(entity.Id, request.Target);
|
||||
if (conversation == null)
|
||||
{
|
||||
response.ErrorCode = ErrorCode.ErrArgs;
|
||||
return;
|
||||
}
|
||||
//检查是否可以发消息,如果会话只有一句,则不允许再发
|
||||
if (!conversation.CanSend(entity.Id))
|
||||
{
|
||||
response.ErrorCode = ErrorCode.MailNotReply;
|
||||
return;
|
||||
}
|
||||
|
||||
var mail = MailFactory.Create(entity.Scene, request.Content);
|
||||
mail.Sender = entity.Id;
|
||||
mail.OwnerId = request.Target;
|
||||
await conversation.Add(mail);
|
||||
|
||||
var res = new Game2C_HaveMail()
|
||||
{
|
||||
Mail = mail.ToMailInfo(),
|
||||
Key = conversation.Key
|
||||
};
|
||||
//同步客户端
|
||||
entity.Scene.NetworkMessagingComponent.Send(entity.SessionRunTimeId, res);
|
||||
|
||||
// var chatUnit = chatUnitManage.Get(request.Target);
|
||||
//
|
||||
// if (chatUnit != null)
|
||||
// {
|
||||
// //对方在线
|
||||
// entity.Scene.NetworkMessagingComponent.Send(chatUnit.GateRouteId, res);
|
||||
// }
|
||||
}
|
||||
}
|
||||
@@ -1,56 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using Fantasy;
|
||||
using Fantasy.Entitas;
|
||||
using Fantasy.Helper;
|
||||
using NB.Game;
|
||||
|
||||
namespace NB.Chat;
|
||||
|
||||
public static class MailBoxFactory
|
||||
{
|
||||
/// <summary>
|
||||
/// 创建一个邮件箱
|
||||
/// </summary>
|
||||
/// <param name="scene"></param>
|
||||
/// <param name="sendAccountId"></param>
|
||||
/// <param name="mail"></param>
|
||||
/// <param name="expireTime"></param>
|
||||
/// <param name="accountIds"></param>
|
||||
/// <returns></returns>
|
||||
public static MailBox Create(Scene scene, long sendAccountId, Mail mail, int expireTime, List<long> accountIds)
|
||||
{
|
||||
var mailBox = Entity.Create<MailBox>(scene, true, true);
|
||||
mailBox.SendAccountId = sendAccountId;
|
||||
mailBox.Mail = mail;
|
||||
mailBox.ExpireTime = TimeHelper.Now + expireTime;
|
||||
mailBox.CreateTime = TimeHelper.Now;
|
||||
if (accountIds == null || accountIds.Count <= 0)
|
||||
{
|
||||
return mailBox;
|
||||
}
|
||||
|
||||
foreach (var accountId in accountIds)
|
||||
{
|
||||
mailBox.AccountId.Add(accountId);
|
||||
}
|
||||
|
||||
return mailBox;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建一个邮件箱
|
||||
/// </summary>
|
||||
/// <param name="scene"></param>
|
||||
/// <param name="sendAccountId"></param>
|
||||
/// <param name="expireTime"></param>
|
||||
/// <param name="accountIds"></param>
|
||||
/// <param name="content"></param>
|
||||
/// <param name="items"></param>
|
||||
/// <returns></returns>
|
||||
public static MailBox Create(Scene scene, long sendAccountId, int expireTime, List<long> accountIds,
|
||||
string content, List<AwardItem> items = null)
|
||||
{
|
||||
var mail = MailFactory.Create(scene, content, items);
|
||||
return Create(scene, sendAccountId, mail, expireTime, accountIds);
|
||||
}
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
using Fantasy;
|
||||
using Fantasy.Async;
|
||||
using NB.Game;
|
||||
|
||||
namespace NB.Chat;
|
||||
|
||||
public static class MailConversationHelper
|
||||
{
|
||||
/// <summary>
|
||||
/// 从数据库中读取GameAccount
|
||||
/// </summary>
|
||||
/// <param name="scene"></param>
|
||||
/// <param name="firstId"></param>
|
||||
/// <param name="secondId"></param>
|
||||
/// <returns></returns>
|
||||
public static async FTask<MailConversation> LoadDataBase(Scene scene, long firstId, long secondId)
|
||||
{
|
||||
var conversation =
|
||||
await scene.World.Database.First<MailConversation>(d => d.FirstId == firstId && d.SecondId == secondId);
|
||||
if (conversation == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
conversation.Deserialize(scene);
|
||||
return conversation;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 从数据库中移除
|
||||
/// </summary>
|
||||
/// <param name="scene"></param>
|
||||
/// <param name="id"></param>
|
||||
public static async FTask DeleteDataBase(Scene scene,long id)
|
||||
{
|
||||
await scene.World.Database.Remove<MailConversation>(id);
|
||||
}
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using Fantasy;
|
||||
using Fantasy.Entitas;
|
||||
using Fantasy.Helper;
|
||||
using Fantasy.Serialize;
|
||||
using NB.Game;
|
||||
|
||||
namespace NB.Chat;
|
||||
|
||||
public static class MailFactory
|
||||
{
|
||||
private static readonly ISerialize _serializer = SerializerManager.BsonPack;
|
||||
|
||||
public static Mail Create(Scene scene, string content, List<AwardItem> items = null)
|
||||
{
|
||||
|
||||
var mail = Entity.Create<Mail>(scene, true, true);
|
||||
mail.Content = content;
|
||||
mail.State = MailState.Unread;
|
||||
mail.CreateTime = TimeHelper.Now;
|
||||
|
||||
if (items != null && items.Count > 0)
|
||||
{
|
||||
foreach (var item in items)
|
||||
{
|
||||
// mail.Items.Add(_serializer.Clone(item));
|
||||
}
|
||||
}
|
||||
|
||||
return mail;
|
||||
}
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
using Fantasy;
|
||||
using Fantasy.Async;
|
||||
|
||||
namespace NB.Chat;
|
||||
|
||||
/// <summary>
|
||||
/// 发送邮件接口
|
||||
/// </summary>
|
||||
public static class MailHelper
|
||||
{
|
||||
|
||||
public static async FTask Send(Scene scene, MailBox mailBox)
|
||||
{
|
||||
if (mailBox.BoxType == MailBoxType.None)
|
||||
{
|
||||
Log.Error("不支持的邮件类型");
|
||||
return;
|
||||
}
|
||||
|
||||
switch (mailBox.BoxType)
|
||||
{
|
||||
case MailBoxType.All:
|
||||
{
|
||||
break;
|
||||
}
|
||||
case MailBoxType.Specify:
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,80 +0,0 @@
|
||||
using System.Linq;
|
||||
using Fantasy;
|
||||
using Fantasy.Async;
|
||||
using Fantasy.Entitas.Interface;
|
||||
using Fantasy.Helper;
|
||||
|
||||
namespace NB.Chat;
|
||||
|
||||
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 static class MailComponentSystem
|
||||
{
|
||||
public static async FTask Add(this MailComponent self, Mail mail, bool sync)
|
||||
{
|
||||
mail.CreateTime = TimeHelper.Now;
|
||||
mail.ExpireTime = TimeHelper.Now + MailComponent.MaxExpireTime;
|
||||
|
||||
if (self.Mails.Count >= MailComponent.MaxMailCount)
|
||||
{
|
||||
//删除最老的邮件
|
||||
var (_, value) = self.Timer.First();
|
||||
foreach (var removeId in value)
|
||||
{
|
||||
await self.Remove(removeId, sync);
|
||||
}
|
||||
}
|
||||
|
||||
self.Mails.Add(mail.Id, mail);
|
||||
self.Timer.Add(mail.ExpireTime, mail.Id);
|
||||
|
||||
if (sync)
|
||||
{
|
||||
//同步客户端
|
||||
self.Scene.NetworkMessagingComponent.Send(0,new Game2C_HaveMail()
|
||||
{
|
||||
Mail = mail.ToMailInfo(),
|
||||
});
|
||||
}
|
||||
|
||||
await self.Scene.World.Database.Save(self);
|
||||
Log.Info($"MailComponent Add id:{self.Id} mailId:{mail.Id} count:{self.Mails.Count}");
|
||||
}
|
||||
|
||||
public static async FTask<uint> Remove(this MailComponent self, long mailId, bool sync)
|
||||
{
|
||||
if (!self.Mails.Remove(mailId, out var mail))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
self.Timer.RemoveValue(mail.ExpireTime, mail.Id);
|
||||
mail.Dispose();
|
||||
|
||||
if (sync)
|
||||
{
|
||||
//同步客户端
|
||||
self.Scene.NetworkMessagingComponent.Send(0,new Game2C_MailState()
|
||||
{
|
||||
MailState = (int)MailState.Deleted,
|
||||
MailId = mailId,
|
||||
});
|
||||
}
|
||||
|
||||
await self.Scene.World.Database.Save(self);
|
||||
Log.Info($"MailComponent Remove id:{self.Id} mailId:{mail.Id} count:{self.Mails.Count}");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -1,128 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Fantasy;
|
||||
using Fantasy.Async;
|
||||
using Fantasy.Entitas.Interface;
|
||||
using Fantasy.Helper;
|
||||
using NB.Game;
|
||||
|
||||
namespace NB.Chat;
|
||||
|
||||
public class MailConversationDeserializeSystem : DeserializeSystem<MailConversation>
|
||||
{
|
||||
protected override void Deserialize(MailConversation self)
|
||||
{
|
||||
self.Key = $"{self.FirstId}-{self.SecondId}";
|
||||
}
|
||||
}
|
||||
|
||||
public class MailConversationDestroySystem : DestroySystem<MailConversation>
|
||||
{
|
||||
protected override void Destroy(MailConversation self)
|
||||
{
|
||||
foreach (var mail in self.Mails)
|
||||
{
|
||||
mail.Dispose();
|
||||
}
|
||||
|
||||
self.Mails.Clear();
|
||||
self.FirstId = 0;
|
||||
self.SecondId = 0;
|
||||
self.Key = string.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
public static class MailConversationSystem
|
||||
{
|
||||
public static async FTask Add(this MailConversation self, Mail mail)
|
||||
{
|
||||
self.Mails.Add(mail);
|
||||
if (self.Mails.Count > AppConfig.MaxConversationCount)
|
||||
{
|
||||
self.Mails.RemoveAt(0);
|
||||
}
|
||||
|
||||
if (mail.Items != null && mail.Items.Count > 0)
|
||||
{
|
||||
//有附件需要立马保存
|
||||
await self.Save(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
await self.Save(false);
|
||||
}
|
||||
}
|
||||
|
||||
public static async FTask Save(this MailConversation self, bool forceSave = true)
|
||||
{
|
||||
// self.NeedSave = true;
|
||||
// self.NeedSaveTime = TimeHelper.Now + AppConfig.PlayerDataAutoSaveTime;
|
||||
if (forceSave)
|
||||
{
|
||||
self.UpdateTime = TimeHelper.Now;
|
||||
await self.Scene.World.Database.Save(self);
|
||||
}
|
||||
else
|
||||
{
|
||||
self.NeedSave = true;
|
||||
self.NeedSaveTime = TimeHelper.Now + AppConfig.ChatDataAutoSaveTime;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 是否可以发送邮件
|
||||
/// </summary>
|
||||
/// <param name="self"></param>
|
||||
/// <param name="sendId"></param>
|
||||
/// <returns></returns>
|
||||
public static bool CanSend(this MailConversation self, long sendId)
|
||||
{
|
||||
if (self.Mails.Count < 1) return true;
|
||||
foreach (var mail in self.Mails)
|
||||
{
|
||||
if (mail.Sender != sendId)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
#region 转换
|
||||
|
||||
public static async FTask<List<ConversationInfo>> ToInfo(this List<MailConversation> self, Scene scene, long selfId)
|
||||
{
|
||||
List<ConversationInfo> ret = new List<ConversationInfo>();
|
||||
HashSet<long> ids = new HashSet<long>();
|
||||
foreach (var conversation in self)
|
||||
{
|
||||
if (conversation.RemoveId.Contains(selfId)) continue;
|
||||
ids.Add(conversation.FirstId);
|
||||
ids.Add(conversation.SecondId);
|
||||
}
|
||||
|
||||
ids.Remove(selfId);
|
||||
|
||||
var infos = await CacheHandler.GetPlayerBasicCacheInfos(scene, ids.ToList());
|
||||
foreach (var conversation in self)
|
||||
{
|
||||
if (conversation.RemoveId.Contains(selfId)) continue;
|
||||
var item = new ConversationInfo();
|
||||
item.List = conversation.Mails.ToMailInfo();
|
||||
var otherId = conversation.FirstId == selfId ? conversation.SecondId : conversation.FirstId;
|
||||
var info = infos.Find(t => t.RoleId == otherId);
|
||||
if (info != null)
|
||||
{
|
||||
item.RoleInfo = info;
|
||||
}
|
||||
|
||||
ret.Add(item);
|
||||
}
|
||||
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -1,94 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using Fantasy;
|
||||
using Fantasy.Async;
|
||||
using Fantasy.Entitas;
|
||||
using Fantasy.Entitas.Interface;
|
||||
using Fantasy.Helper;
|
||||
using NB.Game;
|
||||
|
||||
namespace NB.Chat;
|
||||
|
||||
public class MailManageComponentDestroySystem : DestroySystem<MailManageComponent>
|
||||
{
|
||||
protected override void Destroy(MailManageComponent self)
|
||||
{
|
||||
foreach (var (_, conversation) in self.Conversations)
|
||||
{
|
||||
conversation.Dispose();
|
||||
}
|
||||
|
||||
self.Conversations.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
public static class MailManageComponentSystem
|
||||
{
|
||||
public static async FTask DeleteConversation(this MailManageComponent self, long selfId, long otherId)
|
||||
{
|
||||
var firstId = selfId;
|
||||
var secondId = otherId;
|
||||
if (otherId < selfId)
|
||||
{
|
||||
firstId = otherId;
|
||||
secondId = selfId;
|
||||
}
|
||||
|
||||
var key = $"{firstId}-{secondId}";
|
||||
|
||||
if (self.Conversations.Remove(key, out var conversation))
|
||||
{
|
||||
await MailConversationHelper.DeleteDataBase(conversation.Scene, conversation.Id);
|
||||
conversation.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
public static async FTask<MailConversation?> GetConversation(this MailManageComponent self, long selfId,
|
||||
long otherId)
|
||||
{
|
||||
var firstId = selfId;
|
||||
var secondId = otherId;
|
||||
if (otherId < selfId)
|
||||
{
|
||||
firstId = otherId;
|
||||
secondId = selfId;
|
||||
}
|
||||
|
||||
var key = $"{firstId}-{secondId}";
|
||||
if (!self.Conversations.TryGetValue(key, out var conversation))
|
||||
{
|
||||
//检查数据库中是否存在
|
||||
conversation = await MailConversationHelper.LoadDataBase(self.Scene, firstId, secondId);
|
||||
if (conversation == null)
|
||||
{
|
||||
//检查id是否合法
|
||||
var roleInfo = await CacheHandler.GetPlayerBasicCacheInfo(self.Scene, otherId);
|
||||
if (roleInfo == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
conversation = Entity.Create<MailConversation>(self.Scene, true, true);
|
||||
|
||||
conversation.FirstId = firstId;
|
||||
conversation.SecondId = secondId;
|
||||
|
||||
conversation.Key = key;
|
||||
await conversation.Save(false);
|
||||
}
|
||||
|
||||
self.Conversations.Add(key, conversation);
|
||||
}
|
||||
|
||||
return conversation;
|
||||
}
|
||||
|
||||
public static async FTask<List<MailConversation>> GetConversations(this MailManageComponent self, long id)
|
||||
{
|
||||
List<MailConversation> players =
|
||||
await self.Scene.World.Database.QueryByPageOrderBy<MailConversation>(
|
||||
d => d.FirstId == id || d.SecondId == id, 1, 50,
|
||||
d => d.UpdateTime);
|
||||
|
||||
return players;
|
||||
}
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using Fantasy;
|
||||
using Fantasy.Entitas.Interface;
|
||||
using NB.Game;
|
||||
|
||||
namespace NB.Chat;
|
||||
|
||||
public class MailDestroySystem : DestroySystem<Mail>
|
||||
{
|
||||
protected override void Destroy(Mail self)
|
||||
{
|
||||
self.OwnerId = 0;
|
||||
self.Sender = 0;
|
||||
self.Content = string.Empty;
|
||||
self.ExpireTime = 0;
|
||||
self.CreateTime = 0;
|
||||
self.State = MailState.None;
|
||||
self.MailType = MailType.None;
|
||||
foreach (var item in self.Items)
|
||||
{
|
||||
item.Dispose();
|
||||
}
|
||||
|
||||
self.Items.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
public static class MailSystem
|
||||
{
|
||||
public static MailInfo ToMailInfo(this Mail mail)
|
||||
{
|
||||
return new MailInfo()
|
||||
{
|
||||
Id = mail.Id,
|
||||
Content = mail.Content,
|
||||
CreateTime = mail.CreateTime,
|
||||
MailState = (int)mail.State,
|
||||
MailType = (int)mail.MailType,
|
||||
Items = mail.Items.ToAwardInfo()
|
||||
};
|
||||
}
|
||||
|
||||
public static List<MailInfo> ToMailInfo(this List<Mail> mails)
|
||||
{
|
||||
var list = new List<MailInfo>();
|
||||
foreach (var mail in mails)
|
||||
{
|
||||
list.Add(mail.ToMailInfo());
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
}
|
||||
@@ -1,146 +0,0 @@
|
||||
// using Fantasy;
|
||||
// using Fantasy.Async;
|
||||
// using Fantasy.Entitas;
|
||||
// using Fantasy.Entitas.Interface;
|
||||
// using NB.Chat;
|
||||
//
|
||||
// namespace NBF.Social;
|
||||
//
|
||||
// public sealed class ChatUnitManageComponentDestroySystem : DestroySystem<SocialUnitManageComponent>
|
||||
// {
|
||||
// protected override void Destroy(SocialUnitManageComponent self)
|
||||
// {
|
||||
// foreach (var chatUnit in self.Units.Values.ToArray())
|
||||
// {
|
||||
// chatUnit.Dispose();
|
||||
// }
|
||||
//
|
||||
// self.Units.Clear();
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// public static class SocialUnitManageComponentSystem
|
||||
// {
|
||||
// #region 消息缓存
|
||||
//
|
||||
// /// <summary>
|
||||
// /// 离线消息,进入待领取队列
|
||||
// /// </summary>
|
||||
// /// <param name="self"></param>
|
||||
// /// <param name="targetId"></param>
|
||||
// /// <param name="message"></param>
|
||||
// public static void SaveOfflineMessage(this SocialUnitManageComponent self, long targetId, ChatMessageInfo message)
|
||||
// {
|
||||
// // self.NotSendMessage.Add(targetId, message);
|
||||
// }
|
||||
//
|
||||
// #endregion
|
||||
//
|
||||
// #region 上线下线
|
||||
//
|
||||
// /// <summary>
|
||||
// /// 玩家上线
|
||||
// /// </summary>
|
||||
// /// <param name="self"></param>
|
||||
// /// <param name="scene"></param>
|
||||
// /// <param name="accountId"></param>
|
||||
// /// <param name="gateRouteId"></param>
|
||||
// public static async FTask<SocialUnit?> Online(this SocialUnitManageComponent self, Scene scene,
|
||||
// long accountId,
|
||||
// long gateRouteId)
|
||||
// {
|
||||
// // var accountId = roleSimpleInfo.RoleId;
|
||||
// if (!self.TryGet(accountId, out var account))
|
||||
// {
|
||||
// account = Entity.Create<SocialUnit>(scene, accountId, true, true);
|
||||
// self.Add(account);
|
||||
// }
|
||||
//
|
||||
// if (account != null)
|
||||
// {
|
||||
// await account.TryComponent<MailComponent>();
|
||||
// account.GateRouteId = gateRouteId;
|
||||
// // account.Role = roleSimpleInfo;
|
||||
// }
|
||||
//
|
||||
// await FTask.CompletedTask;
|
||||
// return account;
|
||||
// }
|
||||
//
|
||||
// public static async FTask Offline(this SocialUnitManageComponent self, Scene scene, long accountId,
|
||||
// long gateRouteId)
|
||||
// {
|
||||
// if (self.TryGet(accountId, out var unit) && unit != null)
|
||||
// {
|
||||
// if (unit.GateRouteId == gateRouteId)
|
||||
// {
|
||||
// Log.Info("退出当前聊天服==");
|
||||
// self.Remove(accountId); //如果当前网关和下线的网关一致
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// await FTask.CompletedTask;
|
||||
// }
|
||||
//
|
||||
// #endregion
|
||||
//
|
||||
// #region 获取&移除
|
||||
//
|
||||
// public static void Add(this SocialUnitManageComponent self, SocialUnit account)
|
||||
// {
|
||||
// self.Units.Add(account.Id, account);
|
||||
// }
|
||||
//
|
||||
// public static SocialUnit? Get(this SocialUnitManageComponent self, long accountId)
|
||||
// {
|
||||
// return self.Units.GetValueOrDefault(accountId);
|
||||
// }
|
||||
//
|
||||
// public static bool TryGet(this SocialUnitManageComponent self, long accountId, out SocialUnit? account)
|
||||
// {
|
||||
// return self.Units.TryGetValue(accountId, out account);
|
||||
// }
|
||||
//
|
||||
// public static void Remove(this SocialUnitManageComponent self, long accountId, bool isDispose = true)
|
||||
// {
|
||||
// if (!self.Units.Remove(accountId, out var account))
|
||||
// {
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// if (!isDispose)
|
||||
// {
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// account.Dispose();
|
||||
// }
|
||||
//
|
||||
// #endregion
|
||||
//
|
||||
// #region 组件
|
||||
//
|
||||
// /// <summary>
|
||||
// /// 尝试给增加相关组件
|
||||
// /// </summary>
|
||||
// /// <param name="socialUnit"></param>
|
||||
// /// <typeparam name="T"></typeparam>
|
||||
// public static async FTask TryComponent<T>(this SocialUnit socialUnit) where T : Entity, new()
|
||||
// {
|
||||
// if (socialUnit.GetComponent<T>() == null)
|
||||
// {
|
||||
// var mailComponent = await socialUnit.Scene.World.Database.Query<T>(socialUnit.Id, true);
|
||||
// if (mailComponent == null)
|
||||
// {
|
||||
// //如果没有邮件组件
|
||||
// socialUnit.AddComponent<T>();
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// socialUnit.AddComponent(mailComponent);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// #endregion
|
||||
// }
|
||||
@@ -1,22 +0,0 @@
|
||||
// using Fantasy.Entitas.Interface;
|
||||
// #pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type.
|
||||
//
|
||||
// namespace NB.Chat;
|
||||
//
|
||||
// public sealed class SocialUnitDestroySystem : DestroySystem<SocialUnit>
|
||||
// {
|
||||
// protected override void Destroy(SocialUnit self)
|
||||
// {
|
||||
// self.Role?.Return();
|
||||
// self.Role = null;
|
||||
// self.GateRouteId = 0;
|
||||
// // 退出当前ChatUnit拥有的所有频道
|
||||
// foreach (var (_,chatChannelComponent) in self.Channels)
|
||||
// {
|
||||
// chatChannelComponent.ExitChannel(self.Id, false);
|
||||
// }
|
||||
// // 理论情况下,这个self.Channels不会存在因为数据的,因为上面已经给清空掉了。
|
||||
// // 但是self.Channels.Clear();还是加上吧,防止以后忘记了。
|
||||
// self.Channels.Clear();
|
||||
// }
|
||||
// }
|
||||
@@ -12,4 +12,9 @@
|
||||
<ProjectReference Include="..\Entity\Entity.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="Game\Condition\" />
|
||||
<Folder Include="Game\Mail\Handler\" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -138,10 +138,9 @@ public sealed class OnCreateSceneEvent : AsyncEventSystem<OnCreateScene>
|
||||
|
||||
private async FTask InitializeSocialScene(Scene scene)
|
||||
{
|
||||
Log.Info($"初始化 Social 场景: {scene.Id}");
|
||||
//用于管理玩家的组件
|
||||
scene.AddComponent<MailManageComponent>();
|
||||
//聊天
|
||||
// Log.Info($"初始化 Social 场景: {scene.Id}");
|
||||
// 离线邮件箱管理组件。
|
||||
await scene.AddComponent<MailBoxManageComponent>().Init();
|
||||
// 聊天频道中控中心组件。
|
||||
scene.AddComponent<ChatChannelCenterComponent>();
|
||||
await FTask.CompletedTask;
|
||||
@@ -154,7 +153,7 @@ public sealed class OnCreateSceneEvent : AsyncEventSystem<OnCreateScene>
|
||||
//用于管理玩家的组件
|
||||
scene.AddComponent<PlayerManageComponent>();
|
||||
scene.AddComponent<PlayerBasicCacheManageComponent>();
|
||||
|
||||
await scene.AddComponent<ItemUseComponent>().Initialize();
|
||||
|
||||
Log.Info("创建地图场景===");
|
||||
var roomManageComponent = scene.AddComponent<RoomManageComponent>();
|
||||
|
||||
Reference in New Issue
Block a user