Development/zh: Difference between revisions

From DDraceNetwork
(Created page with "* 变量命名有三个部分:修饰和前缀、名字。 * 变量命名应该以大写字母开始,除非是单字符例如:<code>i</code>,<code>x</code>,<code>y</code>。 * 变量可以有多于一个的修饰或前缀,也可以没有。")
(修复命令)
(25 intermediate revisions by 2 users not shown)
Line 1: Line 1:
{{MigrateTranslation}}
{{MigrateTranslation}}
<languages/>
<languages/>
本文皆在教您如何对 DDNet '''''开发''''' ,因为这是一款开源游戏(源代码公开),它依赖于一些善良的人们在空余时间的贡献。
本文皆在教您如何对 DDNet '''开发''' ,因为这是一款开源游戏(源代码公开),它依赖于一些善良的人们在空余时间的贡献。




Line 21: Line 21:
DDNet的源代码使用[https://git-scm.com/ Git]托管,这是一个版本控制系统,也是与多人协作开发的重要工具。
DDNet的源代码使用[https://git-scm.com/ Git]托管,这是一个版本控制系统,也是与多人协作开发的重要工具。


如果您的Linux发行版中还没有git,请安装它,例如在大多数基于debian/ubuntu的发行版中,您可以打开终端,输入:<code>sudo-apt-install git</code>。
如果您的Linux发行版中还没有git,请安装它,例如在大多数基于debian/ubuntu的发行版中,您可以打开终端,输入:<code>sudo apt install git</code>。




Line 36: Line 36:
== 安装依赖项 ==
== 安装依赖项 ==


如果您在Linux上,您可以通过阅读DDNet github页面上的自述文件来安装所有需要的依赖项:https://github.com/ddnet/ddnet#dependencies-在linux上--macos
如果您在Linux上,您可以通过阅读DDNet github页面上的自述文件来安装所有需要的依赖项:https://github.com/ddnet/ddnet#dependencies-on-linux--macos


对于Arch Linux:
对于Arch Linux:
Line 187: Line 187:
* 变量可以有多于一个的修饰或前缀,也可以没有。
* 变量可以有多于一个的修饰或前缀,也可以没有。


<div lang="en" dir="ltr" class="mw-content-ltr">
排列方式:<code>[修饰]_[前缀][名字]</code>
These are laid out like this: <code>[qualifiers]_[prefixes][Name]</code>
</div>




<div lang="en" dir="ltr" class="mw-content-ltr">
<span id="Qualifiers"></span>
==== Qualifiers ====
==== 修饰 ====
</div>


<div lang="en" dir="ltr" class="mw-content-ltr">
* 成员变量<code>m</code><code>m_MyVariable</code>
* <code>m</code> for member variables: <code>m_MyVariable</code>.
* 静态变量<code>s</code><code>s_MyStaticVariable</code><code>ms_MyStaticMemberVariable</code>
* <code>s</code> for static variables: <code>s_MyStaticVariable</code>, <code>ms_MyStaticMemberVariable</code>.
* 带外部连接的全局变量<code>g</code><code>gs_MyGlobalStaticVar</code>
* <code>g</code> for global variables with external linkage: <code>gs_MyGlobalStaticVar</code>.
</div>




<div lang="en" dir="ltr" class="mw-content-ltr">
<span id="Prefixes"></span>
==== Prefixes ====
==== 前缀 ====
</div>


<div lang="en" dir="ltr" class="mw-content-ltr">
* 指针前缀<code>p</code><code>pMyPointer</code><code>m_pCharacter</code><code>ppMyPointerToPointer</code>
* <code>p</code> for pointers: <code>pMyPointer</code>, <code>m_pCharacter</code>, <code>ppMyPointerToPointer</code>.
* 数组前缀<code>a</code><code>aMyArray</code><code>aBuf</code>
* <code>a</code> for arrays: <code>aMyArray</code>, <code>aBuf</code>.
* 容器(<code>std::vector</code>)前缀<code>v</code><code>vMyVector</code><code>vpvMyVectorOfPointersToVectors</code>
* <code>v</code> for <code>std::vector</code>s: <code>vMyVector</code>, <code>vpvMyVectorOfPointersToVectors</code>.
* 函数前缀<code>fn</code><code>pfnMyCallback</code><code>m_papfnMyPointerToArrayOfCallbacks</code>
* <code>fn</code> for functions: <code>pfnMyCallback</code>, <code>m_papfnMyPointerToArrayOfCallbacks</code>.
</div>




<div lang="en" dir="ltr" class="mw-content-ltr">
<span id="Common_snippets"></span>
== Common snippets ==
== 常用片段 ==
</div>


<div lang="en" dir="ltr" class="mw-content-ltr">
下面列出经常出现在代码库的代码:
Here is a list of code that you may frequently see across the codebase:
</div>




<div lang="en" dir="ltr" class="mw-content-ltr">
<span id="Formatting_text"></span>
=== Formatting text ===
=== 格式文本 ===
</div>


<div lang="en" dir="ltr" class="mw-content-ltr">
<syntaxhighlight lang="cpp">
<syntaxhighlight lang="cpp">
char aBuf[128];
char aBuf[128];
str_format(aBuf, sizeof(aBuf), "number: %d", 2);
str_format(aBuf, sizeof(aBuf), "number: %d", 2);
</syntaxhighlight>
</syntaxhighlight>
</div>


<div lang="en" dir="ltr" class="mw-content-ltr">
参阅[https://cplusplus.com/reference/cstdio/printf/ printf 文档]查看格式提示符列表。
See [https://cplusplus.com/reference/cstdio/printf/ printf documentation] for a list of all format specifiers.
 
=== Iterating over all players ===
=== 迭代玩家数组 ===
</div>


<div lang="en" dir="ltr" class="mw-content-ltr">
<syntaxhighlight lang="cpp">
<syntaxhighlight lang="cpp">
for(int i = 0; i < MAX_CLIENTS; i++)
for(int i = 0; i < MAX_CLIENTS; i++)
Line 248: Line 232:
}
}
</syntaxhighlight>
</syntaxhighlight>
</div>




<div lang="en" dir="ltr" class="mw-content-ltr">
<span id="Printing_to_the_game_console"></span>
=== Printing to the game console ===
=== 输出到游戏控制台 ===
</div>


<div lang="en" dir="ltr" class="mw-content-ltr">
<syntaxhighlight lang="cpp">
<syntaxhighlight lang="cpp">
Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "wikiprint", "Hello from the ddnet wiki!");
Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "wikiprint", "Hello from the ddnet wiki!");
</syntaxhighlight>
</syntaxhighlight>
</div>






