Jump to content
Sign in to follow this  
Heeeere's johnny!

Which is more efficient - addAction condition or trigger condition?

Recommended Posts

Hi everyone,

as I am very interested in code performance, I'm wondering which of the two titled ways is "faster" when it comes to adding an action using "addAction". I guess they're both equally fast if the condition is identical, but let me give you an example of what I mean.

Say I have a static object like a road sign and I want to have an action named "Read out loud" (just to express the point), what should I use?

I could do

player addAction ["Read out loud", {/*some fancy code*/}, "", 0, false, false, "", 'player distance (getPosATL roadSign) < 5'];

or I could do

_trigger = createTrigger ["EmptyDetector", getPosATL roadSign];
_trigger setTriggerArea [5, 5, 5, false];
_trigger setTriggerActivation ["ANY", "PRESENT", true];
_trigger setTriggerStatements ["player distance (getPosATL roadSign) < 5", "player addAction ['Read out loud', {/*some fancy code*/}];", "player removeAction 0;"];

... where "roadSign" would have to be a public variable in order to prevent this whole "missionNamespace getVariable" thingy being executed in the conditions all the time.

Despite the problems with the removeAction index (I already have a solution for that), which of these two constructs is more efficient or "faster" I'm really interested to know.

To my mind it appears more senseful (efficient) to use the addAction-removeAction-process as the addAction condition will be checked every 0.03 seconds (I guess) while it wouldn't if I removed the action as soon as it's not needed anymore.

Best regards,

Johnny

Share this post


Link to post
Share on other sites

This shouldn't be a question about performance. The first suggestion is most likely more efficient since it doesn't add/remove the addAction but rather hides it. But more importantly it's easier to read and understand. It's less obsfuscated

Share this post


Link to post
Share on other sites

add action to the road sign. not only it will be most efficient, you will not see the action if you are not looking at the sign in the first place.

Share this post


Link to post
Share on other sites

I agree, the first method is way easier to read and takes less code lines to implement.

But as cuel stated, the action is hidden, but it's still there and its condition is constantly being checked to unhide it again as soon as the condition is true.

If you have ever looked into the code of the "Altis Life" mod, there's literally hundreds of addActions, each checking huge and complex conditions. Most of these actions are dependent on the distance of the player to a specific object.

So I'm asking you and myself if that's really "better" than removing actions which are not needed in order to minimize the amount of addAction conditions which have to be checked.

Edited by waltenberg

Share this post


Link to post
Share on other sites
I agree, the first method is way easier to read and takes less code lines to implement.

But as cuel stated, the action is hidden, but it's still there and its condition is constantly being checked to unhide it again as soon as the condition is true.

If you have ever looked into the code of the "Altis Life" mod, there's literally hundreds of addActions, each checking huge and complex conditions. Most of these actions are dependent on the distance of the player to a specific object.

So I'm asking you and myself if that's really "better" than removing actions which are not needed in order to minimize the amount of addAction conditions which have to be checked.

This is a good point and i am interested to know the answer.

Logically it is best to begin with a distance check (A trigger can do this).

And process the complicated code when required (Or the trigger is activated).

Share this post


Link to post
Share on other sites

You only need to worry about addAction performance-wise if you have it attached to a player. If it's not attached to a player, the condition will not check each second, but rather it will only check if a player i within 15m of said object, and only if player is looking at it (cursortarget == object, one would assume)[ref. 'condition']. So, essentially, attaching actions to actual objects instead of players would be a first step.

If you want to actually attach it to a player, it seems rather hard to be performance-friendly (although a distance check takes very little performance, unless done en masse) like you can be when attaching actions to an object. Triggers aren't really a solution, as they take up just as much performance as the check inside the action. I'd say making the actual check as easy as possible would be going in the right direction. I think just seeing how many checks (basic checks like a distance check) can be active at once before mission performance notably decreases.

Share this post


Link to post
Share on other sites

Not sure how often addAction is checked, it can be easily checked by just logging time in the condition. Trigger conditions are technically checked every 0.5 seconds IIRC (sort of relevant to load). So you wouldn't have better performance in that way. I can only assume that action conditions are checked in either the same loop or a similar delay.

