Coding Standards and Guidelines
- Code Formatting
- Merge Requests
- Environment Based Settings
- Continuous Integration / Continuous Delivery (CI/CD)
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 eitherCRLF
orLF
however ensure your git client always converts toLF
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 asBJ_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
.
# Assembley Naming Convention
CThe 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 asmaster
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.