【OpenSourceC#】ET框架

news2024/10/7 12:18:53

1. 前言

ET算是我刚接触客户端时最早知道的框架,ET我最初眼馋的还是他的双端功能。包揽前后端的功能,这个很有吸引力。但是那时候对我来说这框架太复杂了,没法看。

这两天又来看看,曾经很多不懂的地方现在都能看懂了,看了之后发现这框架还是不适合我,原因总结里再说,在这里做一下记录。

首先说一下很多新手看这个框架的疑惑点,再说一下ET最有特色的几个功能:ETTask、事件系统、双端开发。

2. 新手常见问题

这些问题是我以一个新手的视角来看的。也是我最初接触这个框架以来有疑惑的地方。

2.1 目录结构问题

这里以7.2的目录为例。ET6就不用看了,就是闹着玩儿。

代码位置

主要关心以下三个目录,其中Share文件夹下主要是一些工具和分析器,分析器作用是规范C#的代码规范,编码时做出提示,不需过多关注。

代码都在Unity下,DotNet目录下有csproj,引用的Unity/Assets/Scripts/Codes里的文件,这样服务端开发就只关心Dotnet目录下的代码就行,再次强调,代码文件在Unity目录下,DotNet里相当于是软链接。

这样代码统一放到Unity工程里,双端开发也方便(ps: 实际我还是觉得客户端和服务端分开更好)
在这里插入图片描述
在这里插入图片描述

Unity目录

这个就是Unity工程目录,代码在Assets\Scripts 下,这下面又有很多目录,
其中Empty是占位用的,占着几个程序集(ps: 具体啥作用没细看,估计编译需要)
Loader是程序入口,加载程序集
Core、Editor、ThirdParty见名知意
Codes就是我们写程序的目录,DotNet也是链接到这个目录的。
在这里插入图片描述
其中目录如下,四个目录,Model ModelView Hotfix HotfixView,这样划分是为了逻辑和数据分离。 Model只有数据。hotfix只有逻辑。其中 Model view和HotfixView,只有客户端用,用于表现层。

这四个目录的每个目录下分别有Client Server Share文件夹,Client写客户端代码,Server写服务端代码,Share写两端共用的代码,这样服务端也有客户端代码,可以做AI机器人。
在这里插入图片描述

2.2 程序集问题

看了目录划分后对于纯新手来说又有疑惑了,程序集是什么?作用是什么?

这还真是我一开始的疑惑,程序集可以理解为包,一个程序集可以编译成.dll给别的程序集使用。

那为什么这么分程序集呢?

这里你得明白dll或者说so文件的作用,可以动态链接。这样就能实现热重载的功能。
同时能提高编引速度。比如有ABC三个程序集。 A依赖B,B依赖C,这时候如果B修改了,只有AB会重新编译。如果只有A修改了,则只有A会重新编译。

这里你顺便说一个程序域的概念,看源码的时候能看到AppDomain,一个进程可以有多个域,一个域可以加载多个程序集。区域相当于提供一个独立的运行环境。

3. ETTask

为什么不用原生Task呢,因为Task是多线程的,起一个Task会在子线程运行。
ETTask实现了单线程的Task,其他类似的库还有UniTask

使用多线程实际没什么问题,但是要保证另外的线程逻辑是线程安全的,然而有时候你觉得是线程安全的,可能会有各种bug,这种bug就不好找。还要处理数据线程数据同步问题。
而unity主程序本身是单线程的,加上多线程强行增加复杂度,使用单线程异步可以避免很多问题。
Unity对跨线程的处理都是把委托投递到一个队列,主线程Update()不停从队列中取出委托执行

那为什么不用Corotine呢?
Corotine必须在mono脚本下执行,而且效率貌似也不如Task异步。

4. 事件系统与标签

这个可以说是ET的核心了,不过不能被名字欺骗了,这个事件系统不只是其他游戏框架中用到的那种事件,这里面还管理所有的标签类型。

ET的一个特色就是对标签的大量使用,这也是对新手很不友好的地方,也大大提高了代码的阅读难度。

代码就是Core/Module/EventSystem/EventSystem.cs,目前看其中主要实现了对不同标签类型的管理,这里只说两个,常见的事件系统和SystemComponent机制

