Jump to content
Sign in to follow this  
[frl]myke

Extracting unit classnames from config

Recommended Posts

Ok lads, here's the problem.

I have a script which is made to collect all classnames from units based on "CAManBase". Sure i could predefine all classnames but this would either not work with addons or i have to give a way to add them later by missionmaker/user. This is something i want to avoid (don't ask why:p).

So at the end i'll get an array with all available unit classnames, no vehicles of any sort nor static or buildings. You get the idea.

Here is the script which already works so far:

private ["_i", "_entry", "_scope", "_name", "_class"];
GLT_UNITARRAY = [];
_i = count(configFile >> "CfgVehicles") - 1;
while {_i >= 0} do {
if (isClass((configFile >> "CfgVehicles") select _i)) then {
	_entry = (configFile >> "CfgVehicles") select _i;
	_scope = getNumber (_entry >> "scope");
	_name = getText (_entry >> "displayName");
	_class = configName _entry;
	hintsilent format ["%1", _class];
	if (_scope==2 && _name != "" && _class iskindof "CAManBase") then {
		GLT_UNITARRAY = GLT_UNITARRAY + [_class];
		};
	};
	sleep 0.001;
	_i = _i - 1;
};
hint format ["%1", GLT_UNITARRAY];

So far, so fine. But as you might see, it goes through all classes, be it vehicles or buildings or whatsoever.

Sure, i could keep it this way as the result is what i needed but....it's not elegant at all and also not pretty efficient. Did a timecheck for testing and it took 144 seconds to complete. Without the sleep it was done immediately but still not good enough for me (as a sleep would avoid bottlenecking if also other intensive scripts were running at the same time which is more than likely as this will run at mission start).

Already tried to add the CAManBase in the request, like this:

if (isClass((configFile >> "CfgVehicles" >> "CAManBase") select _i)) then {

But this didn't worked. The final array stayed empty.

So if anyone has an idea how i could restrict the collecting routine to only "CAManBase" i would be happy to hear it.

Thanks in advance

Myke

Share this post


Link to post
Share on other sites

Interesting question. If you find a way to efficiently traverse the inheritance heirarchy from parent to child it would be very useful. Unfortunately I can't see any standard functions that allow you to go from parent to a list of children.

it took 144 seconds to complete

That's a lot of classes (I'm guessing over 3000) - you're burning 1 frame every class regardless of cpu load. It's not ideal but you could process them in bigger batches - even 100 at a time should make little difference to cpu load but would reduce your elapsed time dramatically.

Share this post


Link to post
Share on other sites
That's a lot of classes (I'm guessing over 3000)

Well, i have a lots of addons loaded. Total classes is 7606, remaining array with unit classes is 532.

Without the sleep it is done immediately but i guess it's better to have a sleep in there so other scripts might not be influenced. Might not be necessary but i prefer to keep it safe.

If no other solution comes up, i will work with your suggestion and make batches by 100 or like that.

Thanks sbsmac

:EDITH:

Included now a sleep for 0.005 seconds every 150 passes, now it takes a little above 2 seconds to complete through the whole CfgVehicles list. I guess this will do or i'll raise the sleep a little. Have to test it later on how it performs in a real mission.

However, if someone knows a way to narrow the config down so i wouldn't have to go through the whole list, i would be happy to hear.

Edited by [FRL]Myke

Share this post


Link to post
Share on other sites
Included now a sleep for 0.005 seconds

Your sleep period is so small that it doesn't have any effect. (Unless you monster rig is running at over 200 fps!) Effectively what you are saying there is 'wait until the next frame'.

If you're not already, it would help to compile this loop. There are some minor optimisations to be had as well like turning the 'while' into a 'foreach' and therefore being able to make the isClass (...) into a cheaper isClass (_x). Hints are probably redundant as well :)

Conditional evaluations aren't 'lazy' in sqf so there's a slight optimisation in breaking the least successful test into a separate 'if' around the others.

>However, if someone knows a way to narrow the config down so i wouldn't have to go through the whole list, i would be happy to hear.

Yes this would be by far the best solution. Is there a way ?

Share this post


Link to post
Share on other sites
(Unless you monster rig is running at over 200 fps!)

Yours not?:eek: j/k

