# Zenophon's ArmA 3 Co-op Mission Making Framework

## Recommended Posts

On about line 117, it should be:

_defenders = [_blufor, compile format ["!(_this inArea '%1')", _x]] call Zen_ArrayFilterCondition;

I forgot that the formatted marker name must be in quotes. Or you could remove the '_blufor = ...' line entirely and use

_defenders = [_x, [], west] call Zen_GetAllInArea;

Either of those should fix the defender selection error, and thus the Zen_Cache error, and in turn the Zen_IsCached error. Also, the reinforcement function can be defined externally; I just put it in the code for clarity.

##### Share on other sites

Still no luck with

18:30:56  Mission id: 9ce9ec38353944ee2ddaae7ae7ec4d05ad03e4fe
18:31:02 No speaker given for William Turner
18:31:03 MovesType CfgMovesSnakes_F load time 221 ms
18:31:14 Strange convex component317 in a3\rocks_f\blunt\bluntrock_wallv.p3d:geometry
18:31:14 Strange convex component318 in a3\rocks_f\blunt\bluntrock_wallv.p3d:geometry
18:31:14 Strange convex component319 in a3\rocks_f\blunt\bluntrock_wallv.p3d:geometry
18:31:14 Strange convex component317 in a3\rocks_f\blunt\bluntrock_wallv.p3d:geometryView
18:31:14 Strange convex component318 in a3\rocks_f\blunt\bluntrock_wallv.p3d:geometryView
18:31:14 Strange convex component319 in a3\rocks_f\blunt\bluntrock_wallv.p3d:geometryView
18:31:22 MovesType CfgMovesButterfly load time 36 ms
18:31:23 "-- Zen_Cache Error --"
18:31:23 "No cacheable units given"
18:31:23 4.158
18:31:23 [[]]
18:31:23 ["Zen_Cache",[[]],4.158]
18:31:23 "-- Zen_Cache Error --"
18:31:23 "No cacheable units given"
18:31:23 4.321
18:31:23 [[]]
18:31:23 ["Zen_Cache",[[]],4.321]
18:31:23 "-- Zen_Cache Error --"
18:31:23 "No cacheable units given"
18:31:23 4.382
18:31:23 [[]]
18:31:23 ["Zen_Cache",[[]],4.382]
18:31:23 "-- Zen_Cache Error --"
18:31:23 "No cacheable units given"
18:31:23 4.465
18:31:23 [[]]
18:31:23 ["Zen_Cache",[[]],4.158]
18:31:23 "-- Zen_Cache Error --"
18:31:23 "No cacheable units given"
18:31:23 "-- Zen_Cache Error --"
18:31:23 "-- Zen_Cache Error --"
18:31:23 "No cacheable units given"
18:31:23 4.564
18:31:23 [[]]
18:31:23 ["Zen_Cache",[[]],4.382]
18:31:23 4.634
18:31:23 [[]]
18:31:23 ["Zen_Cache",[[]],4.465]
18:31:23 "-- Zen_Cache Error --"
18:31:23 "No cacheable units given"
18:31:23 4.634
18:31:23 [[]]
18:31:23 ["Zen_Cache",[[]],4.634]
18:31:23 "No cacheable units given"
18:31:23 4.705
18:31:23 [[]]
18:31:23 ["Zen_Cache",[[]],4.321]
18:31:23 "-- Zen_Cache Error --"
18:31:23 "No cacheable units given"
18:31:23 4.705
18:31:23 [[]]
18:31:23 ["Zen_Cache",[[]],4.705]
18:31:23 "-- Zen_Cache Error --"
18:31:23 "No cacheable units given"
18:31:23 4.74
18:31:23 [[]]
18:31:23 ["Zen_Cache",[[]],4.564]
18:31:23 "-- Zen_Cache Error --"
18:31:23 "No cacheable units given"
18:31:23 4.74
18:31:23 [[]]
18:31:23 ["Zen_Cache",[[]],4.74]
18:31:23 "-- Zen_Cache Error --"
18:31:23 "No cacheable units given"
18:31:23 4.826
18:31:23 [[]]
18:31:23 ["Zen_Cache",[[]],4.826]
18:31:25 "-- Zen_IsCached Error --"
18:31:25 "Invalid cache identifier given."
18:31:25 6.671
18:31:25 [""]
18:31:25 ["Zen_IsCached",[""],6.671]
18:31:25 Error in expression < [_forEachIndex, false];
};
} else {

if ([_x] call Zen_IsCached) then {
_play>
18:31:25   Error position: <if ([_x] call Zen_IsCached) then {
_play>
18:31:25   Error if: Type Array, expected Bool
18:31:25 File C:\Users\DaVidoSS\Documents\Arma 3\missions\contamination_zone2.Altis\functions\server_fnc.sqf, line 122
18:31:25 "-- Zen_IsCached Error --"
18:31:25 "Invalid cache identifier given."
18:31:25 6.771
18:31:25 [""]
18:31:25 ["Zen_IsCached",[""],6.771]
18:31:25 Error in expression < [_forEachIndex, false];
};
} else {

if ([_x] call Zen_IsCached) then {
_play>
18:31:25   Error position: <if ([_x] call Zen_IsCached) then {
_play>
18:31:25   Error if: Type Array, expected Bool
18:31:25 File C:\Users\DaVidoSS\Documents\Arma 3\missions\contamination_zone2.Altis\functions\server_fnc.sqf, line 122
18:31:25 "-- Zen_IsCached Error --"
18:31:25 "Invalid cache identifier given."
18:31:25 6.851
18:31:25 [""]
18:31:25 ["Zen_IsCached",[""],6.851]
18:31:25 Error in expression < [_forEachIndex, false];
};
} else {

if ([_x] call Zen_IsCached) then {
_play>
18:31:25   Error position: <if ([_x] call Zen_IsCached) then {
_play>
18:31:25   Error if: Type Array, expected Bool
18:31:25 File C:\Users\DaVidoSS\Documents\Arma 3\missions\contamination_zone2.Altis\functions\server_fnc.sqf, line 122


##### Share on other sites

There are actually defenders in those markers? Might seem like a silly question, but since there's no error from Zen_ArrayFilterCondition or Zen_GetAllInArea, they're doing what they're supposed to. If both functions (and you can try the a 'select {_x in Area}' method for good measure) agree that they aren't any units, you should check that those area markers are covering the right spots.

##### Share on other sites

The procedure first spawns groups on every markers than  the cache system is called.

I do already tested this by going in and out, this detected player and throwing errors again on each switch.

##### Share on other sites

I don't know the details or order of execution of your mission, but, as a simple debug, try these lines at the beginning of the caching function:

// Put all the markers into an array
_markers = ["outpost1_1","outpost1_2","outpost1_3","outpost1_4"];

diag_log (allUnits select {_x inArea "outpost1_1"});
diag_log (allUnits select {_x inArea "outpost1_2"});
diag_log (allUnits select {_x inArea "outpost1_3"});
diag_log (allUnits select {_x inArea "outpost1_4"});


If those print out empty arrays, there are no units to cache when the function runs.

As another correction to the script I posted, I forgot to include the reinforcement groups under the cache identifiers. On around line 90, the code to cache the units should be

if (!(isNull (_reinforcementGroups select _forEachIndex)) && {!((leader (_reinforcementGroups select _forEachIndex)) in ([_x] call Zen_GetCachedUnits))}) then {
0 = [(_reinforcementGroups select _forEachIndex), _x] call Zen_Cache;
} else {
0 = [_x] call Zen_Cache;
};


Next framework release, I'll make it easier to integrate units into an uncached identifier at any time (thus you'd be able to add the reinforcements to the identifier at around line 40 without having to cache any units).

##### Share on other sites
Hello everyone.

So I was looking for the forums and it seems that the only option that allows the inclusion of a lodoaut editing system for the AI teamates is this Framework.

Like that included at the beginning of the Dynamic Recon Ops missions posted in steam.

The other option is to leave a teamate as "playable" in the editor and switch to it by pressing "U", edit the lodoaut and return to the main unit (Team leader), but this option ends up giving "extra lives" for the player and breaks immersion.

Saddly I do not have enough scripting knowledge to make this feature to work (and English is not my mother tongue, so it does not help to learn how).

Someone, please, if possible could send me an example of how the script would have to be for the work?

Thank you very much in advance.

PS - Using the tutorials to learn from scratch how to do, who knows a miracle happens and ends up working.

##### Share on other sites

Hello Zenophon

First of all I would like to thank you for making this framework, i'm your big fan as I see it extremely helpful inside my missions.

I have one question though: can I write my mission code inside initServer.sqf file? And do I need to use sleep 1; inside then? I would like to process commands as soon as it's possible.

##### Share on other sites

Hello everyone.

So I was looking for the forums and it seems that the only option that allows the inclusion of a lodoaut editing system for the AI teamates is this Framework.

Like that included at the beginning of the Dynamic Recon Ops missions posted in steam.

The other option is to leave a teamate as "playable" in the editor and switch to it by pressing "U", edit the lodoaut and return to the main unit (Team leader), but this option ends up giving "extra lives" for the player and breaks immersion.

Saddly I do not have enough scripting knowledge to make this feature to work (and English is not my mother tongue, so it does not help to learn how).

Someone, please, if possible could send me an example of how the script would have to be for the work?

Thank you very much in advance.

PS - Using the tutorials to learn from scratch how to do, who knows a miracle happens and ends up working.

Are you describing a GUI that allows the player to modify the loadout of the AI during the mission? A full loadout editing premade GUI like virtual arsenal is not included in the framework (though you could create one using the Dialog system, but that would be a lot of work).

Zen_AddLoadoutDialog is an action for players that allows them to pick from a list of preset loadouts; it's possible to order the AI to access that action. Looking at the code, it should be able to detect any activating unit (potentially an AI) and apply that loadout to them; the dialog would be displayed to the machine (i.e. player) that the AI was local to. The same idea could be applied to the BIS virtual arsenal function, but I can't say if or how it would work.

I think a reasonable solution (in terms of the amount of work) that doesn't require the player to order the AI around would be to create a dialog that displayed a list of AI and a list of loadouts. The player could activate this dialog, click on an AI name, then click on a loadout name, then click the 'OK' button, and the AI would be given that loadout. Creating a dialog that like isn't that hard with the framework's dialog system, and you could use the framework's loadout system or other loadout scripts to equip the AI.

This solution limits the loadout selection to presets (which could potentially be randomized), but it makes the process quick and easy for the player (just a few clicks and their AI squad is equipped). Here's the basic code of such a dialog:

F_OKButtonLoadout = {
0 = [_this select 0, _this select 1] call Zen_GiveLoadoutCustom;
};

_unitNames = ["player"];
_units = [player];

_listAI = ["List",
["List", _unitNames],
["ListData", _units],
["Position", [5, 0]],
["Size", [35,11.5]]
] call Zen_CreateControl;

["Position", [5, 12]],
["Size", [35,11.5]]
] call Zen_CreateControl;

_buttonClose = ["Button",
["Text", "Close"],
["Position", [0, 4]],
["Size", [5,2]],
["ActivationFunction", "Zen_CloseDialog"]
] call Zen_CreateControl;

_buttonOK = ["Button",
["Text", "OK"],
["Position", [0, 0]],
["Size", [5,2]],
] call Zen_CreateControl;

_dialogID = [] call Zen_CreateDialog;

{
0 = [_dialogID, _x] call Zen_LinkControl;
} forEach [_listAI, _listLoadouts, _buttonClose, _buttonOK];

player addAction ["AI Loadout Dialog", {0 = [_this select 3] spawn Zen_InvokeDialog;}, _dialogID];


Of course, you need a proper list of units and loadouts, some limits on where and how often the player can change the AI's loadout, maybe you prefer a different layout/fonts/colors etc. for the dialog, etc..

Hello Zenophon

First of all I would like to thank you for making this framework, i'm your big fan as I see it extremely helpful inside my missions.

I have one question though: can I write my mission code inside initServer.sqf file? And do I need to use sleep 1; inside then? I would like to process commands as soon as it's possible.

You're free to use any alternative to the init.sqf (i.e. these https://community.bistudio.com/wiki/Event_Scripts),while keeping in mind their relative load order (https://community.bistudio.com/wiki/Initialization_Order). All the init files (Init.sqf, InitServer, etc.) for mission start events will begin during the briefing (time = 0).

The 'sleep 1' command exists because during the briefing, the simulation hasn't really started, and the server cannot remote execute commands on clients properly. The framework's server-oriented design requires that functions the mission maker calls from the server be able to affect the clients as necessary to do their job (a good example of this is Zen_InvokeTask vs. Zen_InvokeTaskBriefing; in that case I offer special function that must run all clients). However, e.g. Zen_CreateLoadout must run after that sleep command for clients to have the loadout defined on their machine.

The briefing is actually a great time for the server to perform any intense calculations that don't require immediate remote exec. Things such as complex Zen_FindGroundPosition arguments, Zen_ConfigGetVehicleClasses, etc. will run much faster because the engine's framerate isn't bogged down by simulating the 3D world, but you still have access to all the data about it (e.g. how many trees are in an area, etc.).

##### Share on other sites
@Zenophon

Thanks for the script, I was reading the tutorials and began to understand that is far above what I can do. And I realized how complex and the amount of work to do what I asked.

So, thank you for your time and effort.

I'm finishing the construction of a mission and then I will try to include it in this script that you did.

Again, thank you for taking the time to answer me.
much appreciated.

##### Share on other sites

Update and Release #46
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 will be on Armaholic soon. Please bring any technical issues or mistakes to my attention, so e.g. people don't download the wrong version etc.

Changelog

The framework is back, and this release includes a number of changes appropriate for such a long absence. The only new function, Zen_SpawnFlare, was developed in cooperation with MooseMan (https://forums.bistudio.com/user/906086-pellelil/). This function makes flares much more accessible and should make night and stealth missions (especially without NVGs) more exciting.

A variety of fixes and requests that have been discussed in previous posts are now fully tested and released. This includes Zen_OrderVehicleDrop complying with its documentation, various orders functions failing, Zen_Cache stalling on the initial cache, Zen_InvokeTask etc. getting an icon type parameter, etc.

The dialog system, now supports the new control angle function from BIS; note that this only works for pictures (that's the way BI made the command). There are two new macros for Zen_GiveLoadoutBlufor etc. giving quick access to a little more variety and control. Zen_UnCache can now add units to the cache identifier without uncaching them (and uncache the already assigned units at the same time). The AI caching demonstration has been updated with this and other improvements.

There are various optimizations using new BIS commands as well as basic code optimization. As a general note, when a BIS command and a framework function do nearly the same thing, the BIS command is closer to the engine and thus faster. However, I attempt to make the framework function offer some feature the command cannot (e.g. argument checking, better error messages). Zen_ArrayFilterCondition, for example, can now filter nested arrays recursively for the condition. I'm not going to remove a function like Zen_IsPointInPoly because there's inArea now, so I advise that you be aware of where you need speed (e.g. as I use the commands for internal optimization in the framework) or where you prefer extra features (like when creating a new, complex system or mission where error checking is important).

I've clarified the documentation for the six vector transform macros. This is part of a larger effort to standardize the use of vectors across framework functions in terms of how function interpret coordinates and how they accept those arguments. I'm going to be reviewing more function in the future for this; the goal is allow the mission maker to work/think in whatever coordinate system is convenient, and just transform those vectors with the macros whenever necessary.

The only function for which current arguments may not work is Zen_InvokeTask; the task icon type parameter is now where the name string parameter was. Another thing to watch out for is Zen_ConvertToObjectArray and Zen_ConvertToGroupArray will now print an error when a nested element isn't a convertible type. That error doesn't mean the function didn't work; it's just a warning that it had to filter something.

The topmost readme file has been modified to include the full legal text of the framework (to prevent any confusion between the full legal terms and the simplified version that used to be there). The legal terms have been slightly modified to explicitly state that parts of the framework that were created by someone other than me are covered by the legal terms in the name of their respective author.

9/20/16

• New Function: Zen_SpawnFlare
• Fixed: Zen_ArrayFilterCondition argument check did not allow the first argument to not be an array
• Fixed: Zen_ArrayInsertSlice argument check did not allow the first argument to not be an array
• Fixed: Zen_CreateTemplate now correctly saves templates that are not on the ground
• Fixed: Zen_IsCached gave the wrong default value when given an invalid identifier
• Fixed: Zen_MoveAsSet shifted the set of objects to the height of the given position
• Fixed: Zen_OrderAircraftPatrol, Zen_OrderBoatPatrol, Zen_OrderHelicopterLand, Zen_OrderInfantryMove, Zen_OrderInfantryPatrol, Zen_OrderVehicleMove, and Zen_OrderVehiclePatrol now give duplicate move and addWaypoints commands as a failsafe
• Fixed: Zen_OrderVehicleDrop argument check now enforces the format of its second parameter
• Added: Zen_ArrayFilterCondition parameter to filter nested arrays
• Added: Zen_OrderVehicleDrop argument to delete the aircraft after making the drop
• Improved: Zen_AreInArea, Zen_AreNotInArea, Zen_CreateTemplate, Zen_FindGroundPosition, Zen_IsForestArea, and Zen_IsWaterArea optimized using the new inArea command
• Improved: Zen_ArrayGetRandomSequence, Zen_ArrayInsert, Zen_ArrayRemoveIndex, Zen_IsPointInPoly optimized
• Improved: Zen_ArrayInsert, Zen_ArrayRemoveIndex, Zen_ArrayRemoveIndexedSlice, Zen_ArrayReplaceSlice print an error when an invalid index is given
• Improved: Zen_ArrayRemoveNonLocal now filters non-local groups
• Improved: Zen_Cache initial cache time significantly reduced
• Improved: Zen_Cache and Zen_MoveInVehicle optimized using the new select {} command
• Improved: Zen_CreateTemplate prints an error when it cannot find any objects
• Improved: Zen_GetFreeSeats properly deletes its temporary object variables
• Improved: Zen_ConvertToGroupArray and Zen_ConvertToObjectArray print an error when an incompatible type appears in a nested array
• Improved: Zen_IsPointInPoly now checks that a given string is a marker
• Documentation: Fixed for Zen_OrderVehicleDrop
• Documentation: Fixed Notepad++ SQF language for black background displayed some SQF commands in the wrong color
• Documentation: Improved AI Caching demonstration
• Documentation: Improved for ZEN_STD_Math_VectCartCyl, ZEN_STD_Math_VectCartPolar, ZEN_STD_Math_VectCylCart, ZEN_STD_Math_VectCylPolar, ZEN_STD_Math_VectPolarCart, and ZEN_STD_Math_VectPolarCyl
• Documentation: Updated Notepad++ SQF language and autocompletion file with ArmA 1.62 stable commands
• 1

##### Share on other sites

Thank you for update.

##### Share on other sites

New version frontpaged on the Armaholic homepage.

##### Share on other sites

Hey Zenophon! Awesome update. Your fix:

Fixed: Zen_OrderAircraftPatrol, Zen_OrderBoatPatrol, Zen_OrderHelicopterLand, Zen_OrderInfantryMove, Zen_OrderInfantryPatrol, Zen_OrderVehicleMove, and Zen_OrderVehiclePatrol now give duplicate move and addWaypoints commands as a failsafe

I tested this with the helicopters and it seems to have fixed the problem as not one got "stuck" in a 45 minute run of my test mission. The tanks also worked better but I had some get "stuck" but I don't believe that to be an issue with anything you've done because when I went to the tank it was sitting there with the engine revving but wasn't moving like it was trying to move but the brakes were stuck on.

I also scoped out this from the 1.64 changelog:

Fixed: AI drivers would ignore the â€˜MOVEâ€™ and â€˜LOADâ€™ waypoints

So it looks like they addressed that but still have another issue (probably with physix) that needs to be addressed!

And thank you for adding the delete option to the vehicle drop function.

##### Share on other sites

I'm getting an error in the .rpt and my airdrop script has stopped working. Not sure what it is but see if recognize what's happening?

It spawns the plane and makes the drop ok and (as far as I can see) it moves to the second "Land" position but errors after that with this error! (it repeats and spams the .rpt)

Error in expression <nd;
};

waitUntil {
sleep 2;
scriptDone _landScript;
};
};

call Zen_StackRemove>
Error position: <_landScript;
};
};

call Zen_StackRemove>
Error Undefined variable in expression: _landscript
File mpmissions\__cur_mp.Tanoa\Zen_FrameworkFunctions\Zen_OrdersFunctions\Zen_OrderVehicleDrop.sqf, line 94

My script is this:

_drop = [_plane, [_heliDropPos, _heliEgressPos], _box, "normal", 200, true, true] spawn Zen_OrderVehicleDrop;

I'm using a plane ("B_T_VTOL_01_vehicle_F") as my delivery vehicle if that makes a difference!

##### Share on other sites

I'm getting an error in the .rpt and my airdrop script has stopped working. Not sure what it is but see if recognize what's happening?

It spawns the plane and makes the drop ok and (as far as I can see) it moves to the second "Land" position but errors after that with this error! (it repeats and spams the .rpt)

Error in expression <nd;
};

