New coding guidelines: Difference between revisions

From Multi Theft Auto: Wiki
Jump to navigation Jump to search
m (typo)
(Rework)
Line 1: Line 1:
This page contains new and unofficial coding guidelines.
This page contains current coding guidelines.
<br><br>
<br><br>


<ol>
=Code styling=
<li>Use '''const''' and '''constexpr''' wherever possible.</li>
Please stick to these rules to write nice and good code!
 
<li>Use the '''noexcept''' specifier whenever possible, but be cautious as it can cause the program to terminate if an exception is thrown.</li>
 
<li>Use '''nullptr''' instead of '''NULL''' when setting or returning a null pointer.</li>
 
<li>Functions that only return a value should be placed in header files. For example, instead of:
<syntaxhighlight lang="cpp">
// In .cpp file
int GetGameSpeed()
{
    return m_iGameSpeed;
}
</syntaxhighlight>
Do it in the header:
<syntaxhighlight lang="cpp">
int GetGameSpeed() const { return m_iGameSpeed; }
</syntaxhighlight>
</li>
 
<li>Use early-return to improve code readability. For example, instead of:
<syntaxhighlight lang="cpp">
bool CStaticFunctionDefinitions::RespawnObject(CElement* pElement)
{
    if (IS_OBJECT(pElement))
    {
        CObject* pObject = static_cast<CObject*>(pElement);
        if (pObject)
        {
            pObject->Respawn();
            return true;
        }
    }
 
    return false;
}
</syntaxhighlight>
It's clearer to do:
 
<syntaxhighlight lang="cpp">
bool CStaticFunctionDefinitions::RespawnObject(CElement* pElement)
{
    if (!IS_OBJECT(pElement))
        return false;
 
    CObject* pObject = static_cast<CObject*>(pElement);
    if (!pObject)
        return false;
 
    pObject->Respawn();
 
    return true;
}
</syntaxhighlight>
</li>


<li>Always strive to maintain code readability. If a type is lengthy to write, you can use '''auto''' to improve readability.
===Avoid magic numbers===
<syntaxhighlight lang="cpp">
We always try to avoid magic numbers like memory addresses, offsets, some constant numbers, etc. You can use the '''#define''' macro to define the numbers or at least use comments to document these numbers.  
CDeatchmatchObject* pObject = static_cast<CDeathmatchObject*>(pEntity);
// Can be
auto* pObject = static_cast<CDeathmatchObject*>(pEntity);
</syntaxhighlight>
</li>


<li>If you use addresses of values or functions, document what the address is with a comment or use a '''#define''' macro.
<syntaxhighlight lang="cpp">
<syntaxhighlight lang="cpp">
float CWeatherSA::GetWetRoads() const
float CWeatherSA::GetWetRoads() const
Line 85: Line 25:
</syntaxhighlight>
</syntaxhighlight>


Both methods are '''OK'''.
When using the '''#define''' macro, we use a prefix that specifies what it defines.
</li>


<li>
When using the '''#define''' macro for addresses, you should use an appropriate prefix that indicates what the address represents.
<syntaxhighlight lang="cpp">
<syntaxhighlight lang="cpp">
#define FUNC_RemoveRef                              0x4C4BB0 // Function address
#define FUNC_RemoveRef                              0x4C4BB0 // Function address
Line 100: Line 37:
#define VAR_CTempColModels_ModelPed1                0x968DF0 // Variable address (CColModel colModelPeds)
#define VAR_CTempColModels_ModelPed1                0x968DF0 // Variable address (CColModel colModelPeds)
</syntaxhighlight>
</syntaxhighlight>
</li>


<li>For readability, if a loop or condition is short, omit curly braces. For example, instead of:
===Naming conventions===
We use different naming conventions depending on the context.
<ul>
<li>
Use '''lower camel case''' for variable names and types:
<syntaxhighlight lang="cpp">
<syntaxhighlight lang="cpp">
if (!bStillRunning)
SSomeStruct  valueOne;
{
ESomeEnum     m_valueTwo;
     StopMoving();
}
</syntaxhighlight>
</syntaxhighlight>
You can do:
</li>