4.1 常见的事件系统

使用

就是一般游戏框架中用到的那种事件系统,ET的用法比较特殊,如下图所示,对事件的注册不是显式调用register,而是写一个类,打上Event标签,这个类要继承AEvent,AppStartInitFinish就是事件参数,也是通过这个区分事件的,下图中这个事件对应两个处理方法,触发事件的时候会调用这个类的Run()函数

原理

简单来说,就是EventSystem 启动时找到所有打上Event标签的类统一管理,调用Publish发布事件时,根据事件参数找到对应的事件类。依次调用每个事件类的Run方法。

下面是截代码的图分析:

  1. 启动之前会注册事件,通过Attribute的方式
    在这里插入图片描述

  2. 在Add方法中,会找到所有BaseAttribute标签的类型,所有自定义的标签都是继承自这个标签
    在这里插入图片描述

  3. 再在其中找到所有event标签的类型,加入allEvents统一管理
    在这里插入图片描述

  4. 同理处理Invoke标签的类型。
    在这里插入图片描述

  5. 事件触发,就是从allEvents中找到T类型对应的事件。一个事件可能有多个EventInfo,也就是多个处理响应,依次进行调用。比如下面第2张图中的例子。其中加了一个scene的概念,相当于就是对事件又进行分层,只发到对应的层。
    在这里插入图片描述在这里插入图片描述

  6. 上图中对时间的使用。添加Event标签才能注册到事件系统里。继承AEvent是因为事件系统会调用它的Handle方法,Handle实际调用的Run,Run()就是自己要实现的对事件的处理。

在这里插入图片描述

4.2 SystemComponent机制

这个也是用上面的EventSystem实现的。

  1. 还是如上面的例子在Add()中找到所有ObjectSystem标签并用typeSystems统一管理。
    在这里插入图片描述

  2. 比如Awake的系统。调用EventSystem的Awake后,所有实现该接口的系统都会调用
    在这里插入图片描述

  3. 以MoveComponent为例,它的MoveComponentSystem里实现了AwakeSystem,在这里打断点调试一下,可以看到调用栈如图2,总之就是在添加MoveComponent这个组件时,调用了EventSystem.Instance.Awake(component),从而调用了所有继承AwakeSystem<MoveComponent>的类型的Run。
    在这里插入图片描述
    在这里插入图片描述

4.3 单独声明一下

因为没用ET写过项目,只是看了下代码,可能对这EventSystem理解有偏差,不过应该没啥大问题

5. 热重载

下面两个图就能知道热重载的大概逻辑。
按R调用CodeLoder的LoadHotfix()方法。
这个方法里重新加载Hotfix的dll。
可见热重载之前要先手动编译一下Hotfix dll,再按R。
在这里插入图片描述
在这里插入图片描述

5. 双端开发

实际就是客户端代码写在Client 的目录下,服务端写在Server目录下,实际上客户端和服务端的交互还是通过RPC。

这么一看,双端开发就是能在一个编辑器下开发,我反而觉得很不方便。因为每个目录下都划分client 和server,看着太乱了,不如开两个项目。

关于共用代码,这种需求感觉并不是那么需要,使用的一样的代码直接复制就行了。

总结

最后再声明一下,这个框架我还没有弄得特别透彻。因为现在大致看懂了整体架构之后,觉得不太适合我。也就没有了继续深入的想法。以上只是看源码,demo的一些收获,有错误的地方欢迎指正。

再说几句,我的个人想法,仅代表个人意见。我觉得这样整的过于繁琐了,无论是目录的划分,还是所谓的独特的ECS机制。

也没有体会到这种System-Component的好处,只觉得代码过于散乱,可能是没有实际使用ET开发过,只是看了看例子吧。

双端开发也没有当初一无所知时所认为的那么神秘,还是客户端代码和服务端代码分开了,反而代码混合在一起显得更乱了,不如分开。而且服务端定义的zone、scene这一套,我现在还没完全理解这些概念,估计应该是区、服和进程的区分,相当于得完全在这一套逻辑下使用,没用过所以也不知道方不方便拓展。

