فهرست منبع

Translate documents into English

tanghai 4 سال پیش
والد
کامیت
03026703ea

+ 64 - 0
Book/1.1RunGuide.md

@@ -0,0 +1,64 @@
+# Run steps  
+1. visual studio user instructions.
+   - Versions.
+      - Win10 and above users, use .net6, VS version, must use 2022 and above. Note that VS 2019 does not support .net6 and cannot be used.
+      - Win7 users, can not install VS 2022, need to use .net 5 and VS 2019, but note that additional settings are required to support ET compilation.
+   - Dependencies.
+     - The "Game Development with Unity" extension needs to be installed.
+     - In "Tools-Options-Tools for Unity-General", you need to change the disable full project generation to False in the Miscellaneous section, otherwise it will cause an error in your Codes directory. 2.
+
+2. To use Rider 2021.2.2 (updated to the latest version), you need to install the following:
+   - Rider's Unity plugin  
+   - Install .net6  
+   - NET SDK 6.0.101 is not fully supported in Rider", but it does not actually affect the compilation (2021.12.21)
+   - 2021.3.x fully supports .net6
+
+3. master branch requires unity 2020.3 (C#8 syntax is used)  
+
+4. start Unity, menu File -> Open Project... -> Open Select the ET/Unity folder and click on the Select Folder button. 5.  
+
+5. Click on the Unity menu Assets -> Open C# Project to start vs  
+
+6. Run Tools->BuildCode on the Unity menu, this step will compile the client code  
+
+7. Open ET/Client-Server.sln compile with Rider (**must compile all project, right click VS solution, compile all**)
+   1. first compile "Client-Server/Client/Unity.Mono" separately
+   2. then compile the complete solution "Client-Server"
+
+8. export table tools, compile the command line into the Bin directory after completion, execute dotnet Tools.dll --AppType=ExcelExporter  
+
+9. export protocol tool, compile and enter Bin directory, execute dotnet Tools.dll --AppType=Proto2CS  
+
+10. Double-click the Init scene in the Scenes directory in Unity and click Play to run it.
+
+# Test state synchronization demo
+1. If you want to modify the configuration, go to the Excel directory and modify the corresponding table, do step 6 of the running steps, and then re-run the Server.App project to start the server.
+
+2. Unity->tools menu->Package Tools, select PC, check whether to package exe, click Start Package, and type a PC package in Release directory.
+
+3. Run Unity Login Enter the lobby Enter the scene
+
+4. Run the PC package, log in and enter the lobby
+
+5. Click the right mouse button to move the character
+
+# Cautions.
+
+I. Error causes are.  
+
+1. Chinese directory.  
+2. low version of VS
+3. Rider does not have the relevant components installed
+4. not installed .net6
+5. not compile all projects on the server side
+6. Rider should be updated to the latest version  
+7. Unity version is too low
+8. Win7 users, no special settings
+9. *If there is a dependency problem during the compilation process, it may be due to Unity - External Tools - Generate .csproj files for:
+   When the 
+      1. Registry packages
+      2. Build-in packages
+10. *If the package is missing "StreamingAsset", you can create a new StreamingAsset folder under ET\Unity\Assets.
+
+
+

+ 58 - 0
Book/1.2Why use .net core.md

@@ -0,0 +1,58 @@
+# Why use C# .net core for server-side?
+Game server side from the early single service to distributed, the development is more and more complex, the stability, development efficiency requirements are more and more high. The choice of development language has also gradually changed, from C to C++ to C++ + PYTHON or C++ + LUA, and now many companies are using erlang, go, java, c#. At present, it is a blossoming situation.
+
+But if you were to redo an online game server, without considering the compatibility with the company or what is already there, how would you choose? I thought carefully about this issue, there are probably several aspects of this need to consider: 1.
+
+###### 1. Stability of the language (fatal)
+The game server is characterized by high load and low latency. So generally the server-side process is with state, once hung means data loss, this is intolerable.
+
+###### 2. Runtime hot more (fatal)
+The game server logic is extremely complex and prone to bugs, but it can't be stopped often, so hot shifts to fix bugs are necessary. If a bug occurs, the developer can write code immediately and then fix it with a hot-change, which is not felt by online users at all.
+
+###### 3. Availability of concurrent process support (5 stars importance)
+With distributed server architecture, there is bound to be a lot of interaction between processes. Since it is difficult to split the game logic into multiple threads, it is generally single-threaded logic. If there is no concurrent support, a large number of callbacks are bound to be generated and code maintenance will become very difficult.
+
+###### 4. Compilation speed (5 stars in importance)
+In c++ development, 30% of the time is wasted on compilation. If compilation is fast or not needed, it will greatly improve development efficiency.
+
+###### 5. Cross-platform (4 stars)
+Generally the game server is set up on linux. But the usual development, the use of windows will be more convenient, if cross-platform, development and testing efficiency will be greatly improved, and do not need to get a separate development machine, the local computer can meet the usual development
+
+###### 6. Readability, refactorability (3 stars)
+The code can be reconstructed to greatly reduce the difficulty of writing code
+
+###### 7. Whether the library is complete, whether the ecology is perfect (3 stars)
+Library is complete, ecological good, you need to build their own wheel is less
+
+###### 8. Unified language with the client (3 stars)
+Client-server shared language, the advantages are very obvious, many codes can be reused, logic programmers no longer need to distinguish between the front and back end, both ends can write, a person can complete a function, greatly reducing the time cost of communication.
+
+###### 9. IDE support (3 stars)
+Code hints, refactoring and other support, excellent IDE can improve the development efficiency by several times.
+
+###### 10. Language performance (1 star)
+Currently server performance is not too much of a problem, but good performance is better than poor performance.  
+
+| Languages | C# | C/C++ | Java | Go | Lua | Python | Erlang |
+| -- | :--: | :--: | :--: | :--: | :--: | :--: | :--: |
+| Stability | Stability | Easy to hang | Stability | Stability | Stability | Stability | Stability | Stability | Stability
+| Support | Harder to support | Support | Not support | Support | Support | Support | Support
+| Cross-Platform | Support | Harder to Support | Support | Harder to Support | Support | Support | Support
+| Support | Support | Support | Support | Support | Support | Support | Support | Support
+| Compilation speed | fast | slow | fast | fast | no compilation | no compilation | no compilation | no compilation
+| Good | Fair | Good | Fair | Poor | Poor | Poor|
+| Game Library and Ecology | Good | Good | Average | Average | Poor | Good | Average|
+| Unity | Unity, UE4 | Not available | Not available | Unity, UE4 | UE4 | Not available | Unity, UE4 | Not available | Unity, UE4 | Not available | Unity, UE4 | Not available
+| IDE Support | Good | Good | Average | Poor | Poor | Poor|
+| Language performance | Good | Very good | Good | Good | Poor | Very poor | Poor |
+
+As you can see from the table. 1:
+1. C/C++ has poor stability, slow compilation speed, and fatal flaws
+2. Go does not support hot changes, does not support generics, poor reconfigurability, can not share code with the client, a fatal flaw
+3. poor support for Java concurrency, unable to share code with the client
+4. Lua has few libraries, poor performance, poor code readability and reconfigurability, cross-platform dependence on C/C++, troublesome to handle, and poor ide support
+5. Python poor performance, poor code readability and reconfigurability, unable to share code with clients, poor ide support
+6. Erlang performance is poor, functional style is not easy to get started, ide support is poor
+7. C# .net core is very good in every convenience, but can't share code with UE4
+
+Currently Unity is the hottest game engine, C# server with Unity is a perfect match, basically can not find defects.

+ 119 - 0
Book/2.1CSharp Coroutine.md

@@ -0,0 +1,119 @@
+# What is a concurrent thread
+Speaking of concurrency, let's first understand what is asynchronous. Asynchronous simply means that I want to initiate a call, but the called party (may be other threads, or may be IO) will take some time to produce the result, and I don't want the call to block the entire thread of the caller, so I pass a callback function to the called party, and the called party will call back this callback function after it finishes running to notify the caller to continue The callback function will notify the caller to continue execution. As an example:  
+In the following code, the main thread keeps looping, sleep 1 millisecond per loop, add one to the count, and print once every 10,000 times.
+
+```csharp
+        private static void Main()
+        {
+            int loopCount = 0;
+            while (true)
+            {
+                int temp = watcherValue;
+                
+                Thread.Sleep(1);
+                
+                ++loopCount;
+                if (loopCount % 10000 == 0)
+                {
+                    Console.WriteLine($"loop count: {loopCount}");
+                }
+            }
+        }
+```
+At this point I need to add a function, at the beginning of the program, I want to print the value of loopCount after 5 seconds. Seeing that after 5 seconds we can think of the Sleep method, which will block the thread for a certain amount of time and then continue execution. We obviously can't Sleep in the main thread because it would break the logic of printing once every 10000 counts.
+```csharp
+    // example2_1
+    class Program
+    {
+        private static int loopCount = 0;
+
+        private static void Main()
+        {
+            OneThreadSynchronizationContext _ = OneThreadSynchronizationContext.Instance;
+            
+            WaitTimeAsync(5000, WaitTimeFinishCallback);
+            
+            while (true)
+            {
+                OneThreadSynchronizationContext.Instance.Update();
+                
+                Thread.Sleep(1);
+                
+                ++loopCount;
+                if (loopCount % 10000 == 0)
+                {
+                    Console.WriteLine($"loop count: {loopCount}");
+                }
+            }
+        }
+
+        private static void WaitTimeAsync(int waitTime, Action action)
+        {
+            Thread thread = new Thread(()=>WaitTime(waitTime, action));
+            thread.Start();
+        }
+        
+        private static void WaitTimeFinishCallback()
+        {
+            Console.WriteLine($"WaitTimeAsync finsih loopCount value is: {loopCount}");
+        }
+
+        /// <summary>
+        /// Waiting in another thread
+        /// </summary>
+        private static void WaitTime(int waitTime, Action action)
+        {
+            Thread.Sleep(waitTime);
+            
+            // Throw the action back to the main thread for execution
+            OneThreadSynchronizationContext.Instance.Post((o)=>action(), null);
+        }
+    }
+```
+We have designed a WaitTimeAsync method here. WaitTimeAsync is actually a typical asynchronous method that initiates a call from the main thread, passes in a WaitTimeFinishCallback method as an argument, opens a thread, and after the thread Sleeps for a certain amount of time, throws the passed callback back to the main thread for execution. OneThreadSynchronizationContext is a cross-thread queue, any thread can throw delegates into it, the Update method of OneThreadSynchronizationContext is called in the main thread and will take out these delegates and put them into the main thread for execution. Why does the callback method need to be thrown back to the main thread for execution? Because the loopCount is read in the callback method, and the loopCount is also read and written in the main thread, so either add a lock or always ensure that it is only read and written in the main thread. It is a bad practice to add locks, and having locks all over the code makes it difficult to read and maintain, and it is easy to create multi-threaded bugs. this is a common technique in multi-threaded development to package the logic into a delegate and throw it back to another thread.
+
+We may have a new requirement, after the execution of WaitTimeFinishCallback is finished, we want to wait for 3 seconds and print the loopCount again.
+```csharp
+        private static void WaitTimeAsync(int waitTime, Action action)
+        {
+            Thread thread = new Thread(()=>WaitTime(waitTime, action));
+            thread.Start();
+        }
+        private static void WaitTimeFinishCallback()
+        {
+            Console.WriteLine($"WaitTimeAsync finsih loopCount value is: {loopCount}");
+            WaitTimeAsync(3000, WaitTimeFinishCallback2);
+        }
+        
+        private static void WaitTimeFinishCallback2()
+        {
+            Console.WriteLine($"WaitTimeAsync finsih loopCount value is: {loopCount}");
+        }
+```
+We may also change the requirement at this point, we need to print the loopCount 5 seconds after the program starts, then 4 seconds after, then 3 seconds after, that is, insert another 3 seconds wait in the middle of the above logic.
+```csharp
+        private static void WaitTimeAsync(int waitTime, Action action)
+        {
+            Thread thread = new Thread(()=>WaitTime(waitTime, action));
+            thread.Start();
+        }
+        
+        private static void WaitTimeFinishCallback()
+        {
+            Console.WriteLine($"WaitTimeAsync finsih loopCount value is: {loopCount}");
+            WaitTimeAsync(4000, WaitTimeFinishCallback3);
+        }
+        
+        private static void WaitTimeFinishCallback3()
+        {
+            Console.WriteLine($"WaitTimeAsync finsih loopCount value is: {loopCount}");
+            WaitTimeAsync(3000, WaitTimeFinishCallback2);
+        }
+        
+        private static void WaitTimeFinishCallback2()
+        {
+            Console.WriteLine($"WaitTimeAsync finsih loopCount value is: {loopCount}");
+        }
+```
+This inserts a piece of code in the middle, which seems very cumbersome. Here you can answer what is a concurrent process, in fact this string of callbacks is a concurrent process.
+

+ 77 - 0
Book/2.2Better Coroutine.md

@@ -0,0 +1,77 @@
+# Better Coroutine
+The above article talks about how a string of callbacks is a concurrent process, and obviously writing code this way, adding logic and inserting logic is very error prone. We need to use asynchronous syntax to change the form of this asynchronous callback to a synchronous form, fortunately C# has been designed for us, see the code
+```csharp
+    // example2_2
+    class Program
+    {
+        private static int loopCount = 0;
+        
+        static void Main(string[] args)
+        {
+            OneThreadSynchronizationContext _ = OneThreadSynchronizationContext.Instance;
+
+            Console.WriteLine($"Main Thread: {Thread.CurrentThread.ManagedThreadId}");
+            
+            Crontine();
+            
+            while (true)
+            {
+                OneThreadSynchronizationContext.Instance.Update();
+                
+                Thread.Sleep(1);
+                
+                ++loopCount;
+                if (loopCount % 10000 == 0)
+                {
+                    Console.WriteLine($"loop count: {loopCount}");
+                }
+            }
+        }
+
+        private static async void Crontine()
+        {
+            await WaitTimeAsync(5000);
+            Console.WriteLine($"Current thread: {Thread.CurrentThread.ManagedThreadId}, WaitTimeAsync finsih loopCount's value is: {loopCount}");
+            await WaitTimeAsync(4000);
+            Console.WriteLine($"Current Thread: {Thread.CurrentThread.ManagedThreadId}, WaitTimeAsync finsih The value of loopCount is: {loopCount}");
+            await WaitTimeAsync(3000);
+            Console.WriteLine($"Current Thread: {Thread.CurrentThread.ManagedThreadId}, WaitTimeAsync finsih The value of loopCount is: {loopCount}");
+        }
+        
+        private static Task WaitTimeAsync(int waitTime)
+        {
+            TaskCompletionSource<bool> tcs = new TaskCompletionSource<bool>();
+            Thread thread = new Thread(()=>WaitTime(waitTime, tcs));
+            thread.Start();
+            return tcs.Task;
+        }
+        
+        /// <summary>
+        /// Waiting in another thread
+        /// </summary>
+        private static void WaitTime(int waitTime, TaskCompletionSource<bool> tcs)
+        {
+            Thread.Sleep(waitTime);
+            
+            // throw tcs back to the main thread for execution
+            OneThreadSynchronizationContext.Instance.Post(o=>tcs.SetResult(true), null);
+        }
+    }
+```
+In this code, in the WaitTimeAsync method, we use the TaskCompletionSource class instead of the previously passed Action parameter, and the WaitTimeAsync method returns a Task type result. waitTime we replace action() with tcs. SetResult(true), and the WaitTimeAsync method uses the await keyword in front of it, so that the sequence of callbacks can be changed to a synchronized form. This makes the code look very simple and much easier to develop.  
+
+Here is another trick, we found that WaitTime needs to throw tcs.SetResult back to the main thread for execution, Microsoft gives us a simple way to set up the synchronization context in the main thread by referring to example2_2_2
+```csharp
+// example2_2_2
+SynchronizationContext.SetSynchronizationContext(OneThreadSynchronizationContext.Instance);
+```
+SetResult(true) will be called directly in WaitTime, the callback will be automatically thrown to the synchronization context, and the synchronization context we can take out in the main thread to execute the callback, so automatically able to complete the operation back to the main thread
+```csharp
+        private static void WaitTime(int waitTime, TaskCompletionSource<bool> tcs)
+        {
+            Thread.Sleep(waitTime);
+
+            tcs.SetResult(true);
+        }
+```
+If you do not set the synchronization context, you will find that the printout of the current thread is not the main thread, which is also the use of many third-party libraries and . In fact, I think this design is not necessary, to the library developers to achieve better, especially in the game development, logic is all single-threaded, callback every time you go through the synchronization context is redundant, so the ET framework provides the implementation of ETTask does not use the synchronization context, the code is more concise and efficient, which will be discussed later.

+ 143 - 0
Book/2.3Single-threaded asynchronous.md

@@ -0,0 +1,143 @@
+# Single-threaded asynchronous
+The previous examples are multi-threaded implementations of asynchrony, but asynchrony is obviously not just multi-threaded. We used Sleep in the previous examples to achieve time waiting, each timer needs to use a thread, which will lead to frequent thread switching, this implementation is very inefficient, usually will not do so. General game logic will design a single-threaded timer, we do a simple implementation here, used to explain single-threaded asynchronous.
+```csharp
+    // example2_3
+    class Program
+    {
+        private static int loopCount = 0;
+
+        private static long time;
+        private static Action action;
+        
+        static void Main(string[] args)
+        {
+            Console.WriteLine($"Main thread: {Thread.CurrentThread.ManagedThreadId}");
+
+            Crontine();
+            
+            while (true)
+            {
+                Thread.Sleep(1);
+
+                CheckTimerOut();
+                
+                ++loopCount;
+                if (loopCount % 10000 == 0)
+                {
+                    Console.WriteLine($"loop count: {loopCount}");
+                }
+            }
+        }
+        
+        private static void Crontine()
+        {
+            WaitTimeAsync(5000, WaitTimeAsyncCallback1);
+        }
+
+        private static void WaitTimeAsyncCallback1()
+        {
+            Console.WriteLine($"Current thread: {Thread.CurrentThread.ManagedThreadId}, WaitTimeAsync finsih loopCount's value is: {loopCount}");
+            WaitTimeAsync(4000, WaitTimeAsyncCallback2);
+        }
+        
+        private static void WaitTimeAsyncCallback2()
+        {
+            Console.WriteLine($"Current thread: {Thread.CurrentThread.ManagedThreadId}, WaitTimeAsync finsih loopCount's value is: {loopCount}");
+            WaitTimeAsync(3000, WaitTimeAsyncCallback3);
+        }
+        
+        private static void WaitTimeAsyncCallback3()
+        {
+            Console.WriteLine($"Current thread: {Thread.CurrentThread.ManagedThreadId}, WaitTimeAsync finsih loopCount's value is: {loopCount}");
+        }
+
+        private static void CheckTimerOut()
+        {
+            if (time == 0)
+            {
+                return;
+            }
+            long nowTicks = DateTime.Now.Ticks / 10000;
+            if (time > nowTicks)
+            { return; }
+                return;
+            }
+
+            time = 0;
+            action.Invoke();
+        }
+        
+        private static void WaitTimeAsync(int waitTime, Action a)
+        {
+            Ticks / 10000 + waitTime;
+            action = a;
+        }
+    }
+```
+
+This example also implements a simple timing method, WaitTimeAsync will be called to record the callback method and time, the main thread will call CheckTimerOut every frame, CheckTimerOut inside to determine whether the timer is expired, expired then callback method is called. The whole logic is done in the main thread, also asynchronously. So asynchronous is not multi-threaded, single-threaded can also be asynchronous. The above example can be changed to await as well.
+```csharp
+    // example2_3_2
+    class Program
+    {
+        private static int loopCount = 0;
+
+        private static long time;
+        private static TaskCompletionSource<bool> tcs;
+        
+        static void Main(string[] args)
+        {
+            Console.WriteLine($"Main thread: {Thread.CurrentThread.ManagedThreadId}");
+
+            Crontine();
+            
+            while (true)
+            {
+                Thread.Sleep(1);
+
+                CheckTimerOut();
+                
+                ++loopCount;
+                if (loopCount % 10000 == 0)
+                {
+                    Console.WriteLine($"loop count: {loopCount}");
+                }
+            }
+        }
+        
+        private static async void Crontine()
+        {
+            await WaitTimeAsync(5000);
+            Console.WriteLine($"Current thread: {Thread.CurrentThread.ManagedThreadId}, WaitTimeAsync finsih loopCount's value is: {loopCount}");
+            await WaitTimeAsync(4000);
+            Console.WriteLine($"Current Thread: {Thread.CurrentThread.ManagedThreadId}, WaitTimeAsync finsih The value of loopCount is: {loopCount}");
+            await WaitTimeAsync(3000);
+            Console.WriteLine($"Current Thread: {Thread.CurrentThread.ManagedThreadId}, WaitTimeAsync finsih The value of loopCount is: {loopCount}");
+        }
+
+        private static void CheckTimerOut()
+        {
+            if (time == 0)
+            {
+                return;
+            }
+            long nowTicks = DateTime.Now.Ticks / 10000;
+            if (time > nowTicks)
+            { return; }
+                return;
+            }
+
+            time = 0;
+            tcs.SetResult(true);
+        }
+        
+        private static Task WaitTimeAsync(int waitTime)
+        {
+            TaskCompletionSource<bool> t = new TaskCompletionSource<bool>();
+            Time = DateTime.Now.Ticks / 10000 + waitTime;
+            tcs = t;
+            return t.Task;
+        }
+    }
+```
+The above example all calls are done in the main thread and use await, so await does not open multithreading, await specific use of multithreading depends entirely on the specific implementation

+ 226 - 0
Book/3.2The powerful MongoBson library.md

@@ -0,0 +1,226 @@
+# The powerful MongoBson library
+Back-end development, statistics about these scenarios need to use serialization: 1.
+1. object clone by serialization deserialization
+2. server-side database storage data, binary
+3. distributed server-side, multi-process messages, binary
+4. back-end logs, text format
+5. various server-side configuration files, text format
+
+There are very, very many C# serialization libraries, protobuf, json and so on. But these serialization libraries should not be readable and small for all scenarios. protobuf does not support complex object structures (cannot use inheritance) and is suitable for messages, but not for database storage and log formats. json is suitable for log formats, but is too big for network messages and data storage. We certainly want a library that can satisfy all the above scenarios for the following reasons.
+1. you think about one day your configuration file needs to be saved in the database, you do not need to do the format conversion, the back-end directly to the configuration message sent by the front-end to save to the database, which can not reduce very many errors?
+2. one day some server-side configuration files do not use the file format, need to be placed in the database, again, only a few lines of code to complete the migration.
+3. one day the back-end server crash, you need to scan the logs for data recovery, the logs for deserialization into C# objects, one by one for processing, and then into objects saved to the database is complete.
+4. objects saved in the database, you can directly see the text content, you can do a variety of SQL-like operations
+5. Imagine a scenario where a configuration text object, deserialized into memory, sent via network messages, and stored in the database. The whole process is done in one go.
+
+Simply put, it reduces various data conversions, reduces code, improves development efficiency, and improves maintainability. MongoDB library can serialize both text and BSON binary format, and MongoDB itself is a very much used database in the game. Its support features are as follows.
+1. support complex inheritance structure
+2. support for ignoring certain fields serialization
+3. support field default values
+4. structure with extra fields can still be deserialized, which is very useful for multi-version protocols
+5. support for ISupportInitialize interface, this is a godsend when deserialization
+6. support for text json and binary bson serialization
+7. MongoDB database support
+
+A brief introduction to the mongo bson library
+### 1. Support serialization deserialization into json or bson
+```csharp
+    public sealed class Player
+    {
+        public long Id;
+
+        public string Account { get; private set; }
+
+        public long UnitId { get; set; }
+    }
+
+    Player player1 = new Player() { Id = 1 };
+    string json = player1.ToJson();
+    Console.WriteLine($"player1 to json: {json}");
+    Console.WriteLine($"player to bson: {player.ToBson().ToHex()}");
+    // output:
+    // player to json: { "_id" : NumberLong(1), "C" : [], "Account" : null, "UnitId" : NumberLong(0) }
+    // player to bson: B000000125F69640001000000000000000A4163636F756E740012556E69744964000000000000000000000000
+
+
+```
+Note that mongo's json is a bit different from the standard json, if you want to use the standard json, you can pass in a JsonWriterSettings object and restrict the use of JsonOutputMode.Strict mode
+```csharp
+    // use standard json
+    Player player2 = new Player() { Id = 1 };
+    Console.WriteLine($"player to json: {player2.ToJson(new JsonWriterSettings() {OutputMode = JsonOutputMode.Strict})}");
+    // player to json: { "_id" : 1, "C" : [], "Account" : null, "UnitId" : 0 }
+```
+
+Deserialize json:
+```csharp
+            // deserialize json
+        Player player11 = BsonSerializer.Deserialize<Player>(json);
+        Console.WriteLine($"player11 to json: {player11.ToJson()}");
+```
+Deserialize bson:
+```csharp
+    // deserialize bson
+    using (MemoryStream memoryStream = new MemoryStream(bson))
+    {
+        Player player12 = (Player) BsonSerializer.Deserialize(memoryStream, typeof (Player));
+        Console.WriteLine($"player12 to json: {player12.ToJson()}");
+    }
+```
+
+### 2. Some fields can be ignored
+[BsonIgnore] This tag is used to disable field serialization.
+```csharp
+	public sealed class Player
+	{
+        public long Id;
+
+		[BsonIgnore]
+		public string Account { get; private set; }
+		
+		public long UnitId { get; set; }
+    }
+
+    Player player = new Player() { Id = 2, UnitId = 3, Account = "panda"};
+	Console.WriteLine($"player to json: {player.ToJson()}");
+    // player to json: { "_id" : 2, "UnitId" : 3 }
+```
+### 3. Support for default values and taking aliases
+The [BsonElement] field with this tag will serialize even private fields (only public fields are serialized by default), and the tag can take a string parameter to assign an alias to the field serialization.
+```csharp
+	public sealed class Player
+	{
+        public long Id;
+
+		public string Account { get; private set; }
+
+		[BsonElement("UId")]
+		public long UnitId { get; set; }
+    }
+    Player player = new Player() { Id = 2, UnitId = 3, Account = "panda"};
+	Console.WriteLine($"player to json: {player.ToJson()}");
+    // player to json: { "_id" : 2, "Account" : "panda", "UId" : 3 }
+```
+### 4. Upgrade version support
+[BsonIgnoreExtraElements] This tag is used on top of class, used to ignore extra fields when deserializing, general version compatibility needs to be considered, low version of the protocol needs to be able to deserialize
+otherwise the new version adds fields, the old version structure deserialization will be wrong
+```csharp
+	[BsonIgnoreExtraElements]
+	public sealed class Player
+	public
+        public long Id;
+
+		public string Account { get; private set; }
+
+		[BsonElement("UId")
+		public long UnitId { get; set; }
+    }
+```
+### 5. Support for complex inheritance structures
+The power of the mongo bson library is that it fully supports serialization deserialization inheritance structures. Note that inheritance deserialization requires registration of all parent classes, and there are two ways to do this.
+a. You can declare the inherited subclasses on top of the parent class using the [BsonKnownTypes] tag, so that mongo will automatically register them, e.g.:
+```csharp
+    [BsonKnownTypes(typeof(Entity))]
+    public class Component
+    {
+    }
+    [BsonKnownTypes(typeof(Player))]
+    public class Entity: Component
+    {
+    }
+    public sealed class Player: Entity
+    {
+        public long Id;
+        
+        public string Account { get; set; }
+		
+        public long UnitId { get; set; }
+    }
+```
+This is flawed because the framework doesn't know what subclasses a class will have, and this is invasive to the framework code, and we want to uncouple this
+. You can scan the assembly for the types of all subclass parents and register them with the mongo driver
+```csharp
+			Type[] types = typeof(Game).Assembly.GetTypes();
+			foreach (Type type in types)
+			{
+				if (!type.IsSubclassOf(typeof(Component))))
+				{
+					continue;
+				}
+
+				BsonClassMap.LookupClassMap(type);
+			}
+
+			BsonSerializer.RegisterSerializer(new EnumSerializer<NumericType>(BsonType.String));
+```
+This completely automates the registration and the user does not need to relate whether the class is registered or not.
+
+### 6. ISupportInitialize interface
+mongo bson deserialization supports an ISupportInitialize interface, ISupportInitialize has two methods
+```csharp
+    public interface ISupportInitialize
+    {
+        void BeginInit();
+        void EndInit();
+    }
+```
+BeginInit is called before deserialization and EndInit is called after deserialization. This interface is very useful now to perform some operations after deserialization. For example
+```csharp
+	[BsonIgnoreExtraElements]
+	public class InnerConfig: AConfigComponent
+	{
+		[BsonIgnore]
+		public IPEndPoint IPEndPoint { get; private set; }
+		
+		public string Address { get; set; }
+
+		public override void EndInit()
+		{
+			this.IPEndPoint = NetworkHelper.ToIPEndPoint(this.Address);
+		}
+	}
+````
+InnerConfig is the configuration of the process inner network address in ET. Since IPEndPoint is not very configurable, we can configure it as a string and then convert the string to IPEndPoint in EndInit when deserializing.
+I also added this call to the protobuf deserialization method, refer to ProtobufHelper.cs, ET's protobuf because to support ilruntime, so remove the map support, if we want a map how to do? Here I gave the generated code are done, the proto messages are changed to a partial class, so that we can extend the class themselves, for example.
+```csharp
+message UnitInfo
+{
+	int64 UnitId = 1;
+
+	float X = 2;
+	float Y = 3;
+	float Z = 4;
+}
+
+// protobuf
+message G2C_EnterMap // IResponse
+{
+	int32 RpcId = 90;
+	int32 Error = 91;
+	string Message = 92;
+	// own unit id
+	int64 UnitId = 1;
+	// all the units
+	repeated UnitInfo Units = 2;
+}
+```
+This network message has a repeated UnitInfo field, which is actually an array in protobuf, which is not very convenient to use, I want to convert it to a Dictionary<Int64, UnitInfo> field, we can do something like this
+```csharp
+    public partial class G2C_EnterMap: ISupportInitialize
+    {
+        public Dictionary<Int64, UnitInfo> unitsDict = new Dictionary<long, UnitInfo>();
+        
+        public void BeginInit()
+        {
+        }
+
+        public void EndInit()
+        {
+            foreach (var unit in this.Units)
+            {
+                this.unitsDict.Add(unit.UnitId, unit);
+            }
+        }
+    }
+```
+The message is extended by such a piece of code, and after deserialization, it is automatically converted into a Dictionary.

+ 79 - 0
Book/3.3Everything is Entity.md

@@ -0,0 +1,79 @@
+# Everything is Entity
+The ECS design is very popular right now, mainly because of the success of Watchtower, which has led to the explosion of this technology. The most important design of ECS is the complete separation of logic and data. That is, EC is pure data, System is actually logic, by data-driven logic. What does data-driven logic mean? It is very simple to detect data changes through Update and subscribe to data changes through the event mechanism, which is called data-driven. Other features such as cache hits are not too important in writing logic, modern games are scripted, even the performance of the script can tolerate how will care about cache hits that performance improvement?  
+
+For example, in order to reuse, the data must be split into very small particles, which will lead to a very large number of components. But the game is developed cooperatively by multiple people, each person is basically only familiar with their own modules, which may end up causing a large number of redundant components. Another problem is that the common ECS is flat, with only one layer of Entity and Component. It is like a company, the biggest is the boss, the boss with hundreds of people under him, the boss can not know all the people, to complete a task, the boss can not pick out the people they need. A reasonable approach is to have several managers under the boss, several supervisors under each manager, and several workers under each supervisor, so as to form a tree-like management structure that is easy to manage. This is similar to the ET approach, where Entity can manage Component, Component can manage Entity, and even Component can mount Component. e.g. a person is composed of head, body, hands, feet, and the head is composed of eyes, ears, nose, mouth.
+```csharp
+    Head head = human.AddComponent<Head>();
+    head.AddComponent<Eye>();
+    head.AddComponent<Mouse>();
+    AddComponent<Nose>();
+    AddComponent<Ear>();
+    human.AddComponent<Body>();
+    AddComponent<Hand>();
+    human.AddComponent<Leg>();
+```
+In ET, all data is Entity, including Entity, and Entity can be used either as a component or as a child of other Entity. Generic data is placed on Entity as a member, and less generic data can be hung on Entity as a component. For example, the design of items, all items have fields configured id, quantity, level, these fields are not necessary to make components, put on Entity will be more convenient to use.
+```csharp
+    class Item: Entity
+    {
+        // The configuration Id of the props
+        public int ConfigId { get; set; }
+        // The number of props
+        public int Count { get; set; }
+        // The level of the props
+        public int Level { get; set; }
+    }
+```
+This design data of ET is a kind of tree structure, very hierarchical and can understand the whole game architecture very easily. Scene, and the data of different modules are mounted on top of Game. Scene, and each module can mount a lot of data under itself. You don't have to think too much about how to design the classes, where to put the data, whether mounting here will lead to redundancy, etc. for each new feature. For example, if my player needs to do a prop system, I can design an ItemsComponent to be mounted on the Player, and I need to develop a SpellComponent to be mounted on the Player for skills. If the whole service needs to do an activity, get an activity component to hang on top of the Game. This design will be very easy to assign tasks and very modular.  
+
+# Some details of the component
+### 1. Component creation
+ComponentFactory provides three methods to create components Create, CreateWithParent, CreateWithId. Create is the simplest way to create components, it does several things  
+a. Construct a component based on the component type  
+b. Add the component to the event system and throw an AwakeSystem  
+c. Enables object pooling or not  
+CreateWithParent provides a Parent object on top of Create, which is set to the Component.Parent field. createWithId is used to create ComponentWithId or its subclasses, and you can set an Id on top of Create itself, Component can choose whether to use a pool of objects when it is created. All three types of factory methods have a fromPool parameter, the default is true.
+### 2. Release of components
+Component inherits an IDisposable interface. It should be noted that Component has unmanaged resources and must be called to delete a Component. This interface does the following  
+a. Throw Destroy System  
+b. If the component was created using an object pool, then it is put back into the object pool here  
+c. Remove the component from the global EventSystem and set the InstanceId to 0  
+If the component is mounted on Entity, then when Entity calls Dispose, it will automatically call the Dispose method of all components on it.  
+
+### 3. Role of InstanceId
+Any Component comes with an InstanceId field, which is reset when the component is constructed, or when the component is removed from the object pool, and which identifies the identity of the component. Why is such a field needed? There are several reasons  
+1. the existence of the object pool, the component may not be released, but returned to the object pool. In an asynchronous call, it is likely that the component has already been released and then reused, so that we need a way to be able to distinguish whether the previous component object has been released, such as the following code.
+```csharp
+		public static async ETVoid UpdateAsync(this ActorLocationSender self)
+		{
+			try
+			{
+				long instanceId = self.InstanceId;
+				while (true)
+				{
+					if (self.InstanceId ! = instanceId)
+					{
+						return;
+					}
+					ActorTask actorTask = await self.GetAsync();
+					
+					if (self.InstanceId ! = instanceId)
+					{
+						return;
+					}
+					if (actorTask.ActorRequest == null)
+					{
+						return;
+					}
+
+					await self.RunTask(actorTask);
+				}
+			}
+			catch (Exception e)
+			{
+				Log.Error(e);
+			}
+		}
+```
+While (true) is an asynchronous method, after await self.GetAsync() it is likely that the ActorLocationSender object has been released, and it is even possible that the object has been utilized again by other logic from the object pool. We can determine whether the object has been released by the change of InstanceId. 2.  
+2. InstanceId is globally unique and has location information, so you can find the location of the object by InstanceId and send the message to the object. This design will be utilized in the Actor message. Here for the time being will not talk about it.

+ 2 - 2
Book/3.3一切皆组件.md → Book/3.3一切皆实体.md

@@ -1,4 +1,4 @@
-# 一切皆组件
+# 一切皆实体
 目前十分流行ECS设计,主要是守望先锋的成功,引爆了这种技术。守望先锋采用了状态帧这种网络技术,客户端会进行预测,预测不准需要进行回滚,由于组件式的设计,回滚可以只回滚某些组件即可。ECS最重要的设计是逻辑跟数据的完全分离。即EC是纯数据,System实际上就是逻辑,由数据驱动逻辑。数据驱动逻辑是什么意思呢?很简单通过Update检测数据变化,通过事件机制来订阅数据变化,这就是所谓的数据驱动了。其它的特点例如缓存命中,在编写逻辑上来说并不太重要,现代游戏都用脚本,连脚本的性能都能容忍怎么会在乎缓存命中那点性能提升?ET在设计的时候吸收了这些想法,但是并不完全照搬,目前的设计是我经过长期的思考跟重构得来的,还是有些自己特色。  
 
 传统的ECS写逻辑作者看来存在不少缺陷,比如为了复用,数据必然要拆成非常小的颗粒,会导致组件非常非常多。但是游戏是多人合作开发的,每个人基本上只熟悉自己的模块,最后可能造成组件大量冗余。还有个问题,常见的ECS是扁平式的,Entity跟Component只有一层。组件一多,开发功能可能不知道该使用哪些Component。好比一家公司,最大的是老板,老板手下带几百个人,老板不可能认识所有的人,完成一项任务,老板没法挑出自己需要的人。合理的做法是老板手下应该有几个经理,每个经理手下应该有几个主管,每个主管管理几个工人,这样形成树状的管理结构才会容易管理。这类似ET的做法,Entity可以管理Component,Component管理Entity,甚至Component还可以挂载Component。例如:人由头,身体,手,脚组成,而头又由眼睛,耳朵,鼻子,嘴巴组成。
@@ -12,7 +12,7 @@
     human.AddComponent<Hand>();
     human.AddComponent<Leg>();
 ```
-ET中,所有数据都是Component,包括Entity,Entity继承于ComponentWithId,ComponentWithId继承于Component,所以Entity本质上也是一个Component,只不过它可以挂载其它的Component。实际使用中你可以继承Component,ComponentWithId,Entity三者之一,区别是如果该类需要挂载组件则继承Entity,如果不需要挂载组件但是需要带个逻辑Id则继承ComponentWithId,剩下的继承Component。ET的Entity是可以有数据成员的,通用的数据放在Entity身上作为成员,不太通用的数据可以作为组件挂在Entity身上。比如物品的设计,所有物品都有配置id,数量,等级的字段,这些字段没有必要做成组件,放在Entity身上使用会更加方便。
+ET中,所有数据都是Entity,包括Entity,Entity既可以当成组件使用,也可以当做其它Entity的孩子。通用的数据放在Entity身上作为成员,不太通用的数据可以作为组件挂在Entity身上。比如物品的设计,所有物品都有配置id,数量,等级的字段,这些字段没有必要做成组件,放在Entity身上使用会更加方便。
 ```csharp
     class Item: Entity
     {

+ 134 - 0
Book/3.4EventSystem.md

@@ -0,0 +1,134 @@
+# EventSystem  
+One of the most important features of ECS is the separation of data and logic, and the second is data-driven logic. What is data-driven logic? Not very well understood, let's take an example
+A moba game, the heroes have blood bars, which are displayed on the character's head, and also on the top left avatar UI. This time the server sends a blood deduction message. How do we handle this message? In the first way, we modify the hero's blood value in the message handling function, modify the blood bar display on the avatar, and modify the blood bar on the avatar UI at the same time. This approach obviously causes coupling between modules. In the second method, the blood value is only changed in the blood deduction message processing function, and the change of blood value throws an hpchange event, and both the avatar module and the UI module subscribe to the blood value change event and handle their own logic in the subscribed method, so that each module is responsible for its own logic without coupling.
+ET provides a variety of events, all of which can be subscribed multiple times:  
+1. AwakeSystem, which is thrown after the component factory creates a component, and is thrown only once, with parameters
+```csharp
+    Player player = ComponentFactory.Create<Player>();
+
+    // Subscribe to Player's Awake event
+    public class PlayerAwakeSystem: AwakeSystem<Player>
+    {
+        public override void Awake(Player self)
+        {
+        }
+    }
+````
+2. StartSystem, component UpdateSystem call before throwing
+```csharp
+    // Subscribe to Player's Start event
+    public class PlayerStartSystem: StartSystem<Player>
+    {
+        public override void Start(Player self)
+        {
+        }
+    }
+````
+3. UpdateSystem, component thrown every frame
+```csharp
+    // Subscribe to Player's Update event
+    public class PlayerUpdateSystem: UpdateSystem<Player>
+    {
+        public override void Update(Player self)
+        {
+        }
+    }
+````
+4. DestroySystem, thrown when the component is deleted
+```csharp
+    // Subscribe to Player's Destroy event
+    public class PlayerDestroySystem: DestroySystem<Player>
+    {
+        public override void Destroy(Player self)
+        {
+        }
+    }
+
+    Player player = ComponentFactory.Create<Player>();
+    // The Destroy event will be fired here
+    player.Dispose();
+```
+5. ChangeSystem, thrown when the content of the component changes, needs to be triggered manually by the developer
+```csharp
+    // Subscribe to Player's Destroy event
+    public class PlayerChangeSystem: ChangeSystem<Player>
+    {
+        public override void Change(Player self)
+        {
+        }
+    }
+
+    Player player = ComponentFactory.Create<Player>();
+    // need to trigger ChangeSystem manually
+    Game.EventSystem.Change(player);
+```
+6. DeserializeSystem, thrown after component deserialization
+```csharp
+    // Subscribe to Player's Deserialize event
+    public class PlayerDeserializeSystem: DeserializeSystem<Player>
+    {
+        public override void Deserialize(Player self)
+        {
+        }
+    }
+
+    // Here player2 will trigger the Deserialize event
+    Player player2 = MongoHelper.FromBson<Player>(player.ToBson());
+```
+7. LoadSystem, EventSystem thrown when loading dll, used for server-side hot update, reload dll to do some processing, such as re-register handler
+```csharp
+    // Subscribe to Player's Load event
+    public class PlayerLoadSystem: LoadSystem<Player>
+    {
+        public override void Load(Player self)
+        {
+        }
+    }
+```
+8. normal Event, thrown by the developer himself, can take up to three parameters. Also the client hot change layer can subscribe to the mono layer Event events
+```csharp
+    int oldhp = 10;
+    int newhp = 5;
+    // Throw hp change event
+    Game.EventSystem.Run("HpChange", oldhp, newhp);
+
+    // UI subscribe to the hp change event
+    [Event("HpChange")]
+    public class HpChange_ShowUI: AEvent<int, int>
+    {
+        public override void Run(int a, int b)
+        {
+            throw new NotImplementedException();
+        }
+    }
+
+    // The model header blood bar module also subscribes to the hp change event
+    [Event("HpChange")
+    public class HpChange_ModelHeadChange: AEvent<int, int>
+    {
+        public override void Run(int a, int b)
+        {
+            throw new NotImplementedException();
+        }
+    }
+```
+
+9. There are many other events, such as message events. Message events are declared using MessageHandler and can take parameters to specify which server to subscribe to.
+```csharp
+	[MessageHandler(AppType.Gate)]
+	public class C2G_LoginGateHandler : AMRpcHandler<C2G_LoginGate, G2C_LoginGate>
+	{
+		protected override void Run(Session session, C2G_LoginGate message, Action<G2C_LoginGate> reply)
+		{
+			G2C_LoginGate response = new G2C_LoginGate();
+			reply(reply);
+		}
+	}
+```
+More specific message events will be explained in detail when we talk about messages  
+10. numeric events, numeric module and then explain  
+...... , more events to be developed by yourself.
+
+The logic of the ET framework is driven by the various events above.
+
+

+ 98 - 0
Book/4.1Component-based design.md

@@ -0,0 +1,98 @@
+# Component-based design
+
+In terms of code reuse and organization of data, object-oriented may be the first response. Object-oriented three features inheritance, encapsulation, polymorphism, to a certain extent can solve a lot of code reuse, data reuse problems. But object-oriented is not a panacea, it also has great flaws: # # 1.  
+
+## 1. data structure coupling is very strong
+Once a field is added or removed from a parent class, it may have to affect all subclasses and affect all subclass-related logic. This seems very inflexible, in a complex set of inheritance system, to change the fields in the parent class will become more and more troublesome, let's say ABC is a subclass of D, one day found the need to add a data that AB has, but C does not, then this data is certainly not good to put into the parent class, only AB abstracted out of a parent class E, E inherited from D, AB common fields added to E, once the inheritance structure Once the inheritance structure has changed, the interface may also need to change, let's say there is an interface incoming parameter type is E, when AB no longer needs the common field, then the inheritance relationship needs to be adjusted so that AB inherits D again, then the interface incoming parameter type needs to be changed to D, where the logic code is likely to be adjusted. What's worse is that the game logic changes very complicated and very often, maybe today a field is added, tomorrow it is deleted, if every time to adjust the inheritance structure, it is a nightmare. Inheritance structure feels very powerless in the face of frequent data structure adjustment.    
+## 2. Difficult to hot-plug
+Inheritance structure can't add or delete fields at runtime, for example, Player usually walks, and then rides after using mount. The problem is that the information about the mount would need to be hanging on top of the Player object all the time. This makes it inflexible. Why do I need to have the horse data in memory when I'm not riding? The interface has the same problem, a class implements an interface, then the interface will always stick to the class, you want to get rid of her can not, or horse riding for example, the player player can ride, then may inherit a riding interface, the problem is, when I the Player from the mount, the player player still has the riding interface, there is no way to There is no way to dynamically delete this interface! The example may not be quite right, but the reasoning should be clear.  
+
+The use of object-oriented may lead to disastrous consequences, game development in the new and old, there are good skills, there are poor skills. People like to be lazy, when you find the trouble to adjust the inheritance relationship, it is possible to add a field in AB to save trouble directly into the parent class D. The result is that C somehow has an extra field that is useless. The key can not be found, and finally lead to the parent class D is getting bigger and bigger, in the end, it may simply not ABC, directly let all the objects into D, convenient well! Yes, many games are doing this, the development of the end simply do not care about the inheritance relationship, because you want to manage can not manage.  
+
+## 3. method and data coupling
+Traditional object-oriented are class with methods, and especially advocate virtual function polymorphism. Methods and data put together brings a lot of coupling problems. In order to solve these coupling, we came up with a large number of design patterns, such as dependency interfaces, dependency transposition. To be honest, this is pants down, in order to understand the coupling, make the class into an interface, and then inherit from the interface, is this not called dependency? These practices lead to code that is full of interfaces and extremely difficult to read. There is no standard for writing up code, and the code written by experts and rookies is completely different. Most coders are logic boys, who have time to think about how to design this class every day ah? As the logic becomes more and more complex class inside the method will become increasingly large, the terrible thing is that this is the method of the class, extremely difficult to refactor, many projects can see the class inside the existence of tens of thousands of lines of code of virtual functions. Gosh!
+
+
+Object-oriented in the face of complex game logic is very powerless, so many game developers have gone backwards, using process-oriented development game, process-oriented, simple and brutal, do not consider complex inheritance, do not consider abstraction, do not consider polymorphism, is the development of the session of freestyle, roll up your sleeves on the jerk, but at the same time, the reusability of the code logic, data reusability is also greatly reduced. Process-oriented is also not a good game development model.  
+
+
+Component pattern is a good solution to object-oriented and process-oriented defects, in the game client is very widely used, Unity3d, Unreal 4, and so on are using the component pattern. The characteristics of the component pattern.
+1. Highly modular, a component is a piece of data plus a paragraph of logic  
+2. Components can be hot-pluggable, you need to add, do not need to remove  
+3. Very few dependencies between types, any type of adding or removing components will not affect other types.  
+
+
+But at present only a very small number of server-side design using components, Watchtower server-side should be the use of component design, Watchtower developers called ECS architecture, in fact, is a variant of the component model, E is Entity, C is Component, S is System, in fact, is the component Component logic and data stripped, the logic part called System, the topic is far away, or back to the ET framework to put.  
+
+ET framework uses the design of components. Everything is Entity and Component, any class inherited from Entity can be mounted components, such as the player class.
+
+```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();
+    }
+}
+```
+Mount a MoveComponent to the player object so that the player can move, a Backpack component to the player so that the player can manage items, a Skill component to the player so that the player can cast skills, and a Buff component to manage buffs.  
+
+```C#
+player.AddComponent<MoveComponent>();
+player.AddComponent<ItemsComponent>();
+player.AddComponent<SpellComponent>();
+AddComponent<BuffComponent>(); player.AddComponent<BuffComponent>();
+```
+
+Components are highly reusable, for example, an NPC, he can also move, just put MoveComponent on the NPC, some NPCs can also cast skills, then put SpellComponent on it, NPCs do not need a backpack, then there is no need to hang ItemsComponent  
+
+ET framework modules are all made into the form of components, a process is also made of different components stitched together. Let's say Loginserver needs to connect externally and also needs to connect with the server internally, then login server hooks up  
+
+```C#
+// intranet network component NetInnerComponent, which handles the connection to the intranet  
+Game.Scene.AddComponent<NetInnerComponent, string, int>(innerConfig.Host, innerConfig.Port);
+// NetOuterComponent, an extranet component, handles the connection to the client
+Game.Scene.AddComponent<NetOuterComponent, string, int>(outerConfig.Host, outerConfig.Port);
+```
+
+For example, battle server does not need to connect to the external network (external network messages are forwarded by gateserver), so it is natural to just mount an internal network component.
+Similar to Unity3d components, ET framework also provides component events, such as Awake, Start, Update, etc.. To add these events to a Component or Entity, you must write a helper class. For example, if the NetInnerComponent component needs Awake and Update methods, 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 every frame.
+ET does not use reflection like Unity to implement this kind of functionality, because reflection performance is poor, and the advantage of this implementation is that the class can be placed in the hot update dll, so that the component's Awake Start, Update method and other methods can be placed in the hot update layer. Entity and Component will be made into a class without methods, methods are put into the hot update layer to facilitate the hot update to fix logic bugs.  
+
+The biggest advantage of component-based development is that whether rookie or expert, the development of a function can quickly know how to organize data how to organize the logic. Object-oriented can be completely abandoned. Object-oriented development using the most headache is that I should inherit which class it? Before doing the most horrible is Unreal three, Unreal three inheritance structure is very multi-layer, completely do not know where they need to start inheritance. In the end, it could lead to a very small function that inherits a very large class, which is common in Unreal 3 development. So Unreal 4 switched to the component pattern. The module isolation of the component pattern is very good, the technical rookie a component written very poorly, will not affect the other modules, the big deal is to rewrite the component on the good. 
+
+ET's component design innovation, method and data separation, completely decoupled, no brainstorming how to uncouple, write static methods at will, there is no coupling, even the code written by rookies is easy to refactor.
+
+It is because ET uses the detachable component model, ET can load all server components to the same process, then this one process can be used as a set of distributed servers. From then on it is possible to debug distributed servers with vs. Because of this, the usual development only use a process, when the release of the release into multiple processes on the line. Honestly, not to brag, this is a great invention, this invention solves a big problem in the development of distributed game servers, greatly improving the efficiency of development.    
+
+

+ 95 - 0
Book/5.4Actor Model.md

@@ -0,0 +1,95 @@
+# Actor model
+### Actor introduction
+Before discussing the Actor model, we should discuss the architecture of ET. There are two architectures for game servers in order to use multi-core, single-threaded multi-process and single-process multi-threaded architecture. ET uses single-threaded multi-process architecture, while the traditional Actor model is generally single-process multi-threaded architecture, which is a major difference. The advantages and disadvantages are as follows.  
+1. the logic needs to be single-threaded this is the same, erlang process logic is single-threaded, skynet lua virtual machine is also single-threaded. et in a process is actually equivalent to an erlang process, a skynet lua virtual machine.  
+2. the use of single-threaded multi-process does not need to write their own set of profiler tools, you can use a lot of ready-made profiler tools, such as view memory, cpu occupation directly with top command, this point erlang and skynet need to get another set of tools.  
+3. multi-process single-threaded architecture also has a benefit, a single physical machine and multiple physical machines is no difference, single process multi-threaded also need to consider the processing of multiple physical machines.  
+4. multi-process single-threaded architecture is a bit of a drawback is that messages need to be serialized and deserialized across processes, taking up a bit of resources. In addition, sending network messages will have a few milliseconds delay. Generally these effects can be ignored.  
+
+The original Actor model is used for single-process multi-threaded architecture, there is a reason for this, because multi-threaded architecture developers can easily access shared variables at will, let's say a variable a, thread 1 can access, thread 2 can also access, so that both threads need to add locks when accessing the variable a, shared variables more locks everywhere, will become unmaintainable, the framework must not appear The framework must not have a situation where there are threads sharing variables everywhere. In order to ensure that the multi-threaded architecture does not go wrong, it is necessary to provide a development model that ensures easy and safe multi-threaded development. erlang's concurrency mechanism is the actor model. erlang virtual machine uses multiple threads to take advantage of multiple cores. erlang has designed a mechanism that designs its own processes on top of the virtual machine. At its simplest, each erlang process manages its own variables, and the logic of each erlang process runs on a single thread. The logic between the erlang process and the process is completely isolated, so that there are no two threads accessing the same variable and there is no multithreaded competition. The next question arises, since each erlang process has its own data and the logic is completely isolated, how should the two erlang processes communicate with each other? This is where the Actor model comes in. erlang has designed a messaging mechanism: one process can send messages to other processes, and erlang processes communicate with each other through messages. Isn't this the same message queue used by operating systems for inter-process communication? Yes, in fact, it is similar. erlang inside the process id to get the process can send messages to this process.   
+
+If the message is only sent to the process, it is still a bit inconvenient. For example, if you take an erlang process as a moba team process, and there are 10 players in the battle process, if you use erlang's actor message, the message can only be sent to the battle process, but often the message needs to be sent to a player, then erlang needs to distribute the message to the specific player again according to the player id in the message, so it actually goes around one more time. This is actually an extra detour.
+
+### ET's Actor
+According to the characteristics of its own architecture, ET does not completely copy the Actor model of erlang, but provides the Entity object-level Actor model. In ET, an Actor is an Entity object, and a MailboxComponent component attached to an Entity is an Actor. You only need to know the Entity's InstanceId to send messages to the Entity. In fact, erlang's Actor model is a special case of ET, such as giving the ET server Game.Scene as an Actor, so that it can become a process-level Actor. It only needs to know the InstanceId (ET) or the Pid (erlang) of the process to send it to the other party.
+
+| Language | ET | Erlang | Skynet |
+| | ET | Erlang | Skynet | -- | :--: | :--: | :--: |
+| Architecture | Single-Threaded Multi-Process | Single-Process Multi-Threaded | Single-Process Multi-Threaded |
+| Actor | Entity | erlang process | lua virtual machine |
+| ActorId | Entity.InstanceId | erlang processId | service address |
+
+### Use of ET's Actor
+For a normal Actor, we can refer to the Gate Session. map has a Unit, and the Unit holds the gate session corresponding to the player. thus, if a message in map needs to be sent to the client, it only needs to send the message to the gate session, and the gate session forwards it to the client when it receives the message. The map process sending messages to the gate session is a typical actor model. It doesn't need to know the location of the gate session, it just needs to know its InstanceId. messageHelper.cs gets an ActorMessageSender from GateSessionActorId and sends it.
+```csharp
+// Get an ActorSenderComponent from Game.Scene, then get an ActorMessageSender by InstanceId
+ActorSenderComponent actorSenderComponent = Game.Scene.GetComponent<ActorSenderComponent>();
+ActorMessageSender actorMessageSender = actorSenderComponent.Get(unitGateComponent.GateSessionActorId);
+// send
+actorMessageSender.Send(message);
+
+// rpc
+var response = actorMessageSender.Call(message);
+```
+
+The question is how do you know the InstanceId of the gate session in map? This is where you need to find a way to pass it on, for example in ET, when the player is logging in to gate, the gate session hooks up a mailbox MailBoxComponent, C2G_LoginGateHandler.cs
+```csharp
+session.AddComponent<MailBoxComponent, string>(MailboxType.GateSession);
+```
+The InstanceId of this gate session is brought into the map when the player logs into the map process, in C2G_EnterMapHandler.cs
+```csharp
+M2G_CreateUnit createUnit = (M2G_CreateUnit)await mapSession.Call(new G2M_CreateUnit() { PlayerId = player.Id, GateSessionId = session. InstanceId });
+```
+
+### Handling of Actor messages
+First, the message arrives at the MailboxComponent, which has a type, and different types of mailboxes can do different processing. Currently, there are two types of mailboxes, GateSession and MessageDispatcher; GateSession mailboxes will immediately forward messages to the client when they are received, and MessageDispatcher types will again distribute the Actor messages to the specific Handler for processing. The default MailboxComponent type is MessageDispatcher. customizing a mailbox type is also very simple, inherit the IMailboxHandler interface and add the MailboxHandler tag. So why do we need to add such a feature? This feature does not exist in other actor models, and messages are generally received and distributed. The reason is that GateSession is not designed for distribution, so I added the mailbox type here. messageDispatcher has two ways of handling messages, one is to handle the messages sent by the other party, and the other is rpc messages  
+```csharp
+    // To handle Send messages, you need to inherit the AMActorHandler abstract class. The first generic parameter of the abstract class is the type of the Actor, and the second parameter is the type of the message
+	[ActorMessageHandler(AppType.Map)]
+	public class Actor_TestHandler : AMActorHandler<Unit, Actor_Test>
+	{
+		protected override ETTask Run(Unit unit, Actor_Test message)
+		{
+			Log.Debug(message.Info);
+		}
+	}
+
+    // To handle Rpc messages, you need to inherit the AMActorRpcHandler abstract class, the first generic parameter of the abstract class is the type of the Actor, the second parameter is the type of the message, and the third parameter is the type of the returned message
+    [ActorMessageHandler(AppType.Map)]
+	public class Actor_TransferHandler : AMActorRpcHandler<Unit, Actor_TransferRequest, Actor_TransferResponse>
+	{
+		protected override async ETTask Run(Unit unit, Actor_TransferRequest message, Action<Actor_TransferResponse> reply)
+		{
+			Actor_TransferResponse response = new Actor_TransferResponse();
+
+			try
+			{
+				reply(response);
+			}
+			catch (Exception e)
+			{
+				ReplyError(response, e, reply);
+			}
+		}
+	}
+```
+
+We should note that Actor messages have the potential to deadlock, such as A call to B, B call to C, and C call to A. Because MailboxComponent is essentially a message queue, it opens a concurrent process that will process one message at a time, returning ETTask to indicate that the message processing class will block MailboxComponent queue of other messages. So if there is a deadlock, we don't want a message processing to block the rest of the MailboxComponent messages, we can just open a new thread in the message processing class to handle it. For example:
+```csharp
+	[ActorMessageHandler(AppType.Map)]
+	public class Actor_TestHandler : AMActorHandler<Unit, Actor_Test>
+	{
+		protected override ETTask Run(Unit unit, Actor_Test message)
+		{
+			RunAsync(unit, message).Coroutine();
+		}
+
+        public ETVoid RunAsync(Unit unit, Actor_Test message)
+        {
+            Log.Debug(message.Info);
+        }
+	}
+```
+For related information, you can Google the Actor deadlock problem.
+
+

+ 1 - 1
Book/5.4Actor模型.md

@@ -6,7 +6,7 @@
 3. 多进程单线程架构还有个好处,单台物理机跟多台物理机是没有区别的,单进程多线程还需要考虑多台物理机的处理。  
 4. 多进程单线程架构一点缺陷是消息跨进程需要进行序列化反序列化,占用一点资源。另外发送网络消息会有几毫秒延时。一般这些影响可以忽略。  
 
-最开始Actor模型是给单进程多线程架构使用的,这是有原因的,因为多线程架构开发者很容易随意的访问共享变量,比方说一个变量a, 线程1能访问,线程2也能访问,这样两个线程在访问变量a的时候都需要加锁,共享变量多了之后锁到处都是,会变得无法维护,框架肯定不能出现到处是线程共享变量的情况。为了保证多线程架构不出问题,必须提供一种开发模型保证多线程开发简单又安全。erlang语言的并发机制就是actor模型。erlang虚拟机使用多线程来利用多核。erlang设计了一种机制,它在虚拟机之上设计了自己的进程。最简单的,每个erlang进程都管理自己的变量,每个erlang进程的逻辑都跑在一个线程上,erlang进程跟进程之间逻辑完全隔离,这样就不存在两个线程访问同一变量的情况了也就不存在多线程竞争的问题。接下来问题又出现了,既然每个erlang进程都有自己的数据,逻辑完全是隔离的,两个erlang进程之间应该怎么进行通信呢?这时Actor模型就登场了。erlang设计了一种消息机制:一个进程可以向其它进程发送消息,erlang进程之间通过消息来进行通信,看到这会不会感觉很熟悉?这不就是操作系统进程间通信用的消息队列吗?没错,其实是类似的。erlang里面拿到进程的id就能给这个进程发送消息。   
+最开始Actor模型是给单进程多线程架构使用的,这是有原因的,因为多线程架构开发者很容易随意的访问共享变量,比方说一个变量a, 线程1能访问,线程2也能访问,这样两个线程在访问变量a的时候都需要加锁,共享变量多了之后锁到处都是,会变得无法维护,框架肯定不能出现到处是线程共享变量的情况。为了保证多线程架构不出问题,必须提供一种开发模型保证多线程开发简单又安全。erlang语言的并发机制就是actor模型。erlang虚拟机使用多线程来利用多核。erlang设计了一种机制,它在虚拟机之上设计了自己的进程。最简单的,每个erlang进程都管理自己的变量,每个erlang进程的逻辑都跑在一个线程上,erlang进程跟进程之间逻辑完全隔离,这样就不存在两个线程访问同一变量的情况了也就不存在多线程竞争的问题。接下来问题又出现了,既然每个erlang进程都有自己的数据,逻辑完全是隔离的,两个erlang进程之间应该怎么进行通信呢?这时Actor模型就登场了。erlang设计了一种消息机制:一个进程可以向其它进程发送消息,erlang进程之间通过消息来进行通信,看到这会不会感觉很熟悉?这不就是操作系统进程间通信用的消息队列吗?没错,其实是类似的。erlang里面拿到进程的id就能给这个进程发送消息。   
 
 如果消息只发给进程其实还是有点不方便。比如拿一个erlang进程做moba战队进程,战斗进程中有10个玩家,如果使用erlang的actor消息,消息只能发送给战斗进程,但是很多时候消息是需要发送给一个玩家的,这时erlang需要根据消息中的玩家Id,把消息再次分发给具体的玩家,这样其实多绕了一圈。
 

+ 77 - 0
Book/5.5Actor Location-EN.md

@@ -0,0 +1,77 @@
+# Actor Location
+### Actor Location
+Actor model only needs to know each other's InstanceId to send messages, which is very convenient, but sometimes we may not know each other's InstanceId, or an Actor's InstanceId will change. ET provides a mechanism to send messages to such objects, called Actor Location The mechanism is called Actor Location. The principle is relatively simple.
+1. because the InstanceId is changing, the object's Entity.Id is unchanged, so we can first think of using Entity.Id to send actor messages
+2. provide a location process (Location Server), the Actor object can store its Entity.Id and InstanceId as kv to the location process. Before sending the Actor message, go to the location process to look up the InstanceId of the Actor object before sending the actor message. 3.
+3. When an Actor object is created in a process or migrated to a new process, it needs to register its Id and InstanceId to the Location Server. 4.
+4. because the Actor object can be migrated, the message may be sent to the Actor has been migrated to other processes, so sending the Actor Location message needs to provide a reliable mechanism
+5. ActorLocationSender provides two methods, Send and Call, Send a message also requires the recipient to return a message, and only when the return message is received will the next message be sent. 6.
+6. If the Actor object is migrated away, it will return the error that the Actor does not exist, the sender will wait for 1 second after receiving this error, then go back to get the InstanceId of the Actor and resend it, currently it will try 5 times, after 5 times, it will throw an exception and report the error
+7. ActorLocationSender will not query the Location Server every time it sends a message, because object migration is relatively rare after all, only the first time to query, then cache the InstanceId, and re-query after the failure to send.
+8. actor object in the migration process, it is possible that other processes send over messages, when an error will occur, so the location server provides a Lock mechanism. Before the object is transmitted, the information in the process is deleted, and then a lock is added to the location server, and once the lock is on, other requests for the key will be queued.
+9. before transmission because the other party deleted the actor of the process, so other processes will fail to send, then they will retry. When retrying, they will re-request the location server, which will be found to be locked, so they will keep waiting.
+10. When the transmission is completed, the lock on the location server is unlocked, and the new address is updated, and then other location requests are responded to. Other requests sent to this actor continue.
+
+Note that the Actor model is purely a server-side message communication mechanism, which has nothing to do with the client. We can use the server-side actor model for forwarding, so some client-side messages also inherit the actor interface. What happens if we don't use the actor interface on the client side? For example, the message Frame_ClickMap
+```protobuf
+message Frame_ClickMap // IActorLocationMessage
+{
+	int64 ActorId = 93;
+	int64 Id = 94;
+	
+	float X = 1;
+	float Y = 2;
+	float Z = 3;
+}
+```
+We may not need the field ActorId, the message is sent to Gate, gate sees that it is a Frame_ClickMap message, it needs to be forwarded to the Unit on the Map, forwarding is still good, gate can get the location of the unit corresponding to the map from the session, and then forward it, the problem comes, Frame_ ClickMap message to the map, how does the map know which object the message needs to be given to? There are several designs at this point.
+1. bring the Id of the unit in the underlying protocol of forwarding, which requires more complex underlying protocol support.
+2. use a message to Frame_ClickMap message wrapping, wrapping the message with the Id of the Unit, wrapping with the message means greater consumption, increasing GC.
+Personally, I feel that these two are very poor, not good, and even if distributed to the unit object processing, how to solve the problem of message re-entry it? unit object still needs to hang a message processing queue, and then receive the message thrown into the queue. Isn't this a duplication of the actor model? The current ET message sent to unit in the client did a design, the message into an actor message, gate received found to be an actor message, sent directly to the corresponding actor, the solution can be said to be beautiful. In fact, the client is still using session.send and call to send messages, send the message does not know that the message is an actor message, only to the gate, the gate judgment, refer to OuterMessageDispatcher.cs
+
+### Actor Location message processing
+ActorLocation messages are sent
+```csharp
+// Get the ActorLocationSenderComponent from Game.Scene, then get the ActorLocationSender via Entity.Id
+ActorLocationSender actorLocationSender = Game.Scene.GetComponent<ActorLocationSenderComponent>().Get(unitId);
+// Send the message through the ActorLocationSender
+actorLocationSender.Send(actorLocationMessage);
+// send the Rpc message
+IResponse response = await actorLocationSender.Call(actorLocationRequest);
+```
+
+ActorLocation message processing is almost the same as Actor messages, the difference is that the two abstract classes inherited are different, note that the abstract class of actorlocation has an additional Location
+```csharp
+	// The first generic parameter of the abstract class is the type of the Actor, and the second parameter is the type of the message.
+	[ActorMessageHandler(AppType.Map)]
+	public class Frame_ClickMapHandler : AMActorLocationHandler<Unit, Frame_ClickMap>
+	{
+		protected override ETTask Run(Unit unit, Frame_ClickMap message)
+		{
+			Vector3 target = new Vector3(message.X, message.Y, message.Z);
+			unit.GetComponent<UnitPathComponent>().MoveTo(target).Coroutine();
+			
+		}
+	}
+
+	// To handle Rpc messages, you need to inherit the AMActorRpcHandler abstract class. The first generic parameter of the abstract class is the type of the Actor, the second parameter is the type of the message, and the third parameter is the type of the returned message
+	[ActorMessageHandler(AppType.Map)]
+	public class C2M_TestActorRequestHandler : AMActorLocationRpcHandler<Unit, C2M_TestActorRequest, M2C_TestActorResponse>
+	{
+		protected override async ETTask Run(Unit unit, C2M_TestActorRequest message, Action<M2C_TestActorResponse> reply)
+		{
+			reply(new M2C_TestActorResponse(){Info = "actor rpc response"});
+			await ETTask.CompletedTask;
+		}
+	}
+```
+
+### ET's actor and actor location analogy
+There are many cities (processes) in China, and many people (entity objects) living in the cities, each with an ID number (Entity.Id). A person needs to apply for a residence permit in each city and is assigned a unique residence permit number (InstanceId). The format of the residence permit number is 2 bytes city number + 4 bytes time + 2 bytes increment. The ID number never changes, but the residence permit number changes every time you go to a city.
+Now there is a China Post (actor). Suppose Xiaoming wants to send a letter to his girlfriend Xiaohong
+1. Xiaohong must mount a mailbox (MailboxComponent) himself in order to receive the letter, and Xiaohong will process the message when he receives it. Note that processing is done here one by one. It is possible that Hong will receive letters from many people at the same time. But she must read one letter at a time. Let's say Xiaoming and Xiaobao both send letters to Xiaohong, and Xiaohong receives Xiaoming's letter first, and then Xiaobao's letter. Xiaohong reads Xiaoming's letter first, and Xiaoming's letter asks Xiaohong to make a phone call to her grandmother (to produce a concordance) and then write back to herself, noting that Xiaohong also cannot read the next letter during this period, and must finish the phone call before she can read Xiaobao's letter. Of course Xiao Hong himself can choose to start reading Xiao Bao's letter without finishing the process, by opening a new concatenation for Xiao Ming's letter.
+2. Suppose Xiaoming knows Xiaohong's residence permit number, then the post (actor) can find the city (process) where Xiaohong lives according to the two docks of the residence permit number, and then find Xiaohong and deliver the message to Xiaohong's mailbox (MailboxComponent) according to Xiaohong's residence permit number. This is the simplest native actor model
+3. ET also supports a set of actor location mechanism. Suppose Xiao Ming doesn't know Xiao Hong's residence permit number, but he knows Xiao Hong's ID number, what should he do? The postal service has developed a set of advanced post (actor location) to think of a way, if a person often moves, it still wants to receive letters, then he must report his residence permit and ID card to the central government (location server) when he goes to a new city, so that the advanced post can send mail through the ID card number. The method is to go to the central government to get Hong's residence permit number, and then use the actor mechanism to send. 4.
+4. Suppose Xiao Hong was in Guangzhou city before, and Xiao Ming used Xiao Hong's ID card to send a letter to Xiao Hong. Advanced post obtains Xiao Hong's residence permit number and sends a letter to Xiao Hong. During this process of sending the letter, Xiaohong moved, from Guangzhou to Shenzhen, at which time Xiaohong reported her new residence permit on the central government. When the letter from the senior post arrives in Guangzhou, it is found that Xiao Hong is not in Guangzhou. Then the senior postal service will go to the central government again to get Xiao Hong's residence permit and resend it, which may succeed or fail again, this process will be repeated several times, if it is unsuccessful, it will tell Xiao Ming that the letter has failed to be sent.
+5. senior postal mail is more expensive, and people do not move a lot, usually Xiao Ming will remember Xiao Hong's residence permit after sending letters with senior postal mail, and next time send letters directly with the residence permit, and then send letters with senior postal mail if it fails.
+There are two kinds of return receipts, one without content, just means Xiao Hong received the letter, and one with Xiao Hong's return letter. Xiaoming can choose which return receipt form to use when he sends the letter. Xiao Ming cannot send two letters to Xiao Hong at the same time, he must wait for Xiao Hong's acknowledgement to arrive before Xiao Ming can continue sending the letter.

+ 0 - 0
Book/5.5Actor Location.md → Book/5.5Actor Location-ZH.md


+ 210 - 0
Book/5.6Numerical component design.md

@@ -0,0 +1,210 @@
+Similar to world of warcraft, moba such skills are extremely complex, flexibility requires a very high skill system, must need a set of its flexible numerical structure to match. Numerical structure is well designed, the realization of the skill system will be very simple, otherwise it is a disaster. For example, in World of Warcraft, a character has many numerical attributes, such as movement speed, strength, anger, energy, concentration value, magic value, blood, maximum blood, physical attack, physical defense, spell attack, spell defense, etc. There are dozens of attributes. Attributes and attributes affect each other, buffs will add absolute value to attributes, increase the percentage, or some kind of buff will come back to you after counting all the increased value and doubling it.
+
+## Common practice:
+The general is to write a value class.
+```c#
+class Numeric
+{
+    public int Hp;
+    public int MaxHp;
+    public int Speed;
+    // Energy
+    public int Energy;
+    public int MaxEnergy;
+    // Magic
+    public int Mp;
+    public int MaxMp;
+    .....
+}
+```
+On second thought, I'm a thief using energy why should I have a value of Mp? I am a mage using magic why should there be a field for energy? I'm not sure what to do with this, just pretend you didn't see it? I can not, I come to an inheritance?
+```C#
+// Mage values
+calss MageNumeric: Numeric
+{
+    // magic
+    public int Mp;
+    public int MaxMp;
+}
+
+// Thief value
+calss RougeNumeric: Numeric
+{
+    // Energy
+    public int Energy;
+    public int MaxEnergy;
+}
+````
+10 races, each race 7, 8 kinds of heroes, just these values class inheritance relationship, you have to be confused it. Object-oriented is difficult to adapt to the needs of this flexible and complex.
+
+And look at the Numeric class, each value can not just design a field, for example, I have a buff will increase 10 points Speed, and a kind of buff to increase 50% of the speed, then I must add at least three secondary attribute fields
+```c#
+class Numeric
+{
+    // speed final value
+    public int Speed;
+    // Speed initial value
+    public int SpeedInit;
+    // Speed increase value
+    public int SpeedAdd;
+    // Speed increase percentage value
+    public int SpeedPct;
+}
+```
+After SpeedAdd and SpeedPct are changed, a calculation is performed to calculate the final speed value. buff only needs to go to modify SpeedAdd and SpeedPct on the line.
+```c#
+Speed = (SpeedInit + SpeedAdd) * (100 + SpeedPct) / 100
+```
+Each property may have several indirect effects on the value, you can think about how large this class is, a rough estimate of more than 100 fields. The trouble is that the formula is basically the same, but just can not be unified into a function, such as MaxHp, also has a buff effect
+```c#
+class Numeric
+{
+    public int Speed;
+    public int SpeedInit;
+    public int SpeedAdd;
+    public int SpeedPct;
+    
+    public int MaxHp;
+    public int MaxHpInit;
+    public int MaxHpAdd;
+    public int MaxHpPct;
+}
+```
+Also have to write a formula for calculating Hp
+```c#
+MaxHp = (MaxHpInit + MaxHpAdd) * (100 + MaxHpPct) / 100
+```
+Dozens of properties, you have to write dozens of times, and each secondary property changes to correctly call the corresponding formula calculation. Very troublesome!
+This design also has a big problem, buff configuration table to fill the corresponding attribute field is not very good to fill, for example, sprint buff (increase speed 50%), how to configure the buff table to make the program simple to find and operate the SpeedPct field? Not a good idea.
+
+## ET framework uses the Key Value form to save the value of the property
+```c#
+Using System.Collections.Generic;
+
+Generic; namespace Model
+Generic; namespace Model {
+    public enum NumericType
+    {
+		Max = 10000,
+
+		Speed = 1000,
+		SpeedBase = Speed * 10 + 1,
+	    SpeedAdd = Speed * 10 + 2,
+	    SpeedPct = Speed * 10 + 3,
+	    SpeedFinalAdd = Speed * 10 + 4,
+	    SpeedFinalPct = Speed * 10 + 5,
+
+	    Hp = 1001,
+	    HpBase = Hp * 10 + 1,
+
+	    MaxHp = 1002,
+	    MaxHpBase = MaxHp * 10 + 1,
+	    MaxHpAdd = MaxHp * 10 + 2,
+	    MaxHpPct = MaxHp * 10 + 3,
+	    MaxHpFinalAdd = MaxHp * 10 + 4,
+		MaxHpFinalPct = MaxHp * 10 + 5,
+	}
+
+	public class NumericComponent: Component
+	{
+		public readonly Dictionary<int, int> NumericDic = new Dictionary<int, int>();
+
+		public void Awake()
+		{
+			// initialize base value here
+		}
+
+		public float GetAsFloat(NumericType numericType)
+		{
+			return (float)GetByKey((int)numericType) / 10000;
+		}
+
+		public int GetAsInt(NumericType numericType)
+		{
+			return GetByKey((int)numericType);
+		}
+
+		public void Set(NumericType nt, float value)
+		{
+			this[nt] = (int) (value * 10000);
+		}
+
+		public void Set(NumericType nt, int value)
+		{
+			this[nt] = value;
+		}
+
+		public int this[NumericType numericType]
+		{
+			get
+			{
+				return this.GetByKey((int) numericType);
+			}
+			set
+			{
+				int v = this.GetByKey((int) numericType);
+				if (v == value)
+				{
+					return;
+				}
+
+				NumericDic[(int)numericType] = value;
+
+				Update(numericType);
+			}
+		}
+
+		private int GetByKey(int key)
+		{
+			int value = 0;
+			This.NumericDic.TryGetValue(key, out value);
+			return value;
+		}
+
+		public void Update(NumericType numericType)
+		{
+			if (numericType > NumericType.Max)
+			{
+				return;
+			}
+			int final = (int) numericType / 10;
+			int bas = final * 10 + 1; 
+			int add = final * 10 + 2;
+			int pct = final * 10 + 3;
+			int finalAdd = final * 10 + 4;
+			int finalPct = final * 10 + 5;
+
+			// A value may be affected by a variety of circumstances, such as speed, adding a buff may increase the speed of the absolute value of 100, but also some buffs increase the speed of 10%, so a value can be controlled by 5 values of the final result
+			// final = (((base + add) * (100 + pct) / 100) + finalAdd) * (100 + finalPct) / 100;
+			this.NumericDic[final] = ((this.GetByKey(base) + this.GetByKey(add)) * (100 + this.GetByKey(pct)) / 100 + this.GetByKey(finalAdd)) * (100 + this. GetByKey(finalPct)) / 100;
+			Game.EventSystem.Run(EventIdType.NumbericChange, this.Entity.Id, numericType, final);
+		}
+	}
+}
+```
+1. values are saved with key value, key is the type of value, defined by NumericType, value are integers, float type can also be converted to integers, for example, multiply by 1000; key value to save properties will become very flexible, for example, mage no energy properties, then initialize the mage object does not add energy key value It's fine. Thieves do not have mana, no spell damage, etc., the initialization will not need to add these.  
+
+2. world of warcraft, a value by 5 values to influence, you can unify the use of a formula.
+```
+final = (((base + add) * (100 + pct) / 100) + finalAdd) * (100 + finalPct) / 100;
+```
+For example, the speed value speed, there is an initial value speedbase, there is a buff1 to increase the absolute speed by 10 points, then buff1 will add 10 to speedadd when it is created, buff1 minus 10 to speedadd when it is deleted, buff2 increases the speed by 20%, then buff2 adds to speedpct when it is created The 5 values are changed and the corresponding properties can be recalculated by using the Update function in a unified way. buff configuration is quite simple. If the corresponding NumericType is filled in the buff configuration, the program can easily manipulate the corresponding value.
+
+3. Changes in properties can be uniformly thrown to other modules to subscribe to the event, writing a property change monitor becomes very simple. For example, the achievement module needs to develop an achievement life value over 1000, will get the achievement of longevity master. Then the person developing the achievement module will subscribe to the HP changes as follows.
+```
+	/// Monitor hp value changes
+	[NumericWatcher(NumericType.Hp)
+	public class NumericWatcher_Hp : INumericWatcher
+	{
+		public void Run(long id, int value)
+		{
+		    if (value > 1000)
+		    {
+		        // get achievement longevity master achievement
+		    }
+		}
+	}
+```
+Similarly, recording an exception log for a gold change greater than 10,000 at a time, etc. can be done this way.
+
+With this numerical component, a moba skill system can be said to be half complete.

+ 140 - 0
Book/6.1AI Framwork.md

@@ -0,0 +1,140 @@
+# AI framework
+## 1. Several AI designs
+AI in the game a lot, but why do people always feel ai writing up very difficult, I later thought about it, the main reason is the use of improper methods. Before people write ai mainly have several options.
+### a. State machine  
+I do not know who came up with this approach, really powerless to complain. Originally any data on the object is the state, this method and to define some state into a new kind of node, the object on the state change will cause the conversion between nodes, the implementation of the corresponding method, such as OnEnter OnExit and so on. Here is an example of a monster, monsters can be divided into a variety of states, patrol, attack, chase, return. The state changes of the monster are:
+
+Patrol->Chase Patrol state found a distant enemy to chase state  
+Patrol->Attack Patrol find enemy can be attacked to attack state  
+Attack->Chase The attack state finds an enemy in the distance and goes after it.  
+Attack->Return Attack state find the enemy is too far to return state  
+chase->return chase state found too far from the enemy to return to the state  
+
+There are so many state transitions that it's hard to find out if I've missed them here. Once there are more nodes, any two nodes may need to be connected, and it will become a super complex mesh structure, the complexity is the square of N, and it is very difficult to maintain. In order to solve the problem of complex mesh structure and then upgraded to a hierarchical state machine and so on. Of course, various patching methods still do not solve the essential problem. It is not your problem to use bad state machines, it is the problem of state machines.
+
+### b. Behavior tree
+The ai of the behavior tree is responsive ai, the tree from top to bottom (or from left to right execution, here from top to bottom for example) is actually the action node ranked a priority, the action above the first to determine whether to meet the conditions, meet the implementation. We won't go into details here. The complexity of the behavior tree is N, greatly simplified than the state machine, but there are still many defects, ai too complex when the tree will become very large, and difficult to reconfigure. For example, in our own project, we want to make a robot ai similar to a human, automatically do tasks, fight monsters, play the system in the game, chat with people, and even attack others. Imagine how complex this tree will become! Another drawback of the behavior tree is that some action nodes are a persistent process, that is to say, a concurrent process, behavior tree management up concurrent process is not very good, such as the above example, need to move to the target side, this move is made into a concurrent process it, or every frame move it? This is a difficult problem, how to do it is not comfortable.
+
+## 2. my approach
+What is ai? Very simple, ai is constantly based on the current state, perform the appropriate behavior. Remember these two sentences, it is important, this is the essence of ai! These two sentences are divided into two parts, one is the state judgment, the second is the execution of behavior. State judgment is well understood, what is the behavior? Take the above example of the monster state machine, the behavior of the monster is Patrol, attack the enemy, return to the patrol point. For example.
+
+Patrol (when the monster is within the patrol range, there is no enemy around, choose the next patrol point, move)  
+attack the enemy (when the monster found within the guard range of the enemy, if the attack distance enough to attack, not enough to move over to attack)  
+Return (when the monster found more than a certain distance from the birth point, plus the invincibility buff, move to the birth point, to the birth point, remove the invincibility buff)  
+
+Unlike the state machine, these three state changes do not care about what the last state is, only about whether the current conditions are met, meet the implementation of the behavior. Behavior may be able to perform instantly, but also may be a continuous process, such as patrol, choose the next patrol point to move over, go to a point and then choose a point, and so on and so forth. For example, attacking the enemy, may need to move to the target to attack.
+
+How to design this ai framework? Here it is very simple, abstract ai nodes, each node contains a conditional judgment, with the implementation of behavior. The behavior method should be a concurrent process
+```csharp
+public class AINode
+{
+	public virtual bool Check(Unit unit) // test whether the condition is met
+	{		
+	}
+
+	public virtual ETTask Run(Unit unit)
+	{		
+	}
+}
+```
+Thinking further, if the monster is on patrol and finds an enemy, then the monster should interrupt the current patrol and go on to perform the act of attacking the enemy instead. So our behavior should need to support being interrupted, which means that the behavior concurrent should support cancellation, and this is especially important to note that any concurrent in the behavior Run method should support the cancellation operation!
+```csharp
+public class AINode
+{
+	public virtual bool Check(Unit unit)
+	{		
+	}
+
+	public virtual ETVoid Run(Unit unit, ETCancelToken cancelToken)
+	{
+	}
+}
+````
+
+Implement three ai nodes XunLuoNode(patrol) GongjiNode(attack) FanHuiNode(return)
+
+```csharp
+public class XunLuoNode: AINode
+{
+	public virtual bool Check(Unit unit)
+	{
+		if (not in patrol range)
+		{
+			return false;
+		}
+		if (there are enemies around)
+		{
+			return false;
+		}
+		return true;
+	}
+
+	public virtual ETVoid Run(Unit unit, ETCancelToken cancelToken)
+	{
+		while (true)
+		{
+			Vector3 nextPoint = FindNextPoint();
+			bool ret = await MoveToAsync(nextPoint, cancelToken); // move to the target point, return false means the process is canceled
+			if (!ret)
+			{
+				return;
+			}
+			// stay for two seconds, note that any concurrent process must be able to be cancelled here
+			Wait(2000, cancelToken). bool ret = await TimeComponent;
+			if (!ret)
+			{
+				return;
+			}
+		}
+	}
+}
+```
+The same can be achieved for the other two nodes. It's not enough to design the nodes, you also need to string the nodes together so that the ai can rotate
+```csharp
+AINode[] aiNodes = {xunLuoNode, gongjiNode, fanHuiNode};
+AINode current;
+ETCancelToken cancelToken;
+while(true)
+{
+	// Every second you need to re-determine if the new behavior is satisfied, this time can be set by yourself
+	await TimeComponent.Instance.Wait(1000);
+
+	AINode next;
+	foreach(var node in aiNodes)
+	{
+		if (node.Check())
+		{
+			next = node;
+			break;
+		}
+	}
+
+	if (next == null)
+	{
+		continue;
+	}
+
+	// If the next node is the same as the current one, then it is not executed
+	if (next == current)
+	{
+		continue;
+	}
+
+	// Stop the current concurrent process
+	cancelToken.Cancel();
+
+	// Execute the next concurrent process
+	cancelToken = new ETCancelToken();
+	next.Run(unit, cancelToken).Coroutine();
+}
+```
+This code is very simple, meaning that it iterates through the nodes every second until it finds a node that satisfies the conditions and then executes it, waiting for the next second to determine, before executing the next node, interrupting the currently executing concurrent process.
+A few misconceptions about the use:
+1. behavior if there is a concurrent process must be able to cancel, and pass in cancelToken, otherwise something will go wrong, because once the monster meets the execution of the next node, you need to cancel the current concurrent process.
+2. different from the behavior tree and state machine, the role of the node is only a piece of logic, the node does not need to share. Shared is the concurrent methods, such as MoveToAsync, monster patrol node can be used, the monster attack enemy node in pursuit of the enemy can also be used.
+3. nodes can do very large, such as automatically do the task node, move to the npc, pick up the task, according to the task of subtasks to do subtasks, such as moving to the monster point to fight monsters, move to the collection of things to collect, etc., after doing all the subtasks, move to the task npc to turn in the task. All of this is written in a while loop, using a concurrent string.
+
+Thinking about a big question, how do you design a piezo bot? What does a piezo bot need to do? Automatically do tasks, automatically play various systems, automatically attack enemies, will counterattack, will find people to chat, etc.. Just make an ai node for each of the above mentioned. Brothers, AI simple or not?
+
+
+

+ 0 - 55
README-EN.md

@@ -1,55 +0,0 @@
-# [中文](https://github.com/egametang/Egametang/blob/master/README-CN.md) 
-
-__Chinese Tencent QQ group : 474643097__  
-[google group](https://groups.google.com/forum/#!forum/et-game-framework) 
-
-### 1.A distributed server, can use visual studio debugging,N->1  
-Generally speaking, distributed server starts a lot of processes, once the process is more, single step debugging becomes very difficult, leading to server development basically rely on log to find the problem. Common development has opened a lot of game logic process, not only the slow start, and find the problem and not convenient to log pile check problem in a pile, this feeling is very bad, so many years no one can solve the problem. The ET framework uses a component design similar to the watch pioneer, and all server contents are disassembled into components, and the components that need to be mounted according to the type of server are started. It is a bit like a computer, the computer module is split into memory, CPU, motherboard parts and so on, collocation of different parts can be assembled into a different computer, such as home desktop CPU, motherboard, memory, graphics, display, hard disk. And the company uses the server does not need the display and graphics card, the Internet bar computer may not need hard disk, etc.. Because of this design, the ET framework can be all server components are linked in a server process, the server process has all the functions of the server, a process can be used as a whole set of distributed servers. It's also like a computer, which has all the computer components, and it can be used as a company server or as an Internet cafe.  
-### 2.A Distributed server, can freely split function,1->N  
-Distributed server to develop various types of server processes, such as Login server, gate server, battle server, chat server friend server, a server, the traditional development mode need to know in advance the function which should be put in the server, when more and more functions, such as chat on a central server then, need to split out into a separate server, this will involve a large number of code migration work, tired. The ET framework does not really need to be concerned about what kind of functionality the current development will place on server, and only uses one process to develop it, and the function is developed into a component. Is it convenient to use a multi process configuration to publish it into multiple processes when you publish it? How do you split the server?. You can split it with very few code changes. Different server hangs different components on it?!
-### 3.Cross platform distributed server 
-ET framework uses C# as server-side, and now C# is completely cross platform, install.Netcore on Linux, you can do without modifying any code, you can run. Performance, now.Netcore performance is very strong, faster than Lua, python, JS faster. The game server completely be nothing difficult. We usually use VS to develop debugging on windows, and release it to Linux on the time of release. ET framework also provides a key synchronization tool, open unity->tools->rsync synchronization, you can synchronize the code to the linux  
-```bash
-./Run.sh Config/StartConfig/192.168.12.188.txt 
-```
-You can compile and start the server.  
-### 4.Provide Coroutine support  
-C# naturally supports asynchronous variable synchronous syntax async and await, much more powerful than Lua and python, and the new version of Python and JavaScript language even copy the C#'s co - operation grammar. There is no asynchronous syntax to support remote calls between distributed servers and a large number of servers, and development will be very troublesome. So Java does not have asynchronous syntax, doing single service is OK, not suitable for large-scale distributed game server. For example:  
-
-```c#
-// Send C2R_Ping and wait for response message R2C_Ping
-R2C_Ping pong = await session.Call<R2C_Ping>(new C2R_Ping());
-Log.Debug("recv R2C_Ping");
-
-// Query mongodb for a ID of 1 Player and wait for return
-Player player = await Game.Scene.GetComponent<DBProxyComponent>().Query<Player>(1);
-Log.Debug($"print player name: {player.Name}")
-```
-It can be seen that with async await, asynchronous operations between all servers will become very coherent, without disassembling into multiple sections of logic. Greatly simplifies the development of distributed servers 
-### 5.Provide actor message mechanism similar to Erlang  
-One of the advantages of Erlang language is the location transparent message mechanism. The user does not care about which process the object is in, and when you get the ID, you can send the message to the object. The ET framework also provides a actor message mechanism, the entity object need only hang ActorComponent components, the object becomes a Actor, any server only needs to know the object ID can send a message to it, totally do not care about this entity in which server, in which physical machine. This principle is actually very simple, the ET framework provides a location server, all mounted ActorComoponet object will own ID with location registration to the location server, the other server when sending the message object if you don't know the real position of the object, will go to the location server query, query to the position to be transmitted.
-### 6.Provide server with dynamic update logic function   
-hotfix is an indispensable component of game server function, design using the ET framework, the design can be made to watch the pioneer, only component members, no way, all the way into an expansion method in hotfix DLL, when reload DLL can reload all logic more hot.
-### 7.Client can hotfix
-Because of the IOS restrictions, the previous unity hot update generally use Lua, leading to unity3d developers to write two kinds of code, trouble to death. Fortunately, the ILRuntime library comes out, using the ILRuntime library, unity3d can use the C# language to load the hot update DLL for thermal update. One drawback of ILRuntime is that it doesn't support VS debug at development time, which is a little uncomfortable. The ET framework uses a pre compiled instruction ILRuntime to seamlessly switch. ILRuntime is not used when developing, but using Assembly.Load to load the hot update dynamic library, so that it can be easily used VS single step debugging. At the time of release, defining the precompiled instruction ILRuntime can seamlessly switch to using ILRuntime to load the hot update dynamic library. So it's easy to develop and convenient
-### 8.The client server uses the same language and shares the code  
-Download the ET framework, open the server project, you can see that the server referenced a lot of client code, through the client code approach to achieve a double end shared code. For example, the network message between the client and server can share a file on both sides, adding a message only needs to be modified.  
-### 9.The UDP TCP protocol seamlessly switches
-The ET framework not only supports TCP, but also support the reliable UDP protocol, UDP support is a package of ENet library, using the ENet and hero alliance network library, its characteristic is rapid, and the performance of the network packet loss situation is also very good, that we tested TCP in packet loss 5%, MoBa game card no, but the use of ENet, 20% packet loss still don't feel a card. Very powerful.  
-
-### 10.there are many, I will not detail
-A. and its easy to check CPU occupancy and memory leak check, vs comes with analytical tools, no longer worry about performance and memory leak check  
-B. uses NLog library, hits log and its convenience, when develops normally, may hit all the server log to a document, also does not need each document search log again  
-C. unified the use of Mongodb bson serialization, the message and configuration files are all bson or JSON, and later use mongodb to do the database, and no longer need to format conversion.  
-D. provides a powerful AI behavior tree tool  
-E. provides a synchronization tool  
-F. provides command line configuration tools, configuring the distribution is very simple
-The server side of the ET framework is a powerful and flexible distributed server architecture, which can fully meet the needs of most large games. Using this framework, the client developer can complete the double end development by himself, save a lot of manpower and material resources, and save a lot of communication time.  
-
-Usage method:  
-[start-guide](https://github.com/egametang/Egametang/blob/master/Doc/start-guide.md)    
-[component-design](https://github.com/egametang/Egametang/blob/master/Doc/component-design.md)   
-[network-design](https://github.com/egametang/Egametang/blob/master/Doc/network-design.md) 
-
-__Chinese Tencent QQ group : 474643097__  
-email: egametang@qq.com

+ 162 - 0
README-ZH.md

@@ -0,0 +1,162 @@
+# [English](https://github.com/egametang/Egametang/blob/master/README-EN.md) 
+
+# __讨论QQ群 : 474643097__  
+
+# [ET论坛](https://et-framework.cn)  
+
+# [ET代码商店](https://github.com/egametang/ET/tree/master/Store)  
+
+# [ET6.0视频教程上线](https://edu.uwa4d.com/course-intro/1/375)   
+
+# 重大注意事项:
+1. Hotfix跟HotfixView是纯逻辑的,类中不要带有任何字段,否则热更就会丢失  
+2. ETTask跟要么调用Coroutine要么就await,打开VS中的错误列表窗口,没有使用这两种的会报出问题,虽然既不await也不Coroutine的话能够编译通过,但是会丢失异常,十分危险  
+3. 请不要使用任何虚函数,用逻辑分发替代  
+4. 请不要使用任何继承,除了继承Entity,用组件替代  
+
+
+# ET6 发布!ET6相比ET5有巨大变化,可以说是凤姐变亦菲,6.0拥有如下惊人的特点
+1. 客户端逻辑全热更新(基于ILRuntime),没有不能更的部分  
+2. 客户端服务端均可热重载,开发不用重启客户端服务端即可修改逻辑代码,开发极其方便  
+2. 机器人框架,ET6的客户端的逻辑跟表现分离,机器人程序直接共享利用客户端的逻辑层代码做压测,只需要极少代码即可做出机器人,方便压测服务端  
+3. 测试用例框架,利用客户端的逻辑层代码写单元测试,每个单元测试都是完整的游戏环境,无需各种恶心的mock  
+4. AI框架,比行为树更加方便,写AI比写UI还简单  
+5. 新的服务端架构,极其优美  
+6. 内外网kcp网络,性能强劲,搭配软路由模块,可以防各种网络攻击  
+
+# ET开发的商业mmo项目千古风流成功上线,64核128G内存的单服单物理机1.5W在线(实际线上策划为了生态限制为单服6000人同时在线,6000人的话cpu消耗约为30%)。为了堆栈行号正常,线上跑得是Debug版,如果使用Release版开启优化,性能还能翻一倍,达到单物理机3W在线!上线5个月来十分稳定。千古风流使用了ET框架从零开发,用时两年,这个开发速度可以说无人出其右。千古风流的成功上线证明了ET具备开发任何大型游戏的能力,开发速度,开发效率都令人叹为观止!千古风流使用到的客户端服务器技术:  
+1. 动态副本跟分线,按需分配,用完回收  
+2. 分线合线,分线人数较少会把多条线合并。合线功能基本上其它mmo游戏很少见到  
+3. 客户端服务端场景无缝切换,也就是无缝大世界技术  
+4. 跨服副本,跨服战场  
+5. 前后端一体化,利用客户端代码开发服务器压测机器人,4台24核机器轻松模拟1W人做任务  
+6. 千古风流各种ai设计,使用ET的全新开发的ai框架,使ai开发简单到跟写ui一样简单  
+7. 测试用例框架,大部分重要系统,千古风流都写了测试用例,跟市面上的测试用例不同,每个千古风流的测试用例都是一个完整的游戏环境,针对协议级别,不需要搞各种接口去mock。写起来非常快速。  
+8. 九宫格的aoi实现,动态调整看见的玩家,降低服务器负载  
+9. 防攻击,千古风流开发了软路由功能,即使攻击也只能攻击到软路由,一旦被攻击,玩家客户端发现几秒钟无响应,即可动态切换到其它软路由,用户几乎无感知。整个过程客户端网络连接不断开,数据不丢失。  
+10. 还有很多很多,这里就不啰嗦了  
+
+
+# ET的介绍:
+ET是一个开源的游戏客户端(基于unity3d)服务端双端框架,服务端是使用C# .net core开发的分布式游戏服务端,其特点是开发效率高,性能强,双端共享逻辑代码,客户端服务端热更机制完善,同时支持可靠udp tcp websocket协议,支持服务端3D recast寻路等等  
+
+# ET的功能:
+### 1.可用VS单步调试的分布式服务端,N变1  
+一般来说,分布式服务端要启动很多进程,一旦进程多了,单步调试就变得非常困难,导致服务端开发基本上靠打log来查找问题。平常开发游戏逻辑也得开启一大堆进程,不仅启动慢,而且查找问题及其不方便,要在一堆堆日志里面查问题,这感觉非常糟糕,这么多年也没人解决这个问题。ET框架使用了类似守望先锋的组件设计,所有服务端内容都拆成了一个个组件,启动时根据服务器类型挂载自己所需要的组件。这有点类似电脑,电脑都模块化的拆成了内存,CPU,主板等等零件,搭配不同的零件就能组装成一台不同的电脑,例如家用台式机需要内存,CPU,主板,显卡,显示器,硬盘。而公司用的服务器却不需要显示器和显卡,网吧的电脑可能不需要硬盘等。正因为这样的设计,ET框架可以将所有的服务器组件都挂在一个服务器进程上,那么这个服务器进程就有了所有服务器的功能,一个进程就可以作为整组分布式服务器使用。这也类似电脑,台式机有所有的电脑组件,那它也完全可以当作公司服务器使用,也可以当作网吧电脑。  
+### 2.随意可拆分功能的分布式服务端,1变N  
+分布式服务端要开发多种类型的服务器进程,比如Login server,gate server,battle server,chat server friend server等等一大堆各种server,传统开发方式需要预先知道当前的功能要放在哪个服务器上,当功能越来越多的时候,比如聊天功能之前在一个中心服务器上,之后需要拆出来单独做成一个服务器,这时会牵扯到大量迁移代码的工作,烦不胜烦。ET框架在平常开发的时候根本不太需要关心当前开发的这个功能会放在什么server上,只用一个进程进行开发,功能开发成组件的形式。发布的时候使用一份多进程的配置即可发布成多进程的形式,是不是很方便呢?随便你怎么拆分服务器。只需要修改极少的代码就可以进行拆分。不同的server挂上不同的组件就行了嘛!  
+### 3.跨平台的分布式服务端  
+ET框架使用C#做服务端,现在C#是完全可以跨平台的,在linux上安装.netcore,即可,不需要修改任何代码,就能跑起来。性能方面,现在.netcore的性能非常强,比lua,python,js什么快的多了。做游戏服务端完全不在话下。平常我们开发的时候用VS在windows上开发调试,发布的时候发布到linux上即可。ET框架还提供了一键同步工具,打开unity->tools->rsync同步,即可同步代码到linux上  
+```bash
+./Run.sh Config/StartConfig/192.168.12.188.txt 
+```
+即可编译启动服务器。  
+### 4.提供协程支持  
+C#天生支持异步变同步语法 async和await,比lua,python的协程强大的多,新版python以及javascript语言甚至照搬了C#的协程语法。分布式服务端大量服务器之间的远程调用,没有异步语法的支持,开发将非常麻烦。所以java没有异步语法,做单服还行,不适合做大型分布式游戏服务端。例如:  
+
+```c#
+// 发送C2R_Ping并且等待响应消息R2C_Ping
+R2C_Ping pong = await session.Call(new C2R_Ping()) as R2C_Ping;
+Log.Debug("收到R2C_Ping");
+
+// 向mongodb查询一个id为1的Player,并且等待返回
+Player player = await Game.Scene.GetComponent<DBProxyComponent>().Query<Player>(1);
+Log.Debug($"打印player name: {player.Name}")
+```
+可以看出,有了async await,所有的服务器间的异步操作将变得非常连贯,不用再拆成多段逻辑。大大简化了分布式服务器开发  
+### 5.提供类似erlang的actor消息机制  
+erlang语言一大优势就是位置透明的消息机制,用户完全不用关心对象在哪个进程,拿到id就可以对对象发送消息。ET框架也提供了actor消息机制,实体对象只需要挂上MailBoxComponent组件,这个实体对象就成了一个Actor,任何服务器只需要知道这个实体对象的id就可以向其发送消息,完全不用关心这个实体对象在哪个server,在哪台物理机器上。其实现原理也很简单,ET框架提供了一个位置服务器,所有挂载MailBoxComponent的实体对象都会将自己的id跟位置注册到这个位置服务器,其它服务器向这个实体对象发送消息的时候如果不知道这个实体对象的位置,会先去位置服务器查询,查询到位置再进行发送。
+### 6.提供服务器不停服动态更新逻辑功能  
+热更是游戏服务器不可缺少的功能,ET框架使用的组件设计,可以做成守望先锋的设计,组件只有成员,无方法,将所有方法做成扩展方法放到热更dll中,运行时重新加载dll即可热更所有逻辑。
+### 7.客户端使用C#热更新,热更新一键切换  
+可以使用csharp.lua或者ILRuntime稍加改造即可做客户端热更。再也不用使用狗屎lua了,客户端可以实现所有逻辑热更新,包括协议,config,ui等等。  
+### 8.客户端热重载  
+开发不用重启客户端即可修改客户端逻辑代码,开发极其方便  
+
+### 9.客户端服务端用同一种语言,并且共享代码  
+下载ET框架,打开服务端工程,可以看到服务端引用了客户端很多代码,通过引用客户端代码的方式实现了双端共享代码。例如客户端服务端之间的网络消息两边完全共用一个文件即可,添加一个消息只需要修改一遍。  
+### 10.KCP ENET TCP Websocket协议无缝切换  
+ET框架不但支持TCP,而且支持可靠的UDP协议(ENET跟KCP),ENet是英雄联盟所使用的网络库,其特点是快速,并且网络丢包的情况下性能也非常好,这个我们做过测试TCP在丢包5%的情况下,moba游戏就卡的不行了,但是使用ENet,丢包20%仍然不会感到卡。非常强大。框架还支持使用KCP协议,KCP也是可靠UDP协议,据说比ENET性能更好,使用kcp请注意,需要自己加心跳机制,否则20秒没收到包,服务端将断开连接。协议可以无缝切换。  
+### 11. 3D Recast寻路功能  
+可以Unity导出场景数据,给服务端做recast寻路。做MMO非常方便,demo演示了服务端3d寻路功能  
+### 12. 服务端支持repl,也可以动态执行一段新代码  
+这样就可以打印出进程中任何数据,大大简化了服务端查找问题的难度,开启repl方法,直接在console中输入repl回车即可进入repl模式  
+### 13.提供客户端机器人框架支持  
+几行代码即可创建机器人登录游戏。机器人压测轻而易举,机器人跟正常的玩家完全一样,上线前用机器人做好压测,大大降低上线崩溃几率   
+### 14.AI框架  
+ET的AI框架让AI编写比UI还简单     
+### 15.测试用例框架  
+跟市面上的测试用例不同,ET的测试用例都是一个完整的游戏环境,针对协议级别,不需要搞各种接口去mock。写起来非常快速    
+
+### 16.还有很多很多功能,我就不详细介绍了  
+a.及其方便检查CPU占用和内存泄漏检查,vs自带分析工具,不用再为性能和内存泄漏检查而烦恼  
+b.使用NLog库,打log及其方便,平常开发时,可以将所有服务器log打到一个文件中,再也不用一个个文件搜索log了  
+c.统一使用Mongodb的bson做序列化,消息和配置文件全部都是bson或者json,并且以后使用mongodb做数据库,再也不用做格式转换了。  
+d.提供一个同步工具  
+
+ET框架是一个强大灵活的分布式服务端架构,完全可以满足绝大部分大型游戏需求。使用这套框架,客户端开发者就可以自己完成双端开发,节省大量人力物力,节省大量沟通时间。  
+
+使用方法:  
+[运行指南](https://github.com/egametang/ET/blob/master/Book/1.1%E8%BF%90%E8%A1%8C%E6%8C%87%E5%8D%97.md)  
+  
+相关网站:  
+[ET论坛](https://et-framework.cn)  
+
+群友分享:  
+[行为树与fgui分支(Duke Chiang开发维护)](https://github.com/DukeChiang/ET.git)   
+[ET学习笔记系列(烟雨迷离半世殇写)](https://www.lfzxb.top/)   
+[ET学习笔记系列(咲夜詩写)](https://acgmart.com/unity/)   
+[框架服务端运行流程](http://www.cnblogs.com/fancybit/p/et1.html)  
+[ET启动配置](http://www.cnblogs.com/fancybit/p/et2.html)  
+[框架demo介绍](http://www.jianshu.com/p/f2ea0d26c7c1)  
+[linux部署](http://gad.qq.com/article/detail/35973)  
+[linux部署,mongo安装,资源服搭建](http://www.tinkingli.com/?p=25)  
+[ET框架心跳包组件开发](http://www.tinkingli.com/?p=111)  
+[ET框架Actor使用与心得](http://www.tinkingli.com/?p=117)  
+[基于ET框架和UGUI的简单UI框架实现(渐渐写)](http://www.tinkingli.com/?p=124)  
+[ET框架笔记 (笑览世界写)](http://www.tinkingli.com/?p=76)  
+[ET框架如何用MAC开发](http://www.tinkingli.com/?p=147)  
+[ET的动态添加事件和触发组件](http://www.tinkingli.com/?p=145)  
+
+商业项目:  
+1. [千古风流](https://www.qiangu.com/)  
+2. [魔法点点2](https://www.taptap.com/app/227804)  
+3. [养不大](https://www.taptap.com/app/71064)  
+4. 天天躲猫猫2(ios2019春节下载排行19)  
+5. [牛虎棋牌](https://gitee.com/ECPS_admin/PlanB)  
+6. [五星麻将](https://github.com/wufanjoin/fivestar)  
+
+群友demo:  
+1. [斗地主(客户端服务端)](https://github.com/Viagi/LandlordsCore)  
+2. [背包系统](https://gitee.com/ECPS_admin/planc)  
+3. [ET小游戏合集](https://github.com/Acgmart/ET-MultiplyDemos)  
+
+
+
+视频教程:  
+[字母哥ET6.0教程](https://edu.uwa4d.com/course-intro/1/375)   
+[肉饼老师主讲](http://www.taikr.com/my/course/972)  
+[官剑铭主讲](https://edu.manew.com/course/796)  
+[ET新手教程-初见主讲](https://pan.baidu.com/s/1a5-j2R5QctZpC9n3sMC9QQ) 密码: ru1j  
+[ET新手教程新版-初见主讲](https://www.bilibili.com/video/av33280463/?redirectFrom=h5)  
+[ET在Mac上运行指南-L主讲](https://pan.baidu.com/s/1VUQbdd1Yio7ULFXwAv7X7A) 密码: l3e3  
+[ET框架系列教程-烟雨主讲-6.0版本](https://space.bilibili.com/33595745/favlist?fid=759596845&ftype=create)  
+
+.net core 游戏资源分享  
+[各种dotnet core项目收集](https://github.com/thangchung/awesome-dotnet-core)  
+
+__讨论QQ群 : 474643097__
+
+
+# 支付宝捐赠  
+![使用支付宝对该项目进行捐赠](https://github.com/egametang/ET/blob/master/Book/donate.png)
+
+# 友情链接  
+[Box2DSharp](https://github.com/Zonciu/Box2DSharp)  box2d的C#移植版,性能很强  
+[xasset](https://github.com/xasset/xasset) 致力于为 Unity 项目提供了一套 精简稳健 的资源管理环境  
+[QFramework](https://github.com/liangxiegame/QFramework) Your first K.I.S.S Unity3d Framework  
+[ET UI框架](https://github.com/zzjfengqing/ET-EUI) 字母哥实现的UI框架,ET风格,各种事件分发  
+[ETCsharpToXLua](https://github.com/zzjfengqing/ETCsharpToXLua) 字母哥使用csharp.lua实现的ET客户端热更新  
+[et-6-with-ilruntime](https://www.lfzxb.top/et-6-with-ilruntime) 烟雨使用ILRuntime实现的ET客户端热更新  
+[Luban](https://github.com/focus-creative-games/luban) 适用于大中型项目的游戏配置解决方案  
+

+ 153 - 151
README.md

@@ -1,162 +1,164 @@
-# [English](https://github.com/egametang/Egametang/blob/master/README-EN.md) 
-
-# __讨论QQ群 : 474643097__  
-
-# [ET论坛](https://et-framework.cn)  
-
-# [ET代码商店](https://github.com/egametang/ET/tree/master/Store)  
-
-# [ET6.0视频教程上线](https://edu.uwa4d.com/course-intro/1/375)   
-
-# 重大注意事项:
-1. Hotfix跟HotfixView是纯逻辑的,类中不要带有任何字段,否则热更就会丢失  
-2. ETTask跟要么调用Coroutine要么就await,打开VS中的错误列表窗口,没有使用这两种的会报出问题,虽然既不await也不Coroutine的话能够编译通过,但是会丢失异常,十分危险  
-3. 请不要使用任何虚函数,用逻辑分发替代  
-4. 请不要使用任何继承,除了继承Entity,用组件替代  
-
-
-# ET6 发布!ET6相比ET5有巨大变化,可以说是凤姐变亦菲,6.0拥有如下惊人的特点
-1. 客户端逻辑全热更新(基于ILRuntime),没有不能更的部分  
-2. 客户端服务端均可热重载,开发不用重启客户端服务端即可修改逻辑代码,开发极其方便  
-2. 机器人框架,ET6的客户端的逻辑跟表现分离,机器人程序直接共享利用客户端的逻辑层代码做压测,只需要极少代码即可做出机器人,方便压测服务端  
-3. 测试用例框架,利用客户端的逻辑层代码写单元测试,每个单元测试都是完整的游戏环境,无需各种恶心的mock  
-4. AI框架,比行为树更加方便,写AI比写UI还简单  
-5. 新的服务端架构,极其优美  
-6. 内外网kcp网络,性能强劲,搭配软路由模块,可以防各种网络攻击  
-
-# ET开发的商业mmo项目千古风流成功上线,64核128G内存的单服单物理机1.5W在线(实际线上策划为了生态限制为单服6000人同时在线,6000人的话cpu消耗约为30%)。为了堆栈行号正常,线上跑得是Debug版,如果使用Release版开启优化,性能还能翻一倍,达到单物理机3W在线!上线5个月来十分稳定。千古风流使用了ET框架从零开发,用时两年,这个开发速度可以说无人出其右。千古风流的成功上线证明了ET具备开发任何大型游戏的能力,开发速度,开发效率都令人叹为观止!千古风流使用到的客户端服务器技术:  
-1. 动态副本跟分线,按需分配,用完回收  
-2. 分线合线,分线人数较少会把多条线合并。合线功能基本上其它mmo游戏很少见到  
-3. 客户端服务端场景无缝切换,也就是无缝大世界技术  
-4. 跨服副本,跨服战场  
-5. 前后端一体化,利用客户端代码开发服务器压测机器人,4台24核机器轻松模拟1W人做任务  
-6. 千古风流各种ai设计,使用ET的全新开发的ai框架,使ai开发简单到跟写ui一样简单  
-7. 测试用例框架,大部分重要系统,千古风流都写了测试用例,跟市面上的测试用例不同,每个千古风流的测试用例都是一个完整的游戏环境,针对协议级别,不需要搞各种接口去mock。写起来非常快速。  
-8. 九宫格的aoi实现,动态调整看见的玩家,降低服务器负载  
-9. 防攻击,千古风流开发了软路由功能,即使攻击也只能攻击到软路由,一旦被攻击,玩家客户端发现几秒钟无响应,即可动态切换到其它软路由,用户几乎无感知。整个过程客户端网络连接不断开,数据不丢失。  
-10. 还有很多很多,这里就不啰嗦了  
-
-
-# ET的介绍:
-ET是一个开源的游戏客户端(基于unity3d)服务端双端框架,服务端是使用C# .net core开发的分布式游戏服务端,其特点是开发效率高,性能强,双端共享逻辑代码,客户端服务端热更机制完善,同时支持可靠udp tcp websocket协议,支持服务端3D recast寻路等等  
-
-# ET的功能:
-### 1.可用VS单步调试的分布式服务端,N变1  
-一般来说,分布式服务端要启动很多进程,一旦进程多了,单步调试就变得非常困难,导致服务端开发基本上靠打log来查找问题。平常开发游戏逻辑也得开启一大堆进程,不仅启动慢,而且查找问题及其不方便,要在一堆堆日志里面查问题,这感觉非常糟糕,这么多年也没人解决这个问题。ET框架使用了类似守望先锋的组件设计,所有服务端内容都拆成了一个个组件,启动时根据服务器类型挂载自己所需要的组件。这有点类似电脑,电脑都模块化的拆成了内存,CPU,主板等等零件,搭配不同的零件就能组装成一台不同的电脑,例如家用台式机需要内存,CPU,主板,显卡,显示器,硬盘。而公司用的服务器却不需要显示器和显卡,网吧的电脑可能不需要硬盘等。正因为这样的设计,ET框架可以将所有的服务器组件都挂在一个服务器进程上,那么这个服务器进程就有了所有服务器的功能,一个进程就可以作为整组分布式服务器使用。这也类似电脑,台式机有所有的电脑组件,那它也完全可以当作公司服务器使用,也可以当作网吧电脑。  
-### 2.随意可拆分功能的分布式服务端,1变N  
-分布式服务端要开发多种类型的服务器进程,比如Login server,gate server,battle server,chat server friend server等等一大堆各种server,传统开发方式需要预先知道当前的功能要放在哪个服务器上,当功能越来越多的时候,比如聊天功能之前在一个中心服务器上,之后需要拆出来单独做成一个服务器,这时会牵扯到大量迁移代码的工作,烦不胜烦。ET框架在平常开发的时候根本不太需要关心当前开发的这个功能会放在什么server上,只用一个进程进行开发,功能开发成组件的形式。发布的时候使用一份多进程的配置即可发布成多进程的形式,是不是很方便呢?随便你怎么拆分服务器。只需要修改极少的代码就可以进行拆分。不同的server挂上不同的组件就行了嘛!  
-### 3.跨平台的分布式服务端  
-ET框架使用C#做服务端,现在C#是完全可以跨平台的,在linux上安装.netcore,即可,不需要修改任何代码,就能跑起来。性能方面,现在.netcore的性能非常强,比lua,python,js什么快的多了。做游戏服务端完全不在话下。平常我们开发的时候用VS在windows上开发调试,发布的时候发布到linux上即可。ET框架还提供了一键同步工具,打开unity->tools->rsync同步,即可同步代码到linux上  
+# [中文](https://github.com/egametang/Egametang/blob/master/README-ZH.md) 
+
+# __Discussion QQ group : 474643097__  
+# email: egametang@qq.com  
+
+# [ET Forum](https://et-framework.cn)  
+
+# [ET Code Store](https://github.com/egametang/ET/tree/master/Store)  
+
+# [ET6.0 video tutorial online](https://edu.uwa4d.com/course-intro/1/375)   
+
+# Major Notes.
+1. Hotfix with HotfixView is pure logic, do not have any fields in the class, otherwise the hotfix will be lost  
+2. ETTask and either call Coroutine or await, open the error list window in VS, do not use these two will be reported as a problem, although neither await nor Coroutine, if you can compile through, but will lose the exception, very dangerous  
+3. do not use any dummy functions, use logical distribution instead  
+4. Please do not use any inheritance, except for Entity inheritance, use components instead.  
+
+
+# ET6 has huge changes compared with ET5, and it can be said that Phoenix has become Yifei. 6.0 has the following amazing features
+1. client-side logic full hot update (based on ILRuntime), no part that can not be changed  
+2. client and server can be hot reload, development without restarting the client and server can modify the logic code, development is extremely convenient  
+2. robot framework, ET6 client-side logic and performance separation, robot program directly share the use of client-side logic layer code to do pressure testing, only a very small amount of code to make the robot, easy to pressure test the server  
+3. test case framework, using the client's logic layer code to write unit tests, each unit test is a complete game environment, without all kinds of nasty mock  
+4 AI framework, more convenient than the behavior tree, write AI than writing UI is still simple  
+5. the new server-side architecture, extremely beautiful  
+6. intranet and extranet kcp network, strong performance, with soft routing module, can prevent all kinds of network attacks  
+
+# ET development of commercial mmo project thousand ancient wind flow successfully online, 64 core 128G memory single service single physical machine 1.5W online (the actual online planning for ecological restrictions for a single service 6000 people online at the same time, 6000 people then cpu consumption is about 30%). In order to stack line number normal, online run is Debug version, if you use Release version to open optimization, performance can also double, to reach a single physical machine 3W online! On-line for 5 months is very stable. Thousand ancient wind flow using the ET framework developed from scratch, it took two years, this development speed can be said that no one can be its right. The successful launch of Thousand Ancient Winds proves that ET has the ability to develop any large game, development speed, development efficiency are breathtaking! The client server technology used in Thousand Ancient Winds and Currents: 1.  
+1. dynamic copies and sub-lines, on-demand allocation, recycling after use  
+2. split line merge line, split line less number of people will merge multiple lines. Combined line function basically other mmo games rarely see  
+3. seamless client-server scene switching, that is, seamless world technology  
+4. cross-services copies, cross-services battlefield  
+5. front and back-end integration, the use of client-side code to develop server pressure testing robot, four 24-core machine easily simulate 1W people to do the task  
+6. a variety of ai design, the use of ET's new development of ai framework, so that ai development is as simple as writing ui  
+7 test case framework, most of the important system, the thousand ancient wind flow are written test cases, different from the test cases on the market, each thousand ancient wind flow test cases are a complete game environment, for the protocol level, do not need to engage in a variety of interfaces to mock. write up very fast.  
+8. aoi implementation of the nine-gong grid, dynamic adjustment of the players seen to reduce the server load  
+9. anti-attack, a thousand ancient wind flow developed a soft route function, even if the attack can only attack to the soft route, once attacked, the player client found a few seconds no response, you can dynamically switch to other soft routes, the user almost no perception. The whole process of client network connection does not open, no loss of data.  
+10. there are many, many more, here will not be verbose  
+
+
+# ET's introduction.
+ET is an open source game client (based on unity3d) server-side dual-end framework , the server side is developed using C# .net core distributed game server , which is characterized by high development efficiency , strong performance , dual-end shared logic code , client-side server hot more mechanism is perfect , while supporting reliable udp tcp websocket protocol , support for server-side 3D recast pathfinding, etc.  
+
+# ET features.
+### 1. available VS single-step debugging distributed server, N to 1  
+Generally speaking, distributed server-side has to start many processes, and once there are more processes, single-step debugging becomes very difficult, resulting in server-side development basically relying on playing logs to find problems. ET framework uses a component design similar to Watchtower, all server-side content is broken down into individual components, which are mounted according to the type of server they need when starting. This is somewhat similar to computers, which are modularly broken down into memory, CPU, motherboard and other parts, with different parts can be assembled into a different computer, for example, a home desktop needs memory, CPU, motherboard, graphics card, monitor, hard disk. While servers for companies do not need monitors and graphics cards, computers in Internet cafes may not need hard disks, etc. Because of this design, the ET framework can hang all the server components on one server process, then this server process has all the functions of a server, and one process can be used as a whole group of distributed servers. This is also similar to the computer, the desktop has all the computer components, then it can also be completely used as a company server, but also as an Internet cafe computer.  
+### 2. Distributed server that can be split into functions at will, 1 to N  
+Distributed server to develop a variety of types of server processes, such as login server, gate server, battle server, chat server friend server and so on a large number of various servers, the traditional development method needs to know in advance the current function to be placed on which server, when more and more functions ET framework in the normal development time simply do not need to care about the current development of the function will be placed on what server, only use a process for development, functional development into the form of components. Release time to use a multi-process configuration can be released into the form of multi-process, is not very convenient it? Split the server however you want. You only need to modify a very small amount of code to split it. Different servers hooked up to different components on the line!  
+### 3. Cross-platform distributed server  
+ET framework using C# to do the server , C# is now completely cross-platform , install .netcore on linux , you can , without modifying any code , you can run . performance, now .netcore performance is very strong, than lua, python, js what is much faster. It is much faster than lua, python, js or anything else. It is not a problem to do game server. ET framework also provides a key synchronization tool , open unity->tools->rsync synchronization , you can synchronize the code to linux  
 ```bash
-./Run.sh Config/StartConfig/192.168.12.188.txt 
+. /Run.sh Config/StartConfig/192.168.12.188.txt 
 ```
-即可编译启动服务器。  
-### 4.提供协程支持  
-C#天生支持异步变同步语法 async和await,比lua,python的协程强大的多,新版python以及javascript语言甚至照搬了C#的协程语法。分布式服务端大量服务器之间的远程调用,没有异步语法的支持,开发将非常麻烦。所以java没有异步语法,做单服还行,不适合做大型分布式游戏服务端。例如:  
+That's all it takes to compile and start the server.  
+### 4. Provide concurrent support  
+C# inherently supports asynchronous to synchronous syntax async and await, much more powerful than lua, python's concurrency, new versions of python and javascript language even copied C#'s concurrency syntax. Distributed server-side remote calls between a large number of servers, without the support of asynchronous syntax, development will be very troublesome. So java does not have asynchronous syntax, do a single service is okay, not suitable for large distributed game server. For example.  
 
 ```c#
-// 发送C2R_Ping并且等待响应消息R2C_Ping
+// send C2R_Ping and wait for response message R2C_Ping
 R2C_Ping pong = await session.Call(new C2R_Ping()) as R2C_Ping;
-Log.Debug("收到R2C_Ping");
+Log.Debug("Received R2C_Ping");
 
-// 向mongodb查询一个id为1的Player,并且等待返回
+// query mongodb for a Player with id 1 and wait for the return
 Player player = await Game.Scene.GetComponent<DBProxyComponent>().Query<Player>(1);
-Log.Debug($"打印player name: {player.Name}")
+Log.Debug($"Printing player name: {player.Name}")
 ```
-可以看出,有了async await,所有的服务器间的异步操作将变得非常连贯,不用再拆成多段逻辑。大大简化了分布式服务器开发  
-### 5.提供类似erlang的actor消息机制  
-erlang语言一大优势就是位置透明的消息机制,用户完全不用关心对象在哪个进程,拿到id就可以对对象发送消息。ET框架也提供了actor消息机制,实体对象只需要挂上MailBoxComponent组件,这个实体对象就成了一个Actor,任何服务器只需要知道这个实体对象的id就可以向其发送消息,完全不用关心这个实体对象在哪个server,在哪台物理机器上。其实现原理也很简单,ET框架提供了一个位置服务器,所有挂载MailBoxComponent的实体对象都会将自己的id跟位置注册到这个位置服务器,其它服务器向这个实体对象发送消息的时候如果不知道这个实体对象的位置,会先去位置服务器查询,查询到位置再进行发送。
-### 6.提供服务器不停服动态更新逻辑功能  
-热更是游戏服务器不可缺少的功能,ET框架使用的组件设计,可以做成守望先锋的设计,组件只有成员,无方法,将所有方法做成扩展方法放到热更dll中,运行时重新加载dll即可热更所有逻辑。
-### 7.客户端使用C#热更新,热更新一键切换  
-可以使用csharp.lua或者ILRuntime稍加改造即可做客户端热更。再也不用使用狗屎lua了,客户端可以实现所有逻辑热更新,包括协议,config,ui等等。  
-### 8.客户端热重载  
-开发不用重启客户端即可修改客户端逻辑代码,开发极其方便  
-
-### 9.客户端服务端用同一种语言,并且共享代码  
-下载ET框架,打开服务端工程,可以看到服务端引用了客户端很多代码,通过引用客户端代码的方式实现了双端共享代码。例如客户端服务端之间的网络消息两边完全共用一个文件即可,添加一个消息只需要修改一遍。  
-### 10.KCP ENET TCP Websocket协议无缝切换  
-ET框架不但支持TCP,而且支持可靠的UDP协议(ENET跟KCP),ENet是英雄联盟所使用的网络库,其特点是快速,并且网络丢包的情况下性能也非常好,这个我们做过测试TCP在丢包5%的情况下,moba游戏就卡的不行了,但是使用ENet,丢包20%仍然不会感到卡。非常强大。框架还支持使用KCP协议,KCP也是可靠UDP协议,据说比ENET性能更好,使用kcp请注意,需要自己加心跳机制,否则20秒没收到包,服务端将断开连接。协议可以无缝切换。  
-### 11. 3D Recast寻路功能  
-可以Unity导出场景数据,给服务端做recast寻路。做MMO非常方便,demo演示了服务端3d寻路功能  
-### 12. 服务端支持repl,也可以动态执行一段新代码  
-这样就可以打印出进程中任何数据,大大简化了服务端查找问题的难度,开启repl方法,直接在console中输入repl回车即可进入repl模式  
-### 13.提供客户端机器人框架支持  
-几行代码即可创建机器人登录游戏。机器人压测轻而易举,机器人跟正常的玩家完全一样,上线前用机器人做好压测,大大降低上线崩溃几率   
-### 14.AI框架  
-ET的AI框架让AI编写比UI还简单     
-### 15.测试用例框架  
-跟市面上的测试用例不同,ET的测试用例都是一个完整的游戏环境,针对协议级别,不需要搞各种接口去mock。写起来非常快速    
-
-### 16.还有很多很多功能,我就不详细介绍了  
-a.及其方便检查CPU占用和内存泄漏检查,vs自带分析工具,不用再为性能和内存泄漏检查而烦恼  
-b.使用NLog库,打log及其方便,平常开发时,可以将所有服务器log打到一个文件中,再也不用一个个文件搜索log了  
-c.统一使用Mongodb的bson做序列化,消息和配置文件全部都是bson或者json,并且以后使用mongodb做数据库,再也不用做格式转换了。  
-d.提供一个同步工具  
-
-ET框架是一个强大灵活的分布式服务端架构,完全可以满足绝大部分大型游戏需求。使用这套框架,客户端开发者就可以自己完成双端开发,节省大量人力物力,节省大量沟通时间。  
-
-使用方法:  
-[运行指南](https://github.com/egametang/ET/blob/master/Book/1.1%E8%BF%90%E8%A1%8C%E6%8C%87%E5%8D%97.md)  
+As you can see, with async await, all the asynchronous operations between servers become very coherent and don't have to be split into multiple pieces of logic. Greatly simplifies distributed server development  
+### 5. provide erlang-like actor message mechanism  
+erlang language is a major advantage is the location of transparent messaging mechanism , the user does not care about the object in which the process , get the id can send messages to the object . ET framework also provides an actor message mechanism , the entity object only needs to hang on the MailBoxComponent component , the entity object becomes an Actor , any server only needs to know the Any server only needs to know the id of the entity object can send messages to it, do not care which server the entity object in which physical machine. Its implementation principle is also very simple, ET framework provides a location server, all mounted MailBoxComponent entity objects will be registered to the location server with their id and location, other servers to send messages to this entity object if you do not know the location of the entity object, will first go to the location server query, query the location and then send.
+### 6. Provide server non-stop dynamic update logic function  
+hot is an indispensable feature of the game server , ET framework using the component design , you can make the Watchtower design , the component only members , no methods , all the methods made to extend the method into the hot more dll , reload the dll at runtime to hot more all logic .
+### 7. Client use C# hot update, hot update one key switch  
+You can use csharp.lua or ILRuntime to do client-side hot update with a little modification. No need to use shit lua anymore, client can realize all logic hot update, including protocol, config, ui and so on.  
+### 8. Client-side hot reload  
+Development without restarting the client can modify the client logic code, development is extremely convenient  
+
+### 9. Client-side server in the same language and share code  
+Download the ET framework , open the server-side project , you can see that the server side references the client side of a lot of code , through the reference to the client code to achieve a dual-side shared code . For example, the network messages between the client-side and the server-side completely share a file, add a message only need to modify once.  
+### 10. KCP ENET TCP Websocket protocol seamless switching  
+ET framework not only supports TCP, but also supports reliable UDP protocols (ENET and KCP), ENet is the network library used by League of Legends, which is characterized by fast and very good performance in the case of network packet loss, which we have tested TCP in the case of packet loss of 5%, the moba game on the card can not be, but using ENet, packet loss of 20% will still not feel card. Very powerful. Framework also supports the use of KCP protocol, KCP is also a reliable UDP protocol, said to be better than ENET performance, please note that the use of kcp, you need to add their own heartbeat mechanism, otherwise 20 seconds did not receive the packet, the server will be disconnected. The protocol can be switched seamlessly.  
+### 11. 3D Recast pathfinding function  
+Unity can export scene data to the server side to do recast pathfinding. Very convenient to do MMO, demo demonstrates the server-side 3d pathfinding function  
+### 12. server-side support for repl, you can also dynamically execute a new code  
+This can print out any data in the process, greatly simplifying the difficulty of finding problems on the server side, open the repl method, enter repl directly in the console to enter repl mode  
+### 13. Provide client-side bot framework support  
+A few lines of code to create a robot to log into the game. Robot pressure testing is a breeze, the robot is exactly the same as the normal player, use the robot to do a good pressure test before going online, greatly reducing the chance of crashing online   
+### 14.AI framework  
+ET's AI framework makes AI writing even easier than UI.     
+### 15. Test case framework  
+Unlike the test cases on the market, ET's test cases are a complete game environment, for the protocol level, no need to engage in a variety of interfaces to mock. write up very quickly    
+
+
+### 16. There are many, many more features that I won't go into detail about  
+a. and its convenient to check the CPU occupation and memory leak check, vs comes with analysis tools, no longer have to worry about performance and memory leak check  
+b. The use of NLog library, playing log and its convenience, the usual development, you can play all the server log to a file, no longer have to search for logs one file at a time  
+c.Unify the use of Mongodb bson serialization, messages and configuration files are all bson or json, and later use mongodb to do the database, no longer need to do the format conversion.  
+d. Provide a synchronization tool  
+
+ET framework is a powerful and flexible distributed server-side architecture that can fully meet the needs of most large games. Use this framework, the client developer can complete their own dual-ended development, saving a lot of manpower and resources, saving a lot of communication time.  
+
+Usage.  
+[Run Guide](https://github.com/egametang/ET/blob/master/Book/1.1RunGuide.md)  
   
-相关网站:  
-[ET论坛](https://et-framework.cn)  
-
-群友分享:  
-[行为树与fgui分支(Duke Chiang开发维护)](https://github.com/DukeChiang/ET.git)   
-[ET学习笔记系列(烟雨迷离半世殇写)](https://www.lfzxb.top/)   
-[ET学习笔记系列(咲夜詩写)](https://acgmart.com/unity/)   
-[框架服务端运行流程](http://www.cnblogs.com/fancybit/p/et1.html)  
-[ET启动配置](http://www.cnblogs.com/fancybit/p/et2.html)  
-[框架demo介绍](http://www.jianshu.com/p/f2ea0d26c7c1)  
-[linux部署](http://gad.qq.com/article/detail/35973)  
-[linux部署,mongo安装,资源服搭建](http://www.tinkingli.com/?p=25)  
-[ET框架心跳包组件开发](http://www.tinkingli.com/?p=111)  
-[ET框架Actor使用与心得](http://www.tinkingli.com/?p=117)  
-[基于ET框架和UGUI的简单UI框架实现(渐渐写)](http://www.tinkingli.com/?p=124)  
-[ET框架笔记 (笑览世界写)](http://www.tinkingli.com/?p=76)  
-[ET框架如何用MAC开发](http://www.tinkingli.com/?p=147)  
-[ET的动态添加事件和触发组件](http://www.tinkingli.com/?p=145)  
-
-商业项目:  
-1. [千古风流](https://www.qiangu.com/)  
-2. [魔法点点2](https://www.taptap.com/app/227804)  
-3. [养不大](https://www.taptap.com/app/71064)  
-4. 天天躲猫猫2(ios2019春节下载排行19)  
-5. [牛虎棋牌](https://gitee.com/ECPS_admin/PlanB)  
-6. [五星麻将](https://github.com/wufanjoin/fivestar)  
-
-群友demo:  
-1. [斗地主(客户端服务端)](https://github.com/Viagi/LandlordsCore)  
-2. [背包系统](https://gitee.com/ECPS_admin/planc)  
-3. [ET小游戏合集](https://github.com/Acgmart/ET-MultiplyDemos)  
-
-
-
-视频教程:  
-[字母哥ET6.0教程](https://edu.uwa4d.com/course-intro/1/375)   
-[肉饼老师主讲](http://www.taikr.com/my/course/972)  
-[官剑铭主讲](https://edu.manew.com/course/796)  
-[ET新手教程-初见主讲](https://pan.baidu.com/s/1a5-j2R5QctZpC9n3sMC9QQ) 密码: ru1j  
-[ET新手教程新版-初见主讲](https://www.bilibili.com/video/av33280463/?redirectFrom=h5)  
-[ET在Mac上运行指南-L主讲](https://pan.baidu.com/s/1VUQbdd1Yio7ULFXwAv7X7A) 密码: l3e3  
-[ET框架系列教程-烟雨主讲-6.0版本](https://space.bilibili.com/33595745/favlist?fid=759596845&ftype=create)  
-
-.net core 游戏资源分享  
-[各种dotnet core项目收集](https://github.com/thangchung/awesome-dotnet-core)  
-
-__讨论QQ群 : 474643097__
-
-
-# 支付宝捐赠  
-![使用支付宝对该项目进行捐赠](https://github.com/egametang/ET/blob/master/Book/donate.png)
-
-# 友情链接  
-[Box2DSharp](https://github.com/Zonciu/Box2DSharp)  box2d的C#移植版,性能很强  
-[xasset](https://github.com/xasset/xasset) 致力于为 Unity 项目提供了一套 精简稳健 的资源管理环境  
+Related websites :  
+[ET Forum](https://et-framework.cn)  
+
+Groupies share.  
+[Behavior tree and fgui branching (developed and maintained by Duke Chiang)](https://github.com/DukeChiang/ET.git)   
+[ET Learning Notes Series (written by Smoke and Rain Daze Half World Gothic)](https://www.lfzxb.top/)   
+[ET Learning Notes Series (written by Saki Yoshi)](https://acgmart.com/unity/)   
+[Framework server-side operation process](http://www.cnblogs.com/fancybit/p/et1.html)  
+[ET startup configuration](http://www.cnblogs.com/fancybit/p/et2.html)  
+[framework demo introduction](http://www.jianshu.com/p/f2ea0d26c7c1)  
+[linux deployment](http://gad.qq.com/article/detail/35973)  
+[linux deployment, mongo installation, resource service build](http://www.tinkingli.com/?p=25)  
+[ET Framework heartbeat package component development](http://www.tinkingli.com/?p=111)  
+[ET Framework Actor use and insights](http://www.tinkingli.com/?p=117)  
+[ET Framework and UGUI based on a simple UI framework implementation (gradually write)](http://www.tinkingli.com/?p=124)  
+[ET framework notes (laugh at the world to write)](http://www.tinkingli.com/?p=76)  
+[ET framework how to develop with MAC](http://www.tinkingli.com/?p=147)  
+[ET's dynamic addition of events and trigger components](http://www.tinkingli.com/?p=145)  
+
+Commercial projects :  
+1. [A Thousand Times the Wind](https://www.qiangu.com/)  
+2. [Magic Dots 2](https://www.taptap.com/app/227804)  
+3. [Raise not big](https://www.taptap.com/app/71064)  
+4. [Tian Tian Tian Hide-and-Seek 2](ios2019 Spring Festival Download Ranking 19)  
+5. [Niuhu chess](https://gitee.com/ECPS_admin/PlanB)  
+6. [Five Star Mahjong](https://github.com/wufanjoin/fivestar)  
+
+Groupies demos.  
+1. [Landlord (client-side server)](https://github.com/Viagi/LandlordsCore)  
+2. [Backpack system](https://gitee.com/ECPS_admin/planc)  
+3. [ET mini-game collection](https://github.com/Acgmart/ET-MultiplyDemos)  
+
+
+
+Video tutorials.  
+[Alphabet Brother ET 6.0 Tutorial](https://edu.uwa4d.com/course-intro/1/375)   
+[Meatloaf Teacher Lecture](http://www.taikr.com/my/course/972)  
+[Jianming Guan Lecture](https://edu.manew.com/course/796)  
+[ET Newbie Tutorial - First Look Main Lecture](https://pan.baidu.com/s/1a5-j2R5QctZpC9n3sMC9QQ) Password: ru1j  
+[ET Tutorial for Beginners New Version-Hatsumi Main Lecture](https://www.bilibili.com/video/av33280463/?redirectFrom=h5)  
+[ET Running Guide on Mac-L Main Lecture](https://pan.baidu.com/s/1VUQbdd1Yio7ULFXwAv7X7A) Password: l3e3  
+[ET Framework Tutorial Series - Smoky Rain - Version 6.0](https://space.bilibili.com/33595745/favlist?fid=759596845&ftype=create)  
+
+net core game resources to share  
+[various dotnet core project collection](https://github.com/thangchung/awesome-dotnet-core)  
+
+__discussion QQ group : 474643097__
+
+
+# Paypal donation  
+! [Use Alipay to donate to this project](https://github.com/egametang/ET/blob/master/Book/donate.png)
+
+# Links  
+[Box2DSharp](https://github.com/Zonciu/Box2DSharp) box2d's C# port version, very strong performance  
+[xasset](https://github.com/xasset/xasset) Dedicated to providing a lean and robust resource management environment for Unity projects  
 [QFramework](https://github.com/liangxiegame/QFramework) Your first K.I.S.S Unity3d Framework  
-[ET UI框架](https://github.com/zzjfengqing/ET-EUI) 字母哥实现的UI框架,ET风格,各种事件分发  
-[ETCsharpToXLua](https://github.com/zzjfengqing/ETCsharpToXLua) 字母哥使用csharp.lua实现的ET客户端热更新  
-[et-6-with-ilruntime](https://www.lfzxb.top/et-6-with-ilruntime) 烟雨使用ILRuntime实现的ET客户端热更新  
-[Luban](https://github.com/focus-creative-games/luban) 适用于大中型项目的游戏配置解决方案  
+[ET UI Framework](https://github.com/zzjfengqing/ET-EUI) alphabetical implementation of the UI framework, ET style, a variety of event distribution  
+[ETCsharpToXLua](https://github.com/zzjfengqing/ETCsharpToXLua) Alphabet Brother uses csharp.lua to implement the ET client hot update  
+[et-6-with-ilruntime](https://www.lfzxb.top/et-6-with-ilruntime) Smokey uses ILRuntime to implement the ET client hot update  
+[Luban](https://github.com/focus-creative-games/luban) A game configuration solution for medium and large projects