Jump to content

Recommended Posts

thanks a lot for testing this. u r so nice :)

Share this post


Link to post
Share on other sites

Very interesting results, thanks :)

 

Select seems more powerful than I expected. Would you mind giving this one try aswell?

_alertedUnits = [];
_side = east;
_unit = player;
_distSqr = 2500;
_knowValue = 4;

_alertedUnits = ( ( allGroups select {side _x isEqualTo _side} ) select {_x knowsAbout _unit isEqualTo _knowValue} ) select {((_x getHideFrom _unit) distanceSqr _unit) < _distSqr};

Share this post


Link to post
Share on other sites

Thank you all, very interesting and exactly what I was looking for. :)

Share this post


Link to post
Share on other sites

 

Very interesting results, thanks :)

 

Select seems more powerful than I expected. Would you mind giving this one try aswell?

_alertedUnits = [];
_side = east;
_unit = player;
_distSqr = 2500;
_knowValue = 4;

_alertedUnits = ( ( allGroups select {side _x isEqualTo _side} ) select {_x knowsAbout _unit isEqualTo _knowValue} ) select {((_x getHideFrom _unit) distanceSqr _unit) < _distSqr};

For 800 units in 100 groups: 0.230947 ms.

For 80 units in 10 groups: 0.0283 ms.

 

Very good results, cake still goes to sarogahtyp.

 

Cheers

  • Like 2

Share this post


Link to post
Share on other sites

 

_alertedUnits = [];
_side = east;
_unit = player;
_distSqr = 2500;
_knowValue = 4;

_alertedUnits = ( ( allGroups select {side _x isEqualTo _side} ) select {_x knowsAbout _unit isEqualTo _knowValue} ) select {((_x getHideFrom _unit) distanceSqr _unit) < _distSqr};

Seems to work with allUnits but not allGroups as getHideFrom doesn't work for groups.

 

sarogahtyp's solution doesn't seem to work at all:

rlMqG4x.png

Share this post


Link to post
Share on other sites

_alertedUnits = [];

_side = east;

_unit = player;

_distSqr = 2500;

_knowValue = 4;

{

{

_alertedUnits pushback _x;

true

} count ((units _x) select {((_x getHideFrom _unit) distanceSqr _unit) < _distSqr});

} count ((allGroups select {side _x isEqualTo _side}) select {(_x knowsAbout _unit isEqualTo _knowValue)});

the little "true" in above code shouldnsolve it...

  • Like 1

Share this post


Link to post
Share on other sites

_alertedUnits = [];

_side = east;

_unit = player;

_distSqr = 2500;

_knowValue = 4;

{

{

_alertedUnits pushback _x;

true

} count ((units _x) select {((_x getHideFrom _unit) distanceSqr _unit) < _distSqr});

} count ((allGroups select {side _x isEqualTo _side}) select {(_x knowsAbout _unit isEqualTo _knowValue)});

the little "true" in above code shouldnsolve it...

Works if you also add another true to the second count but it still doesn't return [] after you kill all units in a group, because the (empty) group still knows about you.

If you change alGroups to allUnits then if works as it should.

 

Edit: This works:

_alertedUnits = [];
_side = independent;
_unit = player;
_distSqr = 2500;
_knowValue = 4;

{

{

_alertedUnits pushback _x;
true
} count ((units _x) select {((_x getHideFrom _unit) distanceSqr _unit) < _distSqr});
true
} count (((allGroups select {({alive _x} count units _x) != 0}) select {side _x isEqualTo _side}) select {(_x knowsAbout _unit isEqualTo _knowValue)});

Share this post


Link to post
Share on other sites

Ah very funny indeed, so my solution was the only one that worked to begin with? Heh.

_alertedUnits = [];
_side = resistance;
_unit = player;
_distSqr = 2500;
_knowValue = 4;
_groupsKnowAboutMe = allGroups select {side _x isEqualTo _side AND {_x knowsAbout _unit isEqualTo _knowValue} AND {((leader _x getHideFrom _unit) distanceSqr _unit < _distSqr) AND alive leader _x}};
_groupsKnowAboutMe apply {_alertedUnits append units _x};

Changed pushback to append, added alive check for leader, 0.0335 ms, 80 units, ten groups.

 

Cheers

  • Like 1

Share this post


Link to post
Share on other sites

substitute this:

} count ((units _x) select {((_x getHideFrom _unit) distanceSqr _unit) < _distSqr});

with this:

} count (((units _x) select {alive _x}) select {((_x getHideFrom _unit) distanceSqr _unit) < _distSqr});

this is faster than ur tweak...

  • Like 1

