Jump to content
Zenophon

Zenophon's ArmA 3 Co-op Mission Making Framework

Recommended Posts

Congrats on yet another update, and the largest to date, and the 5 month milestone ;) I am super thankful I happened upon this when you first released it. I've got way too many hours involved but that lets my stuff get pretty complicated, and thus pretty detailed and fun.

Here is a question, maybe request. Zen_AreInArea wants to find all. What about an option to find any? Assume there is a marker created, and you wanted to know if any of the human players or human groups were within that area. A trigger could be used for any blufor etc, but in staying away from those and using scripts, that would be a good feature I think.

In the meantime, anybody have an idea on the best method to use to do the check without using a trigger? The goal is every 30 seconds to test if any unit on the players side (west) are within the perimeter of the AO (area of operations, aka the marker, the radius of objective, etc). If there is one, then do something, if not, then do nothing. Forcing players to stay within the boundries of the AO to complete the objective I guess is the real goal.

Many ways to do it, trying to find the least intensive (of course). Thinking that stepping through the array of west units and checking if distance is < radius is the easiest, but is it the best?

Another feature request could be that Zen_SpawnConvoy allows one to supply an array of vehicle classnames, so that users may define this, and the number as well. The convoy might not stay together once an engagement starts, but there are types of missions/objectives where some armor would be nice to go up against too.

As an FYI Zenophon, I think the issue with InvokeTask was due to using Variable=west and then using Variable in the function call. I changed everything to west and got rid of the Variable, and in the last dozen tests it works every time.

You can use Zen_AreNotInArea. If that returns true, none of the units are in the marker.

waitUntil {
   sleep 2;
   !([_units, _marker] call Zen_AreNotInArea)
};

// Code to run after the first unit enters the area

If you put the waitUntil and resulting code in a function and spawn it as a new thread, it acts like a trigger. Except that you can pass arguments, change 'sleep 2' to control reaction vs. performance, only run the function in certain circumstances, etc.

That's a good idea for Zen_SpawnConvoy; I can just generalize various things for an array of spawned vehicles.

Nice update, have to test more things but for now.

Something that's happening since I've started using it. Zen_SpawnInfatryGarrison on buildings named "military offices" (the big white houes in Stratis Airport) have people spawned on the roof. Which is kind inmersive-broken.

Also, If I place a building with the editor, the framework does not seem to detect it to place units inside. Maybe Arma engine does not consider it as a building??

---------- Post added at 22:57 ---------- Previous post was at 21:57 ----------

PD, can you check if this

ZEN_FMW_Code_SpawnMarker("mkPatrol", 2, west);

is correct and working? it throws me an error.

Zen_FindBuildingPositions was not harsh enough when checking each point for having a roof. It also seems that allowing roof positions resulted in no positions on the first floor. I've corrected and retested the function using the building you name (its object names says 'miloffices_v1_f.p3d'). Here is some test code (works from the debug console):

buildingPos = [cursorTarget, 100] call Zen_FindBuildingPositions;
systemChat str buildingPos;
systemChat str count buildingPos;
0 = [] spawn {{sleep 0.25; player setPosATL _x} forEach buildingPos};

It appears to have a 50-60% success rate, which I attribute to the discrepancy between building's true size and its reported size by boundingBoxReal.

The error from ZEN_FMW_Code_SpawnMarker is actually from Zen_GiveLoadout. It doesn't give Zen_GiveLoadoutBlufor etc. the right 'skip' value so that they use the default loadouts. I've updated the google drive link. You can also fix it yourself quickly; in Zen_GiveLoadout:

// Change line 18 to
_kits = "";

// and change line 49 to
if (count _this < 3) then {

Share this post


Link to post
Share on other sites

Hi again ;)

Can You please explain how to use Zen_GiveLeadoutCustom on dedicated server to give players equipment?

I have tried this:

_lpiech = [
[["uniform","R3F_uniform_apso"],["vest","V_PlateCarrierSpec_rgr"],["backpack","B_AssaultPack_rgr"],["headgear","H_Watchcap_blk"],["assignedItems",["ItemMap","ItemCompass","ItemWatch","tf_anprc152_2","BWA3_ItemNaviPad"]],["weapons",["hlc_rifle_RU5562","RH_m9c"]],["magazines",[["SmokeShell",7],["30Rnd_556x45_Stanag_Tracer_Red",6],["SmokeShellRed",4],["HandGrenade",4],["30Rnd_556x45_Stanag_Tracer_Green",12],["SmokeShellGreen",1],["30Rnd_556x45_Stanag_Tracer_Red",1],["RH_15Rnd_9x19_M9",1]]],["items",["AGM_EarBuds","AGM_Morphine","AGM_Morphine","AGM_CableTie","AGM_Bandage","AGM_Bandage","AGM_Bandage","AGM_Bandage","AGM_Bandage","AGM_Bandage","AGM_Bandage","AGM_CableTie","AGM_Bandage","AGM_Bandage","AGM_Bandage","AGM_Bandage"]],["primaryAttachments",["FHQ_optic_AC11704"]]]
] call Zen_CreateLoadout;


_lpmed = [
[["uniform","R3F_uniform_apso"],["vest","V_PlateCarrierSpec_rgr"],["backpack","rhsusf_falconii"],["headgear","H_Watchcap_camo"],["assignedItems",["ItemMap","ItemCompass","AGM_Altimeter","tf_anprc152","BWA3_ItemNaviPad"]],["weapons",["hlc_rifle_RU5562","RH_m9c"]],["magazines",[["SmokeShell",7],["30Rnd_556x45_Stanag_Tracer_Red",7],["SmokeShellRed",3],["HandGrenade",1],["1Rnd_SmokeBlue_Grenade_shell",2],["1Rnd_SmokePurple_Grenade_shell",2],["1Rnd_SmokeRed_Grenade_shell",2],["SmokeShellGreen",2],["30Rnd_556x45_Stanag_Tracer_Red",1]]],["items",["AGM_EarBuds","AGM_Morphine","AGM_Morphine","AGM_CableTie","AGM_Bandage","AGM_Bandage","AGM_Bandage","AGM_Bandage","AGM_Bandage","AGM_Bandage","AGM_Bandage","AGM_Bandage","AGM_Bandage","AGM_Bandage","AGM_Bandage","AGM_CableTie","AGM_Bandage","AGM_Bandage","AGM_Bandage","AGM_Bandage","AGM_Bandage","AGM_Bandage","AGM_Bandage","AGM_Bandage","AGM_Bandage","AGM_Bandage","AGM_Bandage","AGM_Bandage","AGM_Bandage","AGM_Bandage","AGM_Bandage","AGM_Bandage","AGM_Bandage","AGM_Bandage","AGM_Bandage","AGM_Bandage","AGM_Bandage","AGM_Bandage","AGM_Bandage","AGM_Bandage","AGM_Bandage","AGM_Bandage","AGM_Morphine","AGM_Morphine","AGM_Morphine","AGM_Morphine","AGM_Morphine","AGM_Morphine","AGM_Morphine","AGM_Morphine","AGM_Morphine","AGM_Morphine","AGM_Morphine","AGM_Morphine","AGM_Epipen","AGM_Epipen","AGM_Epipen","AGM_Epipen","AGM_Epipen","AGM_Epipen","AGM_Epipen","AGM_Epipen","AGM_Epipen","AGM_Epipen","AGM_Epipen","AGM_Epipen"]],["primaryAttachments",["FHQ_optic_AC11704"]]]
] call Zen_CreateLoadout;

