Arma 3 Scripting

Topic in Scripting

Multiplayer Scripting

Also available as Markdown and JSON, or read the original wiki page.

This page aims to explain notions and specificities of Multiplayer Scripting and its differences with Singleplayer Scripting.

It features three parts:

  1. #Notions and general knowledge
  2. #Structuring Multiplayer code
  3. Testing locally

Notions and general knowledge

The basics

Note

In Singleplayer, the game acts as a player-hosted server (isServer returns true).

Warning

Some Multiplayer commands do not work in Singleplayer, such as netId!

The other way around, some Singleplayer commands do not work in Multiplayer (e.g setAccTime).

Locality

Definitions

Local Argument a local argument means an argument that is processed on the machine where the command is executed
Global Argument a global argument means any argument, even a remote one
Local Effect a local effect means that the effect will only happen on the machine where the command is executed
Global Effect a global effect means that all the computers will receive it
Server Execution server exec means that the command or function has to be executed on the server machine, either mission host or dedicated server

Note

See also:

Different machines and how to target them

Note

  • For obvious reasons, a server cannot be JIP.
  • Use didJIP to determine if a client joined during the game.
Scripting Commands Server Player client Headless client Note
Dedicated Player-Hosted
sqf
isDedicated
✓ ✗ ✗ ✗ Dedicated server
sqf
hasInterface && isServer
✗ ✓ ✗ ✗ Player server
sqf
hasInterface && not isServer
✗ ✗ ✓ ✗ Player client
sqf
not hasInterface && not isDedicated
✗ ✗ ✗ ✓ Headless client
sqf
isServer
✓ ✓ ✗ ✗ Any server
sqf
hasInterface
✗ ✓ ✓ ✗ Any player
Miscellaneous
sqf
not isServer
✗ ✗ ✓ ✓ All server clients, including headless clients, but excluding player host
sqf
not isDedicated
✗ ✓ ✓ ✓ Everything but a dedicated server
sqf
not hasInterface
✓ ✗ ✗ ✓ Headless clients and dedicated server

For an extended version for all games, click

Note

Before Operation Flashpoint v1.99 and the backport of isServer, the server could be identified by placing a Game Logic in the editor (that would always remain local to the server), then using the following: local myLogic.

Targeted machine Operation Flashpoint Armed Assault Arma 2 Arma 3
Dedicated Server
A server without a human player behind it
sqf
isServer && isNull player
sqf
isServer && isNull player
sqf
isDedicated
sqf
isDedicated
Player Server
A server hosted by a player
sqf
isServer && not isNull player
sqf
isServer && not isNull player
sqf
isServer && not isDedicated
sqf
hasInterface && isServer
Server
Any server, dedicated or hosted
sqf
isServer
sqf
isServer
sqf
isServer
sqf
isServer
Player Client
A player connected since the lobby
sqf
not isServer && not isNull player
sqf
not isServer && not isNull player
sqf
not isServer && not isNull player
sqf
hasInterface && not isServer
JIP Player Client
A player connected in the middle of a mission
N/A sqf
not isServer && isNull player
sqf
not isServer && isNull player
sqf
hasInterface && didJIP
Headless Client
A client without a human player behind it
(used to offload server calculations)
colspan="3" N/A sqf
not hasInterface && not isServer
JIP Headless Client
Headless client connected during the ongoing mission
colspan="3" N/A sqf
not hasInterface && not isServer && didJIP

Note

Arma 3: Since Arma 3, a server-only init file is available: initServer.sqf (see Event Scripts)

Note

Arma 3: BIS_fnc_getNetMode can be used to have a string value representing the local machine status ("DedicatedServer", "Server", "HeadlessClient", "Client", "SinglePlayer" ).

This function doesn't make the JIP distinction and should be used along didJIP.

General information about locality

Locality changes

Note

Arma 3: Since Arma 3 the "Local" Event Handler triggers when an object's locality is changed.

Code examples