Share this post


Link to post
Share on other sites

Man this is a fascinating thread for a script newbie like me... Makes me think we need an Arma script-off tournament. 

Share this post


Link to post
Share on other sites

Man this is a fascinating thread for a script newbie like me... Makes me think we need an Arma script-off tournament. 

 

For certain stuff this would probably be interesting, but fighting for 0.02ms when the command isn't being run on every frame is a bit redundant.

It's just so satisfying to increase the performance as far as you knowledge allows.

All these recently added script commands like append, pushback, apply, joinString, splitString and the changes to select make scripting so much more comfortable than back in the A2 days.

_alertedUnits = [];
_side = independent;
_unit = player;
_distSqr = 2500;
_knowValue = 4;

{

    {

        _alertedUnits pushback _x;
        true

    } count (((units _x) select {alive _x}) select {((_x getHideFrom _unit) distanceSqr _unit) < _distSqr});

    true
    
} count (((allGroups select {({alive _x} count units _x) != 0}) select {side _x isEqualTo _side}) select {(_x knowsAbout _unit isEqualTo _knowValue)});

For 80 units in 10 groups: 0.11279 ms. Damn.

 

Drops to 0.150648 ms when one group knows about the player,

to 0.475285 ms when all 10 groups and all 80 units know about the player (4).

 

This last snippet of mine drops from 0.0302 ms to 0.0356 ms with one group knowing about player,

to 0.0767 ms for all 80 units and 10 groups knowing 4 about the player.

_alertedUnits = [];
_side = resistance;
_unit = player;
_distSqr = 2500;
_knowValue = 4;
_groupsKnowAboutMe = allGroups select {side _x isEqualTo _side AND {_x knowsAbout _unit isEqualTo _knowValue} AND {((leader _x getHideFrom _unit) distanceSqr _unit < _distSqr) AND alive leader _x}};
_groupsKnowAboutMe apply {_alertedUnits append units _x};

This makes it more performant with more than 80% increase over sarogahtyps solution for a case when all units know about the player, now that's interesting. Any ideas why?

So I guess there's more to performance than an initial speed check, seeing how it performs if certain conditions come true actually impacts performance by more than I thought.

 

Aaaand I got curious and tested Tajins modified solution under load:

_alertedUnits = [];
_side = resistance;
_unit = player;
_distSqr = 2500;
_knowValue = 4;
_alertedUnits = allGroups select {
    if (side _x isEqualTo _side) then {
        if (_x knowsAbout _unit == _knowValue) then {
            if (((leader _x getHideFrom _unit) distanceSqr _unit) < _distSqr) then {
                true
            };
        };
    };
};

Unknown to all units this resulted in an average runtime of 0.0318ms.

With one group and ten units this dropped to 0.0344ms,

which further dropped to 0.0607ms when all units knew about the player, making it the clear winner under load.

Under load it's more than 20% faster than my version and nearly 90% faster than sarogahtyps version.

So it still holds, nested if arrays are still the fastest, especially if there's a lot of checks needed.

 

Cheers

  • Like 3

Share this post


Link to post
Share on other sites

Oh, so I don't have to change my habits after all?

 

Still, the new select functionality is sexy. :D

  • Like 2

Share this post


Link to post
Share on other sites

@grumpy:

thank u for ur testing but at last u did not test my code because u chose that which was mixed with ops tweak.

my solution was not shown complete but I told which line to substitute instead of ops tweak.

my solution looks like this:

_alertedUnits = [];
_side = independent;
_unit = player;
_distSqr = 2500;
_knowValue = 4;

{
    {
        _alertedUnits pushback _x;
        true
    } count (((units _x) select {alive _x}) select {((_x getHideFrom _unit) distanceSqr _unit) < _distSqr});
    true    
} count ((allGroups select {side _x isEqualTo _side}) select {(_x knowsAbout _unit isEqualTo _knowValue)});
but i didnt know that one can use lazy syntax within selects condition an so i come up with this now:

_alertedUnits = [];
_side = independent;
_unit = player;
_distSqr = 2500;
_knowValue = 4;

{
    {
        _alertedUnits pushback _x;
        true
    } count ( (units _x) select { alive _x AND {((_x getHideFrom _unit) distanceSqr _unit) < _distSqr} } );
    true    
} count ( allGroups select { side _x isEqualTo _side AND {(_x knowsAbout _unit isEqualTo _knowValue)} } );
you would do me a big favour if u could test this one? please :-)

 

 

@grumpy and Tajin:

 

