Skip to content
C

Coding Standards and Guidelines

Code Formatting

Whitespace

  • Indentations should be of 4 spaces, no tabs.
  • Line breaks should be committed to the repo as LF only. You can develop with either CRLF or LF however ensure your git client always converts to LF when committing the code.
  • No excessive spacing other than in configs in order to line up and "prettify" it so that non-developers can read it easily. Never use this in practical code.
  • No in-line code. One executable statement per line.
  • One space either side of an operator.
  • Line continuations should be indented by 4 spaces.
  • No space after an opening parenthesis or before a closing parenthesis.
  • Single space after if / for / while etc., and after commas.

Naming Conventions

  • Classes, non-local variables and public class variables: PascalCase
  • Local variables, parameters and functions: camelCase
  • Private class variables: \_camelCase
  • For casing, a “word” is anything written without internal spaces, including acronyms. For example, MySql instead of MySQL. The only exception to this is common namespaces such as BJ_Core.

Resource Naming Convention

Resource names should be minimal but descriptive. For example a drug system can just be called drugs instead of xxx_drugsystem_xxx. If a resource contains a namespace please strip it from the folder name. I.e. BJ_Core should become core.

C# Assembley Naming Convention

The following guideline for naming the assemblies is recommended. TMC.(Game/Section).(Project) I.e. TMC.FiveM.Drugs.dll TMC.FiveM.Core.dll TMC.RedM.Law.dll TMC.RedM.Core.dll

Long Running Methods (DB, Web Requests & Lengthy Code)

When interfacing with a database, http request or initialising a long running method please move them outside of the main event handling thread. We should be striving to move to a fully asynchronous code-base.

For example database calls should be asynchronous wherever possible. Code with lots of Waits() (such as animations/actions). These should all be done away from the main thread. If triggered from a function/event it should spawn a new thread to run on (Citizen.CreateThread).

Logging

When logging to the server please be sure to include a resource identifier I.e. \[core\] before your log so other developers can easily track where logs are coming from. This is not necessary on the client due to the log channels that are displayed in console.

Before publishing to live please ensure you minimalise your logging to only what is necessary or make use of the server type in order to decide what can be shown.

Merge Requests

Why

In order for code to move through from develop to live you must create a merge request and assign it to a repository maintainer. This allows them to review the code and ensure that standards are being met prior to accepting the code onto the live environments.

How

  • Once you have completed the development process for a resource change you should create a merge request within the relevant repository.
  • When creating the merge request you should select the source branch as develop and the target branch as master then click create.
  • On the final form please enter a short but descriptive statement of what you are changing and, if needed, expand upon this in the description field.
  • Finally check the comparison to ensure you are merging what you would expect and then select an Assignee. This should be one of the project maintainers of your organisation.
  • Submit the merge request and await a response.

Environment Based Settings

All TMC servers are configured with a convar defining the environment that you are on. This can be used in multiple ways in order to limit when code gets run. At this time there are 2 defined values of DEV & LIVE. Even though it is not documented for RedM the GetConvar function works perfectly on both the client and server. Below is an example use case:

AddEventHandler('playerConnecting', function(name, reason, deferrals)
    local source = source
    deferrals.defer()
    deferrals.update('Authenticating...')

    local serverType = GetConvar('server_type', 'DEV')
    
    if serverType == 'LIVE' or IsPlayerAceAllowed(source, 'DevServer.Access') then
        deferrals.done()
    else
        deferrals.done('You are not authorised to join this server.')
    end
end)

Continuous Integration / Continuous Delivery (CI/CD)

TMC has implemented CI/CD processes to ensure code is easy to manage, test & deploy with minimal issues.

Continuous Integration

Each commit is automatically built against a Lua validator. This should catch any issues with language compilation prior to it being executed on a server. A successful CI build is required before a merge from develop to master is accepted to ensure that we only have functional code on live. (This will not check against natives so there may still be execution issues). Other languages will require custom deployment pipeline configuration prior to being accepted to live.

Continuous Delivery

All projects from the FiveM & RedM namespaces are automatically synced directly to each games server of that type (e.g. FiveM develop branches to the FiveM Dev Server). This means you can develop, commit and then test the code without having to worry about putting files on the server directly.