waitUntil {
sleep 2;
scriptDone _landScript;
};
};

call Zen_StackRemove>
Error position: <_landScript;
};
};

call Zen_StackRemove>
Error Undefined variable in expression: _landscript
File mpmissions\__cur_mp.Tanoa\Zen_FrameworkFunctions\Zen_OrdersFunctions\Zen_OrderVehicleDrop.sqf, line 94

My script is this:

_drop = [_plane, [_heliDropPos, _heliEgressPos], _box, "normal", 200, true, true] spawn Zen_OrderVehicleDrop;
I'm using a plane ("B_T_VTOL_01_vehicle_F") as my delivery vehicle if that makes a difference!

On line 87 of Zen_OrderVehicleDrop, it should be 'spawn Zen_OrderVehicleMove' instead of 'call Zen_OrderVehicleMove'; call does not return a script handle. That's what I get for thinking I can add only one line and have it work without testing it.

##### Share on other sites

On line 87 of Zen_OrderVehicleDrop, it should be 'spawn Zen_OrderVehicleMove' instead of 'call Zen_OrderVehicleMove'; call does not return a script handle. That's what I get for thinking I can add only one line and have it work without testing it.

LMAO! Welcome to my world! Obviously I'm a bad influence on you!

##### Share on other sites

Hey, I think I found an issue with your infantry spawn function. I am not exactly sure how you intended this to work, however, it is extremely unlikely to spawn the maximum number of units.