I think Tajins code isnt a solution of the problem. he is handling groups only and not creating a list of units as needed by op. so it must be faster because its a solution for an easier problem...

correct me if im wrong with this.

Share this post


Link to post
Share on other sites

Yes and no.

Returning units instead of groups is just a minor difference:

_alertedUnits = [];
_side = resistance;
_unit = player;
_distSqr = 2500;
_knowValue = 4;
allGroups select {
    if (side _x isEqualTo _side) then {
        if (_x knowsAbout _unit == _knowValue) then {
            if (((leader _x getHideFrom _unit) distanceSqr _unit) < _distSqr) then {
                _alertedUnits append (units _x); 
            };
        };
    };
};

The check is still as thorough as yours, solving the exact same problem.

getHideFrom is the identical for all units in a group so theres little point in doing a distance check for every single one of them – that is probably the main reason why it's faster

Share this post


Link to post
Share on other sites

i doubt that it is a minor difference between creating a list of 10 or a list of 80 units.

but im with u that its not neccessary to use getHideFrom for each unit. to be honest i never ve known bout that command and upto now i did not read the wiki entry for it. that was my fault.

what u r not checking in ur last code is if the unit is alive. op had a problem with that.

i think one can spare the complete knowsAbout check as well because if that getHideFrom condition is true then that enemy group is knowing the player...

i think also that append is better then counting as well as using select instead of counting

edit:

after getting that new knowledge i changed my code to this which is more similar to urs now but checks if units r alive:

_alertedUnits = [];

_side = independent;

_unit = player;

_distSqr = 2500;

{

_alertedUnits append ( (units _x) select {alive _x});

} count ( allGroups select {side _x isEqualTo _side AND {((leader _x getHideFrom _unit) distanceSqr _unit) < _distSqr} });

Edited by sarogahtyp

Share this post


Link to post
Share on other sites

Tajins snippet properly adds all units from the group that meets the condition to the alerted array, no problem there.

 

Yes and no.

Returning units instead of groups is just a minor difference:

_alertedUnits = [];
_side = resistance;
_unit = player;
_distSqr = 2500;
_knowValue = 4;
allGroups select {
    if (side _x isEqualTo _side) then {
        if (_x knowsAbout _unit == _knowValue) then {
            if (((leader _x getHideFrom _unit) distanceSqr _unit) < _distSqr) then {
                _alertedUnits append (units _x); 
            };
        };
    };
};

The check is still as thorough as yours, solving the exact same problem.

getHideFrom is the identical for all units in a group so theres little point in doing a distance check for every single one of them – that is probably the main reason why it's faster

Runs at 0.0713 ms for 80 units in 10 groups with all having full player knowledge, properly returning all units that know about the player.

Now removing the knowsAbout check here reduces it to 0.0583 ms for 80 units in 10 groups with full player knowledge, with properly returning them all.

 

 

i doubt that it is a minor difference between creating a list of 10 or a list of 80 units.

but im with u that its not neccessary to use getHideFrom for each unit. to be honest i never ve known bout that command and upto now i did not read the wiki entry for it. that was my fault.

what u r not checking in ur last code is if the unit is alive. op had a problem with that.

i think one can spare the complete knowsAbout check as well because if that getHideFrom condition is true then that enemy group is knowing the player...

i think also that append is better then counting as well as using select instead of counting

edit:
after getting that new knowledge i changed my code to this which is more similar to urs now but checks if units r alive:

_alertedUnits = [];
_side = independent;
_unit = player;
_distSqr = 2500;

{
_alertedUnits append ( (units _x) select {alive _x});
} count ( allGroups select {side _x isEqualTo _side AND {((leader _x getHideFrom _unit) distanceSqr _unit) < _distSqr} });

Runs at 0.127437 ms for 80 units in 10 groups with all having full player knowledge, properly returning all units that know about the player.

 

 

Now my latest try without knowsAbout check:

_alertedUnits = [];
_side = resistance;
_unit = player;
_distSqr = 2500;
_groupsKnowAboutMe = allGroups select {side _x isEqualTo _side AND {((leader _x getHideFrom _unit) distanceSqr _unit < _distSqr) AND alive leader _x}};
_groupsKnowAboutMe apply {_alertedUnits append units _x};

0.0653 ms under load, 80 units in 10 groups, all know about player, return also correct.

 

Removing the knowsabout check is a good choice, since getHideFrom returns [0,0,0] when the target is not known.

Tajin, pick up your free cake at that totally unsuspicious van parked in the back alley.

 

Cheers

Share this post


Link to post
Share on other sites

