|
|
(133 intermediate revisions by 5 users not shown) |
Line 1: |
Line 1: |
| {{Informative|This page is an intended replacement for '''[[Code Optimisation]]'''. It is obviously '''a WORK-IN-PROGRESS'''.}} | | [[Category: Sandbox]] |
| [[Category:Sandbox]]
| | {{Feature|informative|To go on [[Initialisation Order]].}} |
| <!--
| |
| TODO: color code about importance of performance saving? (green / yellow / red)
| |
| -->
| |
| ----
| |
| __NOEDITSECTION__
| |
| <div style="float: right; margin-left: 1.5em; margin-bottom: 1em; max-width: 25%;">__TOC__</div>
| |
| = Code Optimisation =
| |
|
| |
|
| == Introduction == | | {| class="wikitable sortable align-center align-left-col-1" |
| This article will try to be a general guide about improving your code '''and''' its performance.
| | |+ Order of Initialisation (use column sorting for respective machine order) |
| | ! rowspan="2" class="unsortable" style="text-align: center" | Task |
| | ! rowspan="2" | Exec Environment |
| | ! rowspan="1" colspan="5" class="unsortable" | Machine |
| | |- |
| | ! Single Player |
| | ! Dedicated Server |
| | ! Hosted Server |
| | ! Multiplayer Client |
| | ! [[Multiplayer Scripting#Join In Progress|JIP]] MP Client |
|
| |
|
| == Rules == | | |- |
| In the domain of development, any rule is a rule of thumb. If a rule states for example that it is ''better'' that a line of code doesn't go over 80 characters, it doesn't mean that any line '''''must not''''' go over 80 characters; sometimes, the situation needs it. If you have a good structure, '''do not''' change your code to enforce a single arbitrary rule. If you break many of them, you may have to change something. Again, this is according to your judgement.<br />
| | | [[Arma 3: Functions Library|Functions]] with <syntaxhighlight lang="cpp" inline>recompile</syntaxhighlight> {{Link|Arma 3: Functions Library#Attributes 3|attribute}} are recompiled |
| <br /> | | | {{n/a}} |
| With that being said, here are the three basic rules to get yourself in the clear:
| | | 1 <!-- Single Player --> |
| | | 1 <!-- Dedicated Server --> |
| | | 1 <!-- Hosted Server --> |
| | | 1 <!-- Multiplayer Client --> |
| | | 1 <!-- JIP MP Client --> |
|
| |
|
| # [[#Make it work|Make it work]]
| | |- |
| # [[#Make it readable|Make it readable]]
| | | [[Arma 3: Functions Library|Functions]] with <syntaxhighlight lang="cpp" inline>preInit</syntaxhighlight> {{Link|Arma 3: Functions Library#Attributes 3|attribute}} are called |
| # [[#Optimise then|Optimise then]]
| | | [[Scheduler#Unscheduled Environment|Unscheduled]] |
| | | 2 <!-- Single Player --> |
| | | 2 <!-- Dedicated Server --> |
| | | 2 <!-- Hosted Server --> |
| | | 2 <!-- Multiplayer Client --> |
| | | 2 <!-- JIP MP Client --> |
|
| |
|
| === Make it work ===
| | |- |
| Your first goal when coding is to make your code do what you want it does. A good way to reach this objective is to read and getting inspired by other people's code. If you understand it by reading it once, it is probably a good source of inspiration.<br />
| | | Object Init Event Handlers are called |
| When starting from scratch if you know what you want but miss the specific steps to get to your point, it is a good practice to write down in your native language what you want to do. E.g ''Get all the units near the city, and [[forEach|for each]] west soldier in them, add damage''.
| | | [[Scheduler#Unscheduled Environment|Unscheduled]] |
| | | 3 <!-- Single Player --> |
| | | 3 <!-- Dedicated Server --> |
| | | 3 <!-- Hosted Server --> |
| | | 3 <!-- Multiplayer Client --> |
| | | {{Icon|unchecked}} <!-- JIP MP Client --> |
|
| |
|
| === Make it readable ===
| | |- |
| Whether you are cleaning your code or a different person's, you must understand the code without twisting your brain:
| | | Expressions of [[Eden Editor: Configuring Attributes|Eden Editor entity attributes]] are called<ref name="isPlayer"><sqf inline>isPlayer _entity</sqf> does not return [[true]] immediately. Once the entity has become a [[player]], it is transferred to the client.</ref> |
| | | [[Scheduler#Unscheduled Environment|Unscheduled]] |
| | | 4 <!-- Single Player --> |
| | | 4 <!-- Dedicated Server --> |
| | | 4 <!-- Hosted Server --> |
| | | {{Icon|unchecked}} <!-- Multiplayer Client --> |
| | | {{Icon|unchecked}} <!-- JIP MP Client --> |
|
| |
|
| * While [[SQF syntax|SQF]] ''is'' impacted by variable name length, this should not take precedence on the fact that code must be readable by a human being. Variables like '''_u''' instead of '''_uniform''' should not be present.
| | |- |
| * ''One-lining'' (putting everything in one statement) memory improvement is not worth the headache it gives when trying to read it. Don't overuse it.
| | | Object initialisation fields are called |
| * Indentation is important for the human mind, and space is too. Space is free, use it.
| | | [[Scheduler#Unscheduled Environment|Unscheduled]] |
| * Finally, camel-casing (namingLikeThis) your variables and commands will naturally make the code more readable, especially for long names.
| | | 5 <!-- Single Player --> |
| | | 5 <!-- Dedicated Server --> |
| | | 5 <!-- Hosted Server --> |
| | | 4 <!-- Multiplayer Client --> |
| | | 3 <!-- JIP MP Client --> |
|
| |
|
| {{Informative| '''_i''' is an accepted variable standard for a [[for]]..[[do]] iteration}}
| | |- style="background-color: #95F0AD" |
| | | [[Event Scripts#init.sqs|init.sqs]] is executed |
| | | |
| | | 6 <!-- Single Player --> |
| | | <!-- Dedicated Server --> |
| | | <!-- Hosted Server --> |
| | | <!-- Multiplayer Client --> |
| | | <!-- JIP MP Client --> |
|
| |
|
| See the following code:
| | |- style="background-color: #95F0AD" |
| <code style="clear: right;">_w=[];{_w pushbackunique primaryweapon _x}foreach((allunits+alldeadmen)select{_x call bis_fnc_objectside==east});</code> | | | [[Event Scripts#init.sqf|init.sqf]] is executed |
| | | [[Scheduler#Scheduled Environment|Scheduled]]<ref name="enginewaits">Note '''in single player''' that while the environment is [[Scheduler#Scheduled Environment|Scheduled]] ([[canSuspend]] returns true), the engine seems to wait until the script is done executing, essentially behaving similarly to an [[Scheduler#Unscheduled Environment|Unscheduled environment]] - infinite loops will freeze the game, [[uiSleep]] may pause the game for up to ~20s (postInit), [[waitUntil]] can cause catastrophic issues, etc.</ref> |
| | | <!-- Single Player --> |
| | | <!-- Dedicated Server --> |
| | | <!-- Hosted Server --> |
| | | <!-- Multiplayer Client --> |
| | | <!-- JIP MP Client --> |
|
| |
|
| The same example is far more readable with proper spacing, good variable names and intermediate results:
| | |- |
| <code>_weaponNames = []; | | | Expressions of [[Eden Editor: Configuring Attributes|Eden Editor scenario attributes]] are called<ref name="playerCommandNotAvailable">[[player]] is not available immediately.</ref> |
| _allUnitsAliveAndDead = allUnits + allDeadMen;
| | | [[Scheduler#Unscheduled Environment|Unscheduled]] |
| _allEastAliveAndDead = _allUnitsAliveAndDead select { _x call BIS_fnc_objectSide == east };
| | | <!-- Single Player --> |
| { _weaponNames pushBackUnique primaryWeapon _x } forEach _allEastAliveAndDead;</code>
| | | <!-- Dedicated Server --> |
| | | <!-- Hosted Server --> |
| | | <!-- Multiplayer Client --> |
| | | <!-- JIP MP Client --> |
|
| |
|
| * if you have a lot of [[if]]..[[else]], you may want to look at a [[switch]] condition, or again break your code in smaller functions.
| | |- style="background-color: #95DEF0" |
| | | Persistent functions are called |
| | | |
| | | <!-- Single Player --> |
| | | <!-- Dedicated Server --> |
| | | <!-- Hosted Server --> |
| | | <!-- Multiplayer Client --> |
| | | <!-- JIP MP Client --> |
|
| |
|
| === Optimise then ===
| | |- |
| Once you know what is what, you can understand your code better.
| | | [[Modules]] are initialised |
| * You were iterating multiple times on the same array?
| | | |
| ** You should be able to spot your issue now.
| | | <!-- Single Player --> |
| * Do you see the same code, but with different parameters?
| | | <!-- Dedicated Server --> |
| ** Time to write a function.
| | | <!-- Hosted Server --> |
| * Are you using [[execVM]] on the same file, many times?
| | | <!-- Multiplayer Client --> |
| ** Store your function in memory to avoid file reading every call with <code>_myFunction = [[compile]] [[preprocessFileLineNumbers]] "myFile.sqf";</code>
| | | {{Icon|unchecked}} <!-- JIP MP Client --> |
| * Is your function code far too long?
| |
| ** Split it in understandable-sized bites, for your own sanity.
| |
| * Is your variable name far too long?
| |
| ** Find a smaller name, according to the variable scope:
| |
| e.g
| |
| { _opforUnitUniform {{=}} uniform _x; systemChat _opforUnitUniform; } forEach _allOpforUnits
| |
| becomes
| |
| { _uniform {{=}} uniform _x; systemChat _uniform; } forEach _allopforUnits
| |
|
| |
|
| | |- style="background-color: #DEF0AD" |
| | | [[Event Scripts#initServer.sqf|initServer.sqf]] is executed |
| | | [[Scheduler#Scheduled Environment|Scheduled]] |
| | | <!-- Single Player --> |
| | | <!-- Dedicated Server --> |
| | | <!-- Hosted Server --> |
| | | {{n/a}} <!-- Multiplayer Client --> |
| | | {{n/a}} <!-- JIP MP Client --> |
|
| |
|
| == Code optimisation == | | |- style="background-color: #DEF0AD" |
| | | [[Event Scripts#initPlayerLocal.sqf|initPlayerLocal.sqf]] is executed |
| | | [[Scheduler#Scheduled Environment|Scheduled]] |
| | | <!-- Single Player --> |
| | | {{n/a}} <!-- Dedicated Server --> |
| | | <!-- Hosted Server --> |
| | | <!-- Multiplayer Client --> |
| | | <!-- JIP MP Client --> |
|
| |
|
| === Successive condition check === | | |- style="background-color: #DEF0AD" |
| In [[SQF syntax|SQF]] the following code will check '''all and every''' condition, even if one fail:
| | | [[Event Scripts#initPlayerServer.sqf|initPlayerServer.sqf]] is executed on the server |
| [[if]] (condition1 && condition2 && condition3) [[then]] { {{codecomment|/* thenCode */}} };
| | | [[Scheduler#Scheduled Environment|Scheduled]] |
| e.g:
| | | <!-- Single Player --> |
| [[if]] ([[alive]] unit1 && [[not]] [[alive]] aPvehicle && [[daytime]] > 5) [[then]] { {{codecomment|/* thenCode */}} };
| | | {{n/a}} <!-- Dedicated Server --> |
| This code will check if {{Inline code|unit1}} is alive, and if it is not {{Inline code|[[not]] [[alive]] aPvehicle && [[daytime]] > 5}} will execute anyway.
| | | ?? <!-- Hosted Server --> |
| To avoid this behaviour, you can either imbricate [[if|ifs]] or use '''lazy evaluation''' such as the following:
| | | <!-- Multiplayer Client --> |
| [[if]] ([[alive]] unit1 && { [[not]] [[alive]] aPvehicle } && {{ [[daytime]] > 5}}) [[then]] { {{codecomment|/* thenCode */}} };
| | | <!-- JIP MP Client --> |
| This lazy evaluation will stop code execution on the first [[false]] statement.
| |
|
| |
|
| Using lazy evaluation is not always the best way as it could speed up the code as well as slow it down, depending on the current condition being evaluated:
| | |- |
| | | [[Arma 3: Functions Library|Functions]] with <syntaxhighlight lang="cpp" inline>postInit</syntaxhighlight> {{Link|Arma 3: Functions Library#Attributes 3|attribute}} are called |
| | | [[Scheduler#Scheduled Environment|Scheduled]]<ref name="enginewaits"/> |
| | | <!-- Single Player --> |
| | | <!-- Dedicated Server --> |
| | | <!-- Hosted Server --> |
| | | <!-- Multiplayer Client --> |
| | | <!-- JIP MP Client --> |
|
| |
|
| [true || {false} || {false}] call BIS_fnc_codePerformance; {{codecomment|// fastest}}
| | |- style="background-color: #95DEF0" |
| [true || false || false ] call BIS_fnc_codePerformance; {{codecomment|// normal}}
| | | [[Event Scripts#init.sqs|init.sqs]] is executed |
| [false || false || false ] call BIS_fnc_codePerformance; {{codecomment|// normal}}
| | | [[Scheduler#Scheduled Environment|Scheduled]] |
| [false || {false} || {false}] call BIS_fnc_codePerformance; {{codecomment|// slowest}}
| | | <!-- Single Player --> |
| | | <!-- Dedicated Server --> |
| | | <!-- Hosted Server --> |
| | | <!-- Multiplayer Client --> |
| | | <!-- JIP MP Client --> |
|
| |
|
| ==== Adding large strings together ====
| | |- style="background-color: #95DEF0" |
| {{Inline code|a = a + b}} works fine for small strings, however the bigger the string gets the slower this becomes:
| | | [[Event Scripts#init.sqf|init.sqf]] is executed |
| s = ""; [[for]] "_i" [[from]] 1 [[to]] 10000 [[do]] {s = s + "123"}; {{codecomment|// 30000 chars @ 290ms}}
| | | [[Scheduler#Scheduled Environment|Scheduled]] |
| | | <!-- Single Player --> |
| | | <!-- Dedicated Server --> |
| | | <!-- Hosted Server --> |
| | | <!-- Multiplayer Client --> |
| | | <!-- JIP MP Client --> |
|
| |
|
| The solution is to use a string array that you will concatenate later:
| | |- |
| strings = []; [[for]] "_i" [[from]] 1 [[to]] 10000 [[do]] {strings [[pushBack]] "123"}; strings = strings [[joinString]] ""; {{codecomment|// 30000 chars @ 30ms}}
| | | [[remoteExec]]'s [[Multiplayer Scripting#Join In Progress|JIP]] queue |
| | | {{n/a}} |
| | | {{n/a}} <!-- Single Player --> |
| | | {{n/a}} <!-- Dedicated Server --> |
| | | {{n/a}} <!-- Hosted Server --> |
| | | {{n/a}} <!-- Multiplayer Client --> |
| | | 42 <!-- JIP MP Client --> |
|
| |
|
| | |- style="background-color: #EEE" |
| | | ''Scenario going'' |
| | | {{n/a}} |
| | | <!-- Single Player --> |
| | | <!-- Dedicated Server --> |
| | | <!-- Hosted Server --> |
| | | <!-- Multiplayer Client --> |
| | | <!-- JIP MP Client --> |
|
| |
|
| === Multiplayer recommendations ===
| | |- |
| ''TODO''
| | | [[Event Scripts#exit.sqf|exit.sqf]] |
| * no [[publicVariable]] or public [[setVariable]] at high frequency
| | | |
| * the server is supposed to have a lot of memory, use it
| | | <!-- Single Player --> |
| | | <!-- Dedicated Server --> |
| | | <!-- Hosted Server --> |
| | | <!-- Multiplayer Client --> |
| | | <!-- JIP MP Client --> |
|
| |
|
| === createSimpleObject vs createVehicle ===
| | |- |
| ''TODO''
| | | [[Event Scripts#exit.sqs|exit.sqs]] |
| create at [0,0,0]
| | | |
| | | <!-- Single Player --> |
| | | <!-- Dedicated Server --> |
| | | <!-- Hosted Server --> |
| | | <!-- Multiplayer Client --> |
| | | <!-- JIP MP Client --> |
|
| |
|
| | |- |
| | | {{Link|Arma 3: Mission Event Handlers#Ended|"Ended" Mission Event Handler}} |
| | | |
| | | <!-- Single Player --> |
| | | <!-- Dedicated Server --> |
| | | <!-- Hosted Server --> |
| | | <!-- Multiplayer Client --> |
| | | <!-- JIP MP Client --> |
|
| |
|
| == Equivalent commands performance ==
| | |- |
| | | {{Link|Arma 3: Mission Event Handlers#MPEnded|"MPEnded" Mission Event Handler}} |
| | | |
| | | <!-- Single Player --> |
| | | <!-- Dedicated Server --> |
| | | <!-- Hosted Server --> |
| | | <!-- Multiplayer Client --> |
| | | <!-- JIP MP Client --> |
|
| |
|
| === if ===
| | |} |
| Use:
| |
| [[if]] (condition1) [[then]] { {{codecomment|/* thenCode */}} } else { {{codecomment|/* elseCode */}} }; {{codecomment|// faster}}
| |
| Instead of:
| |
| [[if]] (condition1) [[then]] [{ {{codecomment|/* thenCode */}} }, { {{codecomment|/* elseCode */}} }]; {{codecomment|// slower}}
| |
|
| |
|
| === for ===
| |
| Use:
| |
| [[for]] "_i" [[from]] 0 [[to]] 100 [[do]] { {{codecomment|/* forCode */}} }; {{codecomment|// faster}}
| |
| Instead of:
| |
| [[for]] [{_i = 0}, {_i < 100}, {_i = _i + 1}] [[do]] { {{codecomment|/* forCode */}} }; {{codecomment|// slower}}
| |
|
| |
|
| === forEach vs count === | | == See Also == |
| Both commands will step through supplied array of elements one by one and both commands will contain reference to current element in the [[_x]] variable.
| |
| However, [[count]] loop is a little faster than [[forEach]] loop, but it does not have [[_forEachIndex]] variable.<br />
| |
| Also, there is a limitation as the code inside [[count]] expects [[Boolean]] or [[Nothing]] while itself returns [[Number]].
| |
|
| |
|
| <code>{[[diag_log]] _x} [[count]] [1,2,3,4,5,6,7,8,9]; {{codecomment|// faster}}</code>
| | * [[Arma 3: Functions Library]]<!-- |
| <code>{[[diag_log]] _x} [[forEach]] [1,2,3,4,5,6,7,8,9]; {{codecomment|// slower}}</code>
| | * [[Arma 2: Functions Library]] --> |
| | | * [[Arma 3: Remote Execution]], [[BIS_fnc_MP]] <!-- keep? --> |
| Usage:
| | * [[Eden Editor: Configuring Attributes|Eden Editor: Configuring Attributes]] |
| <code>_someoneIsNear = {_x [[distance]] [0,0,0] < 1000} [[count]] [[allUnits]] > 0;</code>
| | * [[Event Scripts]] |
| _someoneIsNear = {
| | * [[Scheduler]] |
| [[if]] ([[_x]] [[distance]] [0,0,0] < 1000) [[exitWith]] { [[true]] };
| |
| [[false]]
| |
| } [[forEach]] [[allUnits]];
| |
| ''TODO: findIf?''
| |
| | |
| | |
| | |
| === + and format ===
| |
| When concatenating more than two strings, [[format]] is faster than [[valuea_plus_valueb|+]]. Use:
| |
| [[format]] ["%1%2%3%4%5", "string1", "string2", "string3", "string4", "string5"]; {{codecomment|// faster}}
| |
| Instead of:
| |
| "string1" + "string2" + "string3" + "string4" + "string5"; {{codecomment|// slower}}
| |
| | |
| === select and if ===
| |
| Use:
| |
| result = ["false result", "true result"] [[select]] _condition; {{codecomment|// faster}}
| |
| Instead of the lazy-evaluated [[if]]:
| |
| result = [[if]] (_condition) [[then]] { "true result"; } [[else]] { "false result"; }; {{codecomment|// slower}}
| |
| | |
| === private ===
| |
| Use:
| |
| private _a = 1;
| |
| private _b = 2;
| |
| private _c = 3;
| |
| private _d = 4;
| |
| {{codecomment|// 0.0023 ms}}
| |
| | |
| Instead of:
| |
| private ["_a", "_b", "_c", "_d"];
| |
| _a = 1;
| |
| _b = 2;
| |
| _c = 3;
| |
| _d = 4;
| |
| {{codecomment|// 0.0040 ms}}
| |
| | |
| However:
| |
| [[for]] "_i" from 1 to 100 do
| |
| {
| |
| private _a = 1; private _b = 2; private _c = 3; private _d = 4;
| |
| };
| |
| {{codecomment|// 0.186776 ms}}
| |
| | |
| is slower than:
| |
| private ["_a", "_b", "_c", "_d"];
| |
| for "_i" from 1 to 100 do
| |
| {
| |
| _a = 1;
| |
| _b = 2;
| |
| _c = 3;
| |
| _d = 4;
| |
| };
| |
| {{codecomment|// 0.146327 ms}}
| |
| The reason behind this is that in the first example variables are created, assigned and deleted in each loop.<br />
| |
| In the second example the variables are only created/deleted once and changed often.
| |
| | |
| === objectParent and vehicle ===
| |
| <code>isNull objectParent player {{codecomment|// 0.0013 ms, slightly faster}}</code>
| |
| <code>vehicle player == player {{codecomment|// 0.0022 ms}}</code>
| |
| | |
| === nearEntities and nearestObjects ===
| |
| * [[nearEntities]] is much faster than [[nearestObjects]] given on range and amount of object(s) which are within the given range. | |
| If a range was set to more thean 100 meters it is highly recommend to use [[nearEntities]] instead of [[nearestObjects]].
| |
| | |
| Note: [[nearEntities]] only searches for objects which are alive.
| |
| Killed units, destroyed vehicles, static objects and buildings will be ignored by the [[nearEntities]] command.
| |
| | |
| === Config path delimiter ===
| |
| {{Inline code|>>}} is slightly faster than {{Inline code|/}} when used in config path with [[configFile]] or [[missionConfigFile]]:
| |
| [[configFile]] >> "CfgVehicles" {{codecomment|// 0.0019 ms}}
| |
| is (very slighlty) faster than
| |
| [[configFile]] / "CfgVehicles" {{codecomment|// 0.0023 ms}}
| |
| | |
| === getPos* and setPos* ===
| |
| | |
| | |
| [[getPosWorld]] {{codecomment|// 0.0015 ms}}
| |
| [[getPosASL]] {{codecomment|// 0.0016 ms}}
| |
| [[getPosATL]] {{codecomment|// 0.0016 ms}}
| |
| [[getPos]] {{codecomment|// 0.0020 ms}}
| |
| [[position]] {{codecomment|// 0.0020 ms}}
| |
| [[getPosVisual]] {{codecomment|// 0.0021 ms}}
| |
| [[visiblePosition]] {{codecomment|// 0.0021 ms}}
| |
| [[getPosASLW]] {{codecomment|// 0.0023 ms}}
| |
| | |
| [[setPosWorld]] {{codecomment|// 0.0060 ms}}
| |
| [[setPosASL]] {{codecomment|// 0.0060 ms}}
| |
| [[setPosATL]] {{codecomment|// 0.0060 ms}}
| |
| [[setPos]] {{codecomment|// 0.0063 ms}}
| |
| [[setPosASLW]] {{codecomment|// 0.0068 ms}}
| |
| [[setVehiclePosition]] {{codecomment|// 0.0077 ms "CAN_COLLIDE"}}
| |
| {{codecomment|// 0.0390 ms "NONE"}}
| |
| | |
| | |
| == Conversion from earlier versions ==
| |
| Each iteration of Bohemia games ({{ofp}}, {{arma}}, {{arma2}}, {{tkoh}}, {{arma3}}) brought their own new commands, especially {{arma2}} and {{arma3}}.<br />
| |
| For that, if you are converting scripts from older versions of the engine, some aspects should be reviewed:
| |
| | |
| === Loops ===
| |
| * [[forEach]] loops, depending on the situation, can be replaced by:
| |
| ** [[apply]]
| |
| ** [[count]]
| |
| ** [[findIf]]
| |
| ** [[select]]
| |
| | |
| === Array operations ===
| |
| * '''Adding an item:''' {{Inline code|myArray [[valuea_plus_valueb|+]] [element]}} and {{Inline code|myArray [[set]] <nowiki>[</nowiki>[[count]] myArray, element]}} have been replaced by [[pushBack]]
| |
| * '''Selecting a random item:''' [[BIS_fnc_selectRandom]] has been replaced by [[selectRandom]]
| |
| * '''Removing items:''' {{Inline code|myArray [[set]] [1, objNull]; myArray [[a_-_b|-]] [objNull]}} has been replaced by [[deleteAt]] and [[deleteRange]]
| |
| * '''Concatenating:''' {{Inline code|myArray {{=}} myArray [[valuea_plus_valueb|+]] [element]}} has been ''reinforced'' by [[append]]: if you don't need the original array to be modified, use + | |
| * '''Comparing:''' use [[isEqualTo]] instead of [[BIS_fnc_areEqual]] or a custom comparison function
| |
| ** {{Inline code|[[count]] myArray {{=}}{{=}} 0}} is pretty fast, but direct comparison with [[isEqualTo]] is still a little faster: {{Inline code|myArray [[isEqualTo]] []}}
| |
| * '''Finding common items:''' [[in]] [[forEach]] loop has been replaced by [[arrayIntersect]] | |
| * '''Condition filtering:''' [[forEach]] can be replaced by [[select]] (alternative syntax) | |
| <code>result = [];
| |
| {
| |
| [[if]] (_x % 2 == 0) [[then]]
| |
| {
| |
| result [[pushBack]] [[_x]];
| |
| };
| |
| } [[forEach]] arrayOfNumbers; {{codecomment|// 2.57 ms}}</code>
| |
| result = (arrayOfNumbers [[select]] { _x % 2 == 0 }); {{codecomment|// 1.55 ms}}
| |
| | |
| === String operations ===
| |
| [[String]] manipulation has been simplified with the following commands:
| |
| * string [[select]] index
| |
| * [[toArray]] and [[toString]] have been reinforced with [[splitString]] and [[joinString]]
| |
| | |
| === Multiplayer ===
| |
| * [[BIS_fnc_MP]] has been replaced by [[remoteExec]] and [[remoteExecCall]]
| |