事件系统和标签的使用也感觉不适应,当然熟悉了这种开发方式后也能用,但是就和JEngine中使用的订阅模式的事件系统一样,可以但没有必要,还是传统观察者模式的事件系统更好用一些,其他也没有什么效率上的优化。

热重载是有用,但对于快速开发又不是很必须。对于服务端来说热重载就应该更不需要了吧,就我有限的服务端开发经历,之前写的寻路服务,需要构建全地图的障碍和navmesh信息,重启虽然不是立刻就启动了,但用的时间也不是不能忍受。

当然,这框架的实现还是挺独特的,可能是我还体会不到这框架的好处,虽然现在暂时pass了,以后还会继续关注,可能以后就用到了呢。

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

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

相关文章

数据库拆分5--使用sharding-jdbc来实现水平拆分

有三张表 user log order表&#xff0c;先将user log 和order垂直分库&#xff0c;然后将user表水平拆分 配置文件 spring.shardingsphere.enabledtruespring.shardingsphere.datasource.nameswim-user,wim-orderspring.shardingsphere.datasource.wim-user.typecom.alibaba.…

【JavaEE】多线程之Thread类

一、Thread类常见方法与字段 1、构造方法 构造方法说明Thread()不带参数的构造方法Thread(String name)可以在构造时传入线程的名字Thread(Runnable run)传入Runnable&#xff0c;是创建线程的方法之一Thread(Runnable run,String name)传入线程工作并给线程起名 2、常见属性…

JaveWeb框架(一):Web入门,Http的请求和响应,https介绍,Web实战自定义服务器

Servlet入门 MVC实战项目 仓储管理系统JavaWeb入门介绍Http协议Http请求数据格式Http响应数据格式Web实战Demo&#xff1a;自定义服务器对比Https协议总结Redis章节复习已经过去&#xff0c;新的章节JavaWeb开始了&#xff0c;这个章节中将会回顾JavaWeb实战项目 仓储管理 代码…

机器人开发--电机中的电流环、速度环、位置环

机器人开发--电机中的电流环、速度环、位置环电流环、速度环、位置环1 三环原理1.1 电流环1.2 速度环1.3 位置环2 各环与PID控制2.1 电流环重点在 PID&#xff08;比例、积分和微分&#xff09;2.2 速度环重点在 PI&#xff08;比例和积分&#xff09;2.3 位置环重点在 P&#…

基于JAVA的企业部门报销管理信息系统的设计与实现

开发工具(eclipse/idea/vscode等)&#xff1a; 数据库(sqlite/mysql/sqlserver等)&#xff1a; 功能模块(请用文字描述&#xff0c;至少200字)&#xff1a; 系统部分主要分为以下几个模块&#xff1a;公告类型&#xff0c;公告信息&#xff0c;部门信息&#xff0c;员工信 息&a…

手写Spring9(实现FactoryBean、对象作用域)

文章目录前言目标设计项目结构一、实现1、Bean的作用范围定义和xml解析2、创建和修改对象时候判断单例和原型模式3、定义 FactoryBean 接口4、实现一个 FactoryBean 注册服务5、扩展 AbstractBeanFactory 创建对象逻辑二、测试1、事先准备2、定义 FactoryBean 对象3、配置文件4…

Win32多线程调用gdal库接口

作者:朱金灿 来源:clever101的专栏 为什么大多数人学不会人工智能编程?>>> 效果图和程序说明 效果图如下:   这个程序是基于MFC的GUI程序,用于给指定的文件夹批量创建金字塔。   效果图如下:   这个程序是基于Win32 API的GUI程序,用于给指定的文件创…

期末前端web大作业——动漫客栈响应式bootstarp(7页) 排版整洁,内容丰富,主题鲜明

HTML实例网页代码, 本实例适合于初学HTML的同学。该实例里面有设置了css的样式设置&#xff0c;有div的样式格局&#xff0c;这个实例比较全面&#xff0c;有助于同学的学习,本文将介绍如何通过从头开始设计个人网站并将其转换为代码的过程来实践设计。 ⚽精彩专栏推荐&#x1…

R语言用线性回归模型预测空气质量臭氧数据

尽管线性模型是最简单的机器学习技术之一&#xff0c;但它们仍然是进行预测的强大工具。 最近我们被客户要求撰写关于线性回归模型的研究报告&#xff0c;包括一些图形和统计输出。 这尤其是由于线性模型特别容易解释这一事实。在这里&#xff0c;我将讨论使用空气质量数据集…

