ET实现游戏中邮件系统逻辑思路(服务端)

ET是一个游戏框架,用的编程语言是C#,游戏引擎是Unity,框架作者:熊猫       ET社区

在游戏中我们通常都会看到有邮件系统,邮件系统的作用有给玩家通知、发放奖励等

下面小编使用ET框架带大家看一下邮件系统的一种实现方式。

一、实现思路

小编所理解的ECS编程是这样的:组件实体组件实体之间组装(类似于拼积木)

按照这个想法我们要实现一个邮件系统这就需要邮件的实体和组件了。

玩家的实体是Unit,邮件组件作为玩家的一部分挂到Unit上,那邮件的收发操作是怎么实现的呢?


看美剧一般小镇上每户人家家门口都会有一个小邮箱,邮递员会把邮件放到这个小邮箱里。家里人发现有邮件来了就到这个小邮箱查看并拿回家给具体的收件人。

实现邮件系统思路和拿邮件是类似的,这里我们就需要一个邮件管理组件EmailManagerComponent来作为小邮箱。

1、邮件管理组件EmailManagerComponent 和玩家组件处在同一层级(家门口的小邮箱可以存放不同人的邮件)

2、邮件组件EmailComponent 是玩家组件的子组件(邮件要给具体的收件人)

3、当系统或者其他玩家发送邮件时会先保存到邮件管理组件EmailManagerComponent中(邮递员把邮件放入小邮箱)

4、当玩家点击邮件按钮时会通过自身的Id标识到邮件管理组件去找自己的邮件

5、如果发现有自己的邮件则保存到玩家自己身上(邮件给到具体收件人)

6、保存好后邮件管理组件会将移除玩家已领取的邮件。(释放邮件管理组件资源)

7、发送邮件(收件人的Id作为唯一标识暂时保存到邮件管理组件中等待收件人领取)

二、编码

2.1 EmailInfo

邮件一般会有发送时间、发件人、收件人、标题、内容等等(根据实际情况自己定义)。

那这个邮件实体我们命名为EmailInfo

