Skip to content

Commit 790b093

Browse files
committed
Init Project
1 parent dbb83c2 commit 790b093

File tree

1,310 files changed

+138408
-0
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

1,310 files changed

+138408
-0
lines changed

.gitattributes

+63
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
###############################################################################
2+
# Set default behavior to automatically normalize line endings.
3+
###############################################################################
4+
* text=auto
5+
6+
###############################################################################
7+
# Set default behavior for command prompt diff.
8+
#
9+
# This is need for earlier builds of msysgit that does not have it on by
10+
# default for csharp files.
11+
# Note: This is only used by command line
12+
###############################################################################
13+
#*.cs diff=csharp
14+
15+
###############################################################################
16+
# Set the merge driver for project and solution files
17+
#
18+
# Merging from the command prompt will add diff markers to the files if there
19+
# are conflicts (Merging from VS is not affected by the settings below, in VS
20+
# the diff markers are never inserted). Diff markers may cause the following
21+
# file extensions to fail to load in VS. An alternative would be to treat
22+
# these files as binary and thus will always conflict and require user
23+
# intervention with every merge. To do so, just uncomment the entries below
24+
###############################################################################
25+
#*.sln merge=binary
26+
#*.csproj merge=binary
27+
#*.vbproj merge=binary
28+
#*.vcxproj merge=binary
29+
#*.vcproj merge=binary
30+
#*.dbproj merge=binary
31+
#*.fsproj merge=binary
32+
#*.lsproj merge=binary
33+
#*.wixproj merge=binary
34+
#*.modelproj merge=binary
35+
#*.sqlproj merge=binary
36+
#*.wwaproj merge=binary
37+
38+
###############################################################################
39+
# behavior for image files
40+
#
41+
# image files are treated as binary by default.
42+
###############################################################################
43+
#*.jpg binary
44+
#*.png binary
45+
#*.gif binary
46+
47+
###############################################################################
48+
# diff behavior for common document formats
49+
#
50+
# Convert binary document formats to text before diffing them. This feature
51+
# is only available from the command line. Turn it on by uncommenting the
52+
# entries below.
53+
###############################################################################
54+
#*.doc diff=astextplain
55+
#*.DOC diff=astextplain
56+
#*.docx diff=astextplain
57+
#*.DOCX diff=astextplain
58+
#*.dot diff=astextplain
59+
#*.DOT diff=astextplain
60+
#*.pdf diff=astextplain
61+
#*.PDF diff=astextplain
62+
#*.rtf diff=astextplain
63+
#*.RTF diff=astextplain

.gitignore