// Tried with forEach too...
{0 = [_x, _lpmed] call Zen_GiveLoadoutCustom} count [piech1, piech2];
{0 = [_x, _lpiech] call Zen_GiveLoadoutCustom} count [piech3];

this is in file leadout.sqf. This is my init:

// Sabotaz by Doman
// Version = 12/12/2014
// Tested with ArmA 3 1.36

#include "Zen_FrameworkFunctions\Zen_InitHeader.sqf";
#include "config.sqf";
//#include "briefing.sqf";
//null = [3] execvm "tpwcas\tpwcas_script_init.sqf";

// leadout 1st try
// #include "leadout.sqf";

if (!isServer || !isDedicated) exitWith {};
sleep 1;
// leadout 2nd try
#include "leadout.sqf";

Problems:

In editor I placed three playable man units with names piech1, piech2, piech3. When I disable one slot then there is an error saying that one object is nonexistent (forEach/count error).

1st try: everything is working, when a player will join later his AI has already leadout - and this is how it schould work in my mission but there is error when a player slot is disabled.

2nd try: AI unit has no leadout at mission beginning which lowers milsim immersion (when player joins later).

Share this post


Link to post
Share on other sites

Zenophon, I wonder if there are any issues with InvokeFireSupport? Its as if its using createVehicle rather than createVehicleArray many times. The ordinance is coming in 10's or 100's of meters away from target, as if there is a check for where to spawn like regular createVehicle would do.

I can tighten up the firesupport template values etc, but it still seems to not be accurate if there are objects near or the position came from an object.

Any ideas on what might cause such a thing?

Here is an example template and invoke function

_arSalvoType = ["R_230mm_HE","Sh_155mm_AMOS","Sh_82mm_AMOS","r_80mm_he","r_60mm_he","Bo_Mk82","Bo_GBU12_LGB","M_Titan_AT","M_Titan_AP","M_Mo_120mm_AT","M_Mo_82mm_AT"];
_posTarget = getPosATL (_this select 1);
arArtyStrikeTemplate = [([_arSalvoType] call Zen_ArrayGetRandom),6,1,1,10,25,20] call Zen_CreateFireSupport;
_h_FireSupport = [_posTarget , arArtyStrikeTemplate] spawn Zen_InvokeFireSupport;

where the input parameter is an object (ie. taken from cursorTarget or laserTarget).

Share this post


Link to post
Share on other sites
Hi again ;)

Can You please explain how to use Zen_GiveLeadoutCustom on dedicated server to give players equipment?

I have tried this:

_lpiech = [
[["uniform","R3F_uniform_apso"],["vest","V_PlateCarrierSpec_rgr"],["backpack","B_AssaultPack_rgr"],["headgear","H_Watchcap_blk"],["assignedItems",["ItemMap","ItemCompass","ItemWatch","tf_anprc152_2","BWA3_ItemNaviPad"]],["weapons",["hlc_rifle_RU5562","RH_m9c"]],["magazines",[["SmokeShell",7],["30Rnd_556x45_Stanag_Tracer_Red",6],["SmokeShellRed",4],["HandGrenade",4],["30Rnd_556x45_Stanag_Tracer_Green",12],["SmokeShellGreen",1],["30Rnd_556x45_Stanag_Tracer_Red",1],["RH_15Rnd_9x19_M9",1]]],["items",["AGM_EarBuds","AGM_Morphine","AGM_Morphine","AGM_CableTie","AGM_Bandage","AGM_Bandage","AGM_Bandage","AGM_Bandage","AGM_Bandage","AGM_Bandage","AGM_Bandage","AGM_CableTie","AGM_Bandage","AGM_Bandage","AGM_Bandage","AGM_Bandage"]],["primaryAttachments",["FHQ_optic_AC11704"]]]
] call Zen_CreateLoadout;


_lpmed = [
[["uniform","R3F_uniform_apso"],["vest","V_PlateCarrierSpec_rgr"],["backpack","rhsusf_falconii"],["headgear","H_Watchcap_camo"],["assignedItems",["ItemMap","ItemCompass","AGM_Altimeter","tf_anprc152","BWA3_ItemNaviPad"]],["weapons",["hlc_rifle_RU5562","RH_m9c"]],["magazines",[["SmokeShell",7],["30Rnd_556x45_Stanag_Tracer_Red",7],["SmokeShellRed",3],["HandGrenade",1],["1Rnd_SmokeBlue_Grenade_shell",2],["1Rnd_SmokePurple_Grenade_shell",2],["1Rnd_SmokeRed_Grenade_shell",2],["SmokeShellGreen",2],["30Rnd_556x45_Stanag_Tracer_Red",1]]],["items",["AGM_EarBuds","AGM_Morphine","AGM_Morphine","AGM_CableTie","AGM_Bandage","AGM_Bandage","AGM_Bandage","AGM_Bandage","AGM_Bandage","AGM_Bandage","AGM_Bandage","AGM_Bandage","AGM_Bandage","AGM_Bandage","AGM_Bandage","AGM_CableTie","AGM_Bandage","AGM_Bandage","AGM_Bandage","AGM_Bandage","AGM_Bandage","AGM_Bandage","AGM_Bandage","AGM_Bandage","AGM_Bandage","AGM_Bandage","AGM_Bandage","AGM_Bandage","AGM_Bandage","AGM_Bandage","AGM_Bandage","AGM_Bandage","AGM_Bandage","AGM_Bandage","AGM_Bandage","AGM_Bandage","AGM_Bandage","AGM_Bandage","AGM_Bandage","AGM_Bandage","AGM_Bandage","AGM_Bandage","AGM_Morphine","AGM_Morphine","AGM_Morphine","AGM_Morphine","AGM_Morphine","AGM_Morphine","AGM_Morphine","AGM_Morphine","AGM_Morphine","AGM_Morphine","AGM_Morphine","AGM_Morphine","AGM_Epipen","AGM_Epipen","AGM_Epipen","AGM_Epipen","AGM_Epipen","AGM_Epipen","AGM_Epipen","AGM_Epipen","AGM_Epipen","AGM_Epipen","AGM_Epipen","AGM_Epipen"]],["primaryAttachments",["FHQ_optic_AC11704"]]]
] call Zen_CreateLoadout;

// Tried with forEach too...
{0 = [_x, _lpmed] call Zen_GiveLoadoutCustom} count [piech1, piech2];
{0 = [_x, _lpiech] call Zen_GiveLoadoutCustom} count [piech3];

this is in file leadout.sqf. This is my init:

// Sabotaz by Doman
// Version = 12/12/2014
// Tested with ArmA 3 1.36

#include "Zen_FrameworkFunctions\Zen_InitHeader.sqf";
#include "config.sqf";
//#include "briefing.sqf";
//null = [3] execvm "tpwcas\tpwcas_script_init.sqf";

// leadout 1st try
// #include "leadout.sqf";

if (!isServer || !isDedicated) exitWith {};
sleep 1;
// leadout 2nd try
#include "leadout.sqf";

Problems:

In editor I placed three playable man units with names piech1, piech2, piech3. When I disable one slot then there is an error saying that one object is nonexistent (forEach/count error).

