Эх сурвалжийг харах

1.更新readme增加商业项目案例
2.删除Doc目录,挪到Book

tanghai 6 жил өмнө
parent
commit
9bf5181e1d

+ 0 - 0
Doc/运行指南.md → Book/1.1运行指南.md


+ 0 - 0
Doc/donate.png → Book/donate.png


+ 0 - 11
Doc/Actor使用.md

@@ -1,11 +0,0 @@
-ET的Actor消息提供两种使用方法,假设a是一个Entity,在A服务器上,挂载了MailBoxComponent成了一个Actor,B服务器需要向a发送actor消息。
-
-#### 1. B知道a的InstanceId,这个时候,B调用ActorMessageSender.GetWithActorId(long actorId)方法获取ActorMessageSender发送消息即可。
-
-#### 2. B只能知道a的Id,因为a的InstanceId并不固定,这时可以让a创建后调用MailBoxComponent把自己注册到location上去,这样B调用ActorMessageSender.Get(long id)获取ActorMessageSender发送消息即可。
-
-知道actor的原理就知道为什么有这两种模式:  
-  
-#### 1. 第一种,是最普通的actor消息,erlang就是第一种actor,因为instanceId中已经带有了对象的地址信息,所以,知道instanceId就知道了对象的地址,ActorMessageSender就能把消息发送到a所在的正确的服务器上。消息到了A服务器又能根据InstanceId找到a对象,这样自然能把消息发给a    
-  
-#### 2. 第二种,如果B服务器无法知道a的InstanceId,比如a有可能从一个进程切换到另外一个进程,这种情况很常见,比如从一个场景传送到另外一个场景。a的instanceId是会变化的。怎么保证B进程发送给a的消息能正确呢?这个时候就在创建a的时候把instanceId注册到location上去(调用AddLocation),这样ActorMessageSender会去location获取a的instanceId。然后把消息发送给a。

+ 0 - 80
Doc/component-design.md