<li>
Use '''upper camel case''' for functions and classes:
<syntaxhighlight lang="cpp">
<syntaxhighlight lang="cpp">
if (!bStillRunning)
void UpperCamelCase();
    StopMoving();
class Vector;
</syntaxhighlight>
</syntaxhighlight>
</li>


However, do not omit curly braces for larger blocks:
<li>
Class member, should start with the prefix '''m_'''
<syntaxhighlight lang="cpp">
<syntaxhighlight lang="cpp">
for (dont)
CVector      m_vecPosition;
    for (do)
CVector      m_vecRotation;
        for (this)
bool          m_isVisible;
            ...
bool          m_isFrozen;
</syntaxhighlight>
</syntaxhighlight>
</li>
</li>


<li>Use [https://en.cppreference.com/w/cpp/language/range-for range-based for loops] when possible.
<li>
We '''avoid''' Hungarian notation in new codes, so use it only if necessary for consistency with the current code you are editing.
 
<syntaxhighlight lang="cpp">
<syntaxhighlight lang="cpp">
std::vector<int> vec; // Example std container
float        fValue;               // Local variable
 
unsigned char m_ucValue;            // Class member variable
// Bad:
char          ms_cValue;            // Class static member variable
for (std::vector<int>::iterator it = vec.begin(); it != vec.end(); it++)
bool          g_bCrashTwiceAnHour; // Global variable
 
char*        szUsername;          // Zero-terminated string
// Good:
SString      strUsername;         // String
for (const auto& v : vec)
CVector      vecPosition;         // 3D Vector
for (const int& v : vec)
 
// In case of maps you can use structured binding:
std::map<std::string, int> myMap;
for (const auto& [k, v] : myMap)
 
// There are situations where you must use old style loops, in this case use `auto`
for (auto it = vec.begin(); it != vec.end(); it++)
</syntaxhighlight>
</syntaxhighlight>
</li>
</li>


<li>Define and call functions without arguments simply with empty parentheses.
</ul>
 
===Functions without arguments===
Define and call functions without arguments simply with empty parentheses. Don't use ''void'' in this case as it is an old practice!
<syntaxhighlight lang="cpp">
<syntaxhighlight lang="cpp">
// Bad
// Bad
Line 155: Line 94:
MyFunction();
MyFunction();
</syntaxhighlight>
</syntaxhighlight>
===Code readability===
This is another very important point of the guidelines. Always try to make your code as readable as possible so that anyone can easily read it and understand its purpose.
<ul>
<li>Use '''early-returns''' to improve code readability.
<syntaxhighlight lang="cpp">
// Poor readability
bool CStaticFunctionDefinitions::RespawnObject(CElement* pElement)
{
    if (IS_OBJECT(pElement))
    {
        CObject* pObject = static_cast<CObject*>(pElement);
        if (pObject)
        {
            pObject->Respawn();
            return true;
        }
    }
    return false;
}
// Clearer readability
bool CStaticFunctionDefinitions::RespawnObject(CElement* pElement)
{
    if (!IS_OBJECT(pElement))
        return false;
    CObject* pObject = static_cast<CObject*>(pElement);
    if (!pObject)
        return false;
    pObject->Respawn();
    return true;
}
</syntaxhighlight>
</li>
<li>Always strive to maintain code readability. If a type is lengthy to write, you can use auto to improve readability
<syntaxhighlight lang="cpp">
CDeatchmatchObject* pObject = static_cast<CDeathmatchObject*>(pEntity);
// Can be
auto* pObject = static_cast<CDeathmatchObject*>(pEntity);
</syntaxhighlight>
We prefer to use '''auto*''' when it comes to pointer, even though auto itself is sufficient.
</li>
</li>


<li>When possible, use a logical condition for code readability. Instead of:
<li>Use logical conditions whenever possible
<syntaxhighlight lang="cpp">
<syntaxhighlight lang="cpp">
// Poor readability
const CPositionRotationAnimation* CObject::GetMoveAnimation()
const CPositionRotationAnimation* CObject::GetMoveAnimation()
{
{
Line 170: Line 158:
     }
     }
}
}
</syntaxhighlight>
Do:


