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

cs 复制代码
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的载体挂到玩家身上

cs 复制代码
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上和玩家组件处于同一层级

cs 复制代码
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

cs 复制代码
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

cs 复制代码
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^)┛

相关推荐
fkdw1 小时前
C# Newtonsoft.Json 反序列化派生类数据丢失问题
c#·json
浅尝辄止;4 小时前
C# 异步编程
c#
m0_748251725 小时前
Android webview 打开本地H5项目(Cocos游戏以及Unity游戏)
android·游戏·unity
gantengsheng5 小时前
基于51单片机和OLED12864的小游戏《贪吃蛇》
单片机·嵌入式硬件·游戏·51单片机
264玫瑰资源库5 小时前
从零开始C++棋牌游戏开发之第三篇:游戏的界面布局设计
开发语言·c++·python·游戏·pygame·源代码管理
264玫瑰资源库5 小时前
从零开始C++游戏开发之第七篇:游戏状态机与回合管理
开发语言·c++·游戏
ou.cs7 小时前
c# 实现一个简单的异常日志记录(异常迭代+分片+定时清理)+AOP Rougamo全局注入
c#
一只小小汤圆9 小时前
编译笔记:vs 中 正在从以下位置***加载符号 C# 中捕获C/C++抛出的异常
c++·c#
码农君莫笑9 小时前
Blazor项目中使用EF读写 SQLite 数据库
linux·数据库·sqlite·c#·.netcore·人机交互·visual studio