@@ -1,80 +0,0 @@
-# component design
-In terms of code reuse and organization data, object oriented is probably the first response. The three characteristics of object-oriented inheritance, encapsulation, polymorphism, to a certain extent, can solve a lot of code reuse, data reuse problems. However, object oriented is not omnipotent, it also has great defects: 
-### 1. the data organization and strong coupling
-Once a field is added or deleted in the parent class, all subclasses may be affected, affecting all subclasses related logic. This is not very flexible, in a complex inheritance system, to change the parent class field will become more and more trouble, for example, ABC is a subclass of D, one day found a need to increase the AB of some data, but not C, then this data is certainly not good in a parent class, can only be AB abstract a parent class E inherited from D, E, AB were added to E in some fields, once the inheritance structure changes, may also need to change the interface, for example, before a interface into the parameter type is E, when the AB is not in the field need to be shared, so need to adjust the inheritance relationship, let AB inherited from D, so this interface requires the parameter type logic code into D, which are likely to adjust. Even more frightening is that the game logic changes are very complex, very frequent, may add a field today, and tomorrow deleted, and if each time to adjust the inheritance structure, this is simply a nightmare. Inheritance structure is very weak in the face of frequent data structure adjustment. There is also a serious problem that the inheritance structure can not be run, add delete fields, such as the player Player usually walk, after riding the horse riding. The problem is that the mount's relevant information needs to hang on top of the Player object. This is very inflexible. Why do I have horse data in my memory when I'm not riding?
-### 2. interface logic is difficult to reuse, hot swap.
-The object oriented method of processing the same behavior is to inherit the same parent class or interface. The problem is that the interface does not implement the code, but it needs its subclass to write its own implementation. Obviously, the same function, each subclass can write a similar code. This makes the code for the interface not reusable. There is a problem, a class implements an interface, so the interface will stick to this kind of person, you want to get rid of her not to ride, or as an example, game player Player can ride, then may inherit a riding interface, the problem is, when I Player from the mounts down, Player game player who still has a riding interface, can't delete this dynamic interface! The possible examples are not quite right, but the arguments should be clear.
-### 3. the use of object-oriented could lead to disastrous consequences
-There are new people in the game development, old people, good technology, poor technology. People are lazy, when you find the adjustment inheritance relationship trouble, it is possible to add a field in AB, in order to save, directly into the parent class D to go. C leads to a much more useless field. The key can not be found, and finally led to the father class D more and more big, and finally may simply do not use ABC, directly make all objects become D, convenient! Yes, a lot of games do that, and at the end of the development, they don't care about inheritance, because they don't want to manage it.
-Object oriented is weak in the face of complex game logic, so many game developers had retreated back, using the process oriented development game, process oriented, simple and rough, without considering the complex inheritance, is not considered abstract, without considering the polymorphism, is the development of the freestyle, roll up their sleeves and open up, but at the same time the logic, code reuse, reuse of data is greatly reduced. Process oriented is not a good game development model, either.
-Component mode solves the defects of object oriented and process oriented, which is widely used in game client, Unity3d, unreal 4, and so on. Features of component patterns:
-1. highly modular, a component is a data plus a section of logic
-2. components can be hot plug, need to add, not need to delete
-There is very little dependency between 3. types, and any type of addition or deletion of components does not affect other types.
-At present, only a few have the server to use components design, the server should watch pioneer is the use of component design, and the pioneer developer called ECS architecture, in fact is a variant of component model, E is Entity, C is Component, S is System, which is the logic and data stripping assembly Component the logic part is called System, the topic Cheyuan, or to return to the ET framework.
-The ET framework uses the design of components. Everything is Entity and Component, and any object that inherits from Entity can mount components, such as player objects:
-```C#
-public sealed class Player : Entity
-{
-	public string Account { get; private set; }
-	public long UnitId { get; set; }
-	
-	public void Awake(string account)
-	{
-		this.Account = account;
-	}
-	
-	public override void Dispose()
-	{
-		if (this.Id == 0)
-		{
-			return;
-		}
-		base.Dispose();
-	}
-}
-```
-.
-To mount a MoveComponent mobile game player object component, so you can move the game player, game player to hang a backpack assembly, game player can manage the goods, to hang up the game player skill components, then you can spell the game player, plus the Buff component can manage buff.
-```C#
-player.AddComponent<MoveComponent>();
-player.AddComponent<ItemsComponent>();
-player.AddComponent<SpellComponent>();
-player.AddComponent<BuffComponent>();
-```
-Component is highly reusable, such as a NPC, he can move to NPC MoveComponent hanging on the line, some NPC can also cast skills, then give it to hang SpellComponent, NPC does not require a backpack, then do not hang ItemsComponent
-ET framework modules are all made up of components, and a process is made up of different components. For example, Loginserver needs external connections and also needs to be connected to the server, so login server hangs on
-
-```C#
-// Internal network component NetInnerComponent, processing the internal network connection
-Game.Scene.AddComponent<NetInnerComponent, string, int>(innerConfig.Host, innerConfig.Port);
-// External network component NetOuterComponent, processing and client connection
-Game.Scene.AddComponent<NetOuterComponent, string, int>(outerConfig.Host, outerConfig.Port);
-```
-For example, battle server does not need external network connection (external network message is forwarded by gateserver), so it is natural to install only one intranet component.
-```C#
-// Internal network component NetInnerComponent processing for internal network connection
-Game.Scene.AddComponent<NetInnerComponent, string, int>(innerConfig.Host, innerConfig.Port);
-```
-Like Unity3d components, the ET framework also provides component events, such as Awake, Start, Update, and so on. To add these events to a Component or Entity, you must write a helper class. For example, NetInnerComponent components require Awake and Update methods, and then add a class like this:
-```C#
-	[ObjectEvent]
-	public class NetInnerComponentEvent : ObjectEvent<NetInnerComponent>, IAwake, IUpdate
-	{
-		public void Awake()
-		{
-			this.Get().Awake();
-		}
-
-		public void Update()
-		{
-			this.Get().Update();
-		}
-	}
-```
-In this way, NetInnerComponent calls its Awake method after AddComponent, and calls the Update method per frame.
-ET did not like Unity use reflection to achieve this function, the reflection performance is poor, and thus realize the benefits of this class can be more on the hot DLL, this component of the Awake Start, Update method and other methods are more on the hot layer. Only the data is placed on the model layer to facilitate the heat to repair the logical bug.
-The biggest advantage of component development is that, regardless of the novice or master, the development of a function can quickly know how to organize data, how to organize logic. Object can be completely abandoned. The most difficult thing to use object-oriented development is what class should I inherit? The most frightening thing ever was illusion three, and the inheritance structure of unreal three was very multi-layered, and did not know where to begin. In the end, it may lead to a very small function, inheriting one and its huge class, which is common in unreal three development. So unreal 4 uses component mode. The module isolation of component mode is very good. A component of the technical novice writes very badly, and it doesn't affect other modules, so it is impossible to rewrite this component.
-
-
-

+ 0 - 129
Doc/network-design.md

