Before continuing with public variables topic, which I started in Part 2, I’d like to talk about types of variables or data types if you want.  When variable is undefined it has no data type. When you assign data to your variable it will automatically assume the type of the data you assigned. You can then assign different type of data to the same variable and the variable will again assume new data type. So to make sure you have correct type of data before you process it, you can test it with typeName command. This command will return a string with the name of the current data type.

_var = 0; hint typeName _var; //SCALAR _var = ""; hint typeName _var; //STRING _var = true; hint typeName _var; //BOOL _var = []; hint typeName _var; //ARRAY _var = {}; hint typeName _var; //CODE _var = objNull; hint typeName _var; //OBJECT _var = scriptNull; hint typeName _var; //SCRIPT _var = grpNull; hint typeName _var; //GROUP _var = controlNull; hint typeName _var; //CONTROL _var = teamMemberNull; hint typeName _var; //TEAM_MEMBER _var = displayNull; hint typeName _var; //DISPLAY _var = taskNull; hint typeName _var; //TASK _var = locationNull; hint typeName _var; //LOCATION _var = opfor; hint typeName _var; //SIDE _var = parseText ""; hint typeName _var; //TEXT _var = configFile; hint typeName _var; //CONFIG _var = missionNamespace; hint typeName _var; //NAMESPACE

If a variable is undefined, typeName returns nothing but also doesn’t throw error. In fact you cannot even compare the result of  typeName to anything because it is nothing!

_var = nil; hint typeName _var; //nothing if (typeName _var == "") then { diag_log "true"; } else { diag_log "false"; }; diag_log "neither"; //.rpt //"neither"

There is also a new command in ArmA 3 which is currently undocumented and possibly unsupported. It is a reserved variable nevertheless that returns false, so I thought I’d mention it too.

_var = netObjNull; hint typeName _var; //BOOL

Public global variables

When you need to have the same variable present on all connected computers you can simply define it in init.sqf file, and when mission loads, every machine will execute this file and therefore have your variable. But what if you need to exchange variable value during the mission? This is where you need to use a special command to broadcast your variable over network to all connected machines – publicVariable.

//computer 1 myvar = "somevar"; //computer 2 hint format ["%1", myvar]; //"any" //computer 3 hint format ["%1", myvar]; //"any" //computer 1 myvar = "somevar"; publicVariable "myvar"; //computer 2 hint format ["%1", myvar]; //"somevar" //computer 3 hint format ["%1", myvar]; //"somevar"

The good thing about this type of data exchange is that it is fast and reliable and you can attach public variable event handler addPublicVariableEventHandler to a variable and it will fire as soon as it detects that the value of the monitored variable changed. The bad thing is that being able to broadcast data from any computer to all computers on network can lead to exploits and hacking. At the time of writing there is an ongoing work in ArmA 3 to improve security.

There are 2 more quite useful public variable commands publicVariableClient and publicVariableServer. The difference with these two commands is that you can make a client talk only to the server and the server talk to a specific client. This can seriously reduce network traffic since instead of updating all computers on network you can only update selected ones.

Another way of globally exchanging public variables is by attaching them to objects that exist on all machines, like mission objects or vehicles for example. There is no event handler to sense the change for such variables so this is more suited for storing some additional data with objects, which then is retrieved on demand. To attach a variable to an object you can use setVariable command. This will make the variable public but local to the machine you attached it on.

//computer 1 myobj = (typeOf player) createVehicle (position player); myobj setVariable ["lastCreated", time]; hint str (myobj getVariable ["lastCreated", 0]); //time since mission start publicVariable myobj; //computer 2 hint str (myobj getVariable ["lastCreated", 0]); //"0"

To make lastCreated global you need to set 3rd parameter of the setVariable command to true.

//computer 1 myobj = (typeOf player) createVehicle (position player); myobj setVariable ["lastCreated", time, true]; hint str (myobj getVariable ["lastCreated", 0]); //time since mission start publicVariable myobj; //computer 2 hint str (myobj getVariable ["lastCreated", 0]); //time since mission start

You have to be careful as making variables attached to objects global, is the same as publicVariable variables. If you store frequently updated variable with an object, it is a bad idea to make it global as it will broadcast every change over network, increasing traffic.

Now word of warning before you bash your head against a wall as to “why it ain’t working with this object?!?”. Houses for example like other map objects (and I mean map objects that have been added during map creation, not mission objects) are streamed. Think about it, the maps in ArmA are huge so even if you can load the whole map you will be using too much computer power. This is unnecessary, so map objects are streamed to you as you go. This means that if you attach a variable to an object on your map and try to make it global, on other computers the same object might not exist yet. And when the object appears later on other computers, it might not have variable you attached to it, so remember this.

That’s it for variables for now. I will talk more about the whole client server interaction in future tutorials.

Enjoy,
KK