namespace ET.Server
{[ChildOf(typeof(EmailComponent))]public class EmailInfo: Entity, IAwake,IDestroy{//奖励public List<int> ItemId;        //奖励物品Id列表public List<long> ItemValue;    //奖励物品数量列表//邮件领取状态  0:未领取,1:已领取public int Status;//发件人public string Sender;//收件人public string Receiver;//发送时间public int SenderTime;//标题public string Title;//内容public string Text;//邮件删除状态:1 删除,0 未删除public int DelteType = 0;}
}

2.2 EmailComponent

定义好实体后我们来定义邮件组件EmailComponent 来作为 EmailInfo 的载体挂到玩家身上

namespace ET.Server
{[ComponentOf(typeof(Unit))]public class EmailComponent : Entity, IAwake, IDestroy, IDeserialize, ITransfer, IUnitCache{//邮件Idpublic int EmailId = 1;[BsonDictionaryOptions(DictionaryRepresentation.ArrayOfArrays)]public Dictionary<int, EmailInfo> Emails = new Dictionary<int, EmailInfo>();}
}

2.3 EmailManagerComponent

邮件管理组件挂载到Scene上和玩家组件处于同一层级

namespace ET.Server
{[ComponentOf(typeof(Scene))]public class EmailManagerComponent : Entity,IAwake,IDestroy{public long Timer;// 玩家接收新的邮件 字典Key存储玩家ID,Value采用List是一个玩家可能会收到多封邮件[BsonDictionaryOptions(DictionaryRepresentation.ArrayOfArrays)]public Dictionary<long, List<EmailInfo>> EmailUnitInfos = new Dictionary<long, List<EmailInfo>>();}
}

2.4 EmailComponentSystem

邮件组件所实现的动作:EmailComponentSystem

using System.Collections.Generic;
using System.Linq;namespace ET.Server
{public class EmailInfoComponentDestroySystem: DestroySystem<EmailComponent>{protected override void Destroy(EmailComponent self){self.Emails.Clear();}}[FriendOf(typeof(EmailComponent))][FriendOf(typeof(EmailInfo))]public static class EmailComponentSystem{//Status奖励领取状态  0:未领取,1:已领取public static List<EmailProto> GetEmailList(this EmailComponent self,int SystemType){List<EmailProto> emailProtos = new List<EmailProto>();foreach (var item in self.Emails){//DelteType == 0 未删除if (item.Value.DelteType == 0){int todayKey = (int)TimeHelper.ClientNowSeconds();if (todayKey >= item.Value.StarAt && todayKey <= item.Value.EndAt){emailProtos.Add(new EmailProto(){ItemId = item.Value.ItemId,ItemValue = item.Value.ItemValue,Status = item.Value.Status,Sender = item.Value.Sender,Receiver = item.Value.Receiver,SenderTime = (int)item.Value.StarAt,Title = item.Value.Title,Text = item.Value.Text,EmailId = item.Key,});   }}}List<EmailProto> lists =  emailProtos.OrderByDescending(e => e.SenderTime).ToList();return lists;}//获取新邮件public static void GetNewEmail(this EmailComponent self,List<EmailInfo> emailInfos){if (emailInfos ==null || emailInfos.Count==0){return;}for (int i = 0; i < emailInfos.Count; i++){self.Emails.Add(self.EmailId+=1,new EmailInfo{ItemId = emailInfos[i].ItemId,ItemValue = emailInfos[i].ItemValue,Status = emailInfos[i].Status,Sender = emailInfos[i].Sender,Receiver = emailInfos[i].Receiver,SenderTime = emailInfos[i].SenderTime,Title = emailInfos[i].Title,Text = emailInfos[i].Text,StarAt = emailInfos[i].StarAt,EndAt = emailInfos[i].EndAt,SystemType = emailInfos[i].SystemType,});   }}//删除邮件public static string DeleteEmail(this EmailComponent self, int EmailId){string resultMsg = "该邮件不存在"; if (self.Emails.ContainsKey(EmailId) && self.Emails[EmailId].Status == 1){//self.Emails.Remove(EmailId); self.Emails[EmailId].DelteType = 1;resultMsg = "删除成功";}return resultMsg ;}}
}

2.5 EmailManagerComponentSystem

邮件管理组件所实现的动作:EmailManagerComponentSystem

namespace ET.Server
{public class EmailManagerComponentDestroySystem: DestroySystem<EmailManagerComponent>{protected override void Destroy(EmailManagerComponent self){TimerComponent.Instance.Remove(ref self.Timer);}}public class EmailManagerComponentAwakeSystem: AwakeSystem<EmailManagerComponent>{protected override void Awake(EmailManagerComponent self){self.Timer = TimerComponent.Instance.NewRepeatedTimer(10000, TimerInvokeType.EmailManagerUpdate, self);}}//定时器 每隔10秒钟保存一次邮件信息    [Invoke(TimerInvokeType.EmailManagerUpdate)]public class  EmailManagerComponentTimer : ATimer<EmailManagerComponent>{protected override void Run(EmailManagerComponent self){try{if ( self.IsDisposed || self.Parent == null ){return;}if ( self.DomainScene() == null || self.DomainScene().Name != "Map1"){return;}self?.SaveEmailManagerComponent();}catch (Exception e){Log.Error(e.ToString());}}}[FriendOf(typeof(EmailManagerComponent))][FriendOf(typeof(DBManagerComponent))][FriendOf(typeof(EmailSystemInfo))][FriendOf(typeof(EmailInfo))]public static class EmailManagerComponentSystem{//系统启动时从数据库加载邮件管理组件信息public static async ETTask LoadEmailInfo(this EmailManagerComponent self){var EmailManagerList =  await DBManagerComponent.Instance.GetZoneDB(self.DomainZone()).Query<EmailManagerComponent>(d => true,collection:"EmailManagerComponent");}//玩家之间发送邮件public static void SendNewEmail(this EmailManagerComponent self,long receiveId,EmailProto emailProto){//如果邮件中有附件奖励设置可领取状态if (emailProto.ItemValue == null && emailProto.ItemId == null){emailProto.Status = 1;}else{emailProto.Status = 0;  }EmailInfo emailInfo = new EmailInfo{ItemId = emailProto.ItemId,ItemValue = emailProto.ItemValue,Status = emailProto.Status,Sender = emailProto.Sender,Receiver = emailProto.Receiver,SenderTime = (int) (TimeHelper.ServerNow()/1000),Title = emailProto.Title,Text = emailProto.Text,};if (!self.EmailUnitInfos.ContainsKey(receiveId)){List<EmailInfo> list = new List<EmailInfo>();list.Add(emailInfo);self.EmailUnitInfos.Add(receiveId,list);  }else{self.EmailUnitInfos[receiveId].Add(emailInfo);   }}//获取玩家收到的新邮件public static List<EmailInfo>  ReceiveNewEmail(this EmailManagerComponent self,long unitId){List<EmailInfo> list = new List<EmailInfo>();if (!self.EmailUnitInfos.ContainsKey(unitId)){self.EmailUnitInfos.Add(unitId,list);}else{//玩家接收了此邮件,接收状态改为已接收for (int i = 0; i < self.EmailUnitInfos[unitId].Count; i++){list.Add(self.EmailUnitInfos[unitId][i]);}self.EmailUnitInfos.Remove(unitId);}//根据时间戳进行排序list.OrderByDescending(l => l.SenderTime).ToList();return list;}//获取玩家所有状态的邮件(已接收的和未接收的)public static List<EmailInfo> ReceiveAllEmail(this EmailManagerComponent self, long unitId){List<EmailInfo> list = new List<EmailInfo>();if (!self.EmailUnitInfos.ContainsKey(unitId)){self.EmailUnitInfos.Add(unitId,list);return list;}for (int i = 0; i < self.EmailUnitInfos[unitId].Count; i++){list.Add(self.EmailUnitInfos[unitId][i]);}//根据时间戳进行排序list.OrderByDescending(l => l.SenderTime).ToList();return list;}//保存public static void SaveEmailManagerComponent(this EmailManagerComponent self){Log.Debug("---------------------------开始保存邮件信息");DBManagerComponent.Instance.GetZoneDB(self.DomainZone()).Save(self,"EmailManagerComponent").Coroutine();}}
}

邮件系统的实现思路之一是这样,还要根据具体业务逻辑实现具体动作并写接口去调用组件所实现的这些动作。有不对的地方欢迎大家提出来一起讨论,本篇先介绍到这里,拜拜┏(^0^)┛

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/35809.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

「C系列」C 经典练习实例

文章目录 1. 基本输入输出2. 字符串操作3. 数组与循环4. 函数与递归5. 逻辑与条件6. 数学问题7. 数字与数学8. 数组与字符串9. 逻辑与条件10. 结构体和联合体11. 指针12. 文件操作13. 动态内存分配相关链接 C语言经典练习实例及详细代码可以涵盖多个方面&#xff0c;从基础输入…

中国近10年AGV共部署了351700台……

导语 大家好&#xff0c;我是社长&#xff0c;老K。专注分享智能制造和智能仓储物流等内容。 新书《智能物流系统构成与技术实践》 根据网络上公开数据获得如下信息。仅供参考。 如下为中国近十年AGV部署的公开数据&#xff1a; 2014-2018年&#xff0c;中国AGV机器人累计销量达…

没有思考过 Embedding,不足以谈 AI

在当今的人工智能&#xff08;AI&#xff09;领域&#xff0c;Embedding 是一个不可或缺的概念。如果你没有深入理解过 Embedding&#xff0c;那么就无法真正掌握 AI 的精髓。接下来&#xff0c;我们将深入探讨 Embedding 的基本概念。 1. Embedding的基本概念 1.1 什么是 Emb…

【数据采集】亮数据浏览器、亮网络解锁器实战指南

前言 继上次我们写了数据采集与AI分析&#xff0c;亮数据通义千问助力跨境电商前行的文章之后&#xff0c;好多小伙伴来后台留言&#xff0c;表示对亮数据的数据采集非常感兴趣&#xff0c;并且感觉用起来非常顺手&#xff0c;大大减少了小白用户获取数据的成本。 在这儿&…

【python爬虫实战】爬取书店网站的 书名价格(注释详解)

思路来源&#xff1a;b站视频【【Python爬虫】爆肝两个月&#xff01;拜托三连了&#xff01;这绝对是全B站最用心&#xff08;没有之一&#xff09;的Python爬虫公开课程&#xff0c;从入门到&#xff08;不&#xff09;入狱 &#xff01;-哔哩哔哩】 https://b23.tv/M79rxMd …

docker 学习之路

文章目录 1、官方文档2、常用命令挂载Docker容器内运行的脚本或命令常用 3、介绍4、Dockerfile5、问题6、链接 ​ 1、官方文档 Docker 是一个开源的应用容器引擎&#xff0c;让开发者可以打包他们的应用以及依赖包到一个可移植的镜像中&#xff0c;然后发布到任何流行的 Linux…

基于 Paimon 的袋鼠云实时湖仓入湖实战剖析

在当今数据驱动的时代&#xff0c;企业对数据的实施性能力提出了前所未有的高要求。为了应对这一挑战&#xff0c;构建高效、灵活且可扩展的实时湖仓成为数字化转型的关键。本文将深入探讨袋鼠云数栈如何通过三大核心实践——ChunJun 融合 Flink CDC、MySQL 一键入湖至 Paimon …

我用低代码平台自己搭建了一套MES应用系统,1天搞定!

MES系统是什么 MES系统是一套面向制造企业车间执行层的生产信息化管理系统。它能够为操作人员和管理人员提供计划的执行、跟踪以及所有资源&#xff08;包括人、设备、物料、客户需求等&#xff09;的当前状态。通过MES系统可以对从订单下达到产品完成的整个生产过程进行优化管…

Intellij Idea显示回退和前进按钮的方法

方法1 使用快捷键&#xff1a; 回到上一步 ctrl alt <-&#xff08;左方向键&#xff09;回到下一步 ctrl alt ->&#xff08;右方向键&#xff09; 方法2&#xff1a; Preferences -> Appearance & Behavior -> Menus and Toolbars -> Navigation B…

生信技能50 - 本地构建Clinvar数据库VCF变异位点快速搜索功能

1. Clinvar数据库文件下载 参考本人文章: 生信技能40 - Clinvar数据库VCF文件下载和关键信息提取 # 下载GRCh37 vcf wget -c -b https://ftp.ncbi.nlm.nih.gov/pub/clinvar/vcf_GRCh37/clinvar_20240624.vcf.gz wget https://ftp.ncbi.nlm.nih.gov/pub/clinvar/vcf_GRCh37/…

森林草原火险因子综合监测系统解决方案

一、概述 根据应急管理部和国家统计局发布的数据&#xff0c;2023 年全国共接报火灾 74.5 万起&#xff0c;其中森林火灾 328 起&#xff0c;共发生草原火灾 15 起。为应对这一严峻挑战我国正面临着森林草原火险的严重威胁。森林火灾不仅对生态文明建设构成严重威胁&#xff0c…

顶顶通呼叫中心中间件-透传uuid并且导入对端变量到本端(mod_cti基于Freeswitch)

一、配置拨号方案 win-ccadmin配置方法 点击拨号方案 -> 点击进入排队 -> 根据图中配置。如果不是排队转人工是机器人转人工那么就是在机器人那个拨号方案配置&#xff0c;并且需要配置在"cti_robot"之前即可 action"set" data"sip_h_X_tas…

第2章.现场设备的物联网模式--设备网关

第2章.现场设备的物联网模式 本章列出了与现场设备或事物相关的关键模式。阅读本章后&#xff0c;您将能够识别物联网架构中这些模式的存在。它提供了有关模式适合或适用的场景的详细信息&#xff0c;以及需要考虑的约束。这将帮助您相对轻松地理解现有的物联网架构。 本章涵盖…

【论文阅读】Answering Label-Constrained Reachability Queries via Reduction Techniques

Cai Y, Zheng W. Answering Label-Constrained Reachability Queries via Reduction Techniques[C]//International Conference on Database Systems for Advanced Applications. Cham: Springer Nature Switzerland, 2023: 114-131. Abstract 许多真实世界的图都包含边缘标签…

腾讯云TI平台的大模型精调解决方案

腾讯云TI平台的大模型精调解决方案 随着人工智能和大数据技术的快速发展&#xff0c;大模型在各行各业的应用日益广泛。然而&#xff0c;大规模模型的训练和部署面临着诸多挑战&#xff0c;包括训练资源的高效利用、模型训练的稳定性和国产化适配需求。腾讯云TI平台凭借其强大…

从@Param注解开始,深入了解 MyBatis 参数映射的原理

系列文章目录 MyBatis缓存原理 Mybatis plugin 的使用及原理 MyBatisSpringboot 启动到SQL执行全流程 数据库操作不再困难&#xff0c;MyBatis动态Sql标签解析 Mybatis的CachingExecutor与二级缓存 使用MybatisPlus还是MyBaits &#xff0c;开发者应该如何选择&#xff1f; 巧…

js异常处理方案

文章目录 异常处理方案同步代码的异常处理Promise 的异常处理async await 的异常处理 感谢阅读&#xff0c;觉得有帮助可以点点关注点点赞&#xff0c;谢谢&#xff01; 异常处理方案 在JS开发中&#xff0c;处理异常包括两步&#xff1a;先抛出异常&#xff0c;然后捕获异常。…

AI在创造还是毁掉一些东西

今天突然闪现一个念头&#xff0c;AI真的能带来进步吧。AI能个我们带来什么&#xff1f; 突发这个想法的原因是早上乘车的时候看到一个7,8岁的小孩脖子上带了AI学习机。我在想&#xff0c;小孩都通过AI来学习了&#xff0c;还能提升创造吗&#xff1f;这引起了我的担忧。也许AI…

关于0xc000007b的一种解决方案

今天我在安装qview并运行时时&#xff0c;遇到了这个问题。 我在网上查找了许多解决方案&#xff0c;但它们大多都说是某些dll缺失或错误引起的。 这些说法应该是正确的&#xff0c;但我用了dll修复工具后&#xff0c;一点用都没有。 后来捣鼓半天后&#xff0c;我发现很可能…

模拟实现string【C++】

文章目录 全部的实现代码放在了文章末尾准备工作包含头文件定义命名空间和类类的成员变量 构造函数默认构造拷贝构造 重载赋值拷贝函数析构函数迭代器和获取迭代器迭代器获取迭代器 resize【调整size】图解 reserve【调整capacity】empty【判断串是否为空】operator[]appendpus…