@@ -1,129 +0,0 @@
-The design of # network layer
-The ET framework provides a more powerful network messaging layer, sending messages, subscribing to messages, and making it easy, very clear and simple.
- 
-#### 1. send common message
-There are two main components, NetOuterComponent handles the connection of the client, and NetInnerComponent handles the connection within the server
-The two components can access the connection according to the address, each connection is encapsulated into a Session object, and the Session object has two methods for sending the message:
-``` C#
-// Create or access a connection according to the address
-Session session = Game.Scene.GetComponent<NetInnerComponent>().Get(innerAddress);
-
-// Send only and no return
-session.Send(new R2G_GetLoginKey());
-
-// Send the R2G_GetLoginKey message and wait for the message to return a G2R_GetLoginKey message
-G2R_GetLoginKey g2RGetLoginKey = await session.Call<G2R_GetLoginKey>(new R2G_GetLoginKey() {Account = "zhangsan"});
-Log.Debug("print response message content: " + g2RGetLoginKey.ToJson())
-```
-Because of C#'s powerful async await syntax, ET framework RPC message is very simple, after sending logic to be coherent, without dismantling the two logic, because of this characteristic, C# distributed framework for writing very much, because it is nothing more than a distributed inter process network news. If you don't have this function, think about it, send the message in one place, you have to subscribe to a return message, and the two piece of code is disconnected. Even more frightening is the continuous multiple RPC requests:
-``` C#
-// The client sends an account password to the login server to verify, and waits for the login response message to return, login will assign a gateway to the client
-R2C_Login r2CLogin = await session.Call<R2C_Login>(new C2R_Login() { Account = "a", Password = "b" });
-// Client connect gateway
-Session gateSession = Game.Scene.GetComponent<NetOuterComponent>().Create(r2CLogin.Address);
-// The client sends the message to the gateway and waits for the gateway to verify the return
-G2C_LoginGate g2CLoginGate = await gateSession.Call<G2C_LoginGate>(new C2G_LoginGate(r2CLogin.Key));
-Log.Info("login ok!");
-// 获取玩家的物品信息
-G2C_Items items = await gateSession.Call<G2C_Items>(new C2G_Items());
-```
-You can see the login LoginServer, immediately log on gateserver, after the completion of the query and login the game player items of information, the whole process looks very coherent, if there is no async await, this code will be split into at least 4 pieces in 4 functions. Distributed servers have many RPC calls, and there is no syntax support for async await, which is inconceivable. So some people use nodejs, java to write game server, I can not understand, write a single clothing can also, write distributed server, ha ha!
-#### 2.  ordinary news subscription
-The top is sending messages. How does the server subscribe to processing a message? Very concise:
-```C#
-// Processing login RPC messages and returning response
-[MessageHandler(AppType.Login)]
-public class C2R_LoginHandler : AMRpcHandler<C2R_Login, R2C_Login>
-{
-	protected override async void Run(Session session, C2R_Login message, Action<R2C_Login> reply)
-	{
-		R2C_Login response = new R2C_Login();
-		try
-		{
-			Log.Debug(message.ToJson());
-			reply(response);
-		}
-		catch (Exception e)
-		{
-			ReplyError(response, e, reply);
-		}
-	}
-}
-```
-RPC message only need to add a hotfix class in DLL class, inherited from AMRpcHandler, virtual method, ET uses a declarative message subscription approach, a RPC message processing class, only need to add the MessageHandlerAttribute can automatically be found and registered to the frame frame, does not need to register with manual function. The class MessageHandlerAttribute above sets the AppType.Login, which indicates that only the Login server registers the RPC processing class. Is it very simple? Similarly, registering non RPC messages only needs to add a class that inherits from AMHandler. The entire message handling class does not contain any state, so it can be reload.
-
-#### 3. send actor message
-The ET framework also provides a distributed message mechanism similar to the Erlang language, regardless of any object in the process, only the ActorComponent mount components need, any process can take the object of ID, sending the object message, messages are sent to the object in the process and to the object processing. Sending Actor messages is different from ordinary messages. To send actor messages, server must hang on the ActorProxyComponent components:
-```c#
-// ActorProxyComponent get actorproxy
-ActorProxy actorProxy = Game.Scene.GetComponent<ActorProxyComponent>().Get(id);
-// Sending messages to actor
-actorProxy.Send(new Actor_Test());
-// Sending rpc messages to actor
-ActorRpc_TestResponse response = await actorProxy.Call<ActorRpc_TestResponse>(ActorRpc_TestRequest());
-```
-
-#### 4.actor subscription processing
-Subscribing to actor messages is just like regular messages, just inheriting AMActorHandler and adding ActorMessageHandler tags. The difference is that AMActorHandler needs to provide the type of Actor, such as the following actor message, which is sent to the Player object
-```c#
-[ActorMessageHandler(AppType.Map)]
-public class Actor_TestHandler : AMActorHandler<Player, Actor_Test>
-{
-	protected override async Task<bool> Run(Player player, Actor_Test message)
-	{
-		Log.Debug(message.Info);
-
-		player.GetComponent<UnitGateComponent>().GetActorProxy().Send(message);
-		return true;
-	}
-}
-```
-Similarly, subscribing to ActorRpc messages requires inheritance of AMActorRpcHandler, and also using reply to return response messages.
-```c#
-[ActorMessageHandler(AppType.Map)]
-public class ActorRpc_TestRequestHandler : AMActorRpcHandler<Player, ActorRpc_TestRequest, ActorRpc_TestResponse>
-{
-	protected override async Task<bool> Run(Player entity, ActorRpc_TestRequest message, Action<ActorRpc_TestResponse> reply)
-	{
-		reply(new ActorRpc_TestResponse() {response = "response actor rpc"});
-		return true;
-	}
-}
-```
-
-#### 5.Exception handling rpc message
-ET framework message layer provides a powerful exception handling mechanism, all RPC response messages are inherited with AResponse, AResponse with error and error information,
-```
-public abstract class AResponse: AMessage
-{
-	public uint RpcId;
-	public int Error = 0;
-	public string Message = "";
-}
-```
-You can catch RpcException exceptions and do different exception handling through ErrorCode, such as client login:
-```
-try
-{
-	R2C_Login r2CLogin = await session.Call<R2C_Login>(new C2R_Login() { Account = "a", Password = "b" });
-}
-catch (RpcException e)
-{
-	if (e.Error == ErrorCode.ERR_AccountNotFound)
-	{
-		Log.Debug("account not exist");
-		return;
-	}
-	if (e.Error == ErrorCode.PasswordError;)
-	{
-		Log.Debug("password error");
-		return;
-	}
-}
-```
-The ET framework is the most convenient anomaly information will cross process transfer, for example, the A process to the B process launched a Rpc request, B process needs to request C in response to C request response process before D, before the B results, the D process in the process of occurrence of an exception, the exception will from D- >C->B->A. The A process in try catch to capture the exception, the exception will BCD with the whole process of the stack information, check distributed abnormal bug becomes very simple.
-#### summary
-This paper introduces the network layer usage of ET framework, and the ET framework provides a very perfect distributed network layer, a powerful distributed exception handling mechanism. Because of the use of collaboration, ET send messages and remote call and its simple and convenient, distributed development is as convenient as the development of stand-alone.
-
-
-

