File: CONTRIBUTING.md

package info (click to toggle)
ddnet 19.1-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 68,960 kB
  • sloc: cpp: 195,050; ansic: 58,572; python: 5,568; asm: 946; sh: 941; java: 366; xml: 206; makefile: 31
file content (300 lines) | stat: -rw-r--r-- 6,459 bytes parent folder | download
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/).