<div lang="en" dir="ltr" class="mw-content-ltr">
<span id="Debug_printing"></span>
=== Debug printing ===
=== 调试输出 ===
</div>


<div lang="en" dir="ltr" class="mw-content-ltr">
<syntaxhighlight lang="cpp">
<syntaxhighlight lang="cpp">
int i = 2;
int i = 2;
dbg_msg("wikiprint", "Hello from the ddnet wiki: %d", i);
dbg_msg("wikiprint", "Hello from the ddnet wiki: %d", i);
</syntaxhighlight>
</syntaxhighlight>
</div>


<div lang="en" dir="ltr" class="mw-content-ltr">
=== 在客户端翻译文本 ===
=== Translating text in the client ===
<code>Localize</code> 用于在游戏客户端从用户选定的语言文件中获取特定字串的翻译。<syntaxhighlight lang="cpp">
<code>Localize</code> can be used in the game client to get the translation for a specific string from the language file selected by the user.<syntaxhighlight lang="cpp">
DoButton(..., Localize("Connect"), ...);
DoButton(..., Localize("Connect"), ...);
</syntaxhighlight>The string can also contain format specifiers. The translated string must contain the same format specifiers.<syntaxhighlight lang="cpp">
</syntaxhighlight>字符串可以包含格式说明符,翻译文本必须包含同样的格式说明符(这可能产生某些排序不一致的问题)。<syntaxhighlight lang="cpp">
char aBuf[128];
char aBuf[128];
str_format(aBuf, sizeof(aBuf), Localize("%d of %d servers"), NumServers, TotalServers);
str_format(aBuf, sizeof(aBuf), Localize("%d of %d servers"), NumServers, TotalServers);
</syntaxhighlight>A script is used to scan the code for calls to <code>Localize</code> and collect the strings to update the translation files. For this reason, the call to <code>Localize</code> must not contain any other code, or the script cannot determine the text correctly.<syntaxhighlight lang="cpp">
</syntaxhighlight>在调用<code>Localize</code>时依靠一个脚本来扫描识别调用代码,然后收集字符串上传翻译文件。由于此原因,调用<code>Localize</code> 不能包含任何其他代码,否则脚本无法正确识别文本。<syntaxhighlight lang="cpp">
// Do NOT do this:
// 请勿这样做:
const char *pStr = Localize(Team == TEAM_RED ? "Red team" : "Blue team");
const char *pStr = Localize(Team == TEAM_RED ? "Red team" : "Blue team");
</div>