In Zen_SpawnInfantry you do the following to determine the number of units to spawn.

_c = [_cMin, _cMax] call Zen_FindInRange;


I believe it should be so it rounds to the nearest whole number. This would increase the change of it generating the maximum number of units.

_c = [_cMin, _cMax, true] call Zen_FindInRange;


Correct me if I am wrong, I have just started using it.

##### Share on other sites

You are correct; Zen_SpawnInfantry should be using rounded numbers. Looking at Zen_FindInRange, it isn't rounding the numbers with an equal distribution (edge numbers are 50% less likely). Zen_FindInRange should use

if (_isWholeNumber) then {
_return = floor (_rangeMin + (random (_rangeMax - _rangeMin + 1)));
} else {
_return = _rangeMin + (random (_rangeMax - _rangeMin));
};


_return = _rangeMin + (random (_rangeMax - _rangeMin));

if (_isWholeNumber) then {
_return = round _return;
};

Also, for next release I will modify Zen_SpawnInfantry (and Zen_SpawnInfantryGarrison) to allow the min/max argument to use the new Gaussian distribution feature of the random command. That will allow a wider range of numbers while making the values more predictable.

##### Share on other sites

Hi

I have 20 locations, where  3 enemy  groups are spawned for each of  at mission start.

In total 60 east enemy groups will be  spawned.