+ 0 - 19
Doc/start-guide.md

@@ -1,19 +0,0 @@
-##### 1.visual studio must use vs2017, other versions do not support VS2017, need to check the installation of the following contents:
-.net desktop development
-Using C++ desktop development, VC++ 2017 v141 toolset, XP support for C++
-Visual studio tools for unity.Netcore2.0
-##### must install unity 2017.1.0p5 2. unity to 2017.1.2, the other version is not supported
-3. ##### start menu File->open project->open unity2017, select the Egametang/Unity folder, click to select the folder button.
-4. click the Unity menu Assets->open ##### C# project vs compiler (compiler must start, right-click the VS solution, all the compiler)
-5. ##### opened with vs2017 Egametang/Server/Server.sln compiler (must be compiled, right-click the VS solution, all the compiler)
-##### 6. Unity->tools menu - > command line configuration, select the LocalAllServer.txt which is the start of a single App, if you want to start a group of multi App server, select 127.0.0.1.txt in the command line tool, click start, the specific configuration can they use the command-line utility to modify
-##### 7. click Tools in the start, this will start the server (you can also use VS to start, convenient debugging step)
-##### 8. running Unity, enter the account, then click on the login log connection Gate success, said OK!
-## frame synchronization test
-##### 1. Unity->tools menu - > package ->PC package, hit a PC package in the Release directory
-##### 2. run Unity login into the hall into the scene
-##### 3. run PC package login into the hall then there will be two people (overlap)
-##### 4. click the right mouse button to move characters
-# note:
-The 15.4 version of VS2017 bug, Hotfix Assembly-CSharp.dll will prompt can not find, you need to Hotfix project Unity quoted with Unity.Plugin removed, directly referenced in the Unity\Library\ScriptAssemblies directory with Assembly-CSharp.dll Assembly-CSharp-firstpass.dll two DLL
-The general reason for error is 1. not compiled. 2. Chinese catalogue. 3.vs does not install vs tools or is not the latest vs tools. 4. not installing.Netcore2.0

+ 0 - 85
Doc/组件设计.md

