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
    {
        //邮件Id
        public 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.mfbz.cn/a/752459.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

远程过程调用RPC实现原理

Hi~&#xff01;这里是奋斗的小羊&#xff0c;很荣幸您能阅读我的文章&#xff0c;诚请评论指点&#xff0c;欢迎欢迎 ~~ &#x1f4a5;&#x1f4a5;个人主页&#xff1a;奋斗的小羊 &#x1f4a5;&#x1f4a5;所属专栏&#xff1a;C语言 &#x1f680;本系列文章为个人学习…

深度挖掘数据资产,洞察业务先机:利用先进的数据分析技术,精准把握市场趋势,洞悉客户需求,为业务决策提供有力支持,实现持续增长与创新

在当今日益激烈的商业竞争环境中&#xff0c;企业想要实现持续增长与创新&#xff0c;必须深入挖掘和有效运用自身的数据资产。数据不仅是企业运营过程中的副产品&#xff0c;更是洞察市场趋势、理解客户需求、优化业务决策的重要资源。本文将探讨如何通过利用先进的数据分析技…

多行业预约门店服务小程序源码系统 支持多门店预约 带完整的安装代码包以及搭建教程

系统概述 该系统基于先进的云计算和大数据技术&#xff0c;采用模块化设计&#xff0c;具有高度的可扩展性和可定制性。无论是餐饮、美容美发、健身房还是其他服务行业&#xff0c;都可以通过该系统轻松实现多门店预约功能。同时&#xff0c;我们还提供了丰富的接口和插件&…

stylelint 配置

1.vscode 安装插件Stylelint 2.项目安装插件 pnpm i stylelint stylelint-config-standard stylelint-config-recommended-scss stylelint-config-recommended-vue postcss postcss-html postcss-scss stylelint-config-recess-order stylelint-config-html -D 依赖 说明 备…

如何判断一个Repo是否是Private还是Internal?

Github的Repository分为三种类型&#xff0c;主要是用于决定谁可以访问、查看和克隆该仓库。GitHub 提供了几种不同的可见性选项&#xff0c;包括 Private、Public 和 Internal。 Private 只有仓库的拥有者和被明确邀请为协作者&#xff08;Collaborator&#xff09;的用户才能…

VMware虚拟机移植保姆级教程

文章目录 前言:一、打包与备份二、VMware移植1. 文件介绍2. 移植过程总结:前言: 前几日对电脑做了一个大的更新升级,不仅将硬件进行了升级,还对电脑的软件进行了升级也就是我从Win10今家庭版升级到Win11专业版啦,之前没有升级是因为数据量很多,怕升级后找不到自己需要的…

Windows和Linux C++判断磁盘空间是否充足

基本是由百度Ai写代码生成的&#xff0c;记录一下。实现此功能需要调用系统的API函数。 对于Windows&#xff0c;可调用函数GetDiskFreeSpaceEx&#xff0c;使用该函数需要包含头文件windows.h。该函数的原型&#xff1a; 它的四个参数&#xff1a; lpDirectoryName&#xff0…

基于SpringBoot养老院管理系统设计和实现(源码+LW+调试文档+讲解等)

&#x1f497;博主介绍&#xff1a;✌全网粉丝10W,CSDN作者、博客专家、全栈领域优质创作者&#xff0c;博客之星、平台优质作者、专注于Java、小程序技术领域和毕业项目实战✌&#x1f497; &#x1f31f;文末获取源码数据库&#x1f31f;感兴趣的可以先收藏起来&#xff0c;还…

基于改进天鹰优化算法(IAO)优化RBF神经网络数据回归预测 (IAO-RBF)的数据回归预测(多输入多输出)

改进天鹰优化算法(IAO)见&#xff1a;【智能优化算法】改进的AO算法(IAO)-CSDN博客 代码原理 基于改进天鹰优化算法&#xff08;IAO&#xff09;优化RBF神经网络数据回归预测&#xff08;IAO-RBF&#xff09;的多输入多输出&#xff08;MIMO&#xff09;数据回归预测&#xf…

CVPR24已开源:刷新监督学习SOTA,无监督多目标跟踪时代来临!

论文标题&#xff1a; Matching Anything by Segmenting Anything 论文作者&#xff1a; Siyuan Li, Lei Ke, Martin Danelljan, Luigi Piccinelli, Mattia Segu, Luc Van Gool, Fisher Yu 导读&#xff1a; 在计算机视觉的征途中&#xff0c;多目标跟踪&#xff08;MOT&…

Centos安装redis(附:图形化管理工具)

第一步&#xff1a;下载redis wget http://download.redis.io/releases/redis-6.2.7.tar.gz 第二步&#xff1a;解压 tar zxvf redis-6.2.7.tar.gz 第三步&#xff1a;安装依赖环境 yum -y install gcc-c第四步&#xff1a;安装依赖环境 make install第五步&#xff1a;修…

开源项目-商城管理系统

哈喽&#xff0c;大家好&#xff0c;今天主要给大家带来一个开源项目-商城管理系统 商城管理系统分前后端两部分。前端主要有商品展示&#xff0c;我的订单&#xff0c;个人中心等内容&#xff1b;后端的主要功能包括产品管理&#xff0c;门店管理&#xff0c;会员管理&#x…

C++之STL(十)

1、适配器 2、函数适配器 #include <iostream> using namespace std;#include <algorithm> #include <vector> #include <functional>bool isOdd(int n) {return n % 2 1; } int main() {int a[] {1, 2, 3, 4, 5};vector <int> v(a, a 5);cou…

外贸人该怎么进行客户分类,怎么找出那20%的重要客户?

更多外贸干货及开发见客户的方法&#xff0c;尽在微信【千千外贸干货】 我们往往只是知道这个规则&#xff0c;却不懂怎么去进行客户分类&#xff0c;怎么找出这20%的重要客户&#xff1f; 具体而言&#xff0c;有8个指标来衡量&#xff1a; 1 利润率高 不以盈利为目的的企业…

使用python基于经纬度获取高德地图定位地址【逆地址解析】

一、高德地图api申请 1. 高德开放平台注册&#xff0c;登录 进入网址&#xff1a;高德开放平台 | 高德地图API 注册 -- 支付宝扫码认证 -- 完善个人信息 -- 登录 2. 申请API &#xff08;1&#xff09;点击头像 -- 应用管理 -- 我的应用 -- 创建新应用 &#xff08;2&…

对于恒指你了解够多吗?

不少人进入股市选择投资哪种哪种期货&#xff0c;都是因为听别人说利润大&#xff0c;于是也不管三七二十一&#xff0c;就盲目的跟着投资了&#xff0c;认为所有的期货都应该应用一样的操作办法&#xff0c;随机应变就是了&#xff0c;其实不然&#xff0c;每种期货都有着自己…

springboot3.x的优势在哪里,我们是否要选择springboot3.x

Spring Boot 3.x的优势主要体现在以下几个方面&#xff0c;这些优势使得它成为了一个值得考虑的选择&#xff1a; Java 17支持&#xff1a;Spring Boot 3.x 支持 Java 17&#xff0c;这是一个长期支持&#xff08;LTS&#xff09;版本&#xff0c;带来了许多新特性和性能改进。…

从ChatGPT代码执行逃逸到LLMs应用安全思考

摘要 11月7日OpenAI发布会后&#xff0c;GPT-4的最新更新为用户带来了更加便捷的功能&#xff0c;包括Python代码解释器、网络内容浏览和图像生成能力。这些创新不仅开辟了人工智能应用的新境界&#xff0c;也展示了GPT-4在处理复杂任务方面的惊人能力。然而&#xff0c;与所有…

亚马逊云科技快速上手训练营:模块一

课程目标 初步了解云平台与本地环境的差异初步了解亚马逊云科技平台的基础设施和部分核心服务初步了解亚马逊云科技平台上的弹性高可用架构初步了解亚马逊云科技平台上的架构设计准则初步了解本地架构迁移上云的基本知识 1.亚马逊云科技平台简介 1.1 什么是云计算&#xff1…

倒装COB封装技术与常规SMD封装技术差异对比

倒装COB显示屏与常规SMD LED显示屏一个很大的差异点就是在于封装工艺的不同&#xff0c;COB&#xff08;Chip on Board&#xff09;封装和SMD&#xff08;Surface Mounted Device&#xff09;封装是LED显示屏领域中两种常见的技术&#xff0c;所表现出来的差异主要在于封装结构…