1st try: everything is working, when a player will join later his AI has already leadout - and this is how it schould work in my mission but there is error when a player slot is disabled.

2nd try: AI unit has no leadout at mission beginning which lowers milsim immersion (when player joins later).

If you disable the AI unit on the server, that object name refers to nothing. There are many ways you can deal with this depending upon your mission.

Firstly and most simply, get the name of the group. If you can be 100% sure that one of the units will always exist, use that one.

_playerGroup = group piech1;
0 = [_playerGroup, _lpmed] call Zen_GiveLoadoutCustom;

Second, if you are 100% sure that those player units are the only objects on their side at some point, you can filter all units by side then by player.

_westUnits = [west] call Zen_ConvertToObjectArray;
_playerUnits = [_westUnits, {!(isPlayer _this)}] call Zen_ArrayFilterCondition;
0 = [_playerUnits, _lpmed] call Zen_GiveLoadoutCustom;

Third, you can use getVariable, since all the units are globally named.

_players = [];
for "_i" from 1 to 3 do {
   _unit = missionNamespace getVariable ["piech" + str _i, objNull];
   if !(isNull _unit) then {
       _players pushBack _unit;
   };
};

0 = [_players, _lpmed] call Zen_GiveLoadoutCustom;

If none of these work, I can think of more ways that could work. However, there is one problem with all of these: you cannot give specific loadouts to specific units. If 2 players choose to play as piech1 and piech3, only the getVariable method above could detect that.

The easy solution is to make the loadouts random, either by listing all the loadouts in the argument to Zen_GiveLoadoutCustom, or using the custom loadouts' randomization features. You can also give the loadouts sequentially to the array of players, so that the if piech2 is skipped, piech3 has his loadout.

Zenophon, I wonder if there are any issues with InvokeFireSupport? Its as if its using createVehicle rather than createVehicleArray many times. The ordinance is coming in 10's or 100's of meters away from target, as if there is a check for where to spawn like regular createVehicle would do.

I can tighten up the firesupport template values etc, but it still seems to not be accurate if there are objects near or the position came from an object.

Any ideas on what might cause such a thing?

Here is an example template and invoke function

_arSalvoType = ["R_230mm_HE","Sh_155mm_AMOS","Sh_82mm_AMOS","r_80mm_he","r_60mm_he","Bo_Mk82","Bo_GBU12_LGB","M_Titan_AT","M_Titan_AP","M_Mo_120mm_AT","M_Mo_82mm_AT"];
_posTarget = getPosATL (_this select 1);
arArtyStrikeTemplate = [([_arSalvoType] call Zen_ArrayGetRandom),6,1,1,10,25,20] call Zen_CreateFireSupport;
_h_FireSupport = [_posTarget , arArtyStrikeTemplate] spawn Zen_InvokeFireSupport;

where the input parameter is an object (ie. taken from cursorTarget or laserTarget).

For some types of rounds, spawned with Zen_SpawnVehicle, it seems spawning them gives them some initial velocity that moved them off target. Using Zen_TransformObject directly after spawning fixes that.

For a few rounds, the actual vehicle that fires them must be spawned and forced to fire. There was a timing issue where the velocity of those fired rounds was not corrected for about 0.2 seconds, allowing them to drift off target.

This code should demonstrate 100% accuracy:

arArtyStrikeTemplate = ["r_80mm_he",2,1,1,1,1,1] call Zen_CreateFireSupport;
_h_FireSupport = [player, arArtyStrikeTemplate] spawn Zen_InvokeFireSupport;

I've also optimized some unrelated things in Zen_InvokeFireSupport. The google drive link is updated with this fix.

Share this post


Link to post
Share on other sites

The issue is only in MP because Zen_GiveLoadoutCustom does not remote execute itself with the correct arguments. I forgot that the default of optional arguments must be appended to the remote execution arguments.

The loadout name being shown is the internal string name of the loadout. You can set this when the loadout is created using the second argument to Zen_CreateLoadout.

-----

I've updated the latest framework version for the Google drive link with these two fixes.

Hi Zen,

Good news, weird news. Good news is that I have updated to the latest version of the framework and the error has stopped appearing.

Weird news - when i test the mission on local and in editor, all fine. When I test on dedicated, the opfor custom loadouts are not being called. Any idea why that would work locally but not on dedicated?

Cheers,

CMS

Share this post


Link to post
Share on other sites

When using "Zen_GiveLoadoutBlufor" I have a spam of this in the RPT server/client file (client in editor)

11:41:14 Inventory item with given name: [] not found

Dunno if with other "giveLoadout" is happening too.

Share this post


Link to post
Share on other sites

Here is a quick question.

What is the difference between side and faction when using something like Zen_SpawnInfantry? Does this mean that you spawn EAST but they actually fight for BLU_F if you used those parameters?

Share this post


Link to post
Share on other sites
Here is a quick question.

What is the difference between side and faction when using something like Zen_SpawnInfantry? Does this mean that you spawn EAST but they actually fight for BLU_F if you used those parameters?

Nope, but you can define what type of enemy you fight when defining EAST as side. EAST side include CSAT and any other EAST factions (like Russia for RHS mod, or the CAF agressors mod)

If you do not define it, the units will be selected randomly (it may be a feature or a bug, depending on how you design your mission).

Myslef I use faction selection to assure every unit is being spawned as CSAT forces, for example.

Share this post


Link to post
Share on other sites

So, what you are saying, I think, is that if I just spawn EAST, but do not dictate faction, the spawned units could be CSAT or Independent? Similar to placing units in the editor, you have to pick what side/faction.

Or, is it similar to, or have bearing with, the setting in a mission where you set which side AAF/Ind is friendly/aggressive towards.

To be perfectly honest, I have completely ignored this aspect of the game. I have not even really played many missions and none of the campaign. I am just so happy to be messing with a PC game again and learning the scripting etc, being able to "more or less" do what I want. The scale of the community is just ridiculous. Previous arma titles didn't do much for me, but I really like arma 3 a lot.

So, I guess I will have to experiment a bit with this..

Tnanks for the reply!

Share this post


Link to post
Share on other sites
Hi Zen,

Good news, weird news. Good news is that I have updated to the latest version of the framework and the error has stopped appearing.

Weird news - when i test the mission on local and in editor, all fine. When I test on dedicated, the opfor custom loadouts are not being called. Any idea why that would work locally but not on dedicated?

Cheers,

CMS

If you're equipping AI, there should be no difference as the server always handles that, whether in the editor (server is your machine), local host MP, or a dedicated server. Zen_GiveLoadoutCustom should print an error if the loadout name it's given has not data. If you don't see that error, check that Zen_GiveLoadoutCustom is actually being called.

When using "Zen_GiveLoadoutBlufor" I have a spam of this in the RPT server/client file (client in editor)

11:41:14 Inventory item with given name: [] not found

Dunno if with other "giveLoadout" is happening too.

That debug appears when a null string ("") is given to any engine command dealing with giving items to inventories. Zen_GiveLoadoutBlufor and Zen_GiveLoadoutIndfor use "" when choosing goggles randomly so that some loadouts do not have goggles, a bandanna, etc. The error is harmless and will appear about 50% of the time per unit for most loadouts.

This can be fixed by checking if the randomly selected goggles are "", in which case 'addGoggles' is not used. This fix will be included in the next release.