@@ -1,85 +0,0 @@
-# 组件设计
-
-在代码复用和组织数据方面,面向对象可能是大家第一反应。面向对象三大特性继承,封装,多态,在一定程度上能解决不少代码复用,数据复用的问题。不过面向对象不是万能的,它也有极大的缺陷:
-### 1. 数据组织耦合性及强
-一旦父类中增加或删除某个字段,可能要影响到所有子类,影响到所有子类相关的逻辑。这显得非常不灵活,在一套复杂的继承体系中,往父类中改变字段会变得越来越麻烦,比方说ABC是D的子类,某天发现需要增加一个AB都有的数据,但是C没有,那么这个数据肯定不好放到父类中,只能将AB抽象出来一个父类E,E继承于D,AB共有的字段加到E中,一旦继承结构发生了变化,可能接口也要改变,比方说之前有个接口传入参数类型是E,当AB不在需要共用的那个字段,那么需要调整继承关系,让AB重新继承D,那么这个接口的传入参数类型需要改成D,其中的逻辑代码很可能也要发生调整。更可怕的是游戏逻辑变化非常复杂,非常频繁,可能今天加了个字段,明天又删掉了,假如每次都要去调整继承结构,这简直就是噩梦。继承结构面对频繁的数据结构调整感觉很无力。还有个严重的问题,继承结构无法运行时增加删除字段,比如玩家Player平常是走路,使用坐骑后就骑马。问题是坐骑的相关信息就需要一直挂在Player对象上面。这就显得很不灵活,我不骑马的时候内存中为啥要有马的数据?
-### 2. 接口逻辑难以复用,难以热插拔。
-面向对象处理相同行为所使用的方法是继承相同的父类或者接口。问题是接口并没有实现代码,而是需要其子类自己去写相关实现。很显然相同的功能,每个子类都可能写一份相似的代码。这导致接口的实现代码无法复用。还有个问题,一个类实现了一个接口,那么这个接口就永远粘在了这个类身上,你想甩掉她都不行,还是以骑马为例,玩家Player可以进行骑行,那么可能继承一个骑行的接口,问题是,当我这个Player从坐骑上下来时,玩家Player身上还是有骑行的接口,根本没法动态删掉这个接口!可能例子举得不是很对,但是道理表述的应该很清楚了。
-### 3. 使用面向对象可能导致灾难性后果
-游戏开发中有新人有老人,有技术好的,有技术差的。人都是喜欢偷懒的,当你发现调整继承关系麻烦的时候,有可能AB中增加一个字段为了省事直接就放到父类D中去了。导致C莫名奇妙的多了一个无用的字段。关键还没法发现,最后导致父类D越来越大,到最后有可能干脆就不用ABC了,直接让所有对象都变成D,方便嘛!是的,很多游戏就是这么干的,开发到最后根本就不管继承关系了,因为想管也管不了了。    
-  
-面向对象在面对复杂的游戏逻辑时会很无力,所以很多游戏开发者又倒退了回去,使用面向过程进行开发游戏,面向过程,简单粗暴,不考虑复杂的继承,不考虑抽象,不考虑多态,是开发届的freestyle,挽起袖子就开撸,但同时,代码逻辑的复用性,数据的复用性也大大降低。面向过程也不是一种好的游戏开发模式。
-
-组件模式很好的解决了面向对象以及面向过程的种种缺陷,在游戏客户端中使用非常广泛,Unity3d,虚幻4,等等都使用了组件模式。组件模式的特点:
-1.高度模块化,一个组件就是一份数据加一段逻辑
-2.组件可热插拔,需要就加上,不需要就删除
-3.类型之间依赖极少,任何类型增加或删除组件不会影响到其它类型。
-
-目前只有极少有服务端使用了组件的设计,守望先锋服务端应该是使用了组件的设计,守望先锋的开发人员称之为ECS架构,其实就是组件模式的一个变种,E就是Entity,C就是Component,S是System,其实就是将组件Component的逻辑与数据剥离,逻辑部分叫System,话题扯远了,还是回到ET框架来把。
-
-ET框架使用了组件的设计。一切都是Entity和Component,任何对象继承于Entity都可以挂载组件,例如玩家对象:
-```C#
-public sealed class Player : Entity
-{
-	public string Account { get; private set; }
-	public long UnitId { get; set; }
-	
-	public void Awake(string account)
-	{
-		this.Account = account;
-	}
-	
-	public override void Dispose()
-	{
-		if (this.Id == 0)
-		{
-			return;
-		}
-		base.Dispose();
-	}
-}
-```
-给玩家对象挂载个移动组件MoveComponent,这样玩家就可以移动了,给玩家挂上一个背包组件,玩家就可以管理物品了,给玩家挂上技能组件,那么玩家就可以施放技能了,加上Buff组件就可以管理buff了。
-```C#
-player.AddComponent<MoveComponent>();
-player.AddComponent<ItemsComponent>();
-player.AddComponent<SpellComponent>();
-player.AddComponent<BuffComponent>();
-```
-组件是高度可以复用的,比如一个NPC,他也可以移动,给NPC也挂上MoveComponent就行了,有的NPC也可以施放技能,那么给它挂上SpellComponent,NPC不需要背包,那么就不用挂ItemsComponent了
-
-ET框架模块全部做成了组件的形式,一个进程也是由不同的组件拼接而成。比方说Loginserver需要对外连接也需要与服务器内部进行连接,那么login server挂上
-```C#
-// 内网网络组件NetInnerComponent,处理对内网连接
-Game.Scene.AddComponent<NetInnerComponent, string, int>(innerConfig.Host, innerConfig.Port);
-// 外网网络组件NetOuterComponent,处理与客户端连接
-Game.Scene.AddComponent<NetOuterComponent, string, int>(outerConfig.Host, outerConfig.Port);
-```
-比如battle server就不需要对外网连接(外网消息由gateserver转发),那么很自然的只需要挂载一个内网组件即可。
-```C#
-// 内网网络组件NetInnerComponent处理对内网连接
-Game.Scene.AddComponent<NetInnerComponent, string, int>(innerConfig.Host, innerConfig.Port);
-```
-类似Unity3d的组件,ET框架也提供了组件事件,例如Awake,Start,Update等。要给一个Component或者Entity加上这些事件,必须写一个辅助类。比如NetInnerComponent组件需要Awake跟Update方法,那么添加一个这样的类即可:
-```C#
-	[ObjectEvent]
-	public class NetInnerComponentEvent : ObjectEvent<NetInnerComponent>, IAwake, IUpdate
-	{
-		public void Awake()
-		{
-			this.Get().Awake();
-		}
-
-		public void Update()
-		{
-			this.Get().Update();
-		}
-	}
-```
-这样,NetInnerComponent在AddComponent之后会调用其Awake方法,并且每帧调用Update方法。
-ET没有像Unity使用反射去实现这种功能,反射性能比较差,而且这样实现的好处是这个类可以放到热更dll中,这样组件的Awake Start,Update方法以及其它方法都可以放到热更层中。只有数据放在model层,方便热更修复逻辑bug。
-
-组件式开发最大的好处就是不管菜鸟还是高手,开发一个功能都能很快的知道怎么组织数据怎么组织逻辑。可以完全放弃面向对象。使用面向对象开发最头疼的就是我该继承哪个类呢?之前做过最恐怖的就是虚幻三,虚幻三的继承结构非常多层,完全不知道自己需要从哪里开始继承。最后可能导致一个非常小的功能,继承了一个及其巨大的类,这在虚幻三开发中屡见不鲜。所以虚幻4改用了组件模式。组件模式的模块隔离性非常好,技术菜鸟某个组件写得非常差,也不会影响到其它模块,大不了重写这个组件就好了。
-
-
-

+ 0 - 131
Doc/网络层设计.md

