Jump to content
Sign in to follow this  
DMB

publicVariables and Initialization Order.

Recommended Posts

Hi

--------------------- Update --------------------------

After some more searching, I found this post:Clicky.

And then thanks to sbsmac for his solution, which is simmilar, but more explanitory than above: SOLUTION!!!

---------------------------------------------------------

For the past three evenings I have been struggling with passing the value of a variable to a function (sqf) from a unit's initialization field. The function is called, and the other parameters passed to the function is correct, but not the before mentioned variable.

So without rambling on for too long, let me show the code. In the editor I have placed a helicopter (named oHelicopter1), and a player unit, and in this units initialization field I have placed the code:

_null=[this, "FIRE_TEAM_LEADER", obHelicopter1, bInsertionBusy] execVM "initPlayer.sqf";

Where:

this - the unit

"FIRE_TEAM_LEADER" - the role I wish the unit to perform, used to give the unit a required loadout.

obHelicopter1 - a heli that will be used for insertion.

bInsertionBusy - boolean value to indicate if I want the unit in the vehicle (obHelicopter). This is the problamatic publicVariable...

The code of "initPlayer.sqf":

_oUnit = _this select 0;
_sType = _this select 1;
_oSpawnVehicle = _this select 2;
_bSpawnInVehicle = _this select 3;

//here i do the loadout, this works
[_oUnit, _sType] execVM "armasa_loadouts.sqf";

if ( _bSpawnInVehicle ) then 
{
  _oUnit moveInCargo _oSpawnVehicle;
};

Now one last thing I have to note, and I think this is where the problem lies, the initialization of the variable bInsertionBusy.

1) First I had the following in my init.sqf:

if (!isNil "bInsertionBusy") then
{
  bInsertionBusy=true;
  publicVariable "bInsertionBusy";
};

This did not work, and if I understand things correctly it is because units placed in the editor will be initialized before init.sqf runs. Therefore when the "initPlayer.sqf" is called from the units initialization field the variable is still undefined.

2) So then I though, well remove the above from the init.sqf, and put down a "Game Logic" and put the following in the GL's initialization:

bInsertionBusy=true; publicVariable "bInsertionBusy";

But alas, that did not work either, and then I realized that the "Game Logic" was placed after the player unit, so it's initialization will run after that of the unit, resulting in "bInsertionBusy" not initialized when "initPlayer.sqf" is called.

3) So I opened "mission.sqm" and edited it so that the "GL" is before the player unit in the list of class items. But alas, that also did not work.

Other things to note:

4) If I change "initPlayer.sqf" to be:

_oUnit = _this select 0;
_sType = _this select 1;
_oSpawnVehicle = _this select 2;
_bSpawnInVehicle = _this select 3;

[_oUnit, _sType] execVM "armasa_loadouts.sqf";

if ( bInsertionBusy ) then 
{
_oUnit moveInCargo _oSpawnVehicle;
};

It works, but I need to be able to decide at spawn time if I want the player in the vehicle or not.

5) Everything works for JIP players, therefore I believe it has to be the order of initialization of the objects.

Any help would be appreciated.

Thanks DMB

Edited by DMB
Confirmation of success

Share this post


Link to post
Share on other sites

The best way to think of this (particularly if you want to handle MP and JIP) is as an unsynchronised set of concurrent threads. Ie, relying on _any_ assumption of ordering is bound to give you problems. Therefore you need to code in the dependencies and synchronisation explicitly. In your case you don't want decisions to be made until the value of bInsertionBusy has been set and communicated to a unit.

The appropriate thing to do is therefore something like...

//In your init.sqf
if (isServer) then {
   //Only a single machine (the server) should broadcast the variable
   bInsertionBusy=true; 
   publicVariable "bInsertionBusy";
};

//in your client code
waitUntil{not isNil "bInsertionBusy"};
//do stuff that relies on bInsertionBusy being available
if (bInsertionBusy) then {...

By the way, there is nothing 'magic' about object init fields, they are just a convenient way to include small snippets of code (and have the advantage that when you copy and paste units, the code is also copied). On the flip side, the major restriction with init fields is they are not run in scheduled context so you cannot use constructions such as sleep or waituntil unless you spawn off a separate 'thread' with spawn or execvm (at which point your ordering is also completely undetermined).

If you are only dealing with player units you could use something like this and put everything in init.sqf

//Init.sqf

//"server" code also runs in single-player 
if (isServer) then {
   bInsertionBusy=true; 
   publicVariable "bInsertionBusy";
};

if (isDedicated) exitWith {} ;

//For JIP players, we need to wait until the player unit is initialised
waituntil { not isNull player} ; 

//wait for the variable to be sent/available from the server
waitUntil{not isNil "bInsertionBusy"};
//do stuff that relies on bInsertionBusy being available
if (bInsertionBusy) then {
   ...
} ;

One possible gotcha. IIRC, early versions of arma didn't synchronise public variables for JIP players. If this is still true, one workaround is to write the variable into the namespace of an object (which is synchronised) using setVariable, then read it with getVariable.

Edited by sbsmac

Share this post


Link to post
Share on other sites

Thanks sbsmac

I see, waitUntil{not isNil "bInsertionBusy"} is the key, and then doing the init unit stuff from init.sqf. I will try it a.s.a.p.

Thanks

DMB

Share this post


Link to post
Share on other sites

Please sign in to comment

You will be able to leave a comment after signing in



Sign In Now
Sign in to follow this  

×