But really there are countless amounts of intense scripts running in every single mission, both from BIS and add-ons. SQF is fast and how you choose to show an addAction would have little to no impact on performance. You should be focusing on more CPU-heavy stuff :)

Share this post


Link to post
Share on other sites

Not sure about performance, but with the parameters you're passing to addAction, it might not have the effect you want. Those 2 bool values at the end are important.

priority - I usually set my addActions with a priority of 6, to force my options to the top of the list. The default value is 1.5, so by setting 0 you're forcing it to the bottom of the list.

showWindow (first bool) - Setting this to true will make it so that the action text appears just below the aiming reticule. Players will only know that you can read the signs if they happen to scroll their mouse wheel while looking at the sign, or have their action menu open while looking at the sign for some reason.

hideOnUse (second bool) - Setting this to true will close the action menu after using your custom action. With the way you have it, the menu will stay open after use, possibly leading players to spam click, if your script doesn't have an immediate effect like if you have a sleep command in it (requires you to spawn a new thread).

Depending on what you wanted to do, in your script you would removeAction to prevent players from running the script over and over again. But judging by the action text, you're not spawning any units, so you probably don't want/need to do that.

Edited by DreadedEntity

Share this post


Link to post
Share on other sites
Not sure how often addAction is checked

Roughly, every frame. If you have tonnes of actions and it is overloaded then it will start checking every other frame and so on.

Edited by Killzone_Kid

Share this post


Link to post
Share on other sites
Roughly, every frame. If you have tonnes of actions and it is overloaded then it will start checking every other frame and so on.

Interesting.

Share this post


Link to post
Share on other sites
Interesting.

Sorry I got confused with waitUntil. Condition in addAction executes exactly on each frame in unscheduled environment. Heavy condition or too many of them will lead to drop in FPS.

Share this post


Link to post
Share on other sites
Sorry I got confused with waitUntil. Condition in addAction executes exactly on each frame in unscheduled environment. Heavy condition or too many of them will lead to drop in FPS.

So using a mixture of triggers and addaction scripts would be much more efficient for addactions that are attached to the player?

Share this post


Link to post
Share on other sites
So using a mixture of triggers and addaction scripts would be much more efficient for addactions that are attached to the player?

Probably. But remember what Killzone_Kid said,

Condition in addAction executes exactly on each frame in unscheduled environment. Heavy condition or too many of them will lead to drop in FPS.

It seems that the best way to cut down performance loss would be to use a ton of nested "if" statements

if (alive player) then
{
if (player distance myCustomObject <= 5) then
{
	//do a bunch of code
};
};

Is inherently faster than

if (alive player) and (player distance myCustomObject <= 5) then
{
//do a bunch of code
};

It's the same code, despite being longer, and more confusing to keep track of. Why is this? It works faster because of the way "if" statements are handled in every programming language, ever. In the first code, if (alive player) returns false, BOOM done. Right there. The second "if" statement is skipped because all code inside the first "if" statement gets nuked if the condition is false, the game just no longer cares about what's in it.

But in the second code, I believe the game will check both conditions, even if the first one is false. That is processing power your computer/the server is wasting.

In fact, the fastest way might even be just creating a trigger with the radius being the distance you would like the script to be accessible from, setting the activation to Anybody present, make it repeatable, and type this in activation:

for "_i" from 0 to (count thisList) do
{
(thisList select (_i)) addAction ["My Custom Action", "action.sqf", [], 6, true, true];
};

Now, there is a little problem with this that I didn't think about before I started writing it. After the first player walks in the trigger it fires, and it will not fire again until everybody has left the trigger radius. But I trust that you got it from here.

Share this post


Link to post
Share on other sites

if (alive player) then
{
   if (player distance myCustomObject <= 5) then
   {
       //do a bunch of code
   };
}; 

Isn't this going to be worse than just checking if (player distance myCustomObject <= 5) then

your now doing two checks as player is nearly always going to be alive and if he isn't so what.

I would always put the least common condition first so it doesn't need to check further.

Edited by F2k Sel

Share this post


Link to post
Share on other sites
Isn't this going to be worse

Yes. That was just an example for concept. Of course you wouldn't check if the player is alive for your scripts, 99% require the player to be alive anyway.

Share this post


Link to post
Share on other sites
Probably. But remember what Killzone_Kid said,