@@ -1,131 +0,0 @@
-# 网络层设计
-
-ET框架提供了一个比较强大的网络消息层,发送消息订阅消息都及其方便,非常清晰简单。
-
-#### 1.普通消息的发送
-主要有两个组件,NetOuterComponent处理客户端的连接,NetInnerComponent处理服务端内部的连接
-这两个组件可以根据地址获取连接,每个连接都封装成了一个Session对象,Session对象有两个方法用来发送消息:
-``` C#
-// 根据地址创建或者获取一个连接
-Session session = Game.Scene.GetComponent<NetInnerComponent>().Get(innerAddress);
-
-// 只发送不等待返回
-session.Send(new R2G_GetLoginKey());
-
-// 发送R2G_GetLoginKey消息,并且等待消息返回一个G2R_GetLoginKey消息
-G2R_GetLoginKey g2RGetLoginKey = await session.Call<G2R_GetLoginKey>(new R2G_GetLoginKey() {Account = "zhangsan"});
-Log.Debug("打印响应的消息内容: " + g2RGetLoginKey.ToJson())
-```
-由于C#强大的async await语法,ET框架发送rpc消息显得非常简洁,发送前后逻辑得以连贯,不用拆成两段逻辑,正因为这个特性,C#非常适合写分布式框架,因 为其实分布式无非就是进程间网络消息的处理。假如没有这个功能,你想想,发送消息写在一个地方,你还得订阅一个返回消息处理,两块代码就不连贯。更可怕的是连续多个rpc请求:
-``` C#
-// 客户端发送帐号密码给login server验证,并且等待login响应消息返回,login会分配一个网关给客户端
-R2C_Login r2CLogin = await session.Call<R2C_Login>(new C2R_Login() { Account = "a", Password = "b" });
-// 客户端连接网关
-Session gateSession = Game.Scene.GetComponent<NetOuterComponent>().Create(r2CLogin.Address);
-// 客户端发送消息给网关,等待网关验证返回
-G2C_LoginGate g2CLoginGate = await gateSession.Call<G2C_LoginGate>(new C2G_LoginGate(r2CLogin.Key));
-Log.Info("登陆gate成功!");
-// 获取玩家的物品信息
-G2C_Items items = await gateSession.Call<G2C_Items>(new C2G_Items());
-```
-可以看到登录完loginserver,立即登录gateserver,登录完成后又查询了玩家的物品信息,整个流程看起来非常连贯,假如没有async await,这段代码就得拆成至少4块放到4个函数中。分布式服务器连续rpc调用非常多,没有async await这种协程的语法支持是不可想像的。所以有人用nodejs,java写游戏服务器,我是无法理解的,写单服还可以,写分布式服务器,呵呵!
-#### 2.普通消息订阅
-上面是发送消息,服务器怎么订阅处理某个消息呢?非常简洁:
-```C#
-// 处理login rpc消息,并且返回response
-[MessageHandler(AppType.Login)]
-public class C2R_LoginHandler : AMRpcHandler<C2R_Login, R2C_Login>
-{
-	protected override async void Run(Session session, C2R_Login message, Action<R2C_Login> reply)
-	{
-		R2C_Login response = new R2C_Login();
-		try
-		{
-			Log.Debug(message.ToJson());
-			reply(response);
-		}
-		catch (Exception e)
-		{
-			ReplyError(response, e, reply);
-		}
-	}
-}
-```
-rpc消息只需要在hotfix dll中加个类,类继承于AMRpcHandler,实现虚方法即可,ET使用了声明式订阅消息的手法,一个rpc消息处理类,只需要加上MessageHandlerAttribute就可以自动被框架发现并且注册到框架中,并不需要手动用函数去注册。上面这个类MessageHandlerAttribute设置了AppType.Login,这个参数表示只有Login服务器才会注册这个rpc处理类。是不是非常简单呢?同样的,注册非rpc消息,只需要添加一个类继承于AMHandler即可。整个消息处理类不会包含任何状态,所以是可以热更新的。
-
-#### 3.actor消息发送
-ET框架还提供了类似Erlang语言的分布式消息机制,不管对象在任何进程,只需要挂载ActorComponent组件,任何进程都可以拿着这个对象的id,向这个对象发送消息,消息会发送到该对象所在的进程并且交给该对象处理。发送Actor消息与普通消息不同, 要发送actor消息,server必须挂上ActorProxyComponent组件:
-```c#
-// 从ActorProxyComponent组件中获取actorproxy
-ActorProxy actorProxy = Game.Scene.GetComponent<ActorProxyComponent>().Get(id);
-// 向对象发送消息
-actorProxy.Send(new Actor_Test());
-// 向对象发送rpc消息
-ActorRpc_TestResponse response = await actorProxy.Call<ActorRpc_TestResponse>(ActorRpc_TestRequest());
-```
-
-#### 4.actor订阅处理
-订阅actor消息与普通消息类似,只需要继承AMActorHandler,并且加上ActorMessageHandler的标签。有点不同的是AMActorHandler需要提供Actor的类型,例如下面这个actor消息它是发给Player对象的
-```c#
-[ActorMessageHandler(AppType.Map)]
-public class Actor_TestHandler : AMActorHandler<Player, Actor_Test>
-{
-	protected override async Task<bool> Run(Player player, Actor_Test message)
-	{
-		Log.Debug(message.Info);
-
-		player.GetComponent<UnitGateComponent>().GetActorProxy().Send(message);
-		return true;
-	}
-}
-```
-同样订阅ActorRpc消息,需要继承AMActorRpcHandler,同样使用reply返回响应消息。
-```c#
-[ActorMessageHandler(AppType.Map)]
-public class ActorRpc_TestRequestHandler : AMActorRpcHandler<Player, ActorRpc_TestRequest, ActorRpc_TestResponse>
-{
-	protected override async Task<bool> Run(Player entity, ActorRpc_TestRequest message, Action<ActorRpc_TestResponse> reply)
-	{
-		reply(new ActorRpc_TestResponse() {response = "response actor rpc"});
-		return true;
-	}
-}
-```
-
-#### 5.rpc消息的异常处理
-ET框架消息层提供了强大的异常处理机制,所有rpc响应消息都继承与AResponse,AResponse带有error跟错误信息,
-```
-public abstract class AResponse: AMessage
-{
-	public uint RpcId;
-	public int Error = 0;
-	public string Message = "";
-}
-```
-可以捕获RpcException异常,通过ErrorCode做不同的异常处理,比方说客户端登录:
-```
-try
-{
-	R2C_Login r2CLogin = await session.Call<R2C_Login>(new C2R_Login() { Account = "a", Password = "b" });
-}
-catch (RpcException e)
-{
-	if (e.Error == ErrorCode.ERR_AccountNotFound)
-	{
-		Log.Debug("帐号不存在");
-		return;
-	}
-	if (e.Error == ErrorCode.PasswordError;)
-	{
-		Log.Debug("密码错误");
-		return;
-	}
-}
-```
-ET框架最方便的是异常信息会跨进程传递,比如,A进程向B进程发起了Rpc请求,B进程在响应之前需要请求C,C进程响应B之前需要请求D,结果,D进程在处理过程中发生了一个异常,这个异常会从D->C->B->A, A进程在try catch中捕获了这个异常,这个异常会带有BCD整个过程的堆栈信息,查分布式异常bug会变得非常简单。
-
-#### 总结
-本文详细介绍了ET框架的网络层使用,ET框架提供了非常完善的分布式网络层,强大的分布式异常处理机制。因为协程的使用,ET发送消息以及远程调用及其简单方便,做分布式开发就跟开发单机一样方便。
-
-
-

