From 96f22a3e48c293e7cd613a874e2ba4660f493e52 Mon Sep 17 00:00:00 2001
From: BobSong <605277374@qq.com>
Date: Thu, 31 Jul 2025 23:57:32 +0800
Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E7=9B=B8=E5=85=B3=E5=8D=8F?=
=?UTF-8?q?=E8=AE=AE?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../NetworkProtocol/Outer/OuterMessage.proto | 23 +++++
.../NetworkProtocol/Outer/data/Account.proto | 3 +-
Config/NetworkProtocol/Outer/data/Mail.proto | 15 +--
Entity/Entity.csproj | 1 -
Entity/Game/Item/AwardItem.cs | 17 ++++
Entity/Game/Item/Item.cs | 17 ++++
Entity/Game/Mail/Components/MailComponent.cs | 34 +++++++
Entity/Game/Mail/Entity/Mail.cs | 46 ++++++++++
Entity/Game/Mail/Entity/MailBox.cs | 41 +++++++++
Entity/Game/Mail/Enum/MailEnum.cs | 54 +++++++++++
Entity/Game/Player/Child/PlayerBasic.cs | 34 -------
Entity/Game/Player/Child/PlayerStatistics.cs | 2 +-
Entity/Game/Player/Player.cs | 33 ++++++-
Entity/Generate/NetworkProtocol/Account.cs | 2 +-
Entity/Generate/NetworkProtocol/Mail.cs | 17 ++--
.../Generate/NetworkProtocol/OuterMessage.cs | 92 +++++++++++++++++++
.../Generate/NetworkProtocol/OuterOpcode.cs | 4 +
.../Handler/G2Game_EnterRequestHandler.cs | 26 ++++--
Hotfix/Game/Item/AwardItemSystem.cs | 36 ++++++++
Hotfix/Game/Item/ItemSystem.cs | 62 +++++++++++++
.../Mail/Components/MailComponentSystem.cs | 79 ++++++++++++++++
Hotfix/Game/Mail/Entity/MailBoxSystem.cs | 22 +++++
Hotfix/Game/Mail/Entity/MailSystem.cs | 53 +++++++++++
Hotfix/Game/Mail/Helper/MailBoxFactory.cs | 55 +++++++++++
Hotfix/Game/Mail/Helper/MailFactory.cs | 30 ++++++
Hotfix/Game/Mail/Helper/MailHelper.cs | 31 +++++++
Hotfix/Hotfix.csproj | 4 +
27 files changed, 770 insertions(+), 63 deletions(-)
create mode 100644 Entity/Game/Item/AwardItem.cs
create mode 100644 Entity/Game/Mail/Components/MailComponent.cs
create mode 100644 Entity/Game/Mail/Entity/Mail.cs
create mode 100644 Entity/Game/Mail/Entity/MailBox.cs
create mode 100644 Entity/Game/Mail/Enum/MailEnum.cs
delete mode 100644 Entity/Game/Player/Child/PlayerBasic.cs
create mode 100644 Hotfix/Game/Item/AwardItemSystem.cs
create mode 100644 Hotfix/Game/Item/ItemSystem.cs
create mode 100644 Hotfix/Game/Mail/Components/MailComponentSystem.cs
create mode 100644 Hotfix/Game/Mail/Entity/MailBoxSystem.cs
create mode 100644 Hotfix/Game/Mail/Entity/MailSystem.cs
create mode 100644 Hotfix/Game/Mail/Helper/MailBoxFactory.cs
create mode 100644 Hotfix/Game/Mail/Helper/MailFactory.cs
create mode 100644 Hotfix/Game/Mail/Helper/MailHelper.cs
diff --git a/Config/NetworkProtocol/Outer/OuterMessage.proto b/Config/NetworkProtocol/Outer/OuterMessage.proto
index 56cfa6a..c347b24 100644
--- a/Config/NetworkProtocol/Outer/OuterMessage.proto
+++ b/Config/NetworkProtocol/Outer/OuterMessage.proto
@@ -48,4 +48,27 @@ message Game2C_GetRoleInfoResponse // ICustomRouteResponse
{
string Name;
string RoleId;
+}
+
+///请求邮件列表
+message C2Game_GetMailsRequest // ICustomRouteRequest,Game2C_GetMailsResponse,GameRoute
+{
+
+}
+///获取邮件列表响应
+message Game2C_GetMailsResponse // ICustomRouteResponse
+{
+ repeated MailInfo Mail = 1;
+}
+
+///新邮件推送
+message Game2C_HaveMail // ICustomRouteMessage,GameRoute
+{
+ MailInfo Mail = 1;
+}
+
+message Game2C_MailState // ICustomRouteMessage,GameRoute
+{
+ int32 MailState = 1;
+ int64 MailId = 2;
}
\ No newline at end of file
diff --git a/Config/NetworkProtocol/Outer/data/Account.proto b/Config/NetworkProtocol/Outer/data/Account.proto
index 657b41e..45b0d48 100644
--- a/Config/NetworkProtocol/Outer/data/Account.proto
+++ b/Config/NetworkProtocol/Outer/data/Account.proto
@@ -50,6 +50,7 @@ message VipInfo
int64 ExpirationTime = 2; //到期时间
}
+
///奖励信息
message AwardInfo
{
@@ -65,7 +66,7 @@ message ItemInfo
int32 Count = 3; //数量
int64 ExpirationTime = 4; //失效时间
int64 GetTime = 5; //获得时间
- int64 Abrasion = 6; //耐久度
+ int32 Abrasion = 6; //耐久度
}
///fish信息
diff --git a/Config/NetworkProtocol/Outer/data/Mail.proto b/Config/NetworkProtocol/Outer/data/Mail.proto
index 4d3226d..dbc2adb 100644
--- a/Config/NetworkProtocol/Outer/data/Mail.proto
+++ b/Config/NetworkProtocol/Outer/data/Mail.proto
@@ -3,11 +3,12 @@ package Fantasy.Network.Message;
message MailInfo
{
- int64 Id = 1; //邮件id
- string Title = 2; //标题
- string Content = 3; //内容
- int64 SendTime = 4; //发送时间
- int32 Type = 5; //邮件类型
- repeated AwardInfo Items = 6; //附件列表
- bool IsRead = 7; //是否已读
+ int64 Id = 1; //邮件id
+ string Title = 2; //标题
+ string Content = 3; //内容
+ int64 CreateTime = 4; //发送时间
+ int64 ExpireTime = 4; //发送时间
+ int32 MailType = 5; //邮件类型
+ int32 MailState = 6; //邮件状态
+ repeated AwardInfo Items = 7; //附件列表
}
\ No newline at end of file
diff --git a/Entity/Entity.csproj b/Entity/Entity.csproj
index 71ebf56..be2ab6d 100644
--- a/Entity/Entity.csproj
+++ b/Entity/Entity.csproj
@@ -29,7 +29,6 @@
-
diff --git a/Entity/Game/Item/AwardItem.cs b/Entity/Game/Item/AwardItem.cs
new file mode 100644
index 0000000..9e6e60f
--- /dev/null
+++ b/Entity/Game/Item/AwardItem.cs
@@ -0,0 +1,17 @@
+using Fantasy.Entitas;
+using MongoDB.Bson.Serialization.Attributes;
+
+namespace NB.Game;
+
+public class AwardItem : Entity
+{
+ ///
+ /// 拥有的数量
+ ///
+ [BsonElement("c")] public int Count;
+
+ ///
+ /// 配置id
+ ///
+ [BsonElement("cid")] public int ConfigId;
+}
\ No newline at end of file
diff --git a/Entity/Game/Item/Item.cs b/Entity/Game/Item/Item.cs
index 636077d..b6e0be6 100644
--- a/Entity/Game/Item/Item.cs
+++ b/Entity/Game/Item/Item.cs
@@ -11,6 +11,8 @@ public enum ItemType
Fish,
}
+
+
public class Item : Entity
{
///
@@ -27,4 +29,19 @@ public class Item : Entity
/// 是否绑定
///
[BsonElement("ib")] public bool IsBind;
+
+ ///
+ /// 失效时间
+ ///
+ [BsonElement("et")] public long ExpirationTime;
+
+ ///
+ /// 获得时间
+ ///
+ [BsonElement("gt")] public long GetTime;
+
+ ///
+ /// 耐久度
+ ///
+ [BsonElement("a")] public int Abrasion;
}
\ No newline at end of file
diff --git a/Entity/Game/Mail/Components/MailComponent.cs b/Entity/Game/Mail/Components/MailComponent.cs
new file mode 100644
index 0000000..fc8935f
--- /dev/null
+++ b/Entity/Game/Mail/Components/MailComponent.cs
@@ -0,0 +1,34 @@
+using Fantasy.DataStructure.Collection;
+using Fantasy.Entitas;
+using Fantasy.Helper;
+using MongoDB.Bson.Serialization.Attributes;
+using MongoDB.Bson.Serialization.Options;
+
+namespace NB.Game;
+
+///
+/// 玩家邮件组件
+///
+public class MailComponent : Entity
+{
+ ///
+ /// 最大邮件数据
+ ///
+ public const int MaxMailCount = 50;
+
+ ///
+ /// 邮件最大保留时间
+ ///
+ public const long MaxExpireTime = TimeHelper.OneDay * 365;
+
+ ///
+ /// 邮件列表
+ ///
+ [BsonDictionaryOptions(DictionaryRepresentation.ArrayOfArrays)]
+ public Dictionary Mails = new Dictionary();
+
+ ///
+ /// 按照时间进行排序
+ ///
+ [BsonIgnore] public readonly SortedOneToManyListPool Timer = new SortedOneToManyListPool();
+}
\ No newline at end of file
diff --git a/Entity/Game/Mail/Entity/Mail.cs b/Entity/Game/Mail/Entity/Mail.cs
new file mode 100644
index 0000000..2465f64
--- /dev/null
+++ b/Entity/Game/Mail/Entity/Mail.cs
@@ -0,0 +1,46 @@
+using Fantasy.Entitas;
+
+namespace NB.Game;
+
+public sealed class Mail : Entity
+{
+ ///
+ /// 邮件拥有者
+ ///
+ public long OwnerId;
+
+ ///
+ /// 邮件状态
+ ///
+ public MailState State = MailState.None;
+
+ ///
+ /// 邮件状态
+ ///
+ public MailType MailType = MailType.None;
+
+ ///
+ /// 邮件标题
+ ///
+ public string Title;
+
+ ///
+ /// 邮件内容
+ ///
+ public string Content;
+
+ ///
+ /// 创建时间
+ ///
+ public long CreateTime;
+
+ ///
+ /// 过期时间
+ ///
+ public long ExpireTime;
+
+ ///
+ /// 邮件的附件内容
+ ///
+ public List Items = new List();
+}
\ No newline at end of file
diff --git a/Entity/Game/Mail/Entity/MailBox.cs b/Entity/Game/Mail/Entity/MailBox.cs
new file mode 100644
index 0000000..b57adfb
--- /dev/null
+++ b/Entity/Game/Mail/Entity/MailBox.cs
@@ -0,0 +1,41 @@
+using Fantasy.Entitas;
+
+namespace NB.Game;
+
+public class MailBox : Entity
+{
+ ///
+ /// 邮件
+ ///
+ public Mail Mail;
+
+ ///
+ /// 创建时间
+ ///
+ public long CreateTime;
+
+ ///
+ /// 失效时间
+ ///
+ public long ExpireTime;
+
+ ///
+ /// 邮箱类型
+ ///
+ public MailBoxType BoxType;
+
+ ///
+ /// 发送人
+ ///
+ public long SendAccountId = 0;
+
+ ///
+ /// 收件人
+ ///
+ public HashSet AccountId = new HashSet();
+
+ ///
+ /// 领取过的人
+ ///
+ public HashSet Received = new HashSet();
+}
\ No newline at end of file
diff --git a/Entity/Game/Mail/Enum/MailEnum.cs b/Entity/Game/Mail/Enum/MailEnum.cs
new file mode 100644
index 0000000..16ccbe0
--- /dev/null
+++ b/Entity/Game/Mail/Enum/MailEnum.cs
@@ -0,0 +1,54 @@
+namespace NB.Game;
+
+public enum MailType
+{
+ None = 0,
+ System = 1, //系统邮件
+ Rewards = 2, //奖励邮件
+ User = 3, //个人邮件
+}
+
+public enum MailState
+{
+ None = 0,
+
+ ///
+ /// 未读
+ ///
+ Unread = 1,
+
+ ///
+ /// 已读
+ ///
+ HaveRead = 2,
+
+ ///
+ /// 未领取
+ ///
+ NotClaimed = 3,
+
+ ///
+ /// 已领取
+ ///
+ Received = 4,
+
+ ///
+ /// 已删除
+ ///
+ Deleted = 5,
+}
+
+public enum MailBoxType
+{
+ None = 0,
+
+ ///
+ /// 指定目标
+ ///
+ Specify = 1,
+
+ ///
+ /// 全部人
+ ///
+ All = 2
+}
\ No newline at end of file
diff --git a/Entity/Game/Player/Child/PlayerBasic.cs b/Entity/Game/Player/Child/PlayerBasic.cs
deleted file mode 100644
index efed87a..0000000
--- a/Entity/Game/Player/Child/PlayerBasic.cs
+++ /dev/null
@@ -1,34 +0,0 @@
-using Fantasy.Entitas;
-
-namespace NB;
-
-///
-/// 角色基础数据
-///
-public class PlayerBasic
-{
- ///
- /// 昵称
- ///
- public string NickName;
-
- ///
- /// 头像
- ///
- public string Head;
-
- ///
- /// 国家
- ///
- public string Country;
-
- ///
- /// 等级
- ///
- public int Level;
-
- ///
- /// 当前经验
- ///
- public int Exp;
-}
\ No newline at end of file
diff --git a/Entity/Game/Player/Child/PlayerStatistics.cs b/Entity/Game/Player/Child/PlayerStatistics.cs
index 925b363..c1aad96 100644
--- a/Entity/Game/Player/Child/PlayerStatistics.cs
+++ b/Entity/Game/Player/Child/PlayerStatistics.cs
@@ -5,7 +5,7 @@ namespace NB;
///
/// 角色统计数据
///
-public class PlayerStatistics
+public class PlayerStatistics : Entity
{
///
/// 登录次数
diff --git a/Entity/Game/Player/Player.cs b/Entity/Game/Player/Player.cs
index 5e4345d..a3bac85 100644
--- a/Entity/Game/Player/Player.cs
+++ b/Entity/Game/Player/Player.cs
@@ -9,10 +9,30 @@ public sealed class Player : Entity
[BsonElement("ct")] public long CreateTime;
[BsonElement("lt")] public long LoginTime;
- public PlayerBasic Basic = new PlayerBasic();
- public PlayerStatistics Statistics = new PlayerStatistics();
- public PlayerDayFlags DayFlags = new PlayerDayFlags();
- public PlayerVip Vip = new PlayerVip();
+ ///
+ /// 昵称
+ ///
+ [BsonElement("name")] public string NickName;
+
+ ///
+ /// 头像
+ ///
+ public string Head;
+
+ ///
+ /// 国家
+ ///
+ public string Country;
+
+ ///
+ /// 等级
+ ///
+ [BsonElement("lv")] public int Level;
+
+ ///
+ /// 当前经验
+ ///
+ public int Exp;
///
/// 余额
@@ -24,6 +44,11 @@ public sealed class Player : Entity
///
public int Gold;
+ // public PlayerStatistics Statistics = new PlayerStatistics();
+ // public PlayerDayFlags DayFlags = new PlayerDayFlags();
+ // public PlayerVip Vip = new PlayerVip();
+
+
///
/// 其他货币
///
diff --git a/Entity/Generate/NetworkProtocol/Account.cs b/Entity/Generate/NetworkProtocol/Account.cs
index f5fe2c5..ce1db38 100644
--- a/Entity/Generate/NetworkProtocol/Account.cs
+++ b/Entity/Generate/NetworkProtocol/Account.cs
@@ -229,7 +229,7 @@ namespace Fantasy
[ProtoMember(5)]
public long GetTime { get; set; }
[ProtoMember(6)]
- public long Abrasion { get; set; }
+ public int Abrasion { get; set; }
}
///
/// fish信息
diff --git a/Entity/Generate/NetworkProtocol/Mail.cs b/Entity/Generate/NetworkProtocol/Mail.cs
index 92eedc3..b44fc76 100644
--- a/Entity/Generate/NetworkProtocol/Mail.cs
+++ b/Entity/Generate/NetworkProtocol/Mail.cs
@@ -29,10 +29,11 @@ namespace Fantasy
Id = default;
Title = default;
Content = default;
- SendTime = default;
- Type = default;
+ CreateTime = default;
+ ExpireTime = default;
+ MailType = default;
+ MailState = default;
Items.Clear();
- IsRead = default;
#if FANTASY_NET || FANTASY_UNITY
GetScene().MessagePoolComponent.Return(this);
#endif
@@ -44,12 +45,14 @@ namespace Fantasy
[ProtoMember(3)]
public string Content { get; set; }
[ProtoMember(4)]
- public long SendTime { get; set; }
+ public long CreateTime { get; set; }
[ProtoMember(5)]
- public int Type { get; set; }
+ public long ExpireTime { get; set; }
[ProtoMember(6)]
- public List Items = new List();
+ public int MailType { get; set; }
[ProtoMember(7)]
- public bool IsRead { get; set; }
+ public int MailState { get; set; }
+ [ProtoMember(8)]
+ public List Items = new List();
}
}
diff --git a/Entity/Generate/NetworkProtocol/OuterMessage.cs b/Entity/Generate/NetworkProtocol/OuterMessage.cs
index 66e2b43..de5e21b 100644
--- a/Entity/Generate/NetworkProtocol/OuterMessage.cs
+++ b/Entity/Generate/NetworkProtocol/OuterMessage.cs
@@ -192,4 +192,96 @@ namespace Fantasy
[ProtoMember(3)]
public uint ErrorCode { get; set; }
}
+ ///
+ /// 请求邮件列表
+ ///
+ [ProtoContract]
+ public partial class C2Game_GetMailsRequest : AMessage, ICustomRouteRequest, IProto
+ {
+ public static C2Game_GetMailsRequest Create(Scene scene)
+ {
+ return scene.MessagePoolComponent.Rent();
+ }
+ public override void Dispose()
+ {
+#if FANTASY_NET || FANTASY_UNITY
+ GetScene().MessagePoolComponent.Return(this);
+#endif
+ }
+ [ProtoIgnore]
+ public Game2C_GetMailsResponse ResponseType { get; set; }
+ public uint OpCode() { return OuterOpcode.C2Game_GetMailsRequest; }
+ [ProtoIgnore]
+ public int RouteType => Fantasy.RouteType.GameRoute;
+ }
+ ///
+ /// 获取邮件列表响应
+ ///
+ [ProtoContract]
+ public partial class Game2C_GetMailsResponse : AMessage, ICustomRouteResponse, IProto
+ {
+ public static Game2C_GetMailsResponse Create(Scene scene)
+ {
+ return scene.MessagePoolComponent.Rent();
+ }
+ public override void Dispose()
+ {
+ ErrorCode = default;
+ Mail.Clear();
+#if FANTASY_NET || FANTASY_UNITY
+ GetScene().MessagePoolComponent.Return(this);
+#endif
+ }
+ public uint OpCode() { return OuterOpcode.Game2C_GetMailsResponse; }
+ [ProtoMember(1)]
+ public List Mail = new List();
+ [ProtoMember(2)]
+ public uint ErrorCode { get; set; }
+ }
+ ///
+ /// 新邮件推送
+ ///
+ [ProtoContract]
+ public partial class Game2C_HaveMail : AMessage, ICustomRouteMessage, IProto
+ {
+ public static Game2C_HaveMail Create(Scene scene)
+ {
+ return scene.MessagePoolComponent.Rent();
+ }
+ public override void Dispose()
+ {
+ Mail = default;
+#if FANTASY_NET || FANTASY_UNITY
+ GetScene().MessagePoolComponent.Return(this);
+#endif
+ }
+ public uint OpCode() { return OuterOpcode.Game2C_HaveMail; }
+ [ProtoIgnore]
+ public int RouteType => Fantasy.RouteType.GameRoute;
+ [ProtoMember(1)]
+ public MailInfo Mail { get; set; }
+ }
+ [ProtoContract]
+ public partial class Game2C_MailState : AMessage, ICustomRouteMessage, IProto
+ {
+ public static Game2C_MailState Create(Scene scene)
+ {
+ return scene.MessagePoolComponent.Rent();
+ }
+ public override void Dispose()
+ {
+ MailState = default;
+ MailId = default;
+#if FANTASY_NET || FANTASY_UNITY
+ GetScene().MessagePoolComponent.Return(this);
+#endif
+ }
+ public uint OpCode() { return OuterOpcode.Game2C_MailState; }
+ [ProtoIgnore]
+ public int RouteType => Fantasy.RouteType.GameRoute;
+ [ProtoMember(1)]
+ public int MailState { get; set; }
+ [ProtoMember(2)]
+ public long MailId { get; set; }
+ }
}
diff --git a/Entity/Generate/NetworkProtocol/OuterOpcode.cs b/Entity/Generate/NetworkProtocol/OuterOpcode.cs
index 5b83c2e..231afc0 100644
--- a/Entity/Generate/NetworkProtocol/OuterOpcode.cs
+++ b/Entity/Generate/NetworkProtocol/OuterOpcode.cs
@@ -9,5 +9,9 @@ namespace Fantasy
public const uint G2C_RepeatLogin = 134227729;
public const uint C2Game_GetRoleInfoRequest = 2281711377;
public const uint Game2C_GetRoleInfoResponse = 2415929105;
+ public const uint C2Game_GetMailsRequest = 2281711378;
+ public const uint Game2C_GetMailsResponse = 2415929106;
+ public const uint Game2C_HaveMail = 2147493649;
+ public const uint Game2C_MailState = 2147493650;
}
}
diff --git a/Hotfix/Game/Handler/G2Game_EnterRequestHandler.cs b/Hotfix/Game/Handler/G2Game_EnterRequestHandler.cs
index 5b94f4e..fd66e40 100644
--- a/Hotfix/Game/Handler/G2Game_EnterRequestHandler.cs
+++ b/Hotfix/Game/Handler/G2Game_EnterRequestHandler.cs
@@ -33,19 +33,18 @@ public class G2Game_EnterRequestHandler : RouteRPC(scene, true, true);
account.Items.Add(item.Id, item);
}
-
+
for (int i = 0; i < 500; i++)
{
var item = Entity.Create(scene, true, true);
@@ -86,6 +85,19 @@ public class G2Game_EnterRequestHandler : RouteRPC() == null)
+ {
+ var mailComponent = await scene.World.DataBase.Query(account.Id, true);
+ if (mailComponent == null)
+ {
+ //如果没有邮件组件
+ account.AddComponent();
+ }
+ else
+ {
+ account.AddComponent(mailComponent);
+ }
+ }
await FTask.CompletedTask;
}
diff --git a/Hotfix/Game/Item/AwardItemSystem.cs b/Hotfix/Game/Item/AwardItemSystem.cs
new file mode 100644
index 0000000..adb3fca
--- /dev/null
+++ b/Hotfix/Game/Item/AwardItemSystem.cs
@@ -0,0 +1,36 @@
+using Fantasy;
+using Fantasy.Entitas.Interface;
+
+namespace NB.Game;
+
+public class AwardItemDestroySystem : DestroySystem
+{
+ protected override void Destroy(AwardItem self)
+ {
+ self.ConfigId = 0;
+ self.Count = 0;
+ }
+}
+
+public static class AwardItemSystem
+{
+ public static AwardInfo ToAwardInfo(this AwardItem item)
+ {
+ return new AwardInfo()
+ {
+ ConfigId = item.ConfigId,
+ Count = item.Count
+ };
+ }
+
+ public static List ToAwardInfo(this List items)
+ {
+ var list = new List();
+ foreach (var item in items)
+ {
+ list.Add(item.ToAwardInfo());
+ }
+
+ return list;
+ }
+}
\ No newline at end of file
diff --git a/Hotfix/Game/Item/ItemSystem.cs b/Hotfix/Game/Item/ItemSystem.cs
new file mode 100644
index 0000000..d3ae38a
--- /dev/null
+++ b/Hotfix/Game/Item/ItemSystem.cs
@@ -0,0 +1,62 @@
+using Fantasy;
+using Fantasy.Entitas.Interface;
+
+namespace NB.Game;
+
+public class ItemDestroySystem : DestroySystem-
+{
+ protected override void Destroy(Item self)
+ {
+ self.ConfigId = 0;
+ self.Count = 0;
+ self.IsBind = false;
+ self.ExpirationTime = 0;
+ self.GetTime = 0;
+ self.Abrasion = 0;
+ }
+}
+
+public static class ItemSystem
+{
+ public static ItemInfo ToItemInfo(this Item item)
+ {
+ return new ItemInfo()
+ {
+ ConfigId = item.ConfigId,
+ Id = item.Id,
+ Count = item.Count,
+ // ExpirationTime = item.IsBind;
+ };
+ }
+
+ public static List ToItemInfo(this List
- items)
+ {
+ var list = new List();
+ foreach (var item in items)
+ {
+ list.Add(item.ToItemInfo());
+ }
+
+ return list;
+ }
+
+ public static AwardInfo ToAwardInfo(this Item item)
+ {
+ return new AwardInfo()
+ {
+ ConfigId = item.ConfigId,
+ Count = item.Count
+ };
+ }
+
+ public static List ToAwardInfo(this List
- items)
+ {
+ var list = new List();
+ foreach (var item in items)
+ {
+ list.Add(item.ToAwardInfo());
+ }
+
+ return list;
+ }
+}
\ No newline at end of file
diff --git a/Hotfix/Game/Mail/Components/MailComponentSystem.cs b/Hotfix/Game/Mail/Components/MailComponentSystem.cs
new file mode 100644
index 0000000..e647123
--- /dev/null
+++ b/Hotfix/Game/Mail/Components/MailComponentSystem.cs
@@ -0,0 +1,79 @@
+using Fantasy;
+using Fantasy.Async;
+using Fantasy.Entitas.Interface;
+using Fantasy.Helper;
+
+namespace NB.Game;
+
+public class MailComponentDestroySystem : DestroySystem
+{
+ 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.SendInnerRoute(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 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.SendInnerRoute(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;
+ }
+}
\ No newline at end of file
diff --git a/Hotfix/Game/Mail/Entity/MailBoxSystem.cs b/Hotfix/Game/Mail/Entity/MailBoxSystem.cs
new file mode 100644
index 0000000..c16daa1
--- /dev/null
+++ b/Hotfix/Game/Mail/Entity/MailBoxSystem.cs
@@ -0,0 +1,22 @@
+using Fantasy.Entitas.Interface;
+
+namespace NB.Game;
+
+public class MailBoxDestroySystem : DestroySystem
+{
+ protected override void Destroy(MailBox self)
+ {
+ if (self.Mail != null)
+ {
+ self.Mail.Dispose();
+ self.Mail = null;
+ }
+
+ self.BoxType = MailBoxType.None;
+ self.CreateTime = 0;
+ self.ExpireTime = 0;
+ self.SendAccountId = 0;
+ self.AccountId.Clear();
+ self.Received.Clear();
+ }
+}
\ No newline at end of file
diff --git a/Hotfix/Game/Mail/Entity/MailSystem.cs b/Hotfix/Game/Mail/Entity/MailSystem.cs
new file mode 100644
index 0000000..c754982
--- /dev/null
+++ b/Hotfix/Game/Mail/Entity/MailSystem.cs
@@ -0,0 +1,53 @@
+using Fantasy;
+using Fantasy.Entitas.Interface;
+
+namespace NB.Game;
+
+public class MailDestroySystem : DestroySystem
+{
+ protected override void Destroy(Mail self)
+ {
+ self.OwnerId = 0;
+ self.Title = string.Empty;
+ 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,
+ Title = mail.Title,
+ Content = mail.Content,
+ ExpireTime = mail.ExpireTime,
+ CreateTime = mail.CreateTime,
+ MailState = (int)mail.State,
+ MailType = (int)mail.MailType,
+ Items = mail.Items.ToAwardInfo()
+ };
+ }
+
+ public static List ToMailInfo(this List mails)
+ {
+ var list = new List();
+ foreach (var mail in mails)
+ {
+ list.Add(mail.ToMailInfo());
+ }
+
+ return list;
+ }
+}
\ No newline at end of file
diff --git a/Hotfix/Game/Mail/Helper/MailBoxFactory.cs b/Hotfix/Game/Mail/Helper/MailBoxFactory.cs
new file mode 100644
index 0000000..5f5f7b8
--- /dev/null
+++ b/Hotfix/Game/Mail/Helper/MailBoxFactory.cs
@@ -0,0 +1,55 @@
+using Fantasy;
+using Fantasy.Entitas;
+using Fantasy.Helper;
+
+namespace NB.Game;
+
+public static class MailBoxFactory
+{
+ ///
+ /// 创建一个邮件箱
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static MailBox Create(Scene scene, long sendAccountId, Mail mail, int expireTime, List accountIds)
+ {
+ var mailBox = Entity.Create(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;
+ }
+
+ ///
+ /// 创建一个邮件箱
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static MailBox Create(Scene scene, long sendAccountId, int expireTime, List accountIds, string title,
+ string content, List items = null)
+ {
+ var mail = MailFactory.Create(scene, title, content, items);
+ return Create(scene, sendAccountId, mail, expireTime, accountIds);
+ }
+}
\ No newline at end of file
diff --git a/Hotfix/Game/Mail/Helper/MailFactory.cs b/Hotfix/Game/Mail/Helper/MailFactory.cs
new file mode 100644
index 0000000..b43a4b1
--- /dev/null
+++ b/Hotfix/Game/Mail/Helper/MailFactory.cs
@@ -0,0 +1,30 @@
+using Fantasy;
+using Fantasy.Entitas;
+using Fantasy.Helper;
+using Fantasy.Serialize;
+
+namespace NB.Game;
+
+public static class MailFactory
+{
+ private static readonly ISerialize _serializer = SerializerManager.GetSerializer(FantasySerializerType.Bson);
+
+ public static Mail Create(Scene scene, string title, string content, List items = null)
+ {
+ var mail = Entity.Create(scene, true, true);
+ mail.Title = title;
+ 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;
+ }
+}
\ No newline at end of file
diff --git a/Hotfix/Game/Mail/Helper/MailHelper.cs b/Hotfix/Game/Mail/Helper/MailHelper.cs
new file mode 100644
index 0000000..1e0aa09
--- /dev/null
+++ b/Hotfix/Game/Mail/Helper/MailHelper.cs
@@ -0,0 +1,31 @@
+using Fantasy;
+using Fantasy.Async;
+
+namespace NB.Game;
+
+///
+/// 发送邮件接口
+///
+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;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/Hotfix/Hotfix.csproj b/Hotfix/Hotfix.csproj
index 2707d36..99d72ad 100644
--- a/Hotfix/Hotfix.csproj
+++ b/Hotfix/Hotfix.csproj
@@ -12,4 +12,8 @@
+
+
+
+