How to write cache loop for it?

##### Share on other sites

In this case the core code is a switch based upon the players being near the groups, which is iterated over every set of groups and accounts for them being wiped out. I use a list of markers in the code, but you could also compute the position of the sets directly from the units using Zen_FindCenterPosition or Zen_FindAveragePosition (which is statistically equivalent if they are constrained to patrol within the marker).

This time I can test the code and it is working; note that the responsiveness is reduced by each set added due to the 'sleep 1' in the forEach loop. If your mission isn't script-heavy, you could reduce that to 0.5 to 0.25 to get a faster cache/uncache reaction time.

// define all the area markers
_markers = [];
for "_i" from 0 to 3 do {
_markers pushBack ("marker_" + str _i);
};

// define an array of units that can trigger uncaching
_players = [player];

// define the distance at which to cache/uncache
_cacheDist = 500;

_cacheArray = [];
{
// spawn the groups in some way
_groups = [([_x, west, 1, [2, 4]] call Zen_SpawnInfantry)];

_cacheID = [_groups] call Zen_Cache;
_cacheArray pushBack _cacheID;
} forEach _markers;

while {true} do {
if (count _cacheArray == 0) exitWith {};
sleep 1;
_indexesToRemove = [];
{
sleep 1;
if ([_x] call Zen_IsCached) then {
// if the unit is cached, only check if they need to be uncached
if !([_players, getMarkerPos (_markers select _forEachIndex), [_cacheDist, _cacheDist], 0, "ellipse"] call Zen_AreNotInArea) then {
0 = [_x] call Zen_UnCache;
};
} else {
_units = [([_x] call Zen_GetCachedUnits)] call Zen_ConvertToObjectArray;
// if the units have been uncached, they could have been killed
if ({alive _x} count _units == 0) then {
_indexesToRemove pushBack _forEachIndex;
} else {
// if they are alive, check for caching
if ([_players, getMarkerPos (_markers select _forEachIndex), [_cacheDist, _cacheDist], 0, "ellipse"] call Zen_AreNotInArea) then {
0 = [_x] call Zen_Cache;
};
};
};
} forEach _cacheArray;

// keep the marker and cache arrays aligned
ZEN_FMW_Array_RemoveIndexes(_markers, _indexesToRemove)
ZEN_FMW_Array_RemoveIndexes(_cacheArray, _indexesToRemove)
};