+ 0 - 59
Doc/网络组件学习笔记.MD

@@ -1,59 +0,0 @@
-# 在ET的客户端中,使用网络要用到以下几个组件(不介绍基础设施)。
-
-组件名称| 组件作用
----|---
-OpcodeTypeComponent|消息类型加载组件。加载标记了【MessageAttribute】注解的类,作为消息执行的类型,并存储在这个组件的opcodeTypes字段下,提供后续方法使用。
-MessageDispatcherComponent|消息分发组件,加载消息处理器。加载所有标记了【MessageHandlerAttribute】属性的类,并提供Handle方法,将传入的MessageInfo发送给指定的消息处理器
-NetworkComponent |NetworkComponent是其他上层网络访问组件的基类,这个类型在服务端和客端项目公用。用于 指定该协议、指定构包解析方式、指定消息转发器,开始socket监听、创建session。内部有一个AService字段。抽象了udp和tcp协议的连接工厂,用于创建channel使用tcp做服端的时候可以创建多个Session,每个Session都是一个连接的高层抽象。这个类型在服务端和客户端项目公用。其提供的MessageDispatch和MessagePacker仅在客户端项目使用。一个是客户端消息转发器,一个是客户端消息打包器。
-NetOuterComponent |继承自NetworkComponent,用于对外网的连接。可以在Awake中指定协议,指定包解析器。客户端使用的session都是通过这个组件创建的。需要切换网络协议或者数据序列化方式就在这个组件的Awake方法中指定对应的参数就可以了。
-SessionComponent    |SessionComponent 组件用于存储Seesion,目前客户端只会存在一个在用的session。登录后获得的GateSession会存储在这个组件中。会在之后的对服务器端的调用中使用这个session。
-ClientFrameComponent | 用于处理帧同步。
-
-# 很重要的Session对象的解释
-   每个Session都是一个连接的高层抽象。
-向session另一端做rpc调用可以调用它的Call方法,发送消息可以调用Send,
-二者的区别在于是否需要服务器响应一个反馈消息。
-定义消息或者rpc请求的时候使用Message标签设置消息类型与opcode的对应关系。
-session是由NetworkComponent创建的,参数是 NetworkComponent的本类实例 + 用于收发字节码的AChannel实例。这个AChannel则是由NetworkComponent中的AService工厂创建的。
-
-## 流程:
-    1创建session后(调用构造函数),session开始StartRecv()方法,这个方法循环通过异步方法调用channel的Recv()方法,接收链接另一端发来的数据。
-    2接收到消息后调用Run方法,run方法检查接收到的数据包是否有压缩,并指向相应的操作。
-    3处理完压缩解压操作后交给RunDecompressedBytes,该方法比较厉害,调用绑定在Scene实体上的NetWorkConponent上的注册的解包器(默认是Bson)解包。
-    4解包操作结束后就将其交给绑定在Scene实体上的NetWorkConponent上的messageDispatcher做转发。转发给相应的handler处理。
-    
-# 在大致了解了各组件的作用后,需要有一个大致的流程,把几个组件串联起来,实现客服端的网络功能:
-
-## 网络流程如下:
-### 1.	OpcodeTypeComponent加载封装好的网络消息。
-### 2.	MessageDispatcherComponent加载所有的Handler
-### 3.	开启网络监听。NetOuterComponent加入到Scene,我们使用udp,做如下操作:、
-- a)	通过工厂从对象池中取出实例,调用父类Disposer的构造方法,加入到对象事件中心。
-- b)	调用父类NetworkComponent的构造方法,创建对应协议的连接工厂(AService)。
-- c)	调用NetOuterComponent的Awake()方法,指定网络协议、消息解包器和消息转发器。
-- d)	NetworkComponent因为注册了Update,所以会在每一帧执行Update,Update中会执行service的update。service的update中会执行poller的Update,这个Update实际上是 每一帧都要轮询出所有的主机上的队列事件,并且调用其委托。这些事件包括:开始连接、接收数据、断开连接。这些事件的触发,会调用poller实体上的socket的对应的响应方法。 socket事件的委托是在创建UChannel时注册的。
-- e)	UChannel的OnRecv()将接受到的消息放入到队列中,等待被Session轮询调用UChannel. Recv()方法取出。
-- f)	取出消息后就会调用给NetOuterComponent指定的消息转发器。
-由于是客户端,所以使用ClientDispatcher作为消息转发器。这个消息转发器在接收到帧循环消息后会进行客户端时间补偿处理。否则就直接将普通的rpc等消息交给MessageDispatcherComponent去做转发了。当然,帧循环消息最终也会交给MessageDispatcherComponent做转发。
-- g)	Handle接收到消息后作出最终的处理。
-- h)	D-g步骤是循环执行滴。
-- i)	底层enet等不深入讨论,对我等透明。
-- j)	到此,网络设施已经创建完毕,网络监听已经开启,并等待使用。
-### 4.	创建对外连接。创建对外连接指的是连接到服务器。一般情况下从登陆开始创建对外连接。并且存储会话Gatesession。在整个客户端游戏生命周期中,Gatesession是一直存在的而且只有一份。
-- a)	使用NetOuterComponent创建session。需指定要连接的地址和端口。这时候创建的session一般会是登录服务器,因为登录服务器在登录成功后会返回一个网关地址。
-- b)	然后再根据这个网关地址创建游戏使用的session并且存入到SessionComponent中。
-- c)	SessionComponent要加入到Scene实体保存。
-
-### 5.	使用session通讯。
-- a)	await SessionComponent.Instance.Session.Call<G2C_LoginGate>(new C2G_LoginGate() {Key = r2CLogin.Key})
-- b)	详细参考doc中的《网络层设计》使用说明书。
-### 6.	拓展网络功能以及建议。
-- a)	这个嘛,仁者见仁啦。 
-- b)	注意。使用c#的异步语法实现异步网络调用,是一件很舒服的事情,请详细研究异步语法。并使用之。
-# - 登录流程示例讲解:
-    //TODO
-在掌握了ET客户端网络功能之后基本就掌握了ET的客户端框架。其他的一些框架特性是为了增加功能方便开发,当然如果实在掌握不了或者不喜欢用某个组件,可以用其他的方式实现,比如那个行为树。当然,一定要举一反三,通过学习研究网络组件,对整个et框架有个更深的认识,能够理解组件设计模式的精髓。组件包含数据和功能、实体包含组件,逻辑就是整个系统调用组件的过程。这也是最近闹得沸沸扬扬的ECS。另外,此处只是客户端的逻辑,服务端的逻辑TODO。
-
-
-
-