<div lang="en" dir="ltr" class="mw-content-ltr">
// 应该这样做:
// Do this instead:
const char *pStr = Team == TEAM_RED ? Localize("Red team") : Localize("Blue team");
const char *pStr = Team == TEAM_RED ? Localize("Red team") : Localize("Blue team");
</syntaxhighlight>
</syntaxhighlight>
</div>


<div lang="en" dir="ltr" class="mw-content-ltr">
<span id="External_resources"></span>
== External resources ==
== 外部资料 ==
</div>
 
* [[Special:MyLanguage/User:Ryozuki|Ryozuki]]:[https://edgarluque.com/blog/ui-code-ddnet/ UI Code in DDraceNetwork]。
* [[Special:MyLanguage/User:Ryozuki|Ryozuki]]:[https://edgarluque.com/blog/intro-to-ddnet/ An intro to the DDraceNetwork game source code]。
* [[Special:MyLanguage/User:Ryozuki|Ryozuki]]:[https://edgarluque.com/blog/code-conventions-in-ddnet/ Code conventions in DDraceNetwork]。
* [[Special:MyLanguage/User:Ryozuki|Ryozuki]]:[https://edgarluque.com/blog/chat-command-ddracenetwork/ Implementing a chat command in DDraceNetwork]。
* [https://codedoc.ddnet.org/ Auto generated docs]。
* [https://ddnet.org/libtw2-doc/ Technical documentation of Teeworlds file formats and network protocol]。
* [https://heinrich5991.github.io/blog/blog/one-tick-unfreeze The Anatomy of a One Tick Unfreeze]。
* ChillerDragon:[https://www.youtube.com/playlist?list=PLhJkqAQmOh5LyYOfnMy4PJB6CSZltQyTc Teeworlds programming YouTube tutorial]。
 
<span id="About_Tee_Skin_Rendering"></span>
== 关于提交皮肤 ==
 
此部分介绍如何提交皮肤。


<div lang="en" dir="ltr" class="mw-content-ltr">
由 Patiga 提供的各种参数值
* [https://edgarluque.com/blog/ui-code-ddnet/ UI Code in DDraceNetwork] by [[Special:MyLanguage/User:Ryozuki|Ryozuki]]
特别鸣谢 Jupstar
* [https://edgarluque.com/blog/intro-to-ddnet/ An intro to the DDraceNetwork game source code] by [[Special:MyLanguage/User:Ryozuki|Ryozuki]]
* [https://edgarluque.com/blog/code-conventions-in-ddnet/ Code conventions in DDraceNetwork]  by [[Special:MyLanguage/User:Ryozuki|Ryozuki]]
各部分缩放比例:
* [https://edgarluque.com/blog/chat-command-ddracenetwork/ Implementing a chat command in DDraceNetwork]  by [[Special:MyLanguage/User:Ryozuki|Ryozuki]]
    身体-body: 100%
* [https://codedoc.ddnet.org/ Auto generated docs]
    脚脚-feet: 150%
* [https://ddnet.org/libtw2-doc/ Technical documentation of Teeworlds file formats and network protocol]
    眼睛-eyes: 120%
* [https://heinrich5991.github.io/blog/blog/one-tick-unfreeze The Anatomy of a One Tick Unfreeze]
    眨眼-eye blink: 45%
* [https://www.youtube.com/playlist?list=PLhJkqAQmOh5LyYOfnMy4PJB6CSZltQyTc Teeworlds programming YouTube tutorial] by ChillerDragon
    手手-hand: 93.75%
</div>
   
位置:
    64/64 = 1 = 身体部分的宽高比
    下面给出各部分与边缘距离占总宽或者高的比值
    身体-body: 4/64 上边缘
    脚脚-feet:
        10/64 下边缘
        7/64 左右边缘
    眼睛初始位置:
        0.125 上边缘
        0.05 左右边缘
    眼动范围-eye movement:
        设 dir = 眼睛角度 (辅助线角度), right = 0
        眼睛偏移坐标:
            x: cos(dir) * 0.125
            y: sin(dir) * 0.1
        眼间距:
            x: abs(cos(dir)) * 0.01

Revision as of 14:23, 6 March 2024

本文皆在教您如何對 DDNet 開發 ,因為這是一款開源遊戲(原始碼公開),它依賴於一些善良的人們在空餘時間的貢獻。


開發環境

截至目前,基於以下原因,我們強烈推薦使用Linux系統進行DDNet開發:

  • 大多數DDNet貢獻者使用Linux,使用Linux與之前的開發者交流起來更加方便。
  • 軟體包管理更簡單,您可以輕鬆地安裝所有需要的庫。
  • 本文專注於Linux,還沒有涉及Windows。

首先,DDNet由 C++ 語言編寫,開發者需要對它相當熟悉,但您也可以在只有基礎知識的情況下慢慢學習深入。

學習C++的一些有用資源:

DDNet的原始碼使用Git託管,這是一個版本控制系統,也是與多人協作開發的重要工具。

如果您的Linux發行版中還沒有git,請安裝它,例如在大多數基於debian/ubuntu的發行版中,您可以打開終端,輸入:sudo apt install git


獲取原始碼

原始碼位於Github,您沒有帳戶的情況下可以通過Clone獲得原始碼,但如果想更改官方原始碼,則需要登錄帳號。

如果您不熟悉git/github,可以在這裡學習基礎知識: Hello World - Github


安裝依賴項

如果您在Linux上,您可以通過閱讀DDNet github頁面上的自述文件來安裝所有需要的依賴項:https://github.com/ddnet/ddnet#dependencies-on-linux--macos

對於Arch Linux:

控制台輸入 sudo pacman -S --needed base-devel cmake curl ffmpeg freetype2 git glew glslang gmock libnotify libpng opusfile python rust sdl2 spirv-tools sqlite vulkan-headers vulkan-icd-loader wavpack x264

對於Debian:

控制台輸入 sudo apt install build-essential cargo cmake git glslang-tools google-mock libavcodec-extra libavdevice-dev libavfilter-dev libavformat-dev libavutil-dev libcurl4-openssl-dev libfreetype6-dev libglew-dev libnotify-dev libogg-dev libopus-dev libopusfile-dev libpng-dev libsdl2-dev libsqlite3-dev libssl-dev libvulkan-dev libwavpack-dev libx264-dev python rustc spirv-tools4

編譯DDNet

我們使用CMake來控制編譯進程,如果你安裝完成所有的依賴項,之後只需要簡單輸入這些命令(確保你在DDNet文件夾下):

mkdir build
cd build
cmake ..
make -j$(nproc)


基本信息

以下是一些基本信息:

  • 目前,原始碼是使用C++17標準編譯的,但您會看到代碼的許多部分更像C,因為只有大多數新代碼使用C++17。
  • std::string很少使用,字符數組加system.h方法才是常態。
  • 大多數輸入輸出代碼、格式化和Print都是使用system.h提供的方法完成的。


原始碼布局

現在你可以構建DDNet並開始編輯它了。


src/base 目錄

由於DDNet是一個跨平台遊戲,需要一個抽象層來簡化開發,因此該目錄包含許多有用的函數來處理這一問題。


src/engine 目錄

遊戲引擎所在位置,它處理大多數與玩法無關的東西,比如圖形、聲音、網絡等。


src/game 目錄

所有玩法的代碼所在位置,分為客戶端和伺服器。


伺服器端

這個遊戲使用自己的面向對象的實體分級系統,所有其他實體源於主類CEntity,位於src/game/server/e ntity.h目錄。

遊戲世界在src/game/server/gameworld.h路徑下,管理這些實體。

一些重要實體有:

  • CCharacter: 代表一個活著的Tee , 當一個Tee生成時會被實例化,當它死亡時會被刪除。有關玩家在死亡之間的信息,請參閱CPlayer


客戶端

客戶端由許多組件構成,都是繼承CComponent的類:這些組件通過實現視覺方法來提供功能,例如OnInitOnMessage等等。


網絡

網絡協議幾乎由python腳本生成並輸出c++代碼,例如說,datasrc/network.py定義了所有網絡包。


代碼規範

代碼規範的討論還在持續:ddnet#2945

目前已經應用了下面的部分:


縮進格式

採用Allman 風格

此風格將控制語句關聯的大括號放在下一行並且縮進到相同位置,內部語句則縮進到下一級。

while(x == y)
{
    Something();
    SomethingElse();
}

FinalThing();

類和結構體

必須帶有前綴C(由於歷史遺留原因有一些結構體沒有遵循,例如圖形代碼部分)或者代表接口的I。新的結構體需要帶前綴S

示例:

class CCharacter : public CEntity
{
    // ...
}


枚舉和常量

應該採用大蛇式命名法(所有單詞大寫並且用下劃線間隔),例如MAX_PLAYERS

enum
{
	FAKETUNE_FREEZE = 1,
	FAKETUNE_SOLO = 2,
	FAKETUNE_NOJUMP = 4,
	FAKETUNE_NOCOLL = 8,
	FAKETUNE_NOHOOK = 16,
	FAKETUNE_JETPACK = 32,
	FAKETUNE_NOHAMMER = 64,
};


變量命名

  • 變量命名有三個部分:修飾和前綴、名字。
  • 變量命名應該以大寫字母開始,除非是單字符例如:ixy
  • 變量可以有多於一個的修飾或前綴,也可以沒有。

排列方式:[修饰]_[前缀][名字]


修飾

  • 成員變量mm_MyVariable
  • 靜態變量ss_MyStaticVariablems_MyStaticMemberVariable
  • 帶外部連接的全局變量ggs_MyGlobalStaticVar


前綴

  • 指針前綴ppMyPointerm_pCharacterppMyPointerToPointer
  • 數組前綴aaMyArrayaBuf
  • 容器(std::vector)前綴vvMyVectorvpvMyVectorOfPointersToVectors
  • 函數前綴fnpfnMyCallbackm_papfnMyPointerToArrayOfCallbacks


常用片段

下面列出經常出現在代碼庫的代碼:


格式文本

char aBuf[128];
str_format(aBuf, sizeof(aBuf), "number: %d", 2);

參閱printf 文檔查看格式提示符列表。

迭代玩家數組

for(int i = 0; i < MAX_CLIENTS; i++)
{
    // Server-side
    CPlayer *pPlayer = GameServer()->m_apPlayers[i];
}


輸出到遊戲控制台

Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "wikiprint", "Hello from the ddnet wiki!");


調試輸出

int i = 2;
dbg_msg("wikiprint", "Hello from the ddnet wiki: %d", i);

在客戶端翻譯文本

Localize 用於在遊戲客戶端從用戶選定的語言文件中獲取特定字串的翻譯。

DoButton(..., Localize("Connect"), ...);

字符串可以包含格式說明符,翻譯文本必須包含同樣的格式說明符(這可能產生某些排序不一致的問題)。

char aBuf[128];
str_format(aBuf, sizeof(aBuf), Localize("%d of %d servers"), NumServers, TotalServers);

在調用Localize時依靠一個腳本來掃描識別調用代碼,然後收集字符串上傳翻譯文件。由於此原因,調用Localize 不能包含任何其他代碼,否則腳本無法正確識別文本。

// 请勿这样做:
const char *pStr = Localize(Team == TEAM_RED ? "Red team" : "Blue team");

// 应该这样做:
const char *pStr = Team == TEAM_RED ? Localize("Red team") : Localize("Blue team");

外部資料

關於提交皮膚

此部分介紹如何提交皮膚。

由 Patiga 提供的各种参数值
特别鸣谢 Jupstar

各部分缩放比例:
   身体-body: 100%
   脚脚-feet: 150%
   眼睛-eyes: 120%
   眨眼-eye blink: 45%
   手手-hand: 93.75%

位置:
   64/64 = 1 = 身体部分的宽高比
   下面给出各部分与边缘距离占总宽或者高的比值
   身体-body: 4/64 上边缘
   脚脚-feet:
       10/64 下边缘
       7/64 左右边缘
   眼睛初始位置:
       0.125 上边缘
       0.05 左右边缘

   眼动范围-eye movement:
       设 dir = 眼睛角度 (辅助线角度), right = 0
       眼睛偏移坐标:
           x: cos(dir) * 0.125
           y: sin(dir) * 0.1
       眼间距:
           x: abs(cos(dir)) * 0.01