Development/en: Difference between revisions

From DDraceNetwork
FuzzyBot (talk | contribs)
Updating to match new version of source page
Tags: mobile web edit mobile edit
FuzzyBot (talk | contribs)
Updating to match new version of source page
 
(One intermediate revision by the same user not shown)
Line 1: Line 1:
{{MigrateTranslation}}
<languages />
<languages/>
 
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==


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.
* Easier package management, you can easily install all the needed libraries and begin contributing.
*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.
*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.
First and 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++:
Some useful resources to learn C++:
* [https://www.learncpp.com/ learncpp.com]
*[https://www.learncpp.com/ learncpp.com]
* [https://en.cppreference.com/w/ cppreference.com]
*[https://en.cppreference.com/w/ cppreference.com]
* Your search engine of preference
*Your search engine of preference


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.
Line 23: Line 23:




== Getting the source code ==
==Getting the source code==


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.
Line 30: Line 30:




== Installing the dependencies ==
==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
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
Line 43: Line 43:


<syntaxhighlight lang="bash">
<syntaxhighlight lang="bash">
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
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 python3 rustc spirv-tools
</syntaxhighlight>
</syntaxhighlight>


== Compiling DDNet ==
==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):
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):
Line 58: Line 58:




== General information ==
==General information==


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.
* <code>std::string</code> is rarely used, char arrays plus using <code>system.h</code> methods for handling them are the norm.
*<code>std::string</code> is rarely used, char arrays plus using <code>system.h</code> methods for handling them are the norm.
* Most I/O code, formatting and printing is done using <code>system.h</code> provided methods.
*Most I/O code, formatting and printing is done using <code>system.h</code> provided methods.




== The source code layout ==
==The source code layout==


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===


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===


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===


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====


This game uses its own hierarchical object-oriented entity 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 hierarchical object-oriented entity system, the main class to which all other entities derive from is <code>CEntity</code> located in <code>src/game/server/entity.h</code>.
Line 94: Line 94:
Some important entities are:
Some important entities are:


* [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.
* [https://github.com/ddnet/ddnet/blob/master/src/game/server/player.h CPlayer] contains information not related to the [[Common Terminology/fr#Tee|Tee]] (nickname, flag, etc.).




==== Client side ====
====Client side====


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 [https://github.com/ddnet/ddnet/blob/master/src/game/client/component.h CComponent] defined in <code>src/game/client/component.h</code>. These components can implement the virtual methods such as <code>OnInit</code>, <code>OnMessage</code>, etc. to provide their functionality.




==== Networking ====
====Networking====


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==


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]
Line 114: Line 115:




=== Indentation style ===
===Indentation style===


[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.
Line 132: Line 133:
</syntaxhighlight>
</syntaxhighlight>


=== Classes and Structs ===
===Classes and Structs===


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. New <code>struct</code>s should be prefixed by <code>S</code>.
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. New <code>struct</code>s should be prefixed by <code>S</code>.
Line 146: Line 147:




=== Enums and constants ===
===Enums and constants===


Should be screaming snake case, for example: <code>MAX_PLAYERS</code>
Should be ''screaming snake case [https://en.wikipedia.org/wiki/Snake_case]'', for example: <code>MAX_PLAYERS</code>


<syntaxhighlight lang="cpp">
<syntaxhighlight lang="cpp">
Line 164: Line 165:




=== Variable naming ===
===Variable naming===


* 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).


These are laid out like this: <code>[qualifiers]_[prefixes][Name]</code>
These are laid out like this: <code>[qualifiers]_[prefixes][Name]</code>




==== Qualifiers ====
====Qualifiers====


* <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>ms_MyStaticMemberVariable</code>.
*<code>s</code> for static variables: <code>s_MyStaticVariable</code>, <code>ms_MyStaticMemberVariable</code>.
* <code>g</code> for global variables with external linkage: <code>gs_MyGlobalStaticVar</code>.
*<code>g</code> for global variables with external linkage: <code>gs_MyGlobalStaticVar</code>.




==== Prefixes ====
====Prefixes====


* <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>.
* <code>v</code> for <code>std::vector</code>s: <code>vMyVector</code>, <code>vpvMyVectorOfPointersToVectors</code>.
*<code>v</code> for <code>std::vector</code>s: <code>vMyVector</code>, <code>vpvMyVectorOfPointersToVectors</code>.
* <code>fn</code> for functions: <code>pfnMyCallback</code>, <code>m_papfnMyPointerToArrayOfCallbacks</code>.
*<code>fn</code> for functions: <code>pfnMyCallback</code>, <code>m_papfnMyPointerToArrayOfCallbacks</code>.




== Common snippets ==
==Common snippets==


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===


<syntaxhighlight lang="cpp">
<syntaxhighlight lang="cpp">
Line 201: Line 202:


See [https://cplusplus.com/reference/cstdio/printf/ printf documentation] for a list of all format specifiers.
See [https://cplusplus.com/reference/cstdio/printf/ printf documentation] for a list of all format specifiers.
=== Iterating over all players ===
===Iterating over all players===


<syntaxhighlight lang="cpp">
<syntaxhighlight lang="cpp">
Line 212: Line 213:




=== Printing to the game console ===
===Printing to the game console===


<syntaxhighlight lang="cpp">
<syntaxhighlight lang="cpp">
Line 219: Line 220:




 
===Debug printing===
=== Debug printing ===


<syntaxhighlight lang="cpp">
<syntaxhighlight lang="cpp">
Line 227: Line 227:
</syntaxhighlight>
</syntaxhighlight>


=== Translating text in the client ===
===Translating text in the client===
<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">
<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"), ...);
Line 241: Line 241:
</syntaxhighlight>
</syntaxhighlight>


== External resources ==
==External resources==
 
*[https://edgarluque.com/blog/ui-code-ddnet/ UI Code in DDraceNetwork] 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/chat-command-ddracenetwork/ Implementing a chat command in DDraceNetwork]  by [[Special:MyLanguage/User:Ryozuki|Ryozuki]]
*[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]
*[https://www.youtube.com/playlist?list=PLhJkqAQmOh5LyYOfnMy4PJB6CSZltQyTc Teeworlds programming YouTube tutorial] by [[User:ChillerDragon|ChillerDragon]]
*[https://chillerdragon.github.io/teeworlds-protocol/ Teeworlds 0.6/0.7 network protocol documentation] by [[User:ChillerDragon|ChillerDragon]]
 
==About Tee Skin Rendering==
 
This section explains how to render a tee skin.


* [https://edgarluque.com/blog/ui-code-ddnet/ UI Code in DDraceNetwork] by [[Special:MyLanguage/User:Ryozuki|Ryozuki]]
Values put together by Patiga
* [https://edgarluque.com/blog/intro-to-ddnet/ An intro to the DDraceNetwork game source code]  by [[Special:MyLanguage/User:Ryozuki|Ryozuki]]
Special Thanks to Jupstar
* [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]]
Segment Scaling:
* [https://codedoc.ddnet.org/ Auto generated docs]
    body: 100%
* [https://ddnet.org/libtw2-doc/ Technical documentation of Teeworlds file formats and network protocol]
    feet: 150%
* [https://heinrich5991.github.io/blog/blog/one-tick-unfreeze The Anatomy of a One Tick Unfreeze]
    eyes: 120%
* [https://www.youtube.com/playlist?list=PLhJkqAQmOh5LyYOfnMy4PJB6CSZltQyTc Teeworlds programming YouTube tutorial] by ChillerDragon
    eye blink: 45%
    hand: 93.75%
  Positioning:
    64/64 = 1 = width or height of the body segment
    body: 4/64 up
    feet:
        10/64 down
        7/64 left/right
    eyes:
        0.125 up
        0.05 left/right
   
    eye movement:
        dir = angle of eyes (view angle), right = 0
        eyes:
            x: cos(dir) * 0.125
            y: sin(dir) * 0.1
        each eye (away from the other):
            x: abs(cos(dir)) * 0.01

Latest revision as of 17:29, 4 May 2024

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 and 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++:

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 ffmpeg freetype2 git glew glslang gmock libnotify libpng opusfile python rust sdl2 spirv-tools sqlite vulkan-headers vulkan-icd-loader wavpack x264

For 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 python3 rustc spirv-tools

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 using system.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 hierarchical object-oriented entity 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.
  • CPlayer contains information not related to the Tee (nickname, flag, etc.).


Client side

The client side is made up of components, these are classes that inherit CComponent defined in src/game/client/component.h. 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. New structs should be prefixed by S.

Example:

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


Enums and constants

Should be screaming snake case [1], 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, ms_MyStaticMemberVariable.
  • g for global variables with external linkage: gs_MyGlobalStaticVar.


Prefixes

  • p for pointers: pMyPointer, m_pCharacter, ppMyPointerToPointer.
  • a for arrays: aMyArray, aBuf.
  • v for std::vectors: vMyVector, vpvMyVectorOfPointersToVectors.
  • 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);

See printf documentation for a list of all format specifiers.

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);

Translating text in the client

Localize can be used in the game client to get the translation for a specific string from the language file selected by the user.

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

The string can also contain format specifiers. The translated string must contain the same format specifiers.

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

A script is used to scan the code for calls to Localize and collect the strings to update the translation files. For this reason, the call to Localize must not contain any other code, or the script cannot determine the text correctly.

// Do NOT do this:
const char *pStr = Localize(Team == TEAM_RED ? "Red team" : "Blue team");

// Do this instead:
const char *pStr = Team == TEAM_RED ? Localize("Red team") : Localize("Blue team");

External resources

About Tee Skin Rendering

This section explains how to render a tee skin.

Values put together by Patiga
Special Thanks to Jupstar

Segment Scaling:
   body: 100%
   feet: 150%
   eyes: 120%
   eye blink: 45%
   hand: 93.75%

Positioning:
   64/64 = 1 = width or height of the body segment
   body: 4/64 up
   feet:
       10/64 down
       7/64 left/right
   eyes:
       0.125 up
       0.05 left/right

   eye movement:
       dir = angle of eyes (view angle), right = 0
       eyes:
           x: cos(dir) * 0.125
           y: sin(dir) * 0.1
       each eye (away from the other):
           x: abs(cos(dir)) * 0.01