Code Argu-ments Effect Description
sqf
remoteUnit setDamage 1;
Global Argument Global Effect Any unit (local or remote) will die, and all the computers will know
sqf
localUnit addMagazine "30Rnd_556x45_STANAG";
Local Argument Global Effect Only a local unit can have its inventory edited with this command, but all the machines will be notified: if a player looks into the localUnit inventory, the added magazine will be there
sqf
remoteUnit setFace "Miller";
Global Argument Local Effect Any unit (local or remote) can get its face changed, but the new face will not be propagated through the network. Only the local machine's player will see the effect of the command
> [!NOTE]
> This command should ideally be executed on every machine, for example with:
>
> sqf
> [remoteUnit, "Miller"] remoteExec ["setFace", 0, true];
>

>
> See the #Remote Execution chapter for more information.
sqf
localCamera cameraEffect ["Internal", "Back"];
Local Argument Local Effect Only a local camera can be entered, and of course only the local machine will see through this camera

Network ID

Network IDs identify machines and network objects. They can be used to target proper machines with remote execution; see the #Remote Execution chapter for more information.

Warning

A machine ID (ownerID) is not to be confused with an object's network ID (netId).

Machine network ID

Every machine, including the server, has a network ID.

A server always has an ID of 2, every new client has the next number (the first client will be number 3, second client number 4, etc.)

Note

0 and 1 are special values:

  • 0 means everyone (including the server)
  • 1 means current machine but is not implemented and should not be used.

Object network ID

Every object synchronised through the network has a network ID, shortened to netId.

Sending information across network

Remote Execution

Since Arma 3 v1.50, remoteExec and remoteExecCall efficient engine network commands are available:

"Message to everyone, including JIP players!" remoteExec ["hint", 0, true];

See Arma 3: Remote Execution for more information.

Arma 3 alpha introduced BIS_fnc_MP (obsolete since Arma 3 v1.50, use the above version):

["Message to everyone, including JIP  players!", "hint", true, true] call BIS_fnc_MP;  // obsolete since Arma 3 v1.50, use remoteExec or remoteExecCall

Arma 2 introduced the Arma 2: Multiplayer Framework (not present in Arma 3):

// having the Functions module placed in the editor
waitUntil { not isNil "BIS_MPF_InitDone"; };
[nil, nil, rHINT, "Message to everyone!"] call RE;

PublicVariable commands

PublicVariable commands allow to send global variables to specified machines.

Command Effect JIP synchronised
publicVariable Set/update a variable value from the local machine to all the other machines (including server) ✓
publicVariableServer Set/update a variable value from a client to the server ✗
publicVariableClient Set/update a variable value from the local machine (not necessarily the server) to a specific client ✗
How it works

The server has the variable ABC_Score to broadcast:

ABC_Score = 5;                // sets the value
publicVariable "ABC_Score"    // publishes the variable (do not forget the quotes!)

This sends the variable name and value to the clients.

setVariable command

Available since Arma 2, the public version of the setVariable command (alternative syntax) allows you to store a variable into an object and spread this variable across the network.

Note

Arma 3: In Arma 3 it is possible to broadcast the nil value, thus deleting the variable from the target.

Player connection events

The following commands will execute given code when a player is connecting or disconnecting. This code will run for players connecting in the lobby and for JIP players!

Note

Before Arma 3 v1.58, use BIS_fnc_addStackedEventHandler for onPlayerConnected/onPlayerDisconnected.

Client state

A client state is the client's connection state. It can be obtained with getClientState and getClientStateNumber commands on both server and clients.

getClientStateNumber getClientState Description
0 "NONE" No client (or singleplayer)
1 "CREATED" Client is created
2 "CONNECTED" Client is connected to server, message formats are registered
3 "LOGGED IN" Identity is created
4 "MISSION SELECTED" Mission is selected
5 "MISSION ASKED" Server was asked to send / not send mission
6 "ROLE ASSIGNED" Role was assigned (and confirmed)
7 "MISSION RECEIVED" Mission received
8 "GAME LOADED" Island loaded, vehicles received
9 "BRIEFING SHOWN" Briefing was displayed
10 "BRIEFING READ" Ready to play mission
11 "GAME FINISHED" Game was finished
12 "DEBRIEFING READ" Debriefing read, ready to continue with next mission

Join In Progress (Armed Assault v1.00)

