Difference between revisions of "Arma 3: Functions Library"

From Bohemia Interactive Community
Jump to navigation Jump to search
m (fixed link to functions viewer)
(96 intermediate revisions by 16 users not shown)
Line 1: Line 1:
[[Category:Arma 3: Editing]]
+
{{TOC|side}}
  
 
Arma 3 '''Functions Library''' is pack of routine script functions available from anywhere in game. Main difference from older [[Functions Library]] is that it runs automatically and doesn't require Functions manager to be present.
 
Arma 3 '''Functions Library''' is pack of routine script functions available from anywhere in game. Main difference from older [[Functions Library]] is that it runs automatically and doesn't require Functions manager to be present.
 +
  
 
== Finding a Function ==
 
== Finding a Function ==
[[File:A3_functionwViewer.png|300px|thumb|right|Functions Viewer]]
 
Before you can use a function, you first need to find it. The easies way is to access the '''Functions Viewer''':
 
  
* In editor, click on [[File:icon editor functions.png|20px]] icon or press Ctrl + F
+
See [[Arma 3: Functions Viewer]].
* In mission, access the [[Mission_Editor:_Debug_Console|debug console]] (automatically visible in pause menu of an editor mission) and click on '''FUNCTIONS''' button.
 
  
Once in the '''Functions Viewer''', you can filter all available functions by location, projects and categories.
+
{{Feature|Informative|Some functions, especially the older ones, may have missing or incomplete headers.<br>We do our best to update them, but if you find some issues, feel free to report them in the [http://feedback.arma3.com/ Feedback Tracker].}}
  
When you find the desired function, look at the code preview on the right. Every function has a header where you can find basic description of its functionality including required arguments, returned values and sometimes examples of use.
+
All functions are also listed in [[:Category:Arma_3:_Functions|Arma 3 Functions]] category.
 
 
{{note|Some functions, especially the older ones, may have missing or incomplete headers.<br />We do our best to update them, but if you find some issues, feel free to report them in the [http://feedback.arma3.com/ Feedback Tracker].}}
 
  
 +
== Calling a Function ==
  
== Calling a Function ==
 
 
Functions can be launched in mission, intro and outro using this [[call]] or [[spawn]] commands:
 
Functions can be launched in mission, intro and outro using this [[call]] or [[spawn]] commands:
 
  _returnedValue = ''arguments'' [[call]] ''functionName'';
 
  _returnedValue = ''arguments'' [[call]] ''functionName'';
Line 23: Line 19:
  
 
=== Arguments ===
 
=== Arguments ===
 +
 
Arguments are data sent into the function, affecting its behavior.
 
Arguments are data sent into the function, affecting its behavior.
  
Line 29: Line 26:
 
* Optional arguments allows more detailed configuration. If you dont send them, the function will use pre-defined default values.
 
* Optional arguments allows more detailed configuration. If you dont send them, the function will use pre-defined default values.
  
{{note|Within the function, '''arguments''' are called '''parameters''', or simply params.}}
+
{{Feature|Informative|Within the function, '''arguments''' are called '''parameters''', or simply params.}}
  
  
Line 39: Line 36:
 
  Ends mission with specific ending.
 
  Ends mission with specific ending.
 
   
 
   
  <span style="color:DarkCyan;">Parameter(s):
+
  {{Color|DarkCyan|Parameter(s):
 
  0 (Optional):
 
  0 (Optional):
 
  STRING - end name (default: "end1")
 
  STRING - end name (default: "end1")
Line 46: Line 43:
 
  2 (Optional):
 
  2 (Optional):
 
  BOOL - true for signature closing shot (default: true)
 
  BOOL - true for signature closing shot (default: true)
  NUMBER - duration of a simple fade out to black</span>
+
  NUMBER - duration of a simple fade out to black}}
 
   
 
   
 
  Returns:
 
  Returns:
Line 54: Line 51:
 
As you can see, all arguments are marked optional and you can call the function without them.
 
As you can see, all arguments are marked optional and you can call the function without them.
  
  [] call BIS_fnc_endMission;
+
  [] [[call]] [[BIS_fnc_endMission]];
 
:This will result in successfull ending of type "end1", preceeded with the signature [[Debriefing|closing shot]].
 
:This will result in successfull ending of type "end1", preceeded with the signature [[Debriefing|closing shot]].
  
  ["end2"] call BIS_fnc_endMission;
+
  ["end2"] [[call]] [[BIS_fnc_endMission]];
 
:Set the ending type to "end2", while keeping the other arguments intact.
 
:Set the ending type to "end2", while keeping the other arguments intact.
  
  ["end2",false,false] call BIS_fnc_endMission;
+
  ["end2", [[false]], [[false]]] [[call]] [[BIS_fnc_endMission]];
 
:Fail the mission without any effect, using "end2" type.
 
:Fail the mission without any effect, using "end2" type.
  
Line 66: Line 63:
 
However, what should you do if you want to set the '''only''' last argument without affecting the previous ones? The solution is simple - put an empty variable [[nil]] on their place.
 
However, what should you do if you want to set the '''only''' last argument without affecting the previous ones? The solution is simple - put an empty variable [[nil]] on their place.
  
  <nowiki>[</nowiki>[[nil]],[[nil]],false] call BIS_fnc_endMission;
+
  [<nowiki/>[[nil]], [[nil]], [[false]]] [[call]] [[BIS_fnc_endMission]];
 
:Disable the closing effects, but keep the other aguments intact (successful "end1").
 
:Disable the closing effects, but keep the other aguments intact (successful "end1").
  
{{note|Some older functions are incompatible with this syntax and using nil would break them. See their header for more information.}}
+
{{Feature | important | Some older functions are incompatible with this syntax and using nil would break them. See their header for more information.}}
  
 
=== Returned Value ===
 
=== Returned Value ===
 +
 
Functions executed by [[call]] command can return back a value. Let's take a look at [[BIS_fnc_sideName]]:
 
Functions executed by [[call]] command can return back a value. Let's take a look at [[BIS_fnc_sideName]]:
  
Line 83: Line 81:
 
  0: SIDE or NUMBER - either side or side ID
 
  0: SIDE or NUMBER - either side or side ID
 
   
 
   
  <span style="color:DarkCyan;">Returns:
+
  {{Color|DarkCyan|Returns:
  STRING</span>
+
  STRING}}
 
  */
 
  */
 
The function returns a [[String]] - localized name of a side.
 
The function returns a [[String]] - localized name of a side.
  _westName = [[west]] call BIS_fnc_sideName;
+
  _westName = [[west]] [[call]] [[BIS_fnc_sideName]];
 
:Variable _westName will now be "BLUFOR" (or other name, based on selected language)
 
:Variable _westName will now be "BLUFOR" (or other name, based on selected language)
  
 
=== Multiplayer ===
 
=== Multiplayer ===
Functions executed using [[call]] or [[spawn]] command will run only on the computer which triggered them. If you'd wish to execute a function remotely on specific clients, use [[BIS_fnc_MP]] function.
 
[arguments,''"functionName"'',''target'',''isPersistent''] call [[BIS_fnc_MP]];
 
  
 +
Functions executed using [[call]] or [[spawn]] command will run only on the computer which triggered them. If you'd wish to execute a function remotely on specific clients, use either [[remoteExec]] or [[remoteExecCall]].<br>
 +
[arguments] [[remoteExec]] ["functionName",target,isPersistent];
 +
 +
=== User Interface ===
 +
 +
Anywhere outside of running mission, refer to the functions stored in [[uiNamespace]].
 +
''arguments'' [[call]] ([[uiNamespace]] [[getVariable]] ''"functionName"'');
  
 
== Adding a Function ==
 
== Adding a Function ==
''WIP''
+
When writing a script, consider registering it into the Functions Library.
=== Mission ===
 
=== Addon ===
 
  
 +
Main benefits:
 +
# '''Automatic compilation upon mission start''' into a global variable - no need to remember direct paths to files.
 +
# '''Anti-hack protection''' using [[compileFinal]] (see [[#Recompiling|Recompiling ]] for more info)
 +
# '''Listing in the Functions Viewer'''
 +
# '''Advanced debugging options'''
 +
# '''Optional immediate execution upon mission start''', without need for manual call
 +
# '''Potential performance improvements'''
  
== Writing a Function ==
 
''WIP''
 
  
<!--
+
Mission and campaign specific functions can be configured in [[Description.ext]], while addon functions are defined in [[Config.cpp]]. Configuration structure is the same in both cases.
== Preview ==
 
[[File:A3_functionwViewer.png|300px|thumb|right|In-game functions viewer]]
 
Use the following code to display function library anywhere in game:
 
[] call [[BIS_fnc_help]];
 
  
In 2D editor, press 'Ctrl + F' to display the viewer or click on icon: [[File:icon editor functions.png|20px]]
+
=== Tag ===
  
Features:
+
Functions are configured within CfgFunctions class. To prevent duplicities, every author must create a subclass with unique ''tag'' and place functions inside it. The tag name will be used when composing a function name.
* Listing through all functions from config or [[Description.ext]] files.
+
class CfgFunctions
* Displaying name, path, description and code of selected functions.
+
{
* Code can be easily copied to clipboard.
+
class {{Color|green|myTag}}
 +
{
 +
class Anything
 +
{
 +
tag = "{{Color|green|myTag}}"; {{cc|Custom tag name}}
 +
requiredAddons[] = {"A3_Data_F"}; {{cc|Optional requirements of CfgPatches classes. When some addons are missing, functions won't be compiled.}}
 +
};
 +
};
 +
};
  
 +
=== Path ===
  
== Execution ==
+
==== File Path ====
=== Singleplayer ===
+
The easiest and the most transparent way is to set path for each function.
Functions can be launched in mission, intro and outro using this syntax:
+
class CfgFunctions
  _fnc = [params] call functionName;
+
  {
or
+
class {{Color|green|myTag}}
  _fnc = [params] spawn functionName;
+
{
 +
class myCategory
 +
{
 +
class {{Color|teal|myFunction}} {file = "{{Color|DarkOrange|myFile.sqf}}";};
 +
};
 +
};
 +
};
 +
This will try to compile function '''<big>{{Color|green|myTag}}_fnc_{{Color|teal|myFunction}}</big>''' from the following file:
 +
  ''%ROOT%''\{{Color|DarkOrange|myFile.sqf}}
 +
Where ''%ROOT%'' is either '''[[Mission_Editor:_External#Mission_Folder|mission root]]''' (where mission.sqm file is), or the '''game root''' (path to an addon is not included and has to be part of the file path, e.g., {{Color|DarkOrange|myAddon\myFile.sqf}}).
  
=== Multiplayer ===
+
==== Folder Path ====
Functions replaces obsolete [[Multiplayer_framework|Multiplayer Framework]]. You can use [[BIS_fnc_MP]] to remotely call function on specific clients and set them to be persistent, so they'll be executed automatically for client upon JIP.
+
You can set folder path and leave the function paths undefined. The functions will then be loaded from the folder.
  [params,"functionName",target,isPersistent] call BIS_fnc_MP;
+
  class CfgFunctions
 +
{
 +
class {{Color|green|myTag}}
 +
{
 +
class myCategory
 +
{
 +
file = "{{Color|DarkOrange|myPath}}";
 +
class {{Color|teal|myFunction}} {};
 +
};
 +
};
 +
};
 +
Compile function '''<big>{{Color|green|myTag}}_fnc_{{Color|teal|myFunction}}</big>''' from the following file:
 +
''%ROOT%''\{{Color|DarkOrange|myPath}}\fn_{{Color|teal|myFunction}}.sqf
 +
{{Color|DarkOrange|myPath}} can be a folder or multiple folders, e.g., {{Color|DarkOrange|myFolder\mySubfolder}}
  
=== GUI ===
+
==== Default Path (Mission Only) ====
Anywhere outside running mission (user interface), refer to functions stored in UInamespace
+
In a mission, you can leave also the folder path undefined and let functions be loaded from the default directory.
  _fnc = [params] call (uinamespace getvariable 'functionName');
+
class CfgFunctions
or
+
{
  _fnc = [params] spawn (uinamespace getvariable 'functionName');
+
class {{Color|green|myTag}}
 +
{
 +
class {{Color|crimson|myCategory}}
 +
{
 +
class {{Color|teal|myFunction}} {};
 +
};
 +
};
 +
  };
 +
Compile function '''<big>{{Color|green|myTag}}_fnc_{{Color|teal|myFunction}}</big>''' from the following file:
 +
  ''%ROOT%''\functions\{{Color|crimson|myCategory}}\fn_{{Color|teal|myFunction}}.sqf
  
 +
=== Attributes ===
  
== Configuration ==
+
Apart from already mentioned ''file'', function class can have additional attributes:
List of functions is defined in config under CfgFunctions container. New ones can be also added in description.ext file of mission or campaign.
 
 
 
 
  class CfgFunctions
 
  class CfgFunctions
 
  {
 
  {
  class A3
+
  class {{Color|green|myTag}}
 
  {
 
  {
tag = "<span style="color:green;">BIS</span>";
+
  class myCategory
requiredAddons[] = {"A3_Data_F"}; {{codecomment|// Optional requirements of CfgPatches classes}}
 
  class <span style="color:crimson;">category</span>
 
 
  {
 
  {
  file = "<span style="color:DarkOrange;">A3\functions_f\Misc</span>";
+
  class {{Color|teal|myFunction}}
class <span style="color:teal;">Test1</span> {description="Testing file 2";};
+
{
class <span style="color:teal;">Test2</span> {description="Testing file 3"; file="<span style="color:DarkOrange;">test.sqf</span>"};
+
preInit = 1; {{cc|(formerly known as "forced") 1 to call the function upon mission start, <u>before</u> objects are initialized. Passed arguments are ["preInit"]}}
class <span style="color:teal;">Test3</span> {description="Testing file 4 (FSM)"; ext="<span style="color:fuchsia;">.fsm</span>"};
+
postInit = 1; {{cc|1 to call the function upon mission start, <u>after</u> objects are initialized. Passed arguments are ["postInit", didJIP]}}
 +
preStart = 1; {{cc|1 to call the function upon game start, before title screen, but after all addons are loaded (config.cpp only)}}
 +
ext = ".fsm"; {{cc|Set file type, can be ".sqf" or ".fsm" (meaning scripted FSM). Default is ".sqf".}}
 +
headerType = -1; {{cc|Set function header type: -1 - no header; 0 - default header; 1 - system header.}}
 +
recompile = 1; {{cc|1 to recompile the function upon mission start (config.cpp only; functions in description.ext are compiled upon mission start already)}}
 +
};
 
  };
 
  };
 
  };
 
  };
 
  };
 
  };
 +
All of these attributes are case sensitive.
 +
 +
==== Pre and Post Init ====
 +
''preInit'' and ''postInit'' attributes are truly powerful ones, as they let you execute your function at the beginning of '''every''' mission. Use them with caution!.<br>
 +
''preInit'' are '''called''' [[Scheduler#Unscheduled_Environment|unscheduled]] so suspension is not allowed. Parameters passed are [ "preInit" ].<br>
 +
''postInit'' are '''called''' [[Scheduler#Scheduled_Environment|scheduled]] so suspension is allowed '''but any long term suspension will halt the mission loading until suspension has finished.''' Parameters passed are [ "postInit", [[didJIP]] ].<br>
 +
 +
* Any scripting error will prevent the mission from being loaded correctly
 +
* Server admins might blacklist your addon if they find out you're using the function for hacking.
 +
<!-- HIDDEN as per note in talk page by STR
 +
 +
==== Header Types ====
 +
The different header types add code to the begining of your functions that can..
 +
*Set up the [[#Meta Variables|Meta Variables]] _fnc_scriptParent and _fnc_scriptName
 +
*Name the current scope via the command [[scriptName]]
 +
*Adds debug information by saving the current execution order in the [[Array]] _fnc_scriptMap.
 +
 +
 +
:'''''No Header'''''<br>
 +
:Adds nothing, literally adds a blank [[String]] to the begining of your function. The function will have no debug or [[#Meta Variables|Meta Variables]] assigned for it and the scope will not be named.
 +
 +
 +
:'''''System Header'''''<br>
 +
:Incorporates the [[#Meta Variables|Meta Variables]] _fnc_scriptParent. Also names the current scope.
 +
:{|
 +
|
 +
private _fnc_scriptNameParent = if (isNil '_fnc_scriptName') then {'%1'} else {_fnc_scriptName};
 +
scriptName '%1';
 +
|}
 +
 +
 +
:'''''Default Header'''''<br>
 +
:The default header changes based on the current [[#Debug Mode:Debug Mode]]
 +
 +
::''Debug Mode 0'' - default<br>
 +
::Incorporates the [[#Meta Variables|Meta Variables]] _fnc_scriptParent and _fnc_scriptName and names the current scope.
 +
::{|
 +
|
 +
private _fnc_scriptNameParent = if (isNil '_fnc_scriptName') then {'%1'} else {_fnc_scriptName};
 +
private _fnc_scriptName = '%1';
 +
scriptName _fnc_scriptName;
 +
|}
 +
 +
::''Debug Mode 1''<br>
 +
::As per ''Debug Mode 0'' and also saves the current execution order in the [[Array]] _fnc_scriptMap.
 +
::{|
 +
|
 +
private _fnc_scriptNameParent = if (isNil '_fnc_scriptName') then {'%1'} else {_fnc_scriptName};
 +
private _fnc_scriptName = '%1';
 +
scriptName _fnc_scriptName;
 +
private _fnc_scriptMap = if (isNil '_fnc_scriptMap') then {[_fnc_scriptName]} else {_fnc_scriptMap + [_fnc_scriptName]};
 +
|}
 +
 +
::''Debug Mode 2''<br>
 +
::As per ''Debug Mode 1'' and also outputs execution order using [[textLogFormat]] ( textLogFormat is not available in the retail version of Arma3 ) is it available in Diagnostics exe?
 +
::{|
 +
|
 +
private _fnc_scriptNameParent = if (isNil '_fnc_scriptName') then {'%1'} else {_fnc_scriptName};
 +
private _fnc_scriptName = '%1';
 +
scriptName _fnc_scriptName;
 +
private _fnc_scriptMap = if (isNil '_fnc_scriptMap') then {[_fnc_scriptName]} else {_fnc_scriptMap + [_fnc_scriptName]};
 +
textLogFormat ['%1 : %2', _fnc_scriptMap joinString ' >> ', _this];
 +
|}
 +
END HIDDEN -->
 +
 +
=== Initialization Order ===
 +
 +
''See [[Initialization_Order]]''
 +
 +
 +
== Writing a Function ==
 +
 +
The most important thing to remember when writing a function is that other people than you are going to use it. Most of them won't understand how does it work, expecting it to do its job without problems.
 +
 +
Your function must be '''robust'''. It shouldn't allow passing arguments of incorrect [[:Category: Data Types| Data Types]] in. When some values are incorrect, it should throw an error explaining what went wrong and how to fix it. And above all, its header must provide complete explanation of usage.
 +
{{Feature | important | What is not documented does not exist!}}
 +
 +
=== Loading Parameters ===
 +
 +
Arguments are the only way how to interact with your function. Let's now see how to make sure they are loaded properly.
 +
 +
We have this very simple function which will let a unit watch a position:
 +
[[params]] ["_unit", "_target"];
 +
_unit [[doWatch]] _target;
 +
 +
Expected way how to call the function is by correctly defining all arguments:
 +
{|
 +
| {{Icon|checked}}
 +
|
 +
[<nowiki/>[[player]], [[position]] myCar] [[call]] myTag_fnc_myFunction;
 +
|}
 +
 +
However, the function will break down when you try to send only one argument in:
 +
{|
 +
| {{Icon|unchecked}}
 +
|
 +
[<nowiki/>[[player]]] [[call]] myTag_fnc_myFunction;
 +
|}
 +
 +
Furthermore, using wrong data type will also lead to a problem:
 +
{|
 +
| {{Icon|unchecked}}
 +
|
 +
[<nowiki/>[[player]], 0] [[call]] myTag_fnc_myFunction;
 +
|}
 +
 +
Variabe ''_target'' expects position array in format [x,y,z]. Scripting error will appear when different number of elements is used:
 +
{|
 +
| {{Icon|unchecked}}
 +
|
 +
[<nowiki/>[[player]], [1, 2, 3, 4]] [[call]] myTag_fnc_myFunction;
 +
|}
 +
 +
 +
As you can see there, the most common problems are:
 +
# '''Param of wrong data type is sent'''
 +
# '''Param is missing'''
 +
# '''Param is an array expecting specific number of elements, but different number is sent'''
 +
 +
Rather than check for these exceptions yourself, you can use existing [[param]] command which will do it for you:
 +
_unit = [[param]] [{{Color|darkorange|0}}, {{Color|teal|objNull}}, {{Color|crimson|[objNull]}}];
 +
For multiple parameters, use the [[params]] command instead.
 +
[[params]] [
 +
[{{Color|green|"_unit"}}, {{Color|teal|objNull}}, {{Color|crimson|[objNull]}}],
 +
[{{Color|green|"_target"}}, {{Color|teal|[0, 0, 0]}}, {{Color|crimson|[[], objNull]}}, {{Color|indigo|[2, 3]}}]
 +
];
 +
_unit [[doWatch]] _target;
 +
* In a [[params]] array first argument is the name of the '''{{Color|green|private variable}}'''. In [[param]] it is the '''{{Color|darkorange|index}}''' number.
 +
* Second argument is the '''{{Color|teal|default value}}'''. It will be used when the argument is missing, is [[nil]] or when wrong data type is used.
 +
* Next is optional '''{{Color|crimson|array of compatible data types}}'''. They are defined by an example of the type, e.g. [[objNull]] will mean an object is allowed. When wrong data type is sent into your function, BIS_fnc_param will log an error message explaining what went wrong and use the default value.
 +
* The last, also optional argument is an '''{{Color|indigo|array of required array sizes}}'''. [2,3] means only array with 2 or 3 elements are allowed. When incorrectly large array is sent into your function, BIS_fnc_param will log an error message explaining what went wrong and use the default value.
 +
 +
 +
Let's see what will happen when you try to use the wrong examples now:
 +
{|
 +
| {{Icon|checked}}
 +
|
 +
[<nowiki/>[[player]]] [[call]] myTag_fnc_myFunction;
 +
|}
 +
: ''_target'' is undefined. Default {{Color|teal|[0, 0, 0]}} is used instead. No error message is logged.
 +
 +
{|
 +
| {{Icon|checked}}
 +
|
 +
[<nowiki/>[[nil]], [[position]] myCar] [[call]] myTag_fnc_myFunction;
 +
|}
 +
: ''_unit'' is undefined (nil is passed instead). Default {{Color|teal|objNull}} is used instead. No error message is logged.
 +
 +
{|
 +
| {{Icon|warning}}
 +
|
 +
[<nowiki/>[[player]], 0] [[call]] myTag_fnc_myFunction;
 +
|}
 +
: ''_target'' has wrong {{Color|crimson|type}}. Default {{Color|teal|[0, 0, 0]}} is used instead. Error message is logged.
 +
 +
{|
 +
| {{Icon|warning}}
 +
|
 +
[<nowiki/>[[player]], [1, 2, 3, 4]] [[call]] myTag_fnc_myFunction;
 +
|}
 +
: ''_target'' has wrong {{Color|indigo|size}}. Default {{Color|teal|[0, 0, 0]}} is used instead. Error message is logged.
 +
 +
 +
Additionally, when only one argument is used, you can send it into the function directly without need to have it in an array.
 +
{|
 +
| {{Icon|checked}}
 +
|
 +
[[player]] [[call]] myTag_fnc_myFunction;
 +
|}
 +
 +
=== Returning Value ===
  
* If ''file'' path is not set for the given function, system will search for file in
+
Users will often save result of your function to a variable. If no value is returned, the variable would be [[nil]] and could lead to script errors.
**<code>'<span style="color:DarkOrange;">file</span>\<span style="color:crimson">category</span>\fn_<span style="color:teal">function</span>.sqf"</code> (if functions is defined in description.ext)
+
_myVar = [<nowiki/>[[player]], [[position]] myCar] [[call]] myTag_fnc_myFunction;
* When ''file'' parameter is defined in category root, all functions in given category will be searched for in this directory.
 
  
Result of example code above is:
+
It's good practice to '''always''' return a value, even if it would be simple [[true]] marking the function as completed. Let's use the example function from above:
* '''<span style="color:green;">BIS</span>_fnc_<span style="color:teal;">Test1</span>''' - will load script <code><span style="color:DarkOrange;">A3\functions_f\Misc</span>\<span style="color:crimson;">category</span>\fn_<span style="color:teal;">Test1</span>.sqf</code>
+
[[params]] [
* '''<span style="color:green;">BIS</span>_fnc_<span style="color:teal;">Test2</span>''' - will load script <code><span style="color:DarkOrange;">test.sqf</span></code> from mission directory
+
["_unit", [[objNull]], [objNull]],
* '''<span style="color:green;">BIS</span>_fnc_<span style="color:teal;">Test3</span>''' - will load FSM <code><span style="color:DarkOrange;">A3\functions_f\Misc</span>\<span style="color:crimson;">category</span>\<span style="color:teal;">Test4</span><span style="color:fuchsia;">.fsm</span></code>
+
["_target", [0, 0, 0], [[], [[objNull]]], [2, 3]]
 +
];
 +
_unit [[doWatch]] _target;
 +
'''[[true]]'''
  
Optional function class params:
+
=== Showing Errors ===
* '''description''' - Short function description. Will be rendered obsolete in further revisions, with script headers serving as the main source of documentation.
 
* '''ext''' - file type, can be ".sqf" or ".fsm" (meaning scripted FSM). Default is ".sqf".
 
* '''file''' - optional direct path to the file.
 
* '''recompile''' (new in Arma 3) - function will be recompile upon mission start.
 
* '''preInit''' (new in Arma 3) - function will be executed automatically upon mission start, before objects are loaded.
 
* '''postInit''' (new in Arma 3) - function will be executed automatically upon mission start, after objects are loaded.
 
  
== Debugging ==
+
While [[param]] and [[params]] can filter out the most common issues, sometimes your function will have special rules which will need to be handled. Let's return back to our example function, where we'd want to terminate the function with error when ''_unit'' is dead:
 +
[[params]] [["_unit", [[objNull]], [objNull]], ["_target", [0, 0, 0], [[], [[objNull]]], [2, 3]]];
 +
'''[[if]] (![[alive]] _unit) [[exitWith]] { ["Unit %1 must be alive.", _unit] [[call]] [[BIS_fnc_error]]; [[false]] };'''
 +
_unit [[doWatch]] _target;
 +
[[true]]
 +
Notice that we're returning [[false]] at the end of [[exitWith]] code.
 +
{{Feature|important|Error states must always return value of the same type as when everything is fine ([[Boolean]] in this case).}}
  
=== Debug Functions ===
 
Use debug functions to register params, display errors and log messages to [[RPT]] file. Printed output of these functions automatically contains name of function from which it was called.
 
  
To prevent RPT spam, logging is disabled by default. Enable it by placing the following parameter to your mission [[Description.ext]]:
+
[[BIS_fnc_error]] accepts [[String]] and [[Array]] of [[format]]ted ext. The error is logged into [[RPT]] and if the mission is previewd from the editor, it will also appear on screen.
allowFunctionsLog = 1;
+
{|
 +
| [[RPT]]
 +
|
 +
"User1/log: ERROR: [BIS_fnc_respawnTickets] #0: 0 is type SCALAR, must be NAMESPACE, SIDE, GROUP, OBJECT, BOOL. true used instead."
 +
|-
 +
| In-game
 +
| [[File:A3 functions error.jpg|800px|On-screen error]]
 +
|}
  
{{Important|Usage of following functions is strongly recommended:
+
=== Logging ===
* [[BIS_fnc_param]]
 
* [[BIS_fnc_log]]
 
* [[BIS_fnc_error]]
 
* [[BIS_fnc_halt]]
 
}}
 
  
Examples of debug outputs:
+
Apart from errors, you can print any debug message you need. Use one of the following functions:
{{codecomment|"Config param 'splendid' not defined in CfgArma." call BIS_fnc_halt;}}
+
* [[BIS_fnc_log]] - log a data of any type (e.g., [[String]], [[Number]], [[Object]], ...)
"Log: HALT: [BIS_fnc_isSplendid] Config param 'splendid' not defined in CfgArma."
+
* [[BIS_fnc_logFormat]] - log [[format]]ted text
 +
Profile name and function name will automatically appear in the output text, helping you identify the source.
  
{{codecomment|_mission <nowiki>=</nowiki> [BIS_Player] call [[BIS_fnc_endMission]];}}
 
"Log: ERROR: [BIS_fnc_endMission] 0: BIS_Player is type OBJECT, must be STRING. "end1" used instead."
 
  
  {{codecomment|["Persistent execution is not allowed when target is %1. Use %2 or %3 instead.",typename 0,typename objnull,typename false] call BIS_fnc_error;}}
+
Usage examples:
  "Log: ERROR: Persistent execution is not allowed when target is SCALAR. Use OBJECT or BOOL instead."
+
{| class="wikitable"
 +
! Expression
 +
! [[RPT]] Output
 +
|-
 +
|
 +
{{Color|green|"Hello World"}} [[call]] [[BIS_fnc_log]];
 +
|
 +
"User1/BIS_fnc_log: [myTag_fnc_myFunction] {{Color|green|Hello World}}"
 +
|-
 +
|
 +
{{Color|green|42}} [[call]] [[BIS_fnc_log]];
 +
|
 +
  "User1/BIS_fnc_log: [myTag_fnc_myFunction] {{Color|green|42}}"
 +
|-
 +
|
 +
[{{Color|green|"I'm playing %1"}}, [[missionName]]] [[call]] [[BIS_fnc_logFormat]];
 +
|
 +
  "User1/BIS_fnc_log: [myTag_fnc_myFunction] {{Color|green|I'm playing FalconWing}}"
 +
|}
  
{{codecomment|42 call BIS_fnc_log;}}
 
"BIS_fnc_log: [BIS_fnc_myFunction]: 42"
 
  
{{codecomment|["Random number is %1",random 999] call BIS_fnc_log;}}
+
To prevent RPT spam, logging is by default enabled only when previewing a mission from the editor. To force it in the mission everywhere, use the following [[Description.ext]] attribute:
"BIS_fnc_log: [BIS_fnc_myFunction] Random number is 808.768"
+
<syntaxhighlight lang="cpp">
 +
allowFunctionsLog = 1;
 +
</syntaxhighlight>
  
 +
=== Recompiling ===
  
=== Allow Recompile ===
+
Once compiled, functions remain unchanged and editing their file won't have any effect in the game. To adjust functions on the fly, you can manually trigger their recompilation.
For security reasons, all functions are compiled using [[compileFinal]] and cannot be rewritten afterwards). When writing and testing a function, this would require game restart after every single change.
+
1 [[call]] [[BIS_fnc_recompile]];
 +
:Recompiles all functions. Can be also achieved by clicking on RECOMPILE button in the Functions Viewer
 +
"''functionName''" [[call]] [[BIS_fnc_recompile]];
 +
:Recompile the given function
  
To allow recompiling [[missionNamespace]] functions, place following param into mission [[Description.ext]]:
+
As a security measure, functions are by default protected against rewriting during the mission. <u>This restriction does not apply in missions previewed from the editor and in missions with the following attribute in [[Description.ext]]</u>:
allowFunctionsRecompile = 1;
+
<syntaxhighlight lang="cpp">
 +
allowFunctionsRecompile = 1;
 +
</syntaxhighlight>
  
''Note: Unavailable in the 0.56.104778 default build, planned for the next one. Dev builds might receive the feature sooner. Use '''recompile = 1;''' function param for debugging your own functions meanwhile.''
+
"Recompile" button in the functions viewer will be enabled only when recompiling is allowed.
 +
 
 +
=== Meta Variables ===
  
 +
System is adding header with basic meta data to all functions. Following local variables are declared there:
 +
* '''_fnc_scriptName''': [[String]] - Function name (e.g., myTag_fnc_myFunction)
 +
* '''_fnc_scriptNameParent''': [[String]] - Name of q function from which the current one was called (_fnc_scriptName used when not defined)
 +
<!--* '''_fnc_scriptMap''': ARRAY - List of all parent scripts (available only in debug mode 1 and higher, see [[#Debug_Mode|above]]).-->
 +
{{Feature|important|Do not modify these values!}}
  
 +
<!--
 
=== Debug Mode ===
 
=== Debug Mode ===
 
Developers can access several debug modes using ''[[BIS_fnc_functionsDebug]]'' function.
 
Developers can access several debug modes using ''[[BIS_fnc_functionsDebug]]'' function.
Line 220: Line 468:
 
#* Variable ''_fnc_scriptMap'' tracking script execution progress is stored in function header
 
#* Variable ''_fnc_scriptMap'' tracking script execution progress is stored in function header
 
# '''Save and log script map'''
 
# '''Save and log script map'''
#* Variable ''_fnc_scriptMap'' tracking script execution progress is stored in functions header and it's printed to debug log.
+
#* Variable ''_fnc_scriptMap'' tracking script execution progress is stored in functions header and it is printed to debug log.
{{Important|Function recompiling has to be allowed!}}
+
{{Feature|important|Function recompiling has to be allowed!}}
 +
-->
  
 
+
[[Category: Scripting Topics]]
=== Meta Variables ===
 
System is adding header with basic meta data to all functions. Following local variables are defined there:
 
* '''_fnc_scriptName''': STRING - Function name (<tag>_fnc_<name>)
 
* '''_fnc_scriptNameParent''': STRING - Name of function from which current one was called (_fnc_scriptName used when not defined)
 
* '''_fnc_scriptMap''': ARRAY - List of all parent scripts (available only in debug mode 1 and higher, see [[#Debug_Mode|above]]).
 
{{Important|Please do not modify these values!}}
 
 
 
 
 
=== Initialization Order ===
 
# '''Functions'''
 
# Init [[ArmA_2:_Event_Handlers|Event Handlers]]
 
# [[Mission.sqm]]
 
# [[Event_Scripts|Init.sqf]]
 
# [[Event_Scripts|Init.sqs]]
 
# [[Triggers]]
 
-->
 

Revision as of 16:39, 13 April 2021

Arma 3 Functions Library is pack of routine script functions available from anywhere in game. Main difference from older Functions Library is that it runs automatically and doesn't require Functions manager to be present.


Finding a Function

See Arma 3: Functions Viewer.

Some functions, especially the older ones, may have missing or incomplete headers.
We do our best to update them, but if you find some issues, feel free to report them in the Feedback Tracker.

All functions are also listed in Arma 3 Functions category.

Calling a Function

Functions can be launched in mission, intro and outro using this call or spawn commands:

_returnedValue = arguments call functionName;
arguments spawn functionName;

Arguments

Arguments are data sent into the function, affecting its behavior.

They can be mandatory or optional.

  • Mandatory arguments are required for function to run. When missing, the function usually stops and throws an error.
  • Optional arguments allows more detailed configuration. If you dont send them, the function will use pre-defined default values.
Within the function, arguments are called parameters, or simply params.


For example, let's take a look at BIS_fnc_endMission, a function which ends a mission with animated closing shot. This is what the header says:

/*
	Author: Karel Moricky

	Description:
	Ends mission with specific ending.

	Parameter(s):
		0 (Optional):
			STRING - end name (default: "end1")
			ARRAY in format [endName,ID], will be composed to "endName_ID" string
		1 (Optional): BOOL - true to end mission, false to fail mission (default: true)
		2 (Optional):
			BOOL - true for signature closing shot (default: true)
			NUMBER - duration of a simple fade out to black

	Returns:
	BOOL
*/

As you can see, all arguments are marked optional and you can call the function without them.

[] call BIS_fnc_endMission;
This will result in successfull ending of type "end1", preceeded with the signature closing shot.
["end2"] call BIS_fnc_endMission;
Set the ending type to "end2", while keeping the other arguments intact.
["end2", false, false] call BIS_fnc_endMission;
Fail the mission without any effect, using "end2" type.


However, what should you do if you want to set the only last argument without affecting the previous ones? The solution is simple - put an empty variable nil on their place.

[nil, nil, false] call BIS_fnc_endMission;
Disable the closing effects, but keep the other aguments intact (successful "end1").
Some older functions are incompatible with this syntax and using nil would break them. See their header for more information.

Returned Value

Functions executed by call command can return back a value. Let's take a look at BIS_fnc_sideName:

/*
	Author: Karel Moricky

	Description:
	Returns side name

	Parameter(s):
	0: SIDE or NUMBER - either side or side ID

	Returns:
	STRING
*/

The function returns a String - localized name of a side.

_westName = west call BIS_fnc_sideName;
Variable _westName will now be "BLUFOR" (or other name, based on selected language)

Multiplayer

Functions executed using call or spawn command will run only on the computer which triggered them. If you'd wish to execute a function remotely on specific clients, use either remoteExec or remoteExecCall.
[arguments] remoteExec ["functionName",target,isPersistent];

User Interface

Anywhere outside of running mission, refer to the functions stored in uiNamespace.

arguments call (uiNamespace getVariable "functionName");

Adding a Function

When writing a script, consider registering it into the Functions Library.

Main benefits:

  1. Automatic compilation upon mission start into a global variable - no need to remember direct paths to files.
  2. Anti-hack protection using compileFinal (see Recompiling for more info)
  3. Listing in the Functions Viewer
  4. Advanced debugging options
  5. Optional immediate execution upon mission start, without need for manual call
  6. Potential performance improvements


Mission and campaign specific functions can be configured in Description.ext, while addon functions are defined in Config.cpp. Configuration structure is the same in both cases.

Tag

Functions are configured within CfgFunctions class. To prevent duplicities, every author must create a subclass with unique tag and place functions inside it. The tag name will be used when composing a function name.

class CfgFunctions
{
	class myTag
	{
		class Anything
		{
			tag = "myTag"; // Custom tag name
			requiredAddons[] = {"A3_Data_F"}; // Optional requirements of CfgPatches classes. When some addons are missing, functions won't be compiled.
		};
	};
};

Path

File Path

The easiest and the most transparent way is to set path for each function.

class CfgFunctions
{
	class myTag
	{
		class myCategory
		{
			class myFunction {file = "myFile.sqf";};
		};
	};
};

This will try to compile function myTag_fnc_myFunction from the following file:

%ROOT%\myFile.sqf

Where %ROOT% is either mission root (where mission.sqm file is), or the game root (path to an addon is not included and has to be part of the file path, e.g., myAddon\myFile.sqf).

Folder Path

You can set folder path and leave the function paths undefined. The functions will then be loaded from the folder.

class CfgFunctions
{
	class myTag
	{
		class myCategory
		{
			file = "myPath";
			class myFunction {};
		};
	};
};

Compile function myTag_fnc_myFunction from the following file:

%ROOT%\myPath\fn_myFunction.sqf

myPath can be a folder or multiple folders, e.g., myFolder\mySubfolder

Default Path (Mission Only)

In a mission, you can leave also the folder path undefined and let functions be loaded from the default directory.

class CfgFunctions
{
	class myTag
	{
		class myCategory
		{
			class myFunction {};
		};
	};
};

Compile function myTag_fnc_myFunction from the following file:

%ROOT%\functions\myCategory\fn_myFunction.sqf

Attributes

Apart from already mentioned file, function class can have additional attributes:

class CfgFunctions
{
	class myTag
	{
		class myCategory
		{
			class myFunction
			{
				preInit = 1;		// (formerly known as "forced") 1 to call the function upon mission start, before objects are initialized. Passed arguments are ["preInit"]
				postInit = 1;		// 1 to call the function upon mission start, after objects are initialized. Passed arguments are ["postInit", didJIP]
				preStart = 1;		// 1 to call the function upon game start, before title screen, but after all addons are loaded (config.cpp only)
				ext = ".fsm";		// Set file type, can be ".sqf" or ".fsm" (meaning scripted FSM). Default is ".sqf".
				headerType = -1;	// Set function header type: -1 - no header; 0 - default header; 1 - system header.
				recompile = 1;		// 1 to recompile the function upon mission start (config.cpp only; functions in description.ext are compiled upon mission start already)
			};
		};
	};
};

All of these attributes are case sensitive.

Pre and Post Init

preInit and postInit attributes are truly powerful ones, as they let you execute your function at the beginning of every mission. Use them with caution!.
preInit are called unscheduled so suspension is not allowed. Parameters passed are [ "preInit" ].
postInit are called scheduled so suspension is allowed but any long term suspension will halt the mission loading until suspension has finished. Parameters passed are [ "postInit", didJIP ].

  • Any scripting error will prevent the mission from being loaded correctly
  • Server admins might blacklist your addon if they find out you're using the function for hacking.

Initialization Order

See Initialization_Order


Writing a Function

The most important thing to remember when writing a function is that other people than you are going to use it. Most of them won't understand how does it work, expecting it to do its job without problems.

Your function must be robust. It shouldn't allow passing arguments of incorrect Data Types in. When some values are incorrect, it should throw an error explaining what went wrong and how to fix it. And above all, its header must provide complete explanation of usage.

What is not documented does not exist!

Loading Parameters

Arguments are the only way how to interact with your function. Let's now see how to make sure they are loaded properly.

We have this very simple function which will let a unit watch a position:

params ["_unit", "_target"];
_unit doWatch _target;

Expected way how to call the function is by correctly defining all arguments:

Ico ok.png
[player, position myCar] call myTag_fnc_myFunction;

However, the function will break down when you try to send only one argument in:

Ico none.png
[player] call myTag_fnc_myFunction;

Furthermore, using wrong data type will also lead to a problem:

Ico none.png
[player, 0] call myTag_fnc_myFunction;

Variabe _target expects position array in format [x,y,z]. Scripting error will appear when different number of elements is used:

Ico none.png
[player, [1, 2, 3, 4]] call myTag_fnc_myFunction;


As you can see there, the most common problems are:

  1. Param of wrong data type is sent
  2. Param is missing
  3. Param is an array expecting specific number of elements, but different number is sent

Rather than check for these exceptions yourself, you can use existing param command which will do it for you:

_unit = param [0, objNull, [objNull]];

For multiple parameters, use the params command instead.

params [
	["_unit", objNull, [objNull]],
	["_target", [0, 0, 0], {{Color|crimson|[[], objNull]}}, [2, 3]]
];
_unit doWatch _target;
  • In a params array first argument is the name of the private variable. In param it is the index number.
  • Second argument is the default value. It will be used when the argument is missing, is nil or when wrong data type is used.
  • Next is optional array of compatible data types. They are defined by an example of the type, e.g. objNull will mean an object is allowed. When wrong data type is sent into your function, BIS_fnc_param will log an error message explaining what went wrong and use the default value.
  • The last, also optional argument is an array of required array sizes. [2,3] means only array with 2 or 3 elements are allowed. When incorrectly large array is sent into your function, BIS_fnc_param will log an error message explaining what went wrong and use the default value.


Let's see what will happen when you try to use the wrong examples now:

Ico ok.png
[player] call myTag_fnc_myFunction;
_target is undefined. Default [0, 0, 0] is used instead. No error message is logged.
Ico ok.png
[nil, position myCar] call myTag_fnc_myFunction;
_unit is undefined (nil is passed instead). Default objNull is used instead. No error message is logged.
Ico warning.png
[player, 0] call myTag_fnc_myFunction;
_target has wrong type. Default [0, 0, 0] is used instead. Error message is logged.
Ico warning.png
[player, [1, 2, 3, 4]] call myTag_fnc_myFunction;
_target has wrong size. Default [0, 0, 0] is used instead. Error message is logged.


Additionally, when only one argument is used, you can send it into the function directly without need to have it in an array.

Ico ok.png
player call myTag_fnc_myFunction;

Returning Value

Users will often save result of your function to a variable. If no value is returned, the variable would be nil and could lead to script errors.

_myVar = [player, position myCar] call myTag_fnc_myFunction;

It's good practice to always return a value, even if it would be simple true marking the function as completed. Let's use the example function from above:

params [
	["_unit", objNull, [objNull]],
	["_target", [0, 0, 0], [[], objNull], [2, 3]]
];
_unit doWatch _target;
true

Showing Errors

While param and params can filter out the most common issues, sometimes your function will have special rules which will need to be handled. Let's return back to our example function, where we'd want to terminate the function with error when _unit is dead:

params [["_unit", objNull, [objNull]], ["_target", [0, 0, 0], [[], objNull], [2, 3]]];
if (!alive _unit) exitWith { ["Unit %1 must be alive.", _unit] call BIS_fnc_error; false };
_unit doWatch _target;
true

Notice that we're returning false at the end of exitWith code.

Error states must always return value of the same type as when everything is fine (Boolean in this case).


BIS_fnc_error accepts String and Array of formatted ext. The error is logged into RPT and if the mission is previewd from the editor, it will also appear on screen.

RPT
"User1/log: ERROR: [BIS_fnc_respawnTickets] #0: 0 is type SCALAR, must be NAMESPACE, SIDE, GROUP, OBJECT, BOOL. true used instead."
In-game On-screen error

Logging

Apart from errors, you can print any debug message you need. Use one of the following functions:

Profile name and function name will automatically appear in the output text, helping you identify the source.


Usage examples:

Expression RPT Output
"Hello World" call BIS_fnc_log;
"User1/BIS_fnc_log: [myTag_fnc_myFunction] Hello World"
42 call BIS_fnc_log;
"User1/BIS_fnc_log: [myTag_fnc_myFunction] 42"
["I'm playing %1", missionName] call BIS_fnc_logFormat;
"User1/BIS_fnc_log: [myTag_fnc_myFunction] I'm playing FalconWing"


To prevent RPT spam, logging is by default enabled only when previewing a mission from the editor. To force it in the mission everywhere, use the following Description.ext attribute:

allowFunctionsLog = 1;

Recompiling

Once compiled, functions remain unchanged and editing their file won't have any effect in the game. To adjust functions on the fly, you can manually trigger their recompilation.

1 call BIS_fnc_recompile;
Recompiles all functions. Can be also achieved by clicking on RECOMPILE button in the Functions Viewer
"functionName" call BIS_fnc_recompile;
Recompile the given function

As a security measure, functions are by default protected against rewriting during the mission. This restriction does not apply in missions previewed from the editor and in missions with the following attribute in Description.ext:

allowFunctionsRecompile = 1;

"Recompile" button in the functions viewer will be enabled only when recompiling is allowed.

Meta Variables

System is adding header with basic meta data to all functions. Following local variables are declared there:

  • _fnc_scriptName: String - Function name (e.g., myTag_fnc_myFunction)
  • _fnc_scriptNameParent: String - Name of q function from which the current one was called (_fnc_scriptName used when not defined)
Do not modify these values!