Jump to content
LSValmont

Optimizing holdAction for performance & Multiplayer

Recommended Posts

Hello A3 Community!

Since there is no topic on HoldAction optimization and tweaking I wanted to create one so we could perhaps answer some questions and share our findings.

 

I love the holdActions implementation in Arma 3 far better than addAction but there is always the concern about performance and multiplayer compatibility.


My first question would be:

 

1) Are Lazy evaluation/Successive condition check doable and beneficial for holdAction conditions and if so how could I implement it and optimize this example holdAction:

Spoiler

 


// vTakeDown.sqf

vTakeDown_ID = -1;

vTakeDown_Action = {

vTakeDown_ID =
[
	player,												
	"Perform Takedown",									
	"\a3\ui_f\data\IGUI\Cfg\holdactions\holdAction_forceRespawn_ca.paa",	
	"\a3\ui_f\data\IGUI\Cfg\holdactions\holdAction_thumbsdown_ca.paa",	
	"
	!isNull cursorTarget &&
	alive cursorTarget &&
	cursorTarget isKindOf ""Man"" &&
	lifeState cursorTarget != ""INCAPACITATED"" &&
	speed cursorTarget < 0.3 &&
	player distance cursorTarget < 3
	",						
	"
	!isNull cursorTarget &&
	alive cursorTarget &&
	cursorTarget isKindOf ""Man"" &&
	lifeState cursorTarget != ""INCAPACITATED"" &&
	speed cursorTarget < 0.3 &&
	player distance cursorTarget < 3
	",													
	{},													
	{},													
	{
	_trg = cursorTarget;
		if (alive _trg) then {
		_trg setVariable ["vTakeDown",true];
		if (currentWeapon player isEqualTo "") then {
		[player, "AwopPercMstpSgthWnonDnon_end"] remoteExec ["switchMove", 0];
		} else {[player, "ThrowGrenade"] remoteExec ["playActionNow", 0];};
		_trg setUnconscious true;
		_trg setHitPointDamage ["hitLegs", 0.6];
			[_trg] spawn 
			{
				params ["_unit"];
				sleep (20 + (random 40));
				_unit setUnconscious false;
				_unit setVariable ["vTakeDown",false];
				[_unit, "ApanPpneMstpSnonWnonDnon_G02"] remoteExecCall ["playMove", 0];
			};	
		};
	},				
	{[player, "ThrowGrenade"] remoteExec ["playActionNow", 0];},													
	[],													
	1.1,													
	999,													
	false,												
	false												
] remoteExec ["BIS_fnc_holdActionAdd", 0, player];

};

// Init
waitUntil { !isNull player };

[] spawn vTakeDown_Action;
player addEventHandler ["Respawn", {
    [] spawn {
        sleep 1;
        [] spawn vTakeDown_Action;
    };
}];

hint "takedown working!";

 

 

 

 

The holdAction is added to the players and displayed when the conditions are met.

The script that adds the holdAction is executed from init.sqf:

nul = [] execVM "vTakeDown.sqf";

The conditions are: 

Spoiler

	!isNull cursorTarget &&
	alive cursorTarget &&
	cursorTarget isKindOf ""Man"" &&
	lifeState cursorTarget != ""INCAPACITATED"" &&
	speed cursorTarget < 0.3 &&
	player distance cursorTarget < 3

 

I worry that these many conditions might affect performance specially when adding other similar player holdActions but targeting only civilians etc.

 

Question nber 2: How many holdActions can we add to a player before it starts lagging things out for that particular client?

  • Like 1

Share this post


Link to post
Share on other sites

Hi mate, 

 

Very interessting topic in my view. 

I use holdactions a lot and i am interested to see what we can collect on the subject. 

 

My thoughts:

It seems to me that first you need to include delays for the condition checks. 

Right now all your checks are done at max frequency with no delays inbetween. 

It should be enough if the cond. are only checked every 0.5 or even 1 sec. 

Not sure if this can be built right into the string. 

If not, i would move your cond. check into a seperate loop (with addequate delay) that returns true to a variable, if met. Then only add the variable as cond. to the holdaction. This way, atleast it only checks 1 boolean at max frequency. 

 

Second: make sure that each condition check is as optimized as possible, e.g is there a quicker way to get to the result. Further, in your example ALL conditions must be met, if one is not met, no point in checking the others. hence lazy evaluation should indeed be applied as you mentioned. Here is how:

 