Python学习基础笔记五十四——多继承

多继承中&#xff0c;我们子类对象调用的一个方法&#xff0c;默认是就近原则&#xff0c;找的顺序是什么&#xff1f; 在经典类中&#xff0c;是深度优先&#xff1b; 在新式类中&#xff0c;是广度优先&#xff1b; Python2.7是经典类和新式类共存&#xff0c;新式类要继承…

领域模型设计模式

前言&#xff1a; 领域是一个组织所做的事情以及其包含的一切&#xff0c;通俗地说&#xff0c;就是组织的业务范围和做事情的方式&#xff0c;也是软件开发的目标范围。比如说淘宝的电商业务&#xff0c;C2C就是电子商务的领域&#xff0c;领域驱动设计就是从领域出发&#x…

安装VS code

五 安装VS Code Visual Studio Code&#xff0c;简称VS Code&#xff0c;是一种简化且高效的代码编辑器&#xff0c;同时支持诸如调试&#xff0c;任务执行和版本管理之类的开发操作。它的目标是提供一种快速的编码编译调试工具。优势&#xff1a; 支持多种语言的编写&#xf…

【大数据处理技术】「#1」本地数据集上传到数据仓库Hive

文章目录实验数据集下载下载实验数据集建立一个用于运行本案例的目录dbtaobao数据集的预处理删除文件第一行记录&#xff0c;即字段名称获取数据集中双11的前100000条数据导入数据仓库实验数据集下载 下载实验数据集 data_format.zip数据集用户行为日志user_log.csv&#xff…

jsp+ssm计算机毕业设计房屋租赁系统【附源码】

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; JSPSSM mybatis Maven等等组成&#xff0c;B/S模式 Mave…

node 使用 pm2 日志管理及使用 pm2-logrotate 进行日志分割

目录 1. 需求背景 2. 什么是 pm2-logrotate &#xff1f; 3. 查看 pm2 自带的日志管理 4. 安装 pm2-logrotate 5. 查看配置指令 6. pm2-logrotate 具体配置说明 7. 如何设置这些值&#xff1f; 8. 停止 pm2-logrotate 服务 9. 补充&#xff1a;pm2 常用命令 1. 需求…

Java学习笔记 --- MySQL-函数

一、合计/统计函数 count Count返回行的总数 SELECT COUNT(*) 列名 FROM table_name WHERE where_definition # 演示 mysql 的统计函数的使用 -- 统计一个班级共有多少学生&#xff1f; SELECT COUNT(*) FROM student -- 统计数学成绩大于90的学生有多少个 SELECT COUNT(*) FR…

Linux——vim的使用

实验5 vim的使用 一、两种模式&#xff1a; 命令行模式和编辑模式&#xff08;前者还有底行模式&#xff0c;命令行模式输入&#xff1a;就是底行模式&#xff09; 切换方法&#xff1a;进入vim后默认在命令模式&#xff0c;可以通过输入a后者i进入编辑模式&#xff0c;或者…

SQL学习day3

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 高级过滤Q1、检索供应商名称Q2、检索并列出已订购产品的清单(稍难&#xff09;Q3、返回所有价格在 3美元到 6美元之间的产品的名称和价格总结Q1、检索供应商名称 编写 SQL 语…

2022全年度吸尘器十大热门品牌销量榜单

近年来&#xff0c;随着社会经济的发展及人们生活水平的提升&#xff0c;吸尘器的市场需求得到不断地释放&#xff0c;行业规模也在不断扩大。但由于起步较晚&#xff0c;居民的消费能力尚未得到完全释放&#xff0c;目前我国吸尘器市场的渗透率还较低。 根据鲸参谋平台的数据统…

初识Go语言

Go是一种静态强类型、编译型、并发型语言。 一、Go语言的设计思维 尽可能少的方式去处理事情&#xff0c;减少选择的烦恼。 go的特点&#xff1a; 仅有25个关键字&#xff0c;简洁的语法内置垃圾回收器&#xff0c;大大降低程序员管理内存的负担去除隐式类型转换、去除指针…