+ 11 - 8
README.md

@@ -68,9 +68,6 @@ ET框架的服务端是一个强大灵活的分布式服务端架构,完全可
 相关网站:  
 [ET论坛](https://bbs.honorworkroom.com/forum.php)  
 
-[组件式设计](https://github.com/egametang/Egametang/blob/master/Doc/%E7%BB%84%E4%BB%B6%E8%AE%BE%E8%AE%A1.md)   
-[网络层设计](https://github.com/egametang/Egametang/blob/master/Doc/%E7%BD%91%E7%BB%9C%E5%B1%82%E8%AE%BE%E8%AE%A1.md)   
-
 有自己觉得写得不错的Module可以pr提交到下面的库中,造福大家!  
 [module共享仓库](https://github.com/egametang/ET-Modules)  
 
@@ -90,11 +87,17 @@ ET框架的服务端是一个强大灵活的分布式服务端架构,完全可
 [ET框架如何用MAC开发](http://www.tinkingli.com/?p=147)  
 [ET的动态添加事件和触发组件](http://www.tinkingli.com/?p=145)  
 
+商业项目:  
+1. [养不大](https://www.taptap.com/app/71064)  
+2. 天天躲猫猫2(ios2019春节下载排行19)  
+3. [牛虎棋牌](https://gitee.com/ECPS_admin/PlanB)  
+
 群友demo:  
-[斗地主(客户端服务端)](https://github.com/Viagi/LandlordsCore)  
-[牛虎棋牌](https://gitee.com/ECPS_admin/PlanB)  
-[背包系统](https://gitee.com/ECPS_admin/planc)  
-[ET小游戏合集](https://github.com/Acgmart/ET-MultiplyDemos)  
+1. [斗地主(客户端服务端)](https://github.com/Viagi/LandlordsCore)  
+2. [背包系统](https://gitee.com/ECPS_admin/planc)  
+3. [ET小游戏合集](https://github.com/Acgmart/ET-MultiplyDemos)  
+
+
 
 视频教程:  
 [肉饼老师主讲](http://www.taikr.com/my/course/972)  
@@ -168,4 +171,4 @@ __讨论QQ群 : 474643097__
 
 
 # 支付宝捐赠  
-![使用支付宝对该项目进行捐赠](https://github.com/egametang/ET/blob/master/Doc/donate.png)
+![使用支付宝对该项目进行捐赠](https://github.com/egametang/ET/blob/master/Book/donate.png)