Join In Progress (JIP) is the ability for a player to connect while a game is running, unlike in Operation Flashpoint where one had to wait for the game to be over.

It was introduced in on Xbox and Armed Assault on PC.

A player that joined in progress will be referred to as JIP player.

Note

To disable JIP on a server:

  • the server admin can disable playable slots on the role selection screen
  • the mission designer can disable AI within mission config However, JIP remains available if respawn is enabled in the mission.

JIP Synchronisation

A JIP player will have a lot of information synchronised (publicVariable'd and setVariable server variables for example) by the game before accessing the mission itself; see below:

Information Arma 1 Arma 2 Arma 3
date/time ✓ ✓ ✓
date/time + setDate/skipTime ✗ ✗ ✓
weather (overcast, fog) ✗ ✓ ✓
weather + setOvercast/setFog/setRain/setLightnings ✗ ✗ ✓
time passed since mission start (time command) ✓
publicVariable-sent variables (Number, String, Structured Text, Array, Code) ✓ ✓ ✓
publicVariable-sent variables (nil) ✗ ✗ ✓
setVariable-assigned variables (when alternative syntax's public parameter is set to true) N/A ✓ ✓
remoteExec- and remoteExecCall-executed code if JIP prerequisites are met colspan="2" N/A ✓

Warning

All the initialisation fields code get executed again for each and every JIP connecting player.

This means that code with global effect Global Effect (such as setDamage) WILL be re-executed (depending on locality)!

See also

Structuring Multiplayer code

Responsibilities

Server

The Server must be considered as the one ruler of the mission. He is the game's referee and all the decisions should come from it. All the values on the server should be considered as true.

Consider the server as a powerful machine where you can put all the mission conditions and heavy scripting on. In case of a very heavy mission, the server can be assisted by Headless Clients (this involves a per-mission specific design).

Server-side code must gather or wait all the variables (potentially from client-side scripts and publicVariableServer) and take and broadcast its decisions accordingly using publicVariable.

Server-side code should ideally not make any reference to a player variable considering a server can potentially be dedicated, unless you want to force this mission to be player-hosted (such as Arma 2's campaign).

Note

Use allPlayers, BIS_fnc_listPlayers, playableUnits (and switchableUnits for SP compatibility) to refer to players.

Client

The Client must be considered as an average machine that can leave the game at any moment. No mission-vital code must be executed on its side and no decisions must be taken client-side.

Again, one must expect that any client can disconnect at any moment.

The client executes all the (local) UI code (Post Process Effects, Dialogs, etc.)

The player's machine should not deal with a great piece of code.

Important

Do not forget that a server can be a player, and therefore should execute player code in that case.

The proper way to check for player-side condition is

if (hasInterface) then { /* (...) */ };

Note that the following example is incorrect:

if (isServer) then
{
    // ...
}
else // WRONG: a server CAN be a player
{
    // ...
};

Code writing

The usual four steps of coding are the following:

See Code Optimisation#Rules for advices and more information.

See also

Local Multiplayer Testing

To ensure all cases, your mission should ideally work properly:

The following chapters explain how to mimic multiple clients on one computer. Of course, nothing prevents you from inviting friends to play your mission and report bugs!

Dedicated Server

To properly test MP scripting locality issues, it is recommended to run a dedicated server and connect with two clients. In order to do so:

loopback = true;    // force LAN-only server
kickDuplicate = 0;    // disable duplicate Arma kick

// needed in case of Headless Client test only
headlessClients[]    = { "127.0.0.1" };
localClient[]        = { "127.0.0.1" };

Important

Be sure to disable BattlEye or it will close any additional instances.

Pros Cons
- Tests almost all "can go wrong" scenarios
- Can test Headless Clients, persistent server, server restart, admin login/logout
- Misses cases where isDedicated is used instead of isServer
- "Big" setup

Player-Hosted Server

While this method covers less cases than the #Dedicated Server Test method above, this method is faster:

Pros Cons
- Fast setup (with quick modlist support)
- Helps find cases where isDedicated is used instead of isServer
- May miss locality issues (code that happens to run on the server because it runs on the server's client like e.g hideObjectGlobal)
- No headless client testing (this can be solved by using a custom server.cfg)

See Also