Here is a quick question.

What is the difference between side and faction when using something like Zen_SpawnInfantry? Does this mean that you spawn EAST but they actually fight for BLU_F if you used those parameters?

Technically speaking, side and faction are just attributes of a unit's class. Logically, factions are subsets of sides, which is reflected graphically in the editor and in the order of parameters to various framework functions. Side determines who units will fire on, so units of the same side and different faction are always allies.

Zen_SpawnInfantry simply passes those arguments along to Zen_ConfigGetVehicleClasses. Without mods, the only side with more than one faction is west, which includes both "BLU_F" and "BLU_G_F". This shows the different factions' units:

player sideChat str (["Men", west, "All", "All"] call Zen_ConfigGetVehicleClasses);
player sideChat str (["Men", west, "All", "BLU_F"] call Zen_ConfigGetVehicleClasses);
player sideChat str (["Men", west, "All", "BLU_G_F"] call Zen_ConfigGetVehicleClasses);

With mods, there could be many factions for each side, and the type of unit ('Men' above) may change as well; this is 'vehicleClass' in the config. The subtype, as Zen_ConfigGetVehicleClasses calls it, can also be used for soldiers (called 'testSingular' in the config), but it's not very reliable for soldiers and mostly meant for vehicles.

Share this post


Link to post
Share on other sites

I'm hoping one of you guys could help me. I'm trying to JIP my mission and all I need sync'ed are the tasks (as I don't use the other functions from the frame work such as give loadout, weather or give magazine etc.). I tried to adapt the JIP solutions that Zenophon has provided but I can't grasp what's happening in that JIP code. And alas it doesn't work! LOL.

If anyone has a solution I'd really appreciate it!

On another note the new patrol system for the divers so far has worked awesome so Thank you for adding that to your framework Zenophon!

Share this post


Link to post
Share on other sites

Thx Zen.