Your sleep period is so small that it doesn't have any effect.

Can't second that. Between sleep 0.001 and sleep 0.005 there is definately a noticeable difference. While wit 0.001 the script is done almost immediately, with 0.005 it takes 2.3 seconds to complete. This should give the CPU some breath in cases where a lot of other things have to be done at the same time.

If you're not already, it would help to compile this loop.

It is planned to do so although the win would be really minor as this code runs only once during a mission, right at the start. But before i do advanced things like precompiling, i usually prefer to optimize beforehand. Also i've just started with the whole thing so there will follow a lot of optimizations during the development.

There are some minor optimisations to be had as well like turning the 'while' into a 'foreach' and therefore being able to make the isClass (...) into a cheaper isClass (_x).

Hmm...you mean something like this:

{
   ...
   sorting code here
   ...
} foreach (configFile >> "CfgVehicles");

Excellent idea. Should make the code indeed much tighter.

Hints are probably redundant as well

I just use hints while developing a new script to check at certain points if and what the scripts does or not. They'll be deleted as soon the script is done.

Share this post


Link to post
Share on other sites

>Yours not? j/k

Alas not - knock a zero off that and you might be close on a good day ;-)

>Can't second that. Between sleep 0.001 and sleep 0.005

Taking your word of 7600 classes, and a batch size of 150, you will be executing sleep about 50 times. _IF_ sleep was truly accurate that would lead to an extra elapsed time for you of around 0.2 seconds with those values ! I took your code and tried it here. I saw no discernable difference between sleeps of 0.001 and 0.005. You're doing the right thing in relinquishing the cpu every so often but AFAIK the script scheduler is round-robin so things will get a chance to run regardless of how long you sleep for.

>If you're not already, it would help to compile this loop.

Yeah ignore this comment, I was thinking there was a way to run uncompiled sqf but I was clearly confused ;-)

>I just use hints while developing a new script to

Understood - just pointing out that it is an 'expensive' operation and thus skewing your results. My tests here showed quite a noticable improvement in performance (>20%) when it was removed.

Share this post


Link to post
Share on other sites

Ok, here i have something that might be interesting for some people out there. It's far from perfect but its a good point to start with:

This scripts extracts and sorts Men class vehicles out of all loaded addons, known or unknown (future addons).

It takes the desired faction classname as argument and spits out an array with subarrays with sorted unit classes.

The array has following format:

[specOps, Group Leaders, AT Units, AA Units, Medics, Sniper, Machine Gunner]

How are they sorted?

Each type is sorted by a rather unique config entry. It might not be 100% accurate but it will get you started:

SpecOps: they are collected by theyr ability to hide dead bodies.

Group Leaders: they have GPS available from config side.

AT Units: threat level 0.9 or higher for armor.

AA Units: threat level 0.9 or higher for air.

Medics: They have the ability to heal.

Sniper: The primary weapon has a midRange engagement distance of 450m or higher.

Machine Gunner: They carry magazines with 65 rounds or more.

All these things are taken directly from the config so changing weaponry with script doesn't affect the sorting.

private ["_i", "_entry", "_weapons", "_unit", "_magazines"];
_GLT_FACTION = _this select 0;
_GLT_UNITARRAY = [];
for [{_i=count(configFile >> "CfgVehicles")-1}, {_i>=0}, {_i=_i-1}] do {
if (isClass((configFile >> "CfgVehicles") select _i)) then {
	_entry = (configFile >> "CfgVehicles") select _i;
	if (getNumber (_entry >> "scope")==2 && (configName _entry) iskindof "CAManBase" && gettext(_entry >> "faction") == _GLT_FACTION) then {
		_GLT_UNITARRAY = _GLT_UNITARRAY + [(configName _entry)];
	};
};
};
_GLT_SO_UNITS = [];	//SpecOps Units
_GLT_LEADERS = [];	//Leaders, Units that have GPS
_GLT_AT_UNITS = [];	//Units with any sort of AT Weapons
_GLT_AA_UNITS = [];	//Units with any sort of AA Weapons
_GLT_MD_UNITS = [];	//Medical Units
_GLT_SN_UNITS = []; //Units with Sniper Rifle
_GLT_MG_UNITS = [];	//Units with Machine Gun