+58
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
.cproject
2+
.project
3+
.pydevproject
4+
.sconsign.dblite
5+
6+
*.pyc
7+
*.suo
8+
9+
.settings/
10+
.localhistory/
11+
Dbg/
12+
Opt/
13+
14+
*/Temp/
15+
*/TestResults/
16+
17+
*/.svn/
18+
.svn/
19+
bin/
20+
Bin/
21+
obj/
22+
_ReSharper.CSharp/
23+
*.opensdf
24+
*.sdf
25+
/CSharp/CSharp.sln.ide
26+
/Unity/Library
27+
/Unity/CSharp60Support/compilation log.txt
28+
/CSharp/CSharp.VC.opendb
29+
/Server/Server.VC.opendb
30+
/Log
31+
/Temp
32+
/Logs
33+
/Unity/CSharp60Support/compilation.log
34+
/.vs
35+
/Server/.vs/
36+
/Unity/.vs/
37+
/Tools/MongoDB
38+
/Excel/md5.txt
39+
/Release
40+
.idea/
41+
/Unity/Logs
42+
/Unity/Assets/StreamingAssets/
43+
/netcoreapp2.0
44+
/Unity/Assets/StreamingAssets.meta
45+
.DS_Store
46+
Server/.DS_Store
47+
/Server/.vscode/
48+
.vs/
49+
.objs/
50+
/Unity/.gradle
51+
/*.user
52+
/ToolsApp/
53+
/Unity/Unity.Editor.csproj
54+
/Unity/Unity.Hotfix.csproj
55+
/Unity/Unity.HotfixView.csproj
56+
/Unity/Unity.Model.csproj
57+
/Unity/Unity.ModelView.csproj
58+
/Unity/Unity.ThirdParty.csproj

Book/1.1运行指南.md

+41
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
# 运行步骤
2+
1. visual studio必须使用vs2019(更新到最新版), VS2019需要勾选安装以下内容:
3+
- .net 桌面开发
4+
- 去net core官网下载安装 .net5
5+
6+
2. master分支需要unity2020.3版(用到了C#8的语法)
7+
8+
3. 启动Unity, 菜单 File -> Open Project... -> Open 选中ET/Unity文件夹,点击选择文件夹按钮。
9+
10+
4. 点击Unity菜单 Assets -> Open C# Project 启动vs编译
11+
12+
5. 用vs2019打开 ET/Client-Server.sln 编译(**一定要全部工程编译,右键VS解决方案,全部编译**
13+
14+
6. 导表工具,编译完成后命令行进入 Bin 目录,执行 dotnet Server.dll --AppType=ExcelExporter
15+
16+
7. 导出协议工具,编译完成后进入 Bin 目录,执行 dotnet Server.dll --AppType=Proto2CS
17+
# 测试状态同步demo
18+
19+
> 帧同步demo已经删除,需要的话请看ET4.0分支
20+
21+
1. 想修改配置就进入 Excel 目录修改对应的表格,做运行步骤的第6步,然后重新运行 Server.App工程来启动服务端。
22+
23+
2. Unity->tools菜单->打包工具,选择PC,勾选是否打包exe,点击开始打包,打出一个PC包在Release目录下
24+
25+
4. 运行Unity 登录 进入大厅 进入场景
26+
27+
5. 运行PC包 登录 进入大厅
28+
29+
6. 点击鼠标右键即可移动人物
30+
31+
# 注意事项:
32+
33+
一. 出错原因都是:
34+
35+
1. 中文目录。
36+
2. vs没有安装vs相关组件
37+
3. 没安装 .net5
38+
4. 没编译服务端所有工程
39+
5. VS要更新到最新版本
40+
6. Unity版本太低
41+

Book/1.2为什么使用.net core.md

+58
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
# 为什么使用C# .net core做服务端?
2+
游戏服务端从早期的单服到分布式,开发越来越复杂,对稳定性,开发效率要求越来越高。开发语言的选择也逐步发生了变化,C 到 C++ 到 C++ + PYTHON 或者C++ + LUA 到现在 很多公司开始使用erlang,go,java,c#。目前是一个百花齐放的局面。
3+
4+
但是如果是要你重新做一个网游server,不考虑对公司或者已有的东西兼容性,你会怎么选择?我仔细想了一下这个问题,大概有这个几个方面需要考虑:
5+
6+
###### 1. 语言的稳定性(致命性)
7+
游戏服务器的特点是高负载低延时。所以一般服务端进程都是带状态的,一旦挂掉就意味着数据丢失,这点是无法容忍的。
8+
9+
###### 2. 运行时热更(致命性)
10+
游戏服务器逻辑极其复杂,很容易出现bug,但是又不能经常停服,所以热更修复bug就显得十分必要。出现错误开发人员可以立即编写代码,然后热更修复,线上用户完全感觉不到。
11+
12+
###### 3. 是否有协程支持(重要性5星)
13+
分布式服务器架构,进程与进程之间必然会有大量交互。由于游戏逻辑很难拆分成多线程,所以一般来说都是逻辑单线程。如果没有协程支持,必然产生大量回调,代码维护会变得非常困难。
14+
15+
###### 4. 编译速度(重要性5星)
16+
使用c++开发,30%的时间都浪费在编译上。假如编译很快或者不需要编译,必定大大提高开发效率。
17+
18+
###### 5. 跨平台(4星)
19+
一般游戏服务器都架设在linux上面。但是平常开发,使用windows会更加方便,如果跨平台,开发以及测试效率会大大提升,并且不需要单独搞一个开发机,本机电脑就可以满足平常开发
20+
21+
###### 6. 可阅读性,可重构性(3星)
22+
代码可以重构能大大减轻写代码的难度
23+
24+
###### 7. 库是否齐全,生态是否完善(3星)
25+
库齐全,生态好,自己需要造的轮子就少
26+
27+
###### 8.跟客户端统一语言(3星)
28+
客户端服务端共用语言,优势十分明显,很多代码可以复用,逻辑程序员不再需要区分前后端,双端都可以写,一个人即可完成一个功能,大大减少了沟通的时间成本。
29+
30+
###### 9. IDE的支持(3星)
31+
代码提示,重构等支持,优秀的IDE能提高几倍的开发效率。
32+
33+
###### 10. 语言的性能(1星)
34+
目前服务器性能都不是太大问题,不过性能好总比性能差要强。
35+
36+
| 语言 | C# | C/C++ | Java | Go | Lua | Python | Erlang |
37+
| -- | :--: | :--: | :--: | :--: | :--: | :--: | :--: |
38+
| 稳定性 | 稳定 | 容易挂 | 稳定 | 稳定 | 稳定 | 稳定 | 稳定 |
39+
| 运行时热更 | 支持 | 较难支持 | 支持 | 不支持 | 支持 | 支持 | 支持 |
40+
| 跨平台 | 支持 | 较难支持 | 支持 | 支持 | 较难支持 | 支持 | 支持 |
41+
| 协程 || 需要自己实现 | 支持不好 | 支持 | 支持 | 支持 | 支持 |
42+
| 编译速度 ||||| 不需要编译 | 不需要编译 | 不需要编译|
43+
| 阅读性重构性 || 一般 || 一般 ||||
44+
| 游戏库跟生态 ||| 一般 | 一般 ||| 一般|
45+
| 客户端统一语言 | Unity | Unity、UE4 | 暂无 | 暂无 | Unity、UE4 | UE4 | 暂无|
46+
| IDE的支持 |||| 普通||||
47+
| 语言的性能 ||极好||||很差||
48+
49+
从表格可以看出:
50+
1. C/C++稳定性差,编译速度慢,存在致命缺陷
51+
2. Go不支持热更,由于不支持泛型,重构性较差,无法跟客户端共享代码,存在致命缺陷
52+
3. Java协程支持差,无法跟客户端共享代码
53+
4. Lua库少,性能差,代码可阅读性可重构性差,跨平台完全依赖C/C++,处理起来麻烦,ide支持差
54+
5. Python 性能很差,代码可阅读性可重构性差,无法跟客户端共享代码,ide支持差
55+
6. Erlang 性能差,函数式风格不好上手,ide支持差
56+
7. C# .net core各个方便都非常优秀,不过跟UE4无法共享代码
57+
58+
当前Unity是最火的游戏引擎,C#服务端搭配Unity完全是天作之合,基本上找不到缺陷。

Book/2.1CSharp的协程.md

+119
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
# 什么是协程
2+
说到协程,我们先了解什么是异步,异步简单说来就是,我要发起一个调用,但是这个被调用方(可能是其它线程,也可能是IO)出结果需要一段时间,我不想让这个调用阻塞住调用方的整个线程,因此传给被调用方一个回调函数,被调用方运行完成后回调这个回调函数就能通知调用方继续往下执行。举个例子:
3+
下面的代码,主线程一直循环,每循环一次sleep 1毫秒,计数加一,每10000次打印一次。
4+
5+
```csharp
6+
private static void Main()
7+
{
8+
int loopCount = 0;
9+
while (true)
10+
{
11+
int temp = watcherValue;
12+
13+
Thread.Sleep(1);
14+
15+
++loopCount;
16+
if (loopCount % 10000 == 0)
17+
{
18+
Console.WriteLine($"loop count: {loopCount}");
19+
}
20+
}
21+
}
22+
```
23+
这时我需要加个功能,在程序一开始,我希望在5秒钟之后打印出loopCount的值。看到5秒后我们可以想到Sleep方法,它会阻塞线程一定时间然后继续执行。我们显然不能在主线程中Sleep,因为会破坏掉每10000次计数打印一次的逻辑。
24+
```csharp
25+
// example2_1
26+
class Program
27+
{
28+
private static int loopCount = 0;
29+
30+
private static void Main()
31+
{
32+
OneThreadSynchronizationContext _ = OneThreadSynchronizationContext.Instance;
33+
34+
WaitTimeAsync(5000, WaitTimeFinishCallback);
35+
36+
while (true)
37+
{
38+
OneThreadSynchronizationContext.Instance.Update();
39+
40+
Thread.Sleep(1);
41+
42+
++loopCount;
43+
if (loopCount % 10000 == 0)
44+
{
45+
Console.WriteLine($"loop count: {loopCount}");
46+
}
47+
}
48+
}
49+
50+
private static void WaitTimeAsync(int waitTime, Action action)
51+
{
52+
Thread thread = new Thread(()=>WaitTime(waitTime, action));
53+
thread.Start();
54+
}
55+
56+
private static void WaitTimeFinishCallback()
57+
{
58+
Console.WriteLine($"WaitTimeAsync finsih loopCount的值是: {loopCount}");
59+
}
60+
61+
/// <summary>
62+
/// 在另外的线程等待
63+
/// </summary>
64+
private static void WaitTime(int waitTime, Action action)
65+
{
66+
Thread.Sleep(waitTime);
67+
68+
// 将action扔回主线程执行
69+
OneThreadSynchronizationContext.Instance.Post((o)=>action(), null);
70+
}
71+
}
72+
```
73+
我们在这里设计了一个WaitTimeAsync方法,WaitTimeAsync其实就是一个典型的异步方法,它从主线程发起调用,传入了一个WaitTimeFinishCallback回调方法做参数,开启了一个线程,线程Sleep一定时间后,将传过来的回调扔回到主线程执行。OneThreadSynchronizationContext是一个跨线程队列,任何线程可以往里面扔委托,OneThreadSynchronizationContext的Update方法在主线程中调用,会将这些委托取出来放到主线程执行。为什么回调方法需要扔回到主线程执行呢?因为回调方法中读取了loopCount,loopCount在主线程中也有读写,所以要么加锁,要么永远保证只在主线程中读写。加锁是个不好的做法,代码中到处是锁会导致阅读跟维护困难,很容易产生多线程bug。这种将逻辑打包成委托然后扔回另外一个线程是多线程开发中常用的技巧。
74+
75+
我们可能又有个新需求,WaitTimeFinishCallback执行完成之后,再想等3秒,再打印一下loopCount。
76+
```csharp
77+
private static void WaitTimeAsync(int waitTime, Action action)
78+
{
79+
Thread thread = new Thread(()=>WaitTime(waitTime, action));
80+
thread.Start();
81+
}
82+
private static void WaitTimeFinishCallback()
83+
{
84+
Console.WriteLine($"WaitTimeAsync finsih loopCount的值是: {loopCount}");
85+
WaitTimeAsync(3000, WaitTimeFinishCallback2);
86+
}
87+
88+
private static void WaitTimeFinishCallback2()
89+
{
90+
Console.WriteLine($"WaitTimeAsync finsih loopCount的值是: {loopCount}");
91+
}
92+
```
93+
我们这时还可能改需求,需要在程序启动5秒后,接下来4秒,再接下来3秒,打印loopCount,也就是上面的逻辑中间再插入一个3秒等待。
94+
```csharp
95+
private static void WaitTimeAsync(int waitTime, Action action)
96+
{
97+
Thread thread = new Thread(()=>WaitTime(waitTime, action));
98+
thread.Start();
99+
}
100+
101+
private static void WaitTimeFinishCallback()
102+
{
103+
Console.WriteLine($"WaitTimeAsync finsih loopCount的值是: {loopCount}");
104+
WaitTimeAsync(4000, WaitTimeFinishCallback3);
105+
}
106+
107+
private static void WaitTimeFinishCallback3()
108+
{
109+
Console.WriteLine($"WaitTimeAsync finsih loopCount的值是: {loopCount}");
110+
WaitTimeAsync(3000, WaitTimeFinishCallback2);
111+
}
112+
113+
private static void WaitTimeFinishCallback2()
114+
{
115+
Console.WriteLine($"WaitTimeAsync finsih loopCount的值是: {loopCount}");
116+
}
117+
```
118+
这样中间插入一段代码,显得非常麻烦。这里可以回答什么是协程了,其实这一串串回调就是协程。
119+

0 commit comments

Comments
 (0)