Sorry to bump this but would there be a way to feasibly expand the alerted units array to include any Independent unit that is aware of any BLUFOR unit without absolutely tanking performance in a mission with few (sub 10) BLUFOR units?

Share this post


Link to post
Share on other sites

Well, for anybody interested, here's what I came up with (not quite what I said above, but you can call it for whichever groups you want to check detection on so it works fine).

 

Bear with me as I am very new to scripting!  

/*

Detection script. This gets the number of units of the selected side that are aware of each member of the target group.

In init.sqf:

fnc_countAlertedUnits = compile (preprocessFileLineNumbers "fnc_countAlertedUnits.sqf");


Parameters: enemy side, name of target group leader, detection accuracy radius (optional, defaults to 1500).

Example:

myVariable = [east,_sneakyFker] call fnc_countAlertedUnits;
indKnowsOfMyGroup = [independent,player,2000] call fnc_countAlertedUnits;

Returns number of units with beef against that group's members up to max group size of 8. Be aware, script will count duplicates of detected units if multiple units in group are detected.

*/

private ["_side","_detectedGroupLead","_distSqr","_detectedGroup","_detectedGroupStrength","_alertedUnits","_unit2","_unit3","_unit4","_unit5","_unit6","_unit7","_unit8"];

_side = _this select 0;
_detectedGroupLead = _this select 1;
_distSqr = if (isNil {_this select 2}) then {1500} else {_this select 2};

_detectedGroup = units group _detectedGroupLead;
_detectedGroupStrength = count _detectedGroup;

_alertedUnits = [];

_getHideFromUnit = {
    private ["_GroupsKnowAboutUnit","_detectedUnit"];
    _detectedUnit = _this select 0;
    _GroupsKnowAboutUnit = allGroups select {
        (side _x isEqualTo _side) && {((leader _x getHideFrom _detectedUnit) distanceSqr _detectedUnit < _distSqr) && alive leader _x}
    };
    _GroupsKnowAboutUnit apply {_alertedUnits append units _x};
};

[_detectedGroupLead] call _getHideFromUnit;
if (_detectedGroupStrength >= 2) then {_unit2 = _detectedGroup select 1; [_unit2] call _getHideFromUnit};
if (_detectedGroupStrength >= 3) then {_unit3 = _detectedGroup select 2; [_unit3] call _getHideFromUnit};
if (_detectedGroupStrength >= 4) then {_unit4 = _detectedGroup select 3; [_unit4] call _getHideFromUnit};
if (_detectedGroupStrength >= 5) then {_unit5 = _detectedGroup select 4; [_unit5] call _getHideFromUnit};
if (_detectedGroupStrength >= 6) then {_unit6 = _detectedGroup select 5; [_unit6] call _getHideFromUnit};
if (_detectedGroupStrength >= 7) then {_unit7 = _detectedGroup select 6; [_unit7] call _getHideFromUnit};
if (_detectedGroupStrength >= 8) then {_unit8 = _detectedGroup select 7; [_unit8] call _getHideFromUnit};

_alertedUnitCount = (0 + (count _alertedUnits));

_alertedUnitCount

Edited by Incontinentia

Share this post


Link to post
Share on other sites

Well if you changed it to local you should call local function

Share this post


Link to post
Share on other sites

Sorry davidoss, any chance you could elaborate on that? What's the difference between calling a local function and what I've done?  It's going slightly beyond my scope of knowledge (like I said, early days!). 

Share this post


Link to post
Share on other sites

line 41
 

_getHideFromUnit = {};

[param] call _getHideFromUnit;
  • Like 1

Share this post


Link to post
Share on other sites

So it's otherwise correct no? 

 

[_unit2] call _getHideFromUnit; is how it's being called elsewhere. 

 

 

Edit: Updated initial script and clarified! 

Edited by Incontinentia

Share this post


Link to post
Share on other sites

You can do even more improvements.

 

for example:

 

you can use params like this:

params ["_side", ["_detectedGroupLead",1500]];

which allows you to remove lines from 23 - 25

_side = _this select 0;
_detectedGroupLead = _this select 1;
_distSqr = if (isNil {_this select 2}) then {1500} else {_this select 2};

then your private array should not contain params variables or removed one

private ["_detectedGroup","_detectedGroupStrength","_alertedUnits","_unit2","_unit3","_unit4","_unit5","_unit6","_unit7","_unit8"];

and obviously  change in line 32

_distSqr to _detectedGroupLead

 (side _x isEqualTo _side) && {((leader _x getHideFrom _detectedUnit) distanceSqr _detectedUnit < _detectedGroupLead) && alive leader _x}

Thats for a quick look

  • Like 1

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

×