-
Notifications
You must be signed in to change notification settings - Fork 0
Development
All standards for writing functions, scripts, configs, macros, documentation, etc. are defined here. Many of these standards are inspired by ACE 3's Coding Guidelines.
1. Variables
Private variables should be used instead of public variables whenever possible. They MUST be prefixed with an underscore.
1.2 Public Variables
Public (or global) variable names MUST use the following format: sia3f_COMPONENT_varName
. the varName
portion MUST NOT begin with fnc_
. They should only be used to save a value that will be used later at an unknown time or place. Passing values through parameters is always preferrable. The GVAR
macro family should always be used to define and access public variables.
All variables MUST be named in a way that is sufficiently descriptive in the context of the scope that they are used in; Single character names should NEVER be used. Most variable names should be at least 3 characters long; However, there may be exceptions to this. For public variables, the naming convention specifies the context as the component, meaning that the variable name only needs to explain what the variable's purpose is in relation to the rest of the component. For a private variable, the scope is the control structure it is initialized in, so the name only needs to explain the variable's purpose in relation to the control structure. See Local Variables Scope and this example (look at the fourth point under "Optimise then").
All callable code should be defined in its own function. Code defined in a private variable is allowed, but strongly discouraged.
All function names MUST use the following format: sia3f_COMPONENT_fnc_functionName
. The PREP
macro should always be used to do this.
All functions MUST be put in their own .sqf
files. The file's name MUST use the following format: fnc_functionName.sqf
. The file MUST be located within the COMPONENT\functions\
subdirectory.
All functions MUST include script_component.hpp
on the first line with all other includes or defines following this. After the includes and/or defines, all functions MUST have a header in the following format:
/*
* Author: [Name of Author(s)]
* [Description]
*
* Arguments:
* 0: The first argument <STRING>
* 1: The second argument <OBJECT>
* 2: Multiple input types <STRING|ARRAY|CODE>
* 3: Optional input <BOOL> (default: true)
* 4: Optional input with multiple types <CODE|STRING> (default: {true})
* 5: Not mandatory input <STRING> (default: nil)
*
* Return Value:
* The return value <BOOL>
*
* Example:
* ["something", player, { some code }] call sia3f_MODULE_fnc_imAnExample
*/
Example function (core\functions\fnc_getObjPosATL.sqf):
#include "script_component.hpp"
#include "some_file.hpp"
#define SOME_CONSTANT value
/*
* Author: Siege
* Returns the object's position in ATL format.
*
* Arguments:
* 0: Player <OBJECT>
*
* Return Value:
* The player's position in ATL format <ARRAY>
*
* Example:
* [player] call sia3f_core_fnc_getObjPosATL
*/
params [
["_object", objNull, [objNull]]
];
getPosATL _object
3. Macros
This section will define the GVAR
and FUNC
macro families as well as any custom macros. To see a more complete list of available macros, see ACE 3's Coding Guidelines or the CBA_A3 Documentation. Note that since sia3f does not make use of a stringtable, the STRING family macros do not apply. No macros are required, but those defined below are recommended.
The GVAR
macro family enables easy access of global variables from the current or other modules. It is strongly recommended to use these in order to prevent duplicate variable names in different modules. The macro family expands as follows, for the example of the module 'balls':
Macros | Description | Expands to |
---|---|---|
GVAR(face) | Gets the face global variable from the current module. |
sia3f_balls_face |
QGVAR(face) | Gets the face global variable from the current module as a string. |
"sia3f_balls_face" |
QQGVAR(face) | Gets the face global variable from the current module with double quotations. Used inside QUOTE macros or other strings where double quotation is required. |
""sia3f_balls_face"" |
EGVAR(leg, face) | Gets the face global variable from the leg module. |
sia3f_leg_face |
QEGVAR(leg, face) | Gets the face global variable from the leg module as a string. |
"sia3f_leg_face" |
QQEGVAR(leg, face) | Gets the face global variable from the leg module with double quotations. Used inside QUOTE macros or other strings where double quotation is required. |
""sia3f_leg_face"" |
The FUNC
macro family enables easy access of functions from the current or other modules. Use of these macros is recommended in order to ensure the proper naming convention is used when attempting to run macros. The macro family expands as follows, for the example of the module 'balls':
Macros | Description | Expands to |
---|---|---|
FUNC(face) | Gets the face function from the current module. |
sia3f_balls_fnc_face |
QFUNC(face) | Gets the face function from the current module as a string. |
"sia3f_balls_fnc_face" |
EFUNC(leg, face) | Gets the face function from the leg module. |
sia3f_leg_fnc_face |
QEFUNC(leg, face) | Gets the face function from the leg module as a string. |
"sia3f_leg_fnc_face" |
These macros log messages and/or variables to the RPT log for debugging. For more info, see the CBA wiki. The RPT logging macros log the following messages, for the example of the function 'test' in the module 'balls':
Macros | Description | Message logged |
---|---|---|
LOG("some string") | Logs a debug message into the RPT log with the module name. Only run if DEBUG_MODE_FULL is defined in script_component.hpp . Parameters can be inserted with LOG_n , where n is any integer from 1-9. The syntax is then identical to the format command. |
[SIA3F] (balls) LOG: some string |
INFO("some string") | Logs a message to the RPT log with the module name. Parameters can be inserted with INFO_n , where n is any integer from 1-9. The syntax is then identical to the format command. |
[SIA3F] (balls) INFO: some string |
WARNING("some string") | Logs a non-critical error in the RPT log with the module name. Parameters can be inserted with WARNING_n , where n is any integer from 1-9. The syntax is then identical to the format command. |
[SIA3F] (balls) WARNING: some string |
ERROR("some string") | Logs a critical error in the RPT log with the module name. Only run if DEBUG_MODE_NORMAL or higher is defined in script_component.hpp . Parameters can be inserted with ERROR_n , where n is any integer from 1-9. The syntax is then identical to the format command. |
[SIA3F] (balls) ERROR: some string |
ERROR_MSG("some string") | Logs a critical error in the RPT log with the module name, file path, and line number (kind of) and displays an error message on screen. Newlines (\n) in the MESSAGE ("some string" part) will be put on separate lines. Parameters can be inserted with ERROR_MSG_n , where n is any integer from 1-9. The syntax is then identical to the format command. |
[SIA3F] (balls) ERROR: /z/sia3f/addons/balls/functions/fnc_test.sqf:12 some string |
ERROR_WITH_TITLE("some title", "some string") | Logs a critical error in the RPT log with a custom title (instead of just "ERROR"), module name, file path, and line number (kind of). Newlines (\n) in the MESSAGE ("some string" part) will be put on separate lines. Parameters can be inserted with LOG_n , where n is any integer from 1-9. The syntax is then identical to the format command where "some string" is formatString . |
[SIA3F] (balls) ERROR: some title /z/sia3f/addons/balls/functions/fnc_test.sqf:12 some string |
MESSAGE_WITH_TITLE("some title", "some string") | Logs a debug title and message into the RPT log with the module name, file path, and line number (kind of). | [SIA3F] (balls) some title: some string /z/sia3f/addons/balls/functions/fnc_test.sqf:13 |
TRACE_1("some string", _someVar) | Logs a message and 1-9 variable names and their respective values (number of variables should equal n in TRACE_n()) to the RPT log with the module name, diag_frameNo, file path, and line number (kind of). Only run if DEBUG_MODE_FULL is defined in script_component.hpp
|
[SIA3F] (balls) TRACE: 887 some string: _someVar="some variable value" /z/sia3f/addons/balls/functions/fnc_test.sqf:14 |
This section will define the most useful custom macros in sia3f. To see a full list of ALL macros, visit the individual module's README. These macros will only be available in the module they are defined in or if they are imported in script_component.hpp
. Each section will define any other modules it imports from directly; To determine ALL of the modules it imports from, go to the imported modules and see what those import from. Unless specified, all modules import from the main
module. This section will be organized alphabetically, except for the main module, which will be first. If a module is not present, one can safely assume that it only imports from main
and does not define any custom macros.
3.4.1 main
Imports CBA macros.
Macros | Description | Expands to |
---|---|---|
GUI_THEME_COLOR | Gets an array of the user defined GUI colors in format RGBA. Intended for use in .hpp files when defining colors for a GUI. |
{0.13,0.54,0.21,0.8} (by default) |
GET_CONFIG(bluforFactionName,"NATO") | Gets the mission config value of bluforFactionName under the configuration module. If the variable is undefined, the default value is returned ("NATO" in this example). See the configuration module README for a list of valid values. |
(getMissionConfigValue ["sia3f_configuration_bluforFactionName", "NATO"]) |
3.4.2 configuration
Macros | Description | Expands to |
---|---|---|
SET_CONFIG(hiddenConfigValues,frameworkInit,true) | Sets the mission config value of frameworkInit , a config value defined under the hiddenConfigValues section, to true. See the configuration module README for a list of all valid section-config pairs. |
"sia3f_configuration_hiddenConfigValues" set3DENMissionAttribute ["sia3f_configuration_frameworkInit", true] |
sia3f's style is identical to ACE3's Code Style.
This section will define standards for how code will be written. The difference between this section and section 4. Code Style is that while code style does not affect how a program is executed, code standards do. Some standards are defined elsewhere, notably variable naming conventions and usage.
All functions must be tested. If one returns an error or does not function properly, it must be fixed before being merged/committed into the main branch.
There shall be no unreachable code. For example, the following code is prohibited:
if (false) then {
// this code is unreachable
};
or
while { true } do {
if (some condition) then {
break;
systemChat "this code will never be executed";
};
};
No conditions that are always true or false shall exist. For example, the following code is prohibited:
if (1 == 1) then {
// this if statement is superfluous since the code within will always be executed.
};
A function should only perform one core task. If an operation (such as getting a value) is sufficiently complex, it may be necessary to move it to a new function. A good rule of thumb is to ensure functions do not surpass 250 lines of code, excluding function headers and includes. This point is largely subjective, so use your best judgement (although if a function is 1000 lines long, it's almost certainly too complex).
If a function is intended to fetch a value, then it MUST always return a value of some sort, even if an error is encountered. If a function is intended to perform a task, no return value is required. However, it is highly recommended to provide a boolean return value to indicate if the function was executed properly.
In commands such as for
and while
, where it is possible to execute code in areas intended for specific actions, no actions other than the intended ones are allowed. For example:
Good:
for [{ private _i = 0 }, { _i < 10 }, { _i = _i + 1 }] do {
systemChat str _i;
};
Bad:
while { someObject setPos (getPos player); true } do {};
Any variable that is a constant MUST be put in a #define
. For private constants used more than once, a define can be put at the top of the file. A comment should also describe its importance if it is not already clear. For public constants (used across multiple functions or modules), there are a few steps that must be taken.
- If the module does not already have one, create a file titled
script_macros.hpp
. - Define the constant
- In
script_component.hpp
, add#include \z\sia3f\addons\MODULE\script_macros.hpp
to a new line. - Add the same include to any other modules' script component.
- If the macro is to be used in functions, document it and all of the modules that import it in section 3.4. For the documentation, the purpose and context of the constant should be described. E.g,
PI
: 3.14 - rounded value of pi - used with circles.
Functions should log any errors that occur, whether they be invalid inputs, failure to fetch a variable, or other errors. Any sufficiently significant events should also be logged (such as some major aspect of the framework starting/finishing loading). See the Section 3.3 RPT Logging Macros.
Parameters of functions should be called through the arguments of call
or spawn
and retrieved through the usage of the params
command. For consistency, the param
command is not allowed. If the function is public (i.e, it is supported for mission makers to use it in their own code), the function must check the data type and value (if applicable) of the passed parameters. The use of the CBA Macro PARAM_x
or BIS_fnc_param
is prohibited. Global variables should NEVER be used to pass information from one function to another.
Good:
// in fnc_someFunc.sqf
params ["_content"];
hint _content;
["Hello world!"] call FUNC(someFunc);
Bad:
// in fnc_someFunc.sqf
hint GVAR(myVar);
GVAR(myVar) = "Hello World!";
call FUNC(someFunc);
Variables should be declared at the smallest feasible scope with a meaningful value. See ACE3's guidelines on Variable Declarations and Variable Initialization for some good examples. When using getVariable
, the value MUST either have a default value given in the statement, or the return value must be checked for a nil
value. A default value may not be given after a nil
check. See ACE3's guidelines on getVariable
for some good examples.
This section will define how functions, configs, and macros shall be documented. All code should be documented both as a part of the code and externally for a general overview. This is done in order to easily understand how each module of the mod functions and relates to the mod as a whole.
Each module MUST have a README.md file located at the file path \addons\MODULE\README.md
. The title MUST be the module's name. Following the title, there should be a concise description (no more than 5 sentences.) of what the module's purpose is in the mod. Elaborate where necessary, but stay within the scope of the module.
Following the module description, any config entries in the file shall be defined under a subsection, "Config Definitions". Optionally, give a brief description of what the configs do. Then, describe each config entry with the config name at the top (e.g, CfgPatches or Cfg3DEN) with all subclasses under its respective config. Since all configs should have their own file, the file name should be a good reference for the config name. As
If the module does not have any config definitions, this can be skipped.
Since all functions are required to have descriptions within the file they are defined in, only public functions (i.e, ones supported for mission makers to use it in their own code) need to be defined in the README file. The functions shall be described under a subsection "Function Definitions" and optionally, a brief description of what the module's functions generally do. The function description must include the full name of the function (see section 2.1 Function Names), the parameters and returns, a brief description or what the function does, examples, and any notes. For the parameters and returns, a table must be used, for example:
Argument | Type | Description | Optional (default value) | |
---|---|---|---|---|
0 | Box | Object | Box to add arsenal items to. | Required |
1 | Items | Array of Strings OR Boolean | Items to add to arsenal. String for specific class names, true to add all items, false to remove all items. | Optional (true) |
R | Success | Boolean | True if items successfully added, False if not | Return value |
See ACE3's framework for more examples; Especially ace_arsenal_fnc_addStat for an example of a function having strict arrays as an argument.
After the config and function definitions, ALL macro definitions shall be defined with their name, a description of what they do, the parameters, what its purpose is/what it evaluates to, and example(s). See the main macro definitions for examples.
This section will define how wiki pages should be formatted. Note that only important macros and public functions need be defined in the wiki.
All macros intended for direct use must be added to section 3.4 Custom Macros of this wiki. Give the macro with an example parameter and context (if applicable), a description of what the macro does, and what it will expand to or directly return, whichever is most applicable.
All public functions must be defined in the Public Functions page of this wiki. Most, if not all, information can be copied from the module's README. The page must include the module name as a header and optionally a short description of what all of the functions generally do (e.g, the movement module might deal with getting position info and moving objects). The function description must include the full name of the function (see section 2.1 Function Names), the parameters and returns, a brief description or what the function does, examples, and any notes. For the parameters and returns, a table must be used. See Section 6.1.2 Function Definitions for an example.
See ACE3's guidelines on Design Considerations section 7.1 - 7.3. I don't know why they include the hashes macros there, but it is irrelevant to this section. Additionally, see their guidelines on Performance Considerations.
These instructions are very similar to those for CBA_A3 and ACE 3.
Note: These requirements are subject to change. If you have problems building in the future, check back here.
- Arma 3 Tools
- project (P) drive
- Python version >= 3.0
- Mikero Tools PboProject
- ArmaScriptCompiler.exe (Optional)
- Ensure that the folder that contains the
addons
folder is namedsia3f
. - Setup the project drive (P:\)
- Ensure that there is no current drive with the 'P' label
- Open Arma 3 Tools
- Click the "Mount the Project Drive" button located in the "Other" section
- Note that you will have to do this every time you restart your computer.
- Run the ArmA3p program from Mikero Tools. This will copy and de-pbo all of Arma's game files to the project drive, which is required for some other projects. The ArmA3p program requires the DeOgg, ExtractPbo, DePbo, and DeRap programs, also from Mikero Tools. After installing all programs, restart your computer, ensure the P:\ drive is mounted, and run ArmA3p (should be at
C:\Program Files (x86)\Mikero\DePboTools\bin\Arma3P.cmd
). For "Enter drive to extract to E..Z", enterP
. For "full extraction including layers, dubbing and missions (base addons only)? [Y,N]?", enterN
. orY
, idgafN
is just faster.
- Setup Mikero Tools PboProject.
- Like the ArmA3p program, this may require you to install other programs from the same page. This is required for using the
make.py
script.
- Like the ArmA3p program, this may require you to install other programs from the same page. This is required for using the
- Download the Arma Script Compiler and move it to the project directory (the same folder as the sqfc.json file).
- Run the
setup.py
script. Ensure that the detected paths AND the paths above them are correct. - Run the
make.py
script. This should build the mod into.\release\@sia3f
.