//Deleting Units without defined Weapons (tactically useless)
{
_weapons = (getarray (configFile >> "CfgVehicles" >> _x >> "weapons")) - ["Throw", "Put", "ItemMap", "ItemCompass", "ItemWatch", "ItemRadio"];
if (count _weapons == 0) then {
	_GLT_UNITARRAY = _GLT_UNITARRAY - [_x];
};
} foreach _GLT_UNITARRAY;


// Collecting SpecOps by checking if they can hide bodies
{
if (getNumber(configFile >> "CfgVehicles" >> _x >> "canHideBodies") == 1) then {
	_GLT_SO_UNITS = _GLT_SO_UNITS + [_x];
	_GLT_UNITARRAY = _GLT_UNITARRAY - [_x];
};
} foreach _GLT_UNITARRAY;

// Collecting Leaders by checking if they have GPS enabled
{
if (getNumber(configFile >> "CfgVehicles" >> _x >> "enableGPS") == 1) then {
	_GLT_LEADERS = _GLT_LEADERS + [_x];
	_GLT_UNITARRAY = _GLT_UNITARRAY - [_x];
};
} foreach _GLT_UNITARRAY;

// Collecting AT Units by threat level
{
if ((getarray(configFile >> "CfgVehicles" >> _x >> "threat")) select 1 >=0.9) then {
	_GLT_AT_UNITS = _GLT_AT_UNITS + [_x];
	_GLT_UNITARRAY = _GLT_UNITARRAY - [_x];
};
} foreach _GLT_UNITARRAY;

// Collecting AA Units by threat level
{
if ((getarray(configFile >> "CfgVehicles" >> _x >> "threat")) select 2 >=0.9) then {
	_GLT_AA_UNITS = _GLT_AA_UNITS + [_x];
	_GLT_UNITARRAY = _GLT_UNITARRAY - [_x];
};
} foreach _GLT_UNITARRAY;

// Collecting Medical Units by attendant config entry
{
if (getNumber(configFile >> "CfgVehicles" >> _x >> "attendant") == 1) then {
	_GLT_MD_UNITS = _GLT_MD_UNITS + [_x];
	_GLT_UNITARRAY = _GLT_UNITARRAY - [_x];
};
} foreach _GLT_UNITARRAY;

//Now something more complicated: Collecting Snipers by checking midRange engaging distance
{
_weapons = (getarray (configFile >> "CfgVehicles" >> _x >> "weapons")) - ["Throw", "Put", "ItemMap", "ItemCompass", "ItemWatch", "ItemRadio"];
_unit = _x;
{
	if (getNumber(configFile >> "CfgWeapons" >> _x >> "midRange") >= 450) exitwith {
		_GLT_SN_UNITS = _GLT_SN_UNITS + [_unit];
		_GLT_UNITARRAY = _GLT_UNITARRAY - [_unit];
	};
} foreach _weapons;
} foreach _GLT_UNITARRAY;

// And finally the Machine Guns. Sorting by Magazine roundcount > 65 (Bizon has 64 rounds)
{
_magazines = getarray (configFile >> "CfgVehicles" >> _x >> "magazines");
_unit = _x;
{
	if (getNumber(configFile >> "CfgMagazines" >> _x >> "count") >= 65) exitwith {
		_GLT_MG_UNITS = _GLT_MG_UNITS + [_unit];
		_GLT_UNITARRAY = _GLT_UNITARRAY - [_unit];
	};
} foreach _magazines;
} foreach _GLT_UNITARRAY;

_GLT_FINALARRAY = [_GLT_SO_UNITS, _GLT_LEADERS, _GLT_AT_UNITS, _GLT_AA_UNITS, _GLT_MD_UNITS, _GLT_SN_UNITS, _GLT_MG_UNITS];
_GLT_FINALARRAY

Feel free to use it, change it, smoke it or whatever comes into your mind. Also some feedback would be nice.

Remember: this is a script to get you a startoff. It might be useful for random group creating or something similar. It is not meant as a final script, just as a helper for you.

Edited by [FRL]Myke

Share this post


Link to post
Share on other sites

Nice job. Last line should read _GLT_FINALARRAY (without semicolon) unless you do not

want to return the array.

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  

×