It seems that the best way to cut down performance loss would be to use a ton of nested "if" statements

if (alive player) then
{
if (player distance myCustomObject <= 5) then
{
	//do a bunch of code
};
};

There is no point in doing nested ifs when you can just do lazy evaluation

if (alive player && {player distance myCustomObject <= 5}) then
{
//code		
};

Share this post


Link to post
Share on other sites
There is no point in doing nested ifs when you can just do lazy evaluation

I may be wrong since there are quite a number of quirks in the Arma engine that I haven't grasped yet, but the reason I see nested if's as a better option is because if the first condition is false, then the entire statement is skipped. But from what I understand about lazy evaluation from other languages I've used, all conditions are checked whether previous conditions are true or false.

So without knowing if the Arma engine efficiently handles lazy evaluations, I saw nesting as the best option.

Share this post


Link to post
Share on other sites
I may be wrong since there are quite a number of quirks in the Arma engine that I haven't grasped yet, but the reason I see nested if's as a better option is because if the first condition is false, then the entire statement is skipped. But from what I understand about lazy evaluation from other languages I've used, all conditions are checked whether previous conditions are true or false.

So without knowing if the Arma engine efficiently handles lazy evaluations, I saw nesting as the best option.

I think you are correct, that is, if the wiki is correct:

"You may expect the engine to stop reading the condition after the group has no knowledge about the object but that's false. The engine will continue evaluating the condition until the end even if any of the previous conditions evaluated false." - source

Not to mention, if you have multiple statements that require the "alive player" condition, the nested approach would likely be slightly quicker (with, or without lazy evaluation).

EDIT: OK, I see they do support lazy evaluation - same source as above (wrapping in {} as per brians example) - latter statement probably still holds some value though.

Edited by Shizweak

Share this post


Link to post
Share on other sites

Just to remind everyone, you can always compare code performance and find out which is faster with BIS_fnc_codePerformance

Share this post


Link to post
Share on other sites
Sorry I got confused with waitUntil. Condition in addAction executes exactly on each frame in unscheduled environment. Heavy condition or too many of them will lead to drop in FPS.

Aye I guess there's a reason for it, just seems weird that addActions are prioritized so high

Share this post


Link to post
Share on other sites

Alright, now as I was playing about a bit with my newly gained knowledge from this thread, I'd like to modify the question a bit.

How about not attaching the addAction to an object, but to a marker/area? Obviously, I cannot attach an addAction to a marker as that is not a visible object and most likely, my area is larger than 30m in diameter.

Now, how about that situation? Would the add/removeAction strategy now be a solution or is there still something better? Feel free to write your mind.

Have a nice Play!

waltenberg

---------- Post added at 19:12 ---------- Previous post was at 17:20 ----------

Oh and - as it just came to my mind, is it possible to add an action to a player which only the other players can use, but not the player it is added to?

Edited by waltenberg

Share this post


Link to post
Share on other sites
Oh and - as it just came to my mind, is it possible to add an action to a player which only the other players can use, but not the player it is added to?

this addAction ["Action","action.sqf",[],1.5,true,true,"_this != _target"];

That should do the trick, technically.

But just technically, because it doesn't work in practice.

Edited by tryteyker

Share this post


Link to post
Share on other sites

Yeah, I was thinking about that as well, but I guess it doesn't work, because addAction is probably not intended to be not-useable by the player it's added to.

Share this post


Link to post
Share on other sites
this addAction ["Action","action.sqf",[],1.5,true,true,"_this != _target"];

That should do the trick, technically.

But just technically, because it doesn't work in practice.

You missed shortcut: this addAction ["Action","action.sqf",[],1.5,true,true,"","_this != _target"]

Share this post


Link to post
Share on other sites
You missed shortcut: this addAction ["Action","action.sqf",[],1.5,true,true,"","_this != _target"]

Well, I didn't have the opportunity yet to test it. So does this work the intended way? If it does, the next question would be, which client the condition is checked on. As you already wrote about adding an action to a road sign, I would guess the condition is checked on each frame on the client of the player it's added to and on the other clients only if they are closer 15m and aim at the player.

That would mean, if I did this with every playing client, no performance will be improved as nothing would have changed. Do I get that right?

Edited by waltenberg

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  

×