##### Share on other sites

Great! Thank you.

However this part will not compile:

    ZEN_FMW_Array_RemoveIndexes(_markers, _indexesToRemove)
ZEN_FMW_Array_RemoveIndexes(_cacheArray, _indexesToRemove)


##### Share on other sites

Great! Thank you.

However this part will not compile:

    ZEN_FMW_Array_RemoveIndexes(_markers, _indexesToRemove)
ZEN_FMW_Array_RemoveIndexes(_cacheArray, _indexesToRemove)


You need to include Zen_FrameworkLibrary.sqf.

#include "path\to\Zen_FrameworkLibrary.sqf"


Like that, but with the relative path to that file.

##### Share on other sites

Thanks thats do the trick.

Anyway i got no errors but looks like nothing being cached because i have 0 FPS.

##### Share on other sites

Hello there,

Having trouble with calling Loadout on dedicated server.

The Loadout code that runs after the 'sleep' command in the init on the server:

loadoutPOW = [
[["uniform","LOP_U_AFR_Civ_02"],["items",[["ACE_quikclot",2],["ACE_morphine",1],["ACE_epinephrine",1],["ACE_EarPlugs",1]]]]


As I read through the topic

The loadouts will work for any machine since Zen_CreateLoadout also propagates data,
as long as it is run after the 'sleep' command in the init (same for any MP synch'ing).

But when I try to execute the code below locally on players machine, the error pops up - â€œ"Argument 2 is void"â€

[player, loadoutPOW] call Zen_GiveLoadoutCustom;


if I try to execute this:

[player, loadoutPOW] remoteExecCall ["Zen_GiveLoadoutCustom", 2];


nothing happens

If I try to execute this on the server

[PrisonerBill, loadoutPOW] call Zen_GiveLoadoutCustom;


If I try to execute same locally it does not.

##### Share on other sites

What you have running on the server is correct, i.e. this

sleep 1;

In short, the assignment 'loadoutPOW = ...' is completely separate from what Zen_CreateLoadout is doing with the data internally. loadoutPOW isn't defined on the clients, but the data is there.

How Zen_CreateLoadout works is different from how remote execution in general works. Zen_CreateLoadout is an abstract data structure that takes information and stores it with a name; that name is just a string that Zen_CreateLoadout returns. The identifier/namestring/key is returned immediately (thus there is no need for the waitUntil), and it really is just a string; it has no meaning outside the loadout system.

Within the loadout system, Zen_CreateLoadout propagates the key and its data to all clients, so the key can be used on the client machines to find the data. When you call Zen_GiveLoadoutCustom on the server, the function passes the literal value of the key to the client, and the client looks up the correct data for that key. The server stores the key string in a variable, but the client receives the key without ever storing it in a variable.

If you want to manually do what Zen_GiveLoadoutCustom is doing for you when you run it on the server, then you you would use something like

// from the server

// and on the client

Now the waitUntil is useful because the PV is a time-dependent event; in contrast to the assignment operation '=', which is local and instant (or rather uninterrupted). Many framework functions like Zen_GiveLoadoutCustom will do this PV process for you using a RE method built into the framework. There are demonstrations about the framework's RE process that explain how it's doing this.