When using an array of groups in Zen_Find2dDistance, it retuns the total lenght of the map (as if the groups didn't exist)

Maybe we can't use arrays of groups?

[_g_players, "Marker"] call Zen_Find2dDistance

Share this post


Link to post
Share on other sites

I've commented mine out when I first started using it. Might help.

The easiest way I can describe it is that, in the case of a coop mission, everything that happens prior to isServer happens to the bots or human players, so anyone joining already has those things. Such as custom gear or defined groups etc. This is because when you JIP you "drop into" the unit and get whatever it had.

For my understanding then, the JIP sync stuff is to put in place data on the client that cannot be known by just "dropping into" a unit. Things like weather or tasks etc etc. Zen does this with the array called Zen_Task_Array_Global, which you create to hold whatever you want to send to clients who are syncing. It might only be 2 elements, such as the time and date. You just structure it the way you want, then the JIP client requests the server to send it the array. When the array exists, the client uses the data in it to setup whatever is needed. In my JIP file I set the weather and viewdistances, add some options like repack magazine and give magazine, and get any tasks to the JIP player. Once Its all ready, I fade in from black.

You will see I commented a good bit of stuff out because I handle it in other ways.

if (_Zen_Is_JIP) then {
// if the player has "Joined In Progress", certain values/data needs to be 
// synced with what the server has as current/correct 

   Zen_Task_Array_Global = 1;

// this packet requests the server to set a public variable for this client
// that contains an array of mission data (date, weather, etc)
   Zen_MP_Closure_Packet = ["Zen_SyncJIPServer", player];
   publicVariableServer "Zen_MP_Closure_Packet";

// after requesting the data, pause until the variable exists on this machine 
// which only happens once the server sends it 
   waitUntil {
       (!(isNil "Zen_JIP_Args_Server") && (typeName Zen_Task_Array_Global == "ARRAY"))
   };

// set a local reference to the data recieved 
   _serverArgs = Zen_JIP_Args_Server;

// data structure
// [time, overcast, overcastForecast, time, p_overcastTime, fog, fogForecast, time, p_fogTime, p_ViewDistance, [varHumanSideUnits]];

// using the data received, set the weather, syncing to what the server and other
// clients are using 
   0 = [["overcast", (_serverArgs select 1), (_serverArgs select 2), (_serverArgs select 3) + (_serverArgs select 4) - (_serverArgs select 0)], ["fog", (_serverArgs select 5), (_serverArgs select 6), (_serverArgs select 7) + (_serverArgs select 8) - (_serverArgs select 0)], ["packet", false]] spawn Zen_SetWeather;

// set other values to sync with server 
   0 = [(_serverArgs select 9), -1, -1, false] call Zen_SetViewDistance;
0 = [(_serverArgs select 10), false] call Zen_AddRepackMagazines;

// test if client has any tasks
   if ((count ([player] call Zen_GetUnitTasks)) == 0) then {
	// if no tasks, tell other (possible) local units to add menu action 
	// remove player from the list and use boolean to not broadcast to other players (keep it local)
       0 = [([(_serverArgs select 10)] call Zen_ConvertToObjectArray) - [player], false] call Zen_AddGiveMagazine;

	// tell self to add menu action (without packet boolean - advanced argument which broadcasts it to mp)
       0 = [player] call Zen_AddGiveMagazine;

	// normally give a loadout here 
       // 0 = [player, BLUFOR_LOADOUTS] call Zen_GiveLoadoutCustom;

	// normally move player to leaders positon
       // player setPosATL ([leader group player, 2 + random 3, random 360] call Zen_ExtendPosition);

	// normally add the event handler 
       // player addMPEventHandler ["MPRespawn", f_HandleRespawn];
	// player addMPEventHandler ["MPRespawn", {Nul = _this execVM "JIP_respawn_group.sqf";}];

	// step through the global array of tasks
	// if players group was assigned the task, add player to array (include him)
       {
           if (leader group player in (_x select 1)) then {
               _x set [1, (_x select 1) + [player]];
           };
       } forEach Zen_Task_Array_Global;

	// send the array to all (with now included player) so all know 
       publicVariable "Zen_Task_Array_Global";
   } else {
       0 = [(_serverArgs select 10), false] call Zen_AddGiveMagazine;
   };

// step through the task array, adding each task to player and its status
   {
       0 = [(_x select 1), (_x select 4), (_x select 5), (_x select 3), false, (_x select 0), (_x select 6)] call Zen_InvokeTaskClient;
       0 = [(_x select 0)] call Zen_UpdateTask;
       sleep 0.1;
   } forEach Zen_Task_Array_Global;

// as player "Joins In Progress", ask server to publish a list of what unit
// has what rank so client can sync to server 
Zen_MP_Closure_Packet = ["f_broadcastRank",[[(_serverArgs select 10)] call Zen_ConvertToObjectArray,player]];
publicVariableServer "Zen_MP_Closure_Packet";

  // all prepared, fade in from black 
titleText ["", "BLACK IN",2];

// display the mission intro message 
// 0 = [] execVM "IntroMessage.sqf";
Zen_MP_Closure_Packet = ["f_requestIntroMessage",player];
publicVariableServer "Zen_MP_Closure_Packet";

};

if (isServer) then {
   Zen_SyncJIPServer = {
       Zen_JIP_Args_Server set [0, time];
       Zen_JIP_Args_Server set [1, overcast];
       Zen_JIP_Args_Server set [2, overcastForecast];
       Zen_JIP_Args_Server set [5, fog];
       Zen_JIP_Args_Server set [6, fogForecast];

       (owner _this) publicVariableClient "Zen_Task_Array_Global";
       (owner _this) publicVariableClient "Zen_Fire_Support_Array_Global";
       (owner _this) publicVariableClient "Zen_Loadout_Array_Global";
       (owner _this) publicVariableClient "Zen_Damage_Increase";
       (owner _this) publicVariableClient "Zen_JIP_Args_Server";
   };
};

---------- Post added at 21:53 ---------- Previous post was at 21:50 ----------

Thx Zen.

When using an array of groups in Zen_Find2dDistance, it retuns the total lenght of the map (as if the groups didn't exist)

Maybe we can't use arrays of groups?

[_g_players, "Marker"] call Zen_Find2dDistance

I believe an array is a position array, and a group would be an array (non-nested). So you should probably try (_g_players select x) as I bet it doesn't handle nested groups.

Share this post


Link to post
Share on other sites
I've commented mine out when I first started using it. Might help.

The easiest way I can describe it is that, in the case of a coop mission, everything that happens prior to isServer happens to the bots or human players, so anyone joining already has those things. Such as custom gear or defined groups etc. This is because when you JIP you "drop into" the unit and get whatever it had.

For my understanding then, the JIP sync stuff is to put in place data on the client that cannot be known by just "dropping into" a unit. Things like weather or tasks etc etc. Zen does this with the array called Zen_Task_Array_Global, which you create to hold whatever you want to send to clients who are syncing. It might only be 2 elements, such as the time and date. You just structure it the way you want, then the JIP client requests the server to send it the array. When the array exists, the client uses the data in it to setup whatever is needed. In my JIP file I set the weather and viewdistances, add some options like repack magazine and give magazine, and get any tasks to the JIP player. Once Its all ready, I fade in from black.

You will see I commented a good bit of stuff out because I handle it in other ways.

if (_Zen_Is_JIP) then {
// if the player has "Joined In Progress", certain values/data needs to be 
// synced with what the server has as current/correct 

   Zen_Task_Array_Global = 1;

// this packet requests the server to set a public variable for this client
// that contains an array of mission data (date, weather, etc)
   Zen_MP_Closure_Packet = ["Zen_SyncJIPServer", player];
   publicVariableServer "Zen_MP_Closure_Packet";

// after requesting the data, pause until the variable exists on this machine 
// which only happens once the server sends it 
   waitUntil {
       (!(isNil "Zen_JIP_Args_Server") && (typeName Zen_Task_Array_Global == "ARRAY"))
   };

// set a local reference to the data recieved 
   _serverArgs = Zen_JIP_Args_Server;

// data structure
// [time, overcast, overcastForecast, time, p_overcastTime, fog, fogForecast, time, p_fogTime, p_ViewDistance, [varHumanSideUnits]];

// using the data received, set the weather, syncing to what the server and other
// clients are using 
   0 = [["overcast", (_serverArgs select 1), (_serverArgs select 2), (_serverArgs select 3) + (_serverArgs select 4) - (_serverArgs select 0)], ["fog", (_serverArgs select 5), (_serverArgs select 6), (_serverArgs select 7) + (_serverArgs select 8) - (_serverArgs select 0)], ["packet", false]] spawn Zen_SetWeather;

// set other values to sync with server 
   0 = [(_serverArgs select 9), -1, -1, false] call Zen_SetViewDistance;
0 = [(_serverArgs select 10), false] call Zen_AddRepackMagazines;

// test if client has any tasks
   if ((count ([player] call Zen_GetUnitTasks)) == 0) then {
	// if no tasks, tell other (possible) local units to add menu action 
	// remove player from the list and use boolean to not broadcast to other players (keep it local)
       0 = [([(_serverArgs select 10)] call Zen_ConvertToObjectArray) - [player], false] call Zen_AddGiveMagazine;

	// tell self to add menu action (without packet boolean - advanced argument which broadcasts it to mp)
       0 = [player] call Zen_AddGiveMagazine;

	// normally give a loadout here 
       // 0 = [player, BLUFOR_LOADOUTS] call Zen_GiveLoadoutCustom;

	// normally move player to leaders positon
       // player setPosATL ([leader group player, 2 + random 3, random 360] call Zen_ExtendPosition);

	// normally add the event handler 
       // player addMPEventHandler ["MPRespawn", f_HandleRespawn];
	// player addMPEventHandler ["MPRespawn", {Nul = _this execVM "JIP_respawn_group.sqf";}];

	// step through the global array of tasks
	// if players group was assigned the task, add player to array (include him)
       {
           if (leader group player in (_x select 1)) then {
               _x set [1, (_x select 1) + [player]];
           };
       } forEach Zen_Task_Array_Global;

	// send the array to all (with now included player) so all know 
       publicVariable "Zen_Task_Array_Global";
   } else {
       0 = [(_serverArgs select 10), false] call Zen_AddGiveMagazine;
   };

// step through the task array, adding each task to player and its status
   {
       0 = [(_x select 1), (_x select 4), (_x select 5), (_x select 3), false, (_x select 0), (_x select 6)] call Zen_InvokeTaskClient;
       0 = [(_x select 0)] call Zen_UpdateTask;
       sleep 0.1;
   } forEach Zen_Task_Array_Global;

// as player "Joins In Progress", ask server to publish a list of what unit
// has what rank so client can sync to server 
Zen_MP_Closure_Packet = ["f_broadcastRank",[[(_serverArgs select 10)] call Zen_ConvertToObjectArray,player]];
publicVariableServer "Zen_MP_Closure_Packet";

  // all prepared, fade in from black 
titleText ["", "BLACK IN",2];

// display the mission intro message 
// 0 = [] execVM "IntroMessage.sqf";
Zen_MP_Closure_Packet = ["f_requestIntroMessage",player];
publicVariableServer "Zen_MP_Closure_Packet";

};

if (isServer) then {
   Zen_SyncJIPServer = {
       Zen_JIP_Args_Server set [0, time];
       Zen_JIP_Args_Server set [1, overcast];
       Zen_JIP_Args_Server set [2, overcastForecast];
       Zen_JIP_Args_Server set [5, fog];
       Zen_JIP_Args_Server set [6, fogForecast];

       (owner _this) publicVariableClient "Zen_Task_Array_Global";
       (owner _this) publicVariableClient "Zen_Fire_Support_Array_Global";
       (owner _this) publicVariableClient "Zen_Loadout_Array_Global";
       (owner _this) publicVariableClient "Zen_Damage_Increase";
       (owner _this) publicVariableClient "Zen_JIP_Args_Server";
   };
};

WOW! Thanks m0nkey this helped alot for me to understand what was happening! I have some questions.

Do you put this in your init.sqf? I've been using a separate file with the #include. Is there an "optimal" position in the init for the include statement? (I'm learning the hard way that placement order is very important!!)

1. How do you assign the group... I use _players = units group X11; with the group leader named X11 and it's located below the if (!isServer) exitWith {}; in the init.sqf. Is this the correct way to do this because on my server I'll have players connected that don't use the group leader position so it will be vacant at times. And I don't use AI. Also I need this to update a player who connects when there are no other players or AI present on the server. (It's a persistent server (somewhat))

2. I don't use any of the serverargs but do I still need to include them or can I comment them out and especially the line:

waitUntil {

(!(isNil "Zen_JIP_Args_Server") && (typeName Zen_Task_Array_Global == "ARRAY"))

};

Do I need to modify this to not wait for the Zen_JIP_Args_Server?

3. And for the final part of it do I need all the extra or can I lose all but:

if (isServer) then {

Zen_SyncJIPServer = {

(owner _this) publicVariableClient "Zen_Task_Array_Global";

};

};

as all I need to update are the tasks and add the player to the units array that receive the tasks?

4. Is there a way to remove players from the array when they disconnect from the server? (Some triggers require the presence of all the group)

Share this post


Link to post
Share on other sites
WOW! Thanks m0nkey this helped alot for me to understand what was happening! I have some questions.

Do you put this in your init.sqf? I've been using a separate file with the #include. Is there an "optimal" position in the init for the include statement? (I'm learning the hard way that placement order is very important!!)

My init.sqf file is broken in 2 sections (as most are) - the client section and the server section. In non-dedicated coop, everyone gets the #include file Zen_InitHeader.sqf, followed by all the settings,variables,etc that each client needs. Functions that run on clients are defined/parsed. In short, everything that is not needed by the "server" should be defined. JIP and Non-JIP both process this section.

The key is that after this section ends, and the server section begins, info/settings that Non-JIP clients receive will not be known to JIP clients. So, in my case anyway, this is at the end of my client section

// Join In Progress code
#include "JIPSync.sqf"
if !(isServer) exitWith {};
sleep 1;

1. How do you assign the group... I use _players = units group X11; with the group leader named X11 and it's located below the if (!isServer) exitWith {}; in the init.sqf. Is this the correct way to do this because on my server I'll have players connected that don't use the group leader position so it will be vacant at times. And I don't use AI. Also I need this to update a player who connects when there are no other players or AI present on the server. (It's a persistent server (somewhat))

I use this in the client section

varRespawnRandomKit = true;
varOtherGroupBehaviour = 0;
varShowFriendlies = 0;
varPlayerAsLeader = true;
varHumanSideUnits = [];
varSingleSupportUse = true;

to setup variables that the server will "pass onto" clients at a later time. One of these is set by the client, just before JIPsync is initialized, like this

// convert all groups on human side to one large array
// this array contains every human side unit available at 
// beginning of play - these should be playable units only 
varHumanSideUnits = [west] call Zen_ConvertToObjectArray;

Later, the "server" sends the values, like this

// parameters are not known to client, so send these parameters to all clients
varRespawnRandomKit = p_respawnRandomKit;
publicVariable "varRespawnRandomKit";
varOtherGroupBehaviour = p_otherGroupBehaviour;
publicVariable "varOtherGroupBehaviour";
varShowFriendlies = p_showFriendlies;
publicVariable "varShowFriendlies";
varPlayerAsLeader = p_playerAsLeader;
publicVariable "varPlayerAsLeader";
varSingleSupportUse = p_singleSupportUse;
publicVariable "varSingleSupportUse";

But as for groups, they are in the "server" section, like this

// define the player groups
PG1 = group x11;
PG2 = group x21;
PG3 = group x31;
// create an array of the player groups 
arPG = [PG1] + [PG2] + [PG3];

So, each "playable unit" is known about at the beginning of my mission because it is a coop with AI. The clients don't need to know about anything but the ones that are declared as "publicVariable". They certainly don't need to know anything about groups. In your case, you will have to define an array on the server side that add/removes units. I don't know if a native command like Join is MP ready or not. If not, a Zen function might do it for you. If not, then you have to use the publicVariable method to get clients the data that the server has that they need.

2. I don't use any of the serverargs but do I still need to include them or can I comment them out and especially the line:

waitUntil {

(!(isNil "Zen_JIP_Args_Server") && (typeName Zen_Task_Array_Global == "ARRAY"))

};

Do I need to modify this to not wait for the Zen_JIP_Args_Server?

This is the key statement really. Just prior to this you, as a JIP client, requested the server send you this array. Now this line is waiting until the public variable Zen_JIP_Args_Server has been created on the client, as well as wait until the variable Zen_Task_Array_Global is an "array" type. Its the information in this array that you want the client to recieve and use to "sync" with the server. At least thats how its setup by Zenophon in this sample.

3. And for the final part of it do I need all the extra or can I lose all but:

if (isServer) then {

Zen_SyncJIPServer = {

(owner _this) publicVariableClient "Zen_Task_Array_Global";

};

};

as all I need to update are the tasks and add the player to the units array that receive the tasks?

That would depend largely on just what sort of data you want to send/recieve/track. Hard to say without knowing all about the mission. I would comment out anything you don't think you are using, run it and see if you get errors. Look at the .rpt file, and modify as needed.

4. Is there a way to remove players from the array when they disconnect from the server? (Some triggers require the presence of all the group)
Zen has functions that will do this, or you can do it manually. I think there is an event for onDisconnect, which is where you would do it. I have not used that. Just see if it is called on all machines and if so, create a function in the client section to do that. If its local, then the server will have to modify the players array (or whatever data structure you are using) and send it to the clients with publicVariable.

I've not been interested in missions without AI,or at least not missions only expecting humans, so a lot of that I am not up to snuff on.

Share this post


Link to post
Share on other sites

The Event Scripts may be of interest to you instead of having all these JIP checks and multi-section init.sqfs :D.

Share this post


Link to post
Share on other sites
The Event Scripts may be of interest to you instead of having all these JIP checks and multi-section init.sqfs :D.

They suck XD

OnPlayerRespawn.sqf executes even at mission start. So you still have to do cheks on wether is a JIP or mission start. Zen just gives a variable that already does this, so I like to stick with it.

Share this post


Link to post
Share on other sites

Introduction

Greetings fellow scripters and Armaholics, in this latest installment, I will continue to discuss the development of the framework and, of course, shamelessly advertise the framework in any way possible.

If this sounds boring, you can download the latest version from the original post. As always, the links to Google Drive for the .7z and .zip versions are already up to date. For those looking for older versions, go to file>revisions. The new version should be on Armaholic when Foxhound sees this or I PM him. Please bring any technical issues or mistakes to my attention, so e.g. people don't download the wrong version etc.

I would also like to announce that, in case you were unaware, I am not the author of the tutorials. Rather, as stated in the tutorials readme file, a friend of mine created them. Although he previously preferred to be anonymous, he recently joined these forums as MimirAesir and asked me to make this announcement. If you have any feedback or bug reports about the tutorials, feel free to PM him.

Changelog

This release's most significant addition is several new tutorials in a series focusing on randomization. These new tutorials are greatly expanded versions of the existing ones, offering a lot of new code. They feature examples for generating and selecting random positions by writing your own filters, using built-in point of interest on the map, and using simple geometry to create grids of markers.

The rest of the update contains minor fixes and improvements suggested by users or found in testing. Zen_ConfigGetVehicleClasses can now filter by parent classes; note that its order of parameter has changed slightly. Zen_SpawnConvoy can, as requested, spawn a list of vehicles.

Zen_InvokeFireSupport has been improved; rounds now simply spawn on the ground and explode instantly, rather than falling from the sky. This is easier and results in fewer issues (you won't the difference notice anyway). Zen_FindPositionPoly and Zen_QuantizeAngles parameters have been overloaded to accept marker names instead of their properties to make them more user friendly.

Custom loadouts have been improved slightly so that items can be denoted like magazines, with a type and number in a nested array. Zen_FindBuildingPositions continues to be tweaked, and I'm sufficiently confident to make it the spotlight function this week. Two demonstrations, relating to Zen_ConfigGetVehicleClasses and custom loadouts are completely up to date. You can see all the other improvements below.

12/24/14

  1. Fixed: Zen_ConfigGetVehicleClasses did not parse all arguments strictly
  2. Fixed: Zen_GiveLoadout did not set the default correctly for preset loadout kits
  3. Fixed: Zen_GiveLoadoutBlufor and Zen_GiveLoadoutIndfor caused engine errors to print in the report log
  4. Fixed: Zen_InvokeFireSupport allowed rounds to drift out of the defined target area
  5. Fixed: Zen_OrderExtraction and Zen_OrderInsertion caused odd behavior for boats
  6. Added: Zen_ConfigGetVehicleClasses parameter for parent classes
  7. Added: Zen_SpawnConvoy parameter for vehicle classnames
  8. Added: Framework macro ZEN_FMW_Math_RandomPointMin
  9. Added: Standard macro ZEN_STD_Array_LastElement
  10. Improved: Zen_FindBuildingPositions roof detection logic and general accuracy
  11. Improved: Zen_FindPositionPoly and Zen_QuantizeAngles accept a marker name
  12. Improved: Zen_GiveLoadoutCargo and Zen_GiveLoadoutCustom now accept a number paired with an item
  13. Improved: Zen_InvokeFireSupport optimized
  14. Improved: Zen_QuantizeAngles order of parameters
  15. Improved: Zen_SpawnConvoy always puts the first vehicle in the lead
  16. Improved: Zen_SpawnConvoy orders the drivers to stop after spawning
  17. Documentation: Added a new series of tutorials focusing on randomization
  18. Documentation: Added for ZEN_FMW_Math_RandomPointMin, ZEN_STD_Array_LastElement
  19. Documentation: Updated for Zen_ConfigGetVehicleClasses, Zen_FindPositionPoly, Zen_QuantizeAngles, Zen_SpawnConvoy
  20. Documentation: Updated Zen_CustomLoadout, Zen_RandomBattle demonstrations

Function Spotlight

As users of my framework know, there is an enormous number of functions at your disposal. The amount of documentation that has to be sifted through can be extremely daunting. Each week I spotlight a function and talk about its usefulness. If you have found an obscure function (not in tutorials, barely seen in demonstrations or sample missions) that you think is useful, PM me and I can spotlight it.

The function chosen for this week is: Zen_FindBuildingPositions. This function dynamically generates 3D positions inside or on the roof of any building. Rather than relying on the building's predetermined positions, you can now use all of the building randomly.

The function's algorithm is basically trial and error to find valid positions, but it does so very quickly. First, I will go over actually getting the building to give to the function. Zen_FindBuildingPositions does not accept an object, but rather a position for ease of use. The function will pick the building nearest that point automatically. This works well with randomization:

_position = ["mkTown"] call Zen_FindGroundPosition;
_buildingPositions = [_position] call Zen_FindBuildingPositions;

If you have a specific building in mind, don't worry; you can just give the building itself. Zen_FindBuildingPositions will translate that building into a position, then that position into a building so it works out in the end. Because a building is an object, the nearest building to it is itself.

// You have defined 'building' somehow
_buildingPositions = [building] call Zen_FindBuildingPositions;

Zen_FindBuildingPositions also offers a parameter for the number of attempts. This does not equal the number of resulting positions, nor is it the number of 3D attempts. Rather, it is the number of 2D attempts the function will make. For each 2D position, the function will search upwards for valid positions. A building with many floors can yield several good positions from a single 2D position on different floors. Similarly, a building with a single floor may yield fewer positions than the number of attempts.

By default, the function sets the number of attempts based upon the area of the building; however, this area is now always accurate. If you simply want one position in the building, set a low number of attempts to not waste time:

// _position is found somehow
_buildingPositions = [_position, 10] call Zen_FindBuildingPositions;
player setPosATL (_buildingPositions select 0);

If you need many points, e.g. for a soldier patrolling a large building, it's worth the time to generate more points:

// _position and _unit are defined
_buildingPositions = [_position, 100] call Zen_FindBuildingPositions;
while {true} do {
   _unit doMove (ZEN_STD_Array_RandElement(_buildingPositions));
   sleep 15;
};

You could also just use Zen_OrderInfantryPatrolBuilding, but example is still valid. Finally, Zen_FindBuildingPositions can filter for roof positions. Be warned that allowing roof positions may generate positions in unreachable places. Zen_FindBuildingPositions cannot know if there's a ladder to the roof or not. The function will also attempt to distinguish balconies from rooftops, but might not always be successful.

Beta

As already stated, the framework is in the beta stage of development. I am making every effort to quality control releases, but there will be bugs. Both new features and old ones could have bugs, issues, and things people just don't like. There is no ETA or plan for a 'final' version. The framework is a work in progress, and it will continue to progress while there are improvements to be made (there always will be).

Some of the bugs have been pointed out by users, and those fixes are included in the changelog above. I want to thank everyone who has used/supported the framework.

Share this post


Link to post
Share on other sites
Guest

Thanks for always informing us about the newest version and merry christmas :)

Release frontpaged on the Armaholic homepage.

================================================

We have also "connected" these pages to your account on Armaholic.

This means soon you will be able to maintain these pages yourself if you wish to do so. Once this new feature is ready we will contact you about it and explain how things work and what options you have.

When you have any questions already feel free to PM or email me!

Share this post


Link to post
Share on other sites

Zen, I have a question, possible feature request.

Zen_InvokeTask - when using child tasks, and all child tasks are complete, how does the parent complete?

Example: parent task - recon area

// create primary task  
tskObj1 = [west,"We have reports of possible opfor activity in this sector. Proceed to the instructed coordinates and recon the AO. Satellite sweep is due in 15. Will keep you UTD on the sit-rep. Good luck.","Recon area",arMissionCoordinates,true] call Zen_InvokeTask;
taskPrimary = "recon";	

// create 1 to 3 recon tasks in the inner area 
for "_i" from 1 to (floor(random(3)) + 1) do {
	_tskPos = [arMissionCoordinates,[0,_intRadii/4]] call Zen_FindGroundPosition;
	_tskChild = [west,"Recon this position","Recon here",_tskPos,false,tskObj1] call Zen_InvokeTask;
	0 = [_tskChild,_tskPos] spawn {
		_bEsc = true;
		while {_bEsc} do {
			sleep 15;
			{
				if (((_this select 1) distance _x) < 15) exitWith {_bEsc = false; 0 = [(_this select 0),"succeeded"] call Zen_UpdateTask;};
			} forEach ([arPG] call Zen_ConvertToObjectArray);
		};
	};
};

What is the proper method to "check" if all child tasks are completed? How do you use child tasks, to set the parent to "succeeded"?

I can always declare a bunch of variables, but do I need to?

Thanks.

---------- Post added at 21:20 ---------- Previous post was at 20:44 ----------

Nevermind. I did this and it works just fine.

// create primary task  
tskObj1 = [west,"We have reports of possible opfor activity in this sector. Proceed to the instructed coordinates and recon the AO. Satellite sweep is due in 15. Will keep you UTD on the sit-rep. Good luck.","Recon area",arMissionCoordinates,true] call Zen_InvokeTask;
taskPrimary = "recon";	

_arReconTasks = [];
// create 1 to 3 recon tasks in the inner area 
for "_i" from 1 to (floor(random(3)) + 1) do {
	_tskPos = [arMissionCoordinates,[0,_intRadii/4]] call Zen_FindGroundPosition;
	_tskChild = [west,"Recon this position","Recon here",_tskPos,false,tskObj1] call Zen_InvokeTask;
	_arReconTasks pushBack _tskChild;
	0 = [_tskChild,_tskPos] spawn {
		_bEsc = true;
		while {_bEsc} do {
			sleep 15;
			{
				if (((_this select 1) distance _x) < 15) exitWith {_bEsc = false; 0 = [(_this select 0),"succeeded"] call Zen_UpdateTask;};
			} forEach ([arPG] call Zen_ConvertToObjectArray);
		};
	};
};

0 = [_arReconTasks] spawn {
	while {true} do {
		sleep 20;
		diag_log format ["are task complete recon :: %1",[tskObj1] call Zen_AreTasksComplete];
		if (([(_this select 0)] call Zen_AreTasksComplete)) exitWith {0 = [tskObj1, "succeeded"] call Zen_UpdateTask;};
	};
};

Share this post


Link to post
Share on other sites

When giving a loadout via "Zen_GiveLoadoutCargo", items are not given. Is just me?

I'm using only items and magazines in the definition, and the magazines are given just fine.

Another bug:

ZEN_FMW_Code_SpawnMarker("mkAirFieldSecure1", 2, west);

Watching with ASM tool, the code above creates a LOT of CPU usage (as far as Arma 3 can handle)., with only 1 player.

FPS keep in 40, but CPS go into 10/15. I have deleted the line and FPS/CPS keep at 40.

CPU meter for the Arma3server process indicates it is at 100% of usage.

Strange thing is that if I disconnect and reconnect, then whatever was happening stops and the engine maintains at 40FPS/CPS.

This has happened at last since previous version, has taken me a while to debug what part of the mission was causing this.

Edited by Zriel
new bug

Share this post


Link to post
Share on other sites
Zen, I have a question, possible feature request.

Zen_InvokeTask - when using child tasks, and all child tasks are complete, how does the parent complete?

Example: parent task - recon area

// create primary task  
tskObj1 = [west,"We have reports of possible opfor activity in this sector. Proceed to the instructed coordinates and recon the AO. Satellite sweep is due in 15. Will keep you UTD on the sit-rep. Good luck.","Recon area",arMissionCoordinates,true] call Zen_InvokeTask;
taskPrimary = "recon";	

// create 1 to 3 recon tasks in the inner area 
for "_i" from 1 to (floor(random(3)) + 1) do {
	_tskPos = [arMissionCoordinates,[0,_intRadii/4]] call Zen_FindGroundPosition;
	_tskChild = [west,"Recon this position","Recon here",_tskPos,false,tskObj1] call Zen_InvokeTask;
	0 = [_tskChild,_tskPos] spawn {
		_bEsc = true;
		while {_bEsc} do {
			sleep 15;
			{
				if (((_this select 1) distance _x) < 15) exitWith {_bEsc = false; 0 = [(_this select 0),"succeeded"] call Zen_UpdateTask;};
			} forEach ([arPG] call Zen_ConvertToObjectArray);
		};
	};
};

What is the proper method to "check" if all child tasks are completed? How do you use child tasks, to set the parent to "succeeded"?

I can always declare a bunch of variables, but do I need to?

Thanks.

---------- Post added at 21:20 ---------- Previous post was at 20:44 ----------

Nevermind. I did this and it works just fine.

// create primary task  
tskObj1 = [west,"We have reports of possible opfor activity in this sector. Proceed to the instructed coordinates and recon the AO. Satellite sweep is due in 15. Will keep you UTD on the sit-rep. Good luck.","Recon area",arMissionCoordinates,true] call Zen_InvokeTask;
taskPrimary = "recon";	

_arReconTasks = [];
// create 1 to 3 recon tasks in the inner area 
for "_i" from 1 to (floor(random(3)) + 1) do {
	_tskPos = [arMissionCoordinates,[0,_intRadii/4]] call Zen_FindGroundPosition;
	_tskChild = [west,"Recon this position","Recon here",_tskPos,false,tskObj1] call Zen_InvokeTask;
	_arReconTasks pushBack _tskChild;
	0 = [_tskChild,_tskPos] spawn {
		_bEsc = true;
		while {_bEsc} do {
			sleep 15;
			{
				if (((_this select 1) distance _x) < 15) exitWith {_bEsc = false; 0 = [(_this select 0),"succeeded"] call Zen_UpdateTask;};
			} forEach ([arPG] call Zen_ConvertToObjectArray);
		};
	};
};

0 = [_arReconTasks] spawn {
	while {true} do {
		sleep 20;
		diag_log format ["are task complete recon :: %1",[tskObj1] call Zen_AreTasksComplete];
		if (([(_this select 0)] call Zen_AreTasksComplete)) exitWith {0 = [tskObj1, "succeeded"] call Zen_UpdateTask;};
	};
};

Zen_UpdateTask offers a parameter to automatically complete parent/child tasks. Setting that to true when you complete all child tasks should update the parent task at the same time. The actual state ('succeeded', 'failed', etc.) should agree with the arguments (even if other child tasks have a different completed state).

When giving a loadout via "Zen_GiveLoadoutCargo", items are not given. Is just me?

I'm using only items and magazines in the definition, and the magazines are given just fine.

Another bug:

ZEN_FMW_Code_SpawnMarker("mkAirFieldSecure1", 2, west);

Watching with ASM tool, the code above creates a LOT of CPU usage (as far as Arma 3 can handle)., with only 1 player.

FPS keep in 40, but CPS go into 10/15. I have deleted the line and FPS/CPS keep at 40.

CPU meter for the Arma3server process indicates it is at 100% of usage.

Strange thing is that if I disconnect and reconnect, then whatever was happening stops and the engine maintains at 40FPS/CPS.

This has happened at last since previous version, has taken me a while to debug what part of the mission was causing this.

Since this is in MP and the server's CPU changes when a client disconnects, it's something that interacts with clients in ZEN_FMW_Code_SpawnMarker. My first guess is loadouts, as spawning is done only on one machine and synch'd automatically by the engine.

The loadout functions remote execute to the clients, then check for locality. If none of the units is local to your machine, the function skips over them all (checks I assume contribute to ASM's CBS number) and does nothing (at least it's supposed to). It's possible some loadout function is entering an infinite remote execution loop (sending requests back and forth very fast). I'll test loadouts in MP with some debug looking for this.

Share this post


Link to post
Share on other sites

I'm talking about Server FPS/CPS not client (just to make clear).

This occurs with one player, so just imagine what happens with 20-30...mission not playable.

Yeah, something is looping, as the CPS won't recover, no matter how much you wait. And I am giving loadouts to units just fine. Just used that code to spawn some patrols easy way, instead of defining point, spawning, and giving loadout.

About a remote execution loop, I would suggest to check fisrt, as I saw on the first failure, with 25 players, that the server was sending 7MBs per second of data.

Edited by Zriel

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

×