Here, also rethink the priority of your conditions, if no target is in range, you dont need to check if its alive first, right? So maybe: ! Isnil - > range - > not Incapacitated - > alive - > moving slow

 

TLDR: tune code compexity and frequency of code execution down

 

Just my 2 cents:)

 

Cheers

Vd

  • Like 1

Share this post


Link to post
Share on other sites
12 hours ago, LSValmont said:

1) Are Lazy evaluation/Successive condition check doable and beneficial for holdAction conditions and if so how could I implement it and optimize this example holdAction:

Yes ofcourse. You do it the same as everywhere else, and it has the same benefit as everywhere else.
Maybe even more as (not sure how often) holdAction condition is checked very often while you look at the target object.

 

Important is also to order the conditions such that the ones most likely to be false are up front, to quit the checking early.

And the heaviest checks should be at the end.

 

 

Taking this example:

 

"
	!isNull cursorTarget &&
	alive cursorTarget &&
	cursorTarget isKindOf ""Man"" &&
	lifeState cursorTarget != ""INCAPACITATED"" &&
	speed cursorTarget < 0.3 &&
	player distance cursorTarget < 3
	"

1st the isNull check is nonsense, alive will return false if it were null.

distance check is expensive so that being at end makes sense.
isKindOf check is even more expensive though.

But on the other hand, distance and isKindOf checks are more likely to be false, so it makes more sense to put them on the front.

 

I would write it like this:

"
alive cursorTarget && {
    player distance cursorTarget < 3 &&
    {cursorTarget isKindOf ""Man""}
    {speed cursorTarget < 0.3 &&}
    {lifeState cursorTarget != ""INCAPACITATED""} &&
}
"

in most cases cursorTarget will probably be null, so in that case we can just skip everything.

For the rest it doesn't make sense readability wise to use nested lazy eval, although it might be more performant.

Readability wise I'd also recommend you fix your indentation, it's probably the most important readability factor.

 

12 hours ago, LSValmont said:

Question nber 2: How many holdActions can we add to a player before it starts lagging things out for that particular client?

0.
Even at one holdAction you cause script evaluation, which causes a fps decrease.

If you want to ask at what point it becomes significant, then the answer is: it depends. On the conditions, target, users computer hardware, users running background processes, users graphics settings...

 

 

10 hours ago, Vandeanson said:

It should be enough if the cond. are only checked every 0.5 or even 1 sec. 

Not sure if this can be built right into the string. 

You'd need to add some caching, which is quite advanced stuff and most likely not worth it.

 

10 hours ago, Vandeanson said:

If not, i would move your cond. check into a seperate loop (with addequate delay) that returns true to a variable, if met. Then only add the variable as cond. to the holdaction. This way, atleast it only checks 1 boolean at max frequency. 

That's a very nice idea. On the other side this might add lag, and if you do that in scheduled (which you would and should) then it might be delayed by 10 seconds or more on a badly scripted mission.

Which for a "takedown" action would be unacceptable.

 

 

 

  • Like 2
  • Thanks 1

Share this post


Link to post
Share on other sites

Change that distance check for distanceSqr and your required distance to 3^2.

As @Dedmen said distance is a very expensive operation even more so if it has to work out the square root.

Where as power of 2 or (3*3) is less computationally expensive.

  • Like 3
  • Thanks 1

Share this post


Link to post
Share on other sites

First of all thank you @Vandeanson, @Dedmen and @Larrow for your invaluable wisdom and specially sharing it with all of us.

 

Any novice and even more advanced scripters/mission creators will surely benefit from everything you've stated here.

 

In any case it seems that the holdAction is a useful tool that must be used wisely and not wildly in order to keep everything above those golden 60 FPSs.

 

Last question from me... in your experience you would say that a holdAction is more expensive than a addAction computationally wise given both have the same checks and conditions or both tools are more or less on par in terms of performance impact?

Share this post


Link to post
Share on other sites
13 hours ago, LSValmont said:

in your experience you would say that a holdAction is more expensive than a addAction computationally wise

A holdAction is an addAction. It just does something like...

addAction[ _title, {
	
	call _codeOnStart;
	
	disable action menu
	
	while { not max frame || progress abort } do {
		
		waitUntil{ time > next frame };
		
		work out icon to display
		
		call _progressCode
		
	};
	
	if ( frame == max frame ) then {
		remove action
		call _codeComplete;
	}else{
		call _codeInterrupted
	};
	
	reset icon
	
	re-enable action menu
	
}];

 

  • 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

×