<syntaxhighlight lang="cpp">
// Good readability
const CPositionRotationAnimation* CObject::GetMoveAnimation()
const CPositionRotationAnimation* CObject::GetMoveAnimation()
{
{
Line 181: Line 167:
</li>
</li>


<li>Use lower camel case for variable names of types like custom structs and enums:
<li>if a loop or condition is short, omit curly braces
<syntaxhighlight lang="cpp">
// Instead of
if (!bStillRunning)
{
    StopMoving();
}
 
// You can do
 
if (!bStillRunning)
    StopMoving();
 
// However, do not omit curly braces for larger blocks:
<syntaxhighlight lang="cpp">
<syntaxhighlight lang="cpp">
SSomeStruct  valueOne;
for (dont)
ESomeEnum     m_valueTwo;
     for (do)
        for (this)
            ...
</syntaxhighlight>
</syntaxhighlight>
</li>
</li>


<li>Functions and classes use UpperCamelCase:
<li>Functions that only return a value should be placed in header files. For example, instead of:
<syntaxhighlight lang="cpp">
<syntaxhighlight lang="cpp">
void UpperCamelCase();
// In .cpp file
class Vector;
int GetGameSpeed()
{
    return m_iGameSpeed;
}
</syntaxhighlight>
</syntaxhighlight>
</li>
Do it in the header:
 
<li>Use Hungarian notation only when necessary to maintain consistency with existing code; however, try to avoid using it in entirely new code (new files, etc.).
<syntaxhighlight lang="cpp">
<syntaxhighlight lang="cpp">
float        fValue;               // Local variable
int GetGameSpeed() const noexcept { return m_iGameSpeed; }
unsigned char m_ucValue;            // Class member variable
char          ms_cValue;            // Class static member variable
bool          g_bCrashTwiceAnHour;  // Global variable
char*        szUsername;          // Zero-terminated string
SString      strUsername;          // String
CVector      vecPosition;          // 3D Vector
</syntaxhighlight>
</syntaxhighlight>
</li>
</li>


<li>
<li>Don't use unnecessary parenthesis.
In C++, prefer using types from the std namespace provided by appropriate headers (such as '''<cstdint>''', '''<cstddef>''', etc.). This is recommended for several reasons:
 
* Namespace Safety: Types defined in these headers are encapsulated within the std namespace, which helps avoid naming conflicts with user-defined types or macros. This follows the C++ standard practice of minimizing global namespace pollution.
 
* Consistency and Readability: Using '''std::''' types ensures consistency and improves code readability by making it clear that these types are part of the standard library.
 
* C++ Standard Compliance: The C++ standard (C++11 and later) includes headers like '''<cstdint>''' and '''<cstddef>''', which provide standardized types:
 
:* <cstdint> includes exact-width integer types such as ''''std::uint32_t''', '''std::int32_t''', etc.
:* <cstddef> includes types like '''std::size_t''', '''std::ptrdiff_t''', etc.
 
* Portability and Maintainability: Using these headers makes your code more portable across different compilers and platforms, as it guarantees that these types are defined in a standardized way. This is especially important in a C++ environment, where the focus is on maintainability and cross-platform compatibility.
 
By adhering to these practices, you ensure that your codebase remains clean, consistent, and adheres to modern C++ standards, which ultimately contributes to better maintainability and fewer integration issues.
</li>
 
<li>
Don't use unnecessary parenthesis. Instead of:
<syntaxhighlight lang="cpp">
<syntaxhighlight lang="cpp">
// Bad
bool CClientPed::IsDead()
bool CClientPed::IsDead()
{
{
     (return (m_status == STATUS_DEAD));
     (return (m_status == STATUS_DEAD));
}
}
</syntaxhighlight>
 
Do:
// Good
<syntaxhighlight lang="cpp">
bool CClientPed::IsDead()
bool CClientPed::IsDead()
{
{
Line 239: Line 217:
}
}
</syntaxhighlight>
</syntaxhighlight>
</li>
<li>Use [https://en.cppreference.com/w/cpp/language/range-for range-based for loops] when possible.
<syntaxhighlight lang="cpp">
std::vector<int> vec; // Example std container
// Bad:
for (std::vector<int>::iterator it = vec.begin(); it != vec.end(); it++)


</li>
// Good:
for (const auto& v : vec)
for (const int& v : vec)


<li>In new codes, try not to use the '''SString''' type anymore, use '''std::string''' instead.</li>
// In case of maps you can use structured binding:
std::map<std::string, int> myMap;
for (const auto& [k, v] : myMap)


<li>Class member, should start with the prefix '''m_'''
// There are situations where you must use old style loops, in this case use `auto`
<syntaxhighlight lang="cpp">
for (auto it = vec.begin(); it != vec.end(); it++)
CVector      m_vecPosition;
CVector      m_vecRotation;
bool          m_isVisible;
bool          m_isFrozen;
</syntaxhighlight>
</syntaxhighlight>
</li>
</li>


<li>Use member initialization lists whenever possible. Instead of doing:
</ul>
 
=Coding conventions=
We always try to create good code that complies with applicable conventions.
 
===Specifiers===
These are the basic specifiers we try to use, especially in new codes:
:* Use [https://en.cppreference.com/w/cpp/keyword/const const] and [https://en.cppreference.com/w/cpp/language/constexpr constexpr] wherever possible.
:* Use the [https://en.cppreference.com/w/cpp/language/noexcept_spec noexcept] specifier whenever possible, but '''be cautious''' as it can cause the program to terminate if an exception is thrown.
 
===Null pointers===
Use [https://en.cppreference.com/w/cpp/language/nullptr nullptr] instead of [https://en.cppreference.com/w/cpp/types/NULL NULL] when setting or returning a null pointer.
 
===Initializing a class member===
Use member initialization lists whenever possible. Instead of doing:
<syntaxhighlight lang="cpp">
<syntaxhighlight lang="cpp">
CObject::CObject(CElement* pParent, CObjectManager* pObjectManager, bool bIsLowLod)  
CObject::CObject(CElement* pParent, CObjectManager* pObjectManager, bool bIsLowLod)  
Line 307: Line 307:
}
}
</syntaxhighlight>
</syntaxhighlight>
</li>


<li>If you want to return an error to the debug script, throw a '''std::invalid_argument''' exception or use '''std::logic_error'''.
===Typing conventions===
<ol>
<li> In C++, prefer using types from the std namespace provided by appropriate headers (such as '''<cstdint>''', '''<cstddef>''', etc.). This is recommended for several reasons:
 
* Namespace Safety: Types defined in these headers are encapsulated within the std namespace, which helps avoid naming conflicts with user-defined types or macros. This follows the C++ standard practice of minimizing global namespace pollution.
 
* Consistency and Readability: Using '''std::''' types ensures consistency and improves code readability by making it clear that these types are part of the standard library.
 
* C++ Standard Compliance: The C++ standard (C++11 and later) includes headers like '''<cstdint>''' and '''<cstddef>''', which provide standardized types:
 
:* <cstdint> includes exact-width integer types such as ''''std::uint32_t''', '''std::int32_t''', etc.
:* <cstddef> includes types like '''std::size_t''', '''std::ptrdiff_t''', etc.
 
* Portability and Maintainability: Using these headers makes your code more portable across different compilers and platforms, as it guarantees that these types are defined in a standardized way. This is especially important in a C++ environment, where the focus is on maintainability and cross-platform compatibility.
 
By adhering to these practices, you ensure that your codebase remains clean, consistent, and adheres to modern C++ standards, which ultimately contributes to better maintainability and fewer integration issues.</li>
 
<li>In new codes, try not to use the '''SString''' type anymore, use '''std::string''' instead.</li>
</ol>
 
=Header files=
<ul>
<li>Always place a copyight comment at the beginning of header files
<syntaxhighlight lang="cpp">
<syntaxhighlight lang="cpp">
if (!CClientBuildingManager::IsValidModel(modelId))
/*****************************************************************************
     throw std::invalid_argument("Invalid building model id");
\
*
*  PROJECT:     Multi Theft Auto
*  LICENSE:     See LICENSE in the top level directory
*  FILE:        Client/mods/deathmatch/logic/CClientIFP.h
*  PURPOSE:     Animations replacement
*
*  Multi Theft Auto is available from https://www.multitheftauto.com/
*
*****************************************************************************/


if (!CClientBuildingManager::IsValidPosition(pos))
#pragma once
    throw std::invalid_argument("Position is outside of game world");
</syntaxhighlight>
</syntaxhighlight>
The '''FILE''' field contains the path of the current header file.
</li>


If you want to throw a warning instead of an error, use [https://github.com/multitheftauto/mtasa-blue/blob/master/Shared/mods/deathmatch/logic/lua/CLuaFunctionParser.h#L22 LuaFunctionError] class with <code>throwWarning = true</code>
<li>Put '''#pragma once''' preprocessor directive next to the copyright comment for new header files and the ones you are modifying for the pull request. Make sure to remove include guard if you are using '''#pragma once'''.</li>
</li>


</ol>
</ul>


[[Category: Development]]
[[Category: Development]]

Revision as of 01:28, 7 July 2024

This page contains current coding guidelines.

Code styling

Please stick to these rules to write nice and good code!

Avoid magic numbers

We always try to avoid magic numbers like memory addresses, offsets, some constant numbers, etc. You can use the #define macro to define the numbers or at least use comments to document these numbers.

float CWeatherSA::GetWetRoads() const
{
    return *(float*)0xC81308; // CWeather::WetRoads
}
// In the header
#define NUM_WETROADS    0xC81308

// In the .cpp
float CWeatherSA::GetWetRoads() const
{
    return *(float*)NUM_WETROADS;
}

When using the #define macro, we use a prefix that specifies what it defines.

#define FUNC_RemoveRef                               0x4C4BB0 // Function address
#define ARRAY_aCannons                               0xC80740 // Array address
#define STRUCT_CAESoundManager                       0xB62CB0 // Struct address
#define SIZE_CWaterCannon                            0x3CC    // Size of object (e.g., struct object)
#define CLASSSIZE_WeaponInfo                         112      // Class size
#define NUM_CWaterCannon_Audio_Offset                0x32C    // Number (e.g., offsets, integers, etc.)
#define CLASS_CText                                  0xC1B340 // Class address
#define VAR_CTempColModels_ModelPed1                 0x968DF0 // Variable address (CColModel colModelPeds)

Naming conventions

We use different naming conventions depending on the context.

  • Use lower camel case for variable names and types:
    SSomeStruct   valueOne;
    ESomeEnum     m_valueTwo;
    
  • Use upper camel case for functions and classes:
    void UpperCamelCase();
    class Vector;
    
  • Class member, should start with the prefix m_
    CVector       m_vecPosition;
    CVector       m_vecRotation;
    bool          m_isVisible;
    bool          m_isFrozen;
    
  • We avoid Hungarian notation in new codes, so use it only if necessary for consistency with the current code you are editing.
    float         fValue;               // Local variable
    unsigned char m_ucValue;            // Class member variable
    char          ms_cValue;            // Class static member variable
    bool          g_bCrashTwiceAnHour;  // Global variable
    char*         szUsername;           // Zero-terminated string
    SString       strUsername;          // String
    CVector       vecPosition;          // 3D Vector
    

Functions without arguments

Define and call functions without arguments simply with empty parentheses. Don't use void in this case as it is an old practice!

// Bad
void MyFunction(void);
MyFunction(void);

// Good
void MyFunction();
MyFunction();

Code readability

This is another very important point of the guidelines. Always try to make your code as readable as possible so that anyone can easily read it and understand its purpose.

  • Use early-returns to improve code readability.
    // Poor readability
    bool CStaticFunctionDefinitions::RespawnObject(CElement* pElement)
    {
        if (IS_OBJECT(pElement))
        {
            CObject* pObject = static_cast<CObject*>(pElement);
            if (pObject)
            {
                pObject->Respawn();
                return true;
            }
        }
    
        return false;
    }
    
    // Clearer readability
    bool CStaticFunctionDefinitions::RespawnObject(CElement* pElement)
    {
        if (!IS_OBJECT(pElement))
            return false;
    
        CObject* pObject = static_cast<CObject*>(pElement);
        if (!pObject)
            return false;
    
        pObject->Respawn();
    
        return true;
    }
    
    
  • Always strive to maintain code readability. If a type is lengthy to write, you can use auto to improve readability
    CDeatchmatchObject* pObject = static_cast<CDeathmatchObject*>(pEntity);
    // Can be
    auto* pObject = static_cast<CDeathmatchObject*>(pEntity);
    

    We prefer to use auto* when it comes to pointer, even though auto itself is sufficient.

  • Use logical conditions whenever possible
    // Poor readability
    const CPositionRotationAnimation* CObject::GetMoveAnimation()
    {
        if (IsMoving())
        {
            return m_pMoveAnimation;
        }
        else
        {
            return nullptr;
        }
    }
    
    // Good readability
    const CPositionRotationAnimation* CObject::GetMoveAnimation()
    {
        return IsMoving() ? m_pMoveAnimation : nullptr;
    }
    
  • if a loop or condition is short, omit curly braces
    // Instead of
    if (!bStillRunning)
    {
        StopMoving();
    }
    
    // You can do
    
    if (!bStillRunning)
        StopMoving();
    
    // However, do not omit curly braces for larger blocks:
    <syntaxhighlight lang="cpp">
    for (dont)
        for (do)
            for (this)
                ...
    
  • Functions that only return a value should be placed in header files. For example, instead of:
    // In .cpp file
    int GetGameSpeed()
    {
        return m_iGameSpeed;
    }
    

    Do it in the header:

    int GetGameSpeed() const noexcept { return m_iGameSpeed; }
    
  • Don't use unnecessary parenthesis.
    // Bad
    bool CClientPed::IsDead()
    {
        (return (m_status == STATUS_DEAD));
    }
    
    // Good
    bool CClientPed::IsDead()
    {
        return m_status == STATUS_DEAD;
    }
    
  • Use range-based for loops when possible.
    std::vector<int> vec; // Example std container
    
    // Bad:
    for (std::vector<int>::iterator it = vec.begin(); it != vec.end(); it++)
    
    // Good:
    for (const auto& v : vec)
    for (const int& v : vec)
    
    // In case of maps you can use structured binding:
    std::map<std::string, int> myMap;
    for (const auto& [k, v] : myMap)
    
    // There are situations where you must use old style loops, in this case use `auto`
    for (auto it = vec.begin(); it != vec.end(); it++)
    

Coding conventions

We always try to create good code that complies with applicable conventions.

Specifiers

These are the basic specifiers we try to use, especially in new codes:

  • Use const and constexpr wherever possible.
  • Use the noexcept specifier whenever possible, but be cautious as it can cause the program to terminate if an exception is thrown.

Null pointers

Use nullptr instead of NULL when setting or returning a null pointer.

Initializing a class member

Use member initialization lists whenever possible. Instead of doing:

CObject::CObject(CElement* pParent, CObjectManager* pObjectManager, bool bIsLowLod) 
    : CElement(pParent), m_bIsLowLod(bIsLowLod), m_pLowLodObject(NULL)
{
    // Init
    m_iType = CElement::OBJECT;
    SetTypeName("object");

    m_pObjectManager = pObjectManager;
    m_usModel = 0xFFFF;
    m_pMoveAnimation = NULL;
    m_ucAlpha = 255;
    m_vecScale = CVector(1.0f, 1.0f, 1.0f);
    m_fHealth = 1000.0f;
    m_bSyncable = true;
    m_pSyncer = NULL;
    m_bIsFrozen = false;
    m_bDoubleSided = false;
    m_bBreakable = false;
    m_bCollisionsEnabled = true;

    // Add us to the manager's list
    pObjectManager->AddToList(this);
}

Do:

CObject::CObject(CElement* pParent, CObjectManager* pObjectManager, bool bIsLowLod)
    : CElement(pParent),
      m_bIsLowLod(bIsLowLod),
      m_pLowLodObject(nullptr),
      m_iType(CElement::OBJECT),
      m_pObjectManager(pObjectManager),
      m_usModel(0xFFFF),
      m_pMoveAnimation(nullptr),
      m_ucAlpha(255),
      m_vecScale(1.0f, 1.0f, 1.0f),
      m_fHealth(1000.0f),
      m_bSyncable(true),
      m_pSyncer(nullptr),
      m_bIsFrozen(false),
      m_bDoubleSided(false),
      m_bBreakable(false),
      m_bCollisionsEnabled(true)
{
    SetTypeName("object");

    // Add us to the manager's list
    pObjectManager->AddToList(this);
}

Typing conventions

  1. In C++, prefer using types from the std namespace provided by appropriate headers (such as <cstdint>, <cstddef>, etc.). This is recommended for several reasons:
    • Namespace Safety: Types defined in these headers are encapsulated within the std namespace, which helps avoid naming conflicts with user-defined types or macros. This follows the C++ standard practice of minimizing global namespace pollution.
    • Consistency and Readability: Using std:: types ensures consistency and improves code readability by making it clear that these types are part of the standard library.
    • C++ Standard Compliance: The C++ standard (C++11 and later) includes headers like <cstdint> and <cstddef>, which provide standardized types:
    • <cstdint> includes exact-width integer types such as 'std::uint32_t, std::int32_t, etc.
    • <cstddef> includes types like std::size_t, std::ptrdiff_t, etc.
    • Portability and Maintainability: Using these headers makes your code more portable across different compilers and platforms, as it guarantees that these types are defined in a standardized way. This is especially important in a C++ environment, where the focus is on maintainability and cross-platform compatibility.
    By adhering to these practices, you ensure that your codebase remains clean, consistent, and adheres to modern C++ standards, which ultimately contributes to better maintainability and fewer integration issues.
  2. In new codes, try not to use the SString type anymore, use std::string instead.

Header files

  • Always place a copyight comment at the beginning of header files
    /*****************************************************************************
    \
    *
    *  PROJECT:     Multi Theft Auto
    *  LICENSE:     See LICENSE in the top level directory
    *  FILE:        Client/mods/deathmatch/logic/CClientIFP.h
    *  PURPOSE:     Animations replacement
    *
    *  Multi Theft Auto is available from https://www.multitheftauto.com/
    *
    *****************************************************************************/
    
    #pragma once
    

    The FILE field contains the path of the current header file.

  • Put #pragma once preprocessor directive next to the copyright comment for new header files and the ones you are modifying for the pull request. Make sure to remove include guard if you are using #pragma once.