1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300
|
# Contributing code to DDNet
## General
Please open an issue first discussing the idea before starting to write code.
It would be unfortunate if you spend time working on a contribution that does not align with the ideals of the DDNet project.
A non-exhaustive list of things that usually get rejected:
- Extending dummy with new gameplay-affecting features.
https://github.com/ddnet/ddnet/pull/8275
https://github.com/ddnet/ddnet/pull/5443#issuecomment-1158437505
- Breaking backwards compatibility in the network protocol or file formats such as skins and demos.
- Breaking backwards compatibility in gameplay:
+ Existing ranks should not be made impossible.
+ Existing maps should not break.
+ New gameplay should not make runs easier on already completed maps.
## Programming languages
We currently use the following languages to develop DDNet.
- C++
- very marginally Rust
- Python for code generation and supporting tools
- CMake for building
Adding code in another programming language is not possible.
For platform support, we also use other programming languages like Java on
Android or Objective-C++ on macOS, but this is confined to platform-specific
code.
## Code style
There are a few style rules. Some of them are enforced by CI and some of them are manually checked by reviewers.
If your github pipeline shows some errors please have a look at the logs and try to fix them.
Such fix commits should ideally be squashed into one big commit using ``git commit --amend`` or ``git rebase -i``.
A lot of the style offenses can be fixed automatically by running the fix script `./scripts/fix_style.py`
We use clang-format 10. If your package manager no longer provides this version, you can download it from https://pypi.org/project/clang-format/10.0.1.1/.
### Upper camel case for variables, methods, class names
With the exception of base/system.{h,cpp}
For single words
- `int length = 0;` ❌
- `int Length = 0;` ✅
For multiple words:
- `int maxLength = 0;` ❌
- `int MaxLength = 0;` ✅
### Variable names should be descriptive
❌ Avoid:
```C++
for(int i = 0; i < MAX_CLIENTS; i++)
{
for(int k = 0; k < NUM_DUMMIES; k++)
{
if(k == 0)
continue;
m_aClients[i].Foo();
}
}
```
✅ Instead do:
```C++
for(int ClientId = 0; ClientId < MAX_CLIENTS; ClientId++)
{
for(int Dummy = 0; Dummy < NUM_DUMMIES; Dummy++)
{
if(Dummy == 0)
continue;
m_aClients[ClientId].Foo();
}
}
```
More examples can be found [here](https://github.com/ddnet/ddnet/pull/8288#issuecomment-2094097306)
### Teeworlds interpretation of the hungarian notation
DDNet inherited the hungarian notation like prefixes from [Teeworlds](https://www.teeworlds.com/?page=docs&wiki=nomenclature)
`m_`
Class member
`g_`
Global variable
`s_`
Static variable
`p`
Pointer
`a`
Fixed array
Combine them appropriately.
Class Prefixes
`C`
Class, CMyClass, This goes for structures as well.
`I`
Interface, IMyClass
Only use those prefixes. The ddnet code base does **NOT** follow the whole hungarian notation strictly.
Do **NOT** use `c` for constants or `b` for booleans or `i` for integers.
Examples:
```C++
class CFoo
{
int m_Foo = 0;
const char *m_pText = "";
void Func(int Argument, int *pPointer)
{
int LocalVariable = 0;
};
};
```
### The usage of `goto` is not encouraged
Do not use the `goto` keyword in new code, there are better control flow constructs in C++.
### Assignments in if statements should be avoided
Do not set variables in if statements.
❌
```C++
int Foo;
if((Foo = 2)) { .. }
```
✅
```C++
int Foo = 2;
if(Foo) { .. }
```
Unless the alternative code is more complex and harder to read.
### Using integers in boolean contexts should be avoided
❌
```C++
int Foo = 0;
if(!Foo) { .. }
```
✅
```C++
int Foo = 0;
if(Foo != 0) { .. }
```
### Methods with default arguments should be avoided
Default arguments tend to break quickly, if you have multiple you have to specify each even if you only want to change the last one.
### Method overloading should be avoided
Try finding descriptive names instead.
### Global/static variables should be avoided
Use member variables or pass state by parameter instead of using global or static variables since static variables share the same value across instances of a class.
Avoid static variables ❌:
```C++
int CMyClass::Foo()
{
static int s_Count = 0;
s_Count++;
return s_Count;
}
```
Use member variables instead ✅:
```C++
class CMyClass
{
int m_Count = 0;
};
int CMyClass::Foo()
{
m_Count++;
return m_Count;
}
```
Constants can be static ✅:
```C++
static constexpr int ANSWER = 42;
```
### Getters should not have a Get prefix
While the code base already has a lot of methods that start with a ``Get`` prefix. If new getters are added they should not contain a prefix.
❌
```C++
int GetMyVariable() { return m_MyVariable; }
```
✅
```C++
int MyVariable() { return m_MyVariable; }
```
### Class member variables should be initialized where they are declared
Instead of doing this ❌:
```C++
class CFoo
{
int m_Foo;
};
```
Do this instead if possible ✅:
```C++
class CFoo
{
int m_Foo = 0;
};
```
### The usage of `class` should be favored over `struct`
### Modern C++ should be used instead of old C styled code
DDNet balances in being portable (easy to compile on all common distributions) and using modern features.
So you are encouraged to use all modern C++ features as long as they are supported by the C++ version we use.
Still be aware that in game loop code you should avoid allocations, so static buffers on the stack can be preferable.
Examples:
- Use `nullptr` instead of `0` or `NULL`.
### Use `true` for success
Do not use `int` as return type for methods that can either succeed or fail.
Use `bool` instead. And `true` means success and `false` means failure.
See https://github.com/ddnet/ddnet/issues/6436
### Filenames
Code file names should be all lowercase and words should be separated with underscores.
❌
```C++
src/game/FooBar.cpp
```
✅
```C++
src/game/foo_bar.cpp
```
## Commit messages
Describe the change your contribution is making for the player/user instead of talking about what you did in a technical sense. Your PR messages will ideally be in a format that can directly be used in the [change log](https://ddnet.org/downloads/).
|