Development: Difference between revisions
Prepared the page for translation |
Marked this version for translation |
||
Line 1: | Line 1: | ||
<languages/> | <languages/> | ||
<translate> | <translate> | ||
<!--T:1--> | |||
This article aims to introduce you into DDNet '''''development''''', since it's an open-source game, it relies on random people kind enough to contribute to it on their free time. | This article aims to introduce you into DDNet '''''development''''', since it's an open-source game, it relies on random people kind enough to contribute to it on their free time. | ||
== Your development environment == | == Your development environment == <!--T:2--> | ||
<!--T:3--> | |||
It is extremely recommended to set up a Linux environment to begin programming in DDNet for the following reasons (as of now): | It is extremely recommended to set up a Linux environment to begin programming in DDNet for the following reasons (as of now): | ||
* Most DDNet contributors actually use Linux to contribute. | * Most DDNet contributors actually use Linux to contribute. | ||
Line 11: | Line 13: | ||
* This article doesn't have yet a Windows version and is focused on Linux. | * This article doesn't have yet a Windows version and is focused on Linux. | ||
<!--T:4--> | |||
First an foremost, DDNet is coded using the C++ programming language, you will need to be fairly familiar with it, but you can also know the basics and learn more with it. | First an foremost, DDNet is coded using the C++ programming language, you will need to be fairly familiar with it, but you can also know the basics and learn more with it. | ||
<!--T:5--> | |||
Some useful resources to learn C++: | Some useful resources to learn C++: | ||
* [https://www.learncpp.com/ learncpp.com] | * [https://www.learncpp.com/ learncpp.com] | ||
Line 18: | Line 22: | ||
* Your search engine of preference | * Your search engine of preference | ||
<!--T:6--> | |||
The source code of DDNet is managed using [https://git-scm.com/ Git], a version control system, an essential tool to collaborate with multiple developers. | The source code of DDNet is managed using [https://git-scm.com/ Git], a version control system, an essential tool to collaborate with multiple developers. | ||
<!--T:7--> | |||
If you don't have git yet in your Linux distribution, make sure to install it, for example in most debian/ubuntu based distributions: <code>sudo apt install git</code>. | If you don't have git yet in your Linux distribution, make sure to install it, for example in most debian/ubuntu based distributions: <code>sudo apt install git</code>. | ||
== Getting the source code == | == Getting the source code == <!--T:8--> | ||
<!--T:9--> | |||
The source code is located on [https://github.com/ddnet/ddnet Github], you can get the source code by cloning without the need of an account, but if you want to ever put your changes to the official source code you will need one. | The source code is located on [https://github.com/ddnet/ddnet Github], you can get the source code by cloning without the need of an account, but if you want to ever put your changes to the official source code you will need one. | ||
<!--T:10--> | |||
If you are not familiar with git/github you can learn the basics here: [https://docs.github.com/en/get-started/quickstart/hello-world Hello World - Github] | If you are not familiar with git/github you can learn the basics here: [https://docs.github.com/en/get-started/quickstart/hello-world Hello World - Github] | ||
== Installing the dependencies == | == Installing the dependencies == <!--T:11--> | ||
<!--T:12--> | |||
If you are on Linux, you can install all the needed dependencies by reading the README on the DDNet github page: https://github.com/ddnet/ddnet#dependencies-on-linux--macos | If you are on Linux, you can install all the needed dependencies by reading the README on the DDNet github page: https://github.com/ddnet/ddnet#dependencies-on-linux--macos | ||
<!--T:13--> | |||
For Arch Linux: | For Arch Linux: | ||
<!--T:14--> | |||
<code>sudo pacman -S --needed base-devel cmake curl freetype2 git glew gmock libnotify opusfile python sdl2 sqlite wavpack</code> | <code>sudo pacman -S --needed base-devel cmake curl freetype2 git glew gmock libnotify opusfile python sdl2 sqlite wavpack</code> | ||
== Compiling DDNet == | == Compiling DDNet == <!--T:15--> | ||
<!--T:16--> | |||
We use CMake to control the compilation process, if you have all the dependencies installed, it's as easy as following these commands (make sure you are on the DDNet folder): | We use CMake to control the compilation process, if you have all the dependencies installed, it's as easy as following these commands (make sure you are on the DDNet folder): | ||
<!--T:17--> | |||
<syntaxhighlight lang="bash"> | <syntaxhighlight lang="bash"> | ||
mkdir build | mkdir build | ||
Line 51: | Line 64: | ||
== General information == | == General information == <!--T:18--> | ||
<!--T:19--> | |||
Here are some general bits of information: | Here are some general bits of information: | ||
* Currently, the source code is compiled with the C++17 standard, but you will see that many parts of the code are more C-like since only mostly new code uses C++17 stuff. | * Currently, the source code is compiled with the C++17 standard, but you will see that many parts of the code are more C-like since only mostly new code uses C++17 stuff. | ||
Line 59: | Line 73: | ||
== The source code layout == | == The source code layout == <!--T:20--> | ||
<!--T:21--> | |||
Now that you can build DDNet you can begin editing it. | Now that you can build DDNet you can begin editing it. | ||
=== The src/base directory === | === The src/base directory === <!--T:22--> | ||
<!--T:23--> | |||
Since DDNet is a cross-platform game, an abstraction layer over that is needed to make development easier, this directory contains many useful functions to handle that. | Since DDNet is a cross-platform game, an abstraction layer over that is needed to make development easier, this directory contains many useful functions to handle that. | ||
=== The src/engine directory === | === The src/engine directory === <!--T:24--> | ||
<!--T:25--> | |||
Here lies the game engine, it handles most stuff that is not gameplay related, such as graphics, sound, network, etc. | Here lies the game engine, it handles most stuff that is not gameplay related, such as graphics, sound, network, etc. | ||
=== The src/game directory === | === The src/game directory === <!--T:26--> | ||
<!--T:27--> | |||
All gameplay related code is here, separated into client and server. | All gameplay related code is here, separated into client and server. | ||
==== Server side ==== | ==== Server side ==== <!--T:28--> | ||
<!--T:29--> | |||
This game uses its own [https://en.wikipedia.org/wiki/Entity_component_system Entity Component System], the main class to which all other entities derive from is <code>CEntity</code> located in <code>src/game/server/entity.h</code>. | This game uses its own [https://en.wikipedia.org/wiki/Entity_component_system Entity Component System], the main class to which all other entities derive from is <code>CEntity</code> located in <code>src/game/server/entity.h</code>. | ||
<!--T:30--> | |||
These entities are managed by the game world located here <code>src/game/server/gameworld.h</code> | These entities are managed by the game world located here <code>src/game/server/gameworld.h</code> | ||
<!--T:31--> | |||
Some important entities are: | Some important entities are: | ||
<!--T:32--> | |||
* [https://github.com/ddnet/ddnet/blob/master/src/game/server/entities/character.h CCharacter]: Represents a [[Special:MyLanguage/Common_Terminology#Tee|tee]] that is alive, it is instantiated when a tee spawns and deleted when it dies. For information about the player kept between deaths, see [https://github.com/ddnet/ddnet/blob/master/src/game/server/player.h CPlayer]. | * [https://github.com/ddnet/ddnet/blob/master/src/game/server/entities/character.h CCharacter]: Represents a [[Special:MyLanguage/Common_Terminology#Tee|tee]] that is alive, it is instantiated when a tee spawns and deleted when it dies. For information about the player kept between deaths, see [https://github.com/ddnet/ddnet/blob/master/src/game/server/player.h CPlayer]. | ||
==== Client side ==== | ==== Client side ==== <!--T:33--> | ||
<!--T:34--> | |||
The client side is made up of components, these are classes that inherit <code>CComponent</code>: These components can implement the virtual methods such as <code>OnInit</code>, <code>OnMessage</code>, etc. to provide their functionality. | The client side is made up of components, these are classes that inherit <code>CComponent</code>: These components can implement the virtual methods such as <code>OnInit</code>, <code>OnMessage</code>, etc. to provide their functionality. | ||
==== Networking ==== | ==== Networking ==== <!--T:35--> | ||
<!--T:36--> | |||
The network protocol is mostly generated by python scripts that output C++ code, for example, <code>datasrc/network.py</code> defines all network packets. | The network protocol is mostly generated by python scripts that output C++ code, for example, <code>datasrc/network.py</code> defines all network packets. | ||
== Code conventions == | == Code conventions == <!--T:37--> | ||
<!--T:38--> | |||
The ongoing discussion on code conventions is located here: [https://github.com/ddnet/ddnet/issues/2945 ddnet#2945] | The ongoing discussion on code conventions is located here: [https://github.com/ddnet/ddnet/issues/2945 ddnet#2945] | ||
<!--T:39--> | |||
Currently, the following applies: | Currently, the following applies: | ||
=== Indentation style === | === Indentation style === <!--T:40--> | ||
<!--T:41--> | |||
[https://en.wikipedia.org/wiki/Indentation_style#Allman_style Allman style] is used. | [https://en.wikipedia.org/wiki/Indentation_style#Allman_style Allman style] is used. | ||
<!--T:42--> | |||
<blockquote> | <blockquote> | ||
This style puts the brace associated with a control statement on the next line, indented to the same level as the control statement. Statements within the braces are indented to the next level. | This style puts the brace associated with a control statement on the next line, indented to the same level as the control statement. Statements within the braces are indented to the next level. | ||
</blockquote> | </blockquote> | ||
<!--T:43--> | |||
<syntaxhighlight lang="cpp"> | <syntaxhighlight lang="cpp"> | ||
while(x == y) | while(x == y) | ||
Line 122: | Line 151: | ||
} | } | ||
<!--T:44--> | |||
Finalthing(); | Finalthing(); | ||
</syntaxhighlight> | </syntaxhighlight> | ||
=== Classes and Structs === | === Classes and Structs === <!--T:45--> | ||
<!--T:46--> | |||
Must be prefixed by <code>C</code> (for legacy reasons this is ignored for structs in some places, such as in graphics code) or <code>I</code> for interfaces. | Must be prefixed by <code>C</code> (for legacy reasons this is ignored for structs in some places, such as in graphics code) or <code>I</code> for interfaces. | ||
<!--T:47--> | |||
Example: | Example: | ||
<!--T:48--> | |||
<syntaxhighlight lang="cpp"> | <syntaxhighlight lang="cpp"> | ||
class CCharacter : public CEntity | class CCharacter : public CEntity | ||
Line 140: | Line 173: | ||
=== Enums and constants === | === Enums and constants === <!--T:49--> | ||
<!--T:50--> | |||
Should be screaming snake case, for example: <code>MAX_PLAYERS</code> | Should be screaming snake case, for example: <code>MAX_PLAYERS</code> | ||
<!--T:51--> | |||
<syntaxhighlight lang="cpp"> | <syntaxhighlight lang="cpp"> | ||
enum | enum | ||
Line 158: | Line 193: | ||
=== Variable naming === | === Variable naming === <!--T:52--> | ||
<!--T:53--> | |||
* The names of variables contain 3 parts: qualifier, prefix and name. | * The names of variables contain 3 parts: qualifier, prefix and name. | ||
* Variable names should start with uppercase unless they are 1 char long without any prefix or qualifier, for example: <code>i</code>, <code>x</code>, <code>y</code>. | * Variable names should start with uppercase unless they are 1 char long without any prefix or qualifier, for example: <code>i</code>, <code>x</code>, <code>y</code>. | ||
* Variables can have more than 1 qualifier (or zero) and more than 1 prefix (or zero). | * Variables can have more than 1 qualifier (or zero) and more than 1 prefix (or zero). | ||
<!--T:54--> | |||
These are laid out like this: <code>[qualifiers]_[prefixes][Name]</code> | These are laid out like this: <code>[qualifiers]_[prefixes][Name]</code> | ||
==== Qualifiers ==== | ==== Qualifiers ==== <!--T:55--> | ||
<!--T:56--> | |||
* <code>m</code> for member variables: <code>m_MyVariable</code>. | * <code>m</code> for member variables: <code>m_MyVariable</code>. | ||
* <code>s</code> for static variables: <code>s_MyStaticVariable</code>. | * <code>s</code> for static variables: <code>s_MyStaticVariable</code>. | ||
Line 174: | Line 212: | ||
==== Prefixes ==== | ==== Prefixes ==== <!--T:57--> | ||
<!--T:58--> | |||
* <code>p</code> for pointers: <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> for arrays: <code>aMyArray</code>, <code>aBuf</code>. | * <code>a</code> for arrays: <code>aMyArray</code>, <code>aBuf</code>. | ||
Line 181: | Line 220: | ||
== Common snippets == | == Common snippets == <!--T:59--> | ||
<!--T:60--> | |||
Here is a list of code that you may frequently see across the codebase: | Here is a list of code that you may frequently see across the codebase: | ||
=== Formatting text === | === Formatting text === <!--T:61--> | ||
<!--T:62--> | |||
<syntaxhighlight lang="cpp"> | <syntaxhighlight lang="cpp"> | ||
char aBuf[128]; | char aBuf[128]; | ||
Line 194: | Line 235: | ||
=== Iterating over all players === | === Iterating over all players === <!--T:63--> | ||
<!--T:64--> | |||
<syntaxhighlight lang="cpp"> | <syntaxhighlight lang="cpp"> | ||
for(int i = 0; i < MAX_CLIENTS; i++) | for(int i = 0; i < MAX_CLIENTS; i++) | ||
Line 205: | Line 247: | ||
=== Printing to the game console === | === Printing to the game console === <!--T:65--> | ||
<!--T:66--> | |||
<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!"); | ||
Line 212: | Line 255: | ||
=== Debug printing === | === Debug printing === <!--T:67--> | ||
<!--T:68--> | |||
<syntaxhighlight lang="cpp"> | <syntaxhighlight lang="cpp"> | ||
int i = 2; | int i = 2; | ||
Line 220: | Line 264: | ||
== External resources == | == External resources == <!--T:69--> | ||
<!--T:70--> | |||
* [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/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/code-conventions-in-ddnet/ Code conventions in DDraceNetwork] by [[Special:MyLanguage/User:Ryozuki|Ryozuki]] |
Revision as of 16:21, 11 February 2023
This article aims to introduce you into DDNet development, since it's an open-source game, it relies on random people kind enough to contribute to it on their free time.
Your development environment
It is extremely recommended to set up a Linux environment to begin programming in DDNet for the following reasons (as of now):
- Most DDNet contributors actually use Linux to contribute.
- Easier package management, you can easily install all the needed libraries and begin contributing.
- This article doesn't have yet a Windows version and is focused on Linux.
First an foremost, DDNet is coded using the C++ programming language, you will need to be fairly familiar with it, but you can also know the basics and learn more with it.
Some useful resources to learn C++:
- learncpp.com
- cppreference.com
- Your search engine of preference
The source code of DDNet is managed using Git, a version control system, an essential tool to collaborate with multiple developers.
If you don't have git yet in your Linux distribution, make sure to install it, for example in most debian/ubuntu based distributions: sudo apt install git
.
Getting the source code
The source code is located on Github, you can get the source code by cloning without the need of an account, but if you want to ever put your changes to the official source code you will need one.
If you are not familiar with git/github you can learn the basics here: Hello World - Github
Installing the dependencies
If you are on Linux, you can install all the needed dependencies by reading the README on the DDNet github page: https://github.com/ddnet/ddnet#dependencies-on-linux--macos
For Arch Linux:
sudo pacman -S --needed base-devel cmake curl freetype2 git glew gmock libnotify opusfile python sdl2 sqlite wavpack
Compiling DDNet
We use CMake to control the compilation process, if you have all the dependencies installed, it's as easy as following these commands (make sure you are on the DDNet folder):
mkdir build
cd build
cmake ..
make -j$(nproc)
General information
Here are some general bits of information:
- Currently, the source code is compiled with the C++17 standard, but you will see that many parts of the code are more C-like since only mostly new code uses C++17 stuff.
std::string
is rarely used, char arrays plus usingsystem.h
methods for handling them are the norm.- Most I/O code, formatting and printing is done using
system.h
provided methods.
The source code layout
Now that you can build DDNet you can begin editing it.
The src/base directory
Since DDNet is a cross-platform game, an abstraction layer over that is needed to make development easier, this directory contains many useful functions to handle that.
The src/engine directory
Here lies the game engine, it handles most stuff that is not gameplay related, such as graphics, sound, network, etc.
The src/game directory
All gameplay related code is here, separated into client and server.
Server side
This game uses its own Entity Component System, the main class to which all other entities derive from is CEntity
located in src/game/server/entity.h
.
These entities are managed by the game world located here src/game/server/gameworld.h
Some important entities are:
- CCharacter: Represents a tee that is alive, it is instantiated when a tee spawns and deleted when it dies. For information about the player kept between deaths, see CPlayer.
Client side
The client side is made up of components, these are classes that inherit CComponent
: These components can implement the virtual methods such as OnInit
, OnMessage
, etc. to provide their functionality.
Networking
The network protocol is mostly generated by python scripts that output C++ code, for example, datasrc/network.py
defines all network packets.
Code conventions
The ongoing discussion on code conventions is located here: ddnet#2945
Currently, the following applies:
Indentation style
Allman style is used.
This style puts the brace associated with a control statement on the next line, indented to the same level as the control statement. Statements within the braces are indented to the next level.
while(x == y)
{
Something();
SomethingElse();
}
Finalthing();
Classes and Structs
Must be prefixed by C
(for legacy reasons this is ignored for structs in some places, such as in graphics code) or I
for interfaces.
Example:
class CCharacter : public CEntity
{
// ...
}
Enums and constants
Should be screaming snake case, for example: MAX_PLAYERS
enum
{
FAKETUNE_FREEZE = 1,
FAKETUNE_SOLO = 2,
FAKETUNE_NOJUMP = 4,
FAKETUNE_NOCOLL = 8,
FAKETUNE_NOHOOK = 16,
FAKETUNE_JETPACK = 32,
FAKETUNE_NOHAMMER = 64,
};
Variable naming
- The names of variables contain 3 parts: qualifier, prefix and name.
- Variable names should start with uppercase unless they are 1 char long without any prefix or qualifier, for example:
i
,x
,y
. - Variables can have more than 1 qualifier (or zero) and more than 1 prefix (or zero).
These are laid out like this: [qualifiers]_[prefixes][Name]
Qualifiers
m
for member variables:m_MyVariable
.s
for static variables:s_MyStaticVariable
.g
for global variables with external linkage:gs_MyGlobalStaticVar
.
Prefixes
p
for pointers:pMyPointer
,m_pCharacter
,ppMyPointerToPointer
.a
for arrays:aMyArray
,aBuf
.fn
for functions:pfnMyCallback
,m_papfnMyPointerToArrayOfCallbacks
.
Common snippets
Here is a list of code that you may frequently see across the codebase:
Formatting text
char aBuf[128];
str_format(aBuf, sizeof(aBuf), "number: %d", 2);
Iterating over all players
for(int i = 0; i < MAX_CLIENTS; i++)
{
// Server-side
CPlayer *pPlayer = GameServer()->m_apPlayers[i];
}
Printing to the game console
Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "wikiprint", "Hello from the ddnet wiki!");
Debug printing
int i = 2;
dbg_msg("wikiprint", "Hello from the ddnet wiki: %d", i);
External resources
- An intro to the DDraceNetwork game source code by Ryozuki
- Code conventions in DDraceNetwork by Ryozuki
- Implementing a chat command in DDraceNetwork by Ryozuki
- Auto generated docs
- Technical documentation of Teeworlds file formats and network protocol
- The Anatomy of a One Tick Unfreeze
- Teeworlds programming YouTube tutorial by ChillerDragon