waitUntil: Difference between revisions

From Bohemia Interactive Community
Jump to navigation Jump to search
No edit summary
m (Text replacement - "[Rr]oehre" to "RoehrenRadio")
 
(65 intermediate revisions by 7 users not shown)
Line 1: Line 1:
{{Command|= Comments
{{RV|type=command
____________________________________________________________________________________________


| arma |= Game name
|game1= arma1
|version1= 1.00


|1.00|= Game version
|game2= arma2
____________________________________________________________________________________________
|version2= 1.00


| Suspend execution of [[function]] or [[SQF_syntax|SQF]] based [[Script|script]] until condition is satisfied.
|game3= arma2oa
<br>
|version3= 1.50
This command will loop and call the code inside <tt>{}</tt> ''mostly'' every frame (depends on complexity of condition and overall engine load) until the [[Code|code]] returns [[true]]. The execution of the rest of the script therefore will be suspended until [[waitUntil]] condition is satisfied and the loop is aborted.
<br>
Because of this script suspension use [[spawn]] or [[execVM]] to safely execute code containing [[waitUntil]]. |= Description
____________________________________________________________________________________________


| '''waitUntil''' condition |= Syntax
|game4= tkoh
|version4= 1.00


|p1= condition: [[Code]] |= Parameter 1
|game5= arma3
|version5= 0.50


| [[Nothing]] |= Return value
|gr1= Program Flow
____________________________________________________________________________________________
 
|x1= <code>[[waitUntil]] { [[not]] [[alive]] [[player]] };</code> |= Example 1


|x2= <code>_i = 0; [[waitUntil]] { _i = _i + 1; _i >= 100 }; </code> |= Example 2
|descr= Suspends execution of [[Scheduler|scheduled]] script until the given condition satisfied.
* This command will loop and call the code inside <sqf inline>{}</sqf> '''mostly every frame''', depends on complexity of the condition and the overall engine load, until the [[Code|code]] returns [[true]]
* If the very first execution of the code returns [[true]] the command will exit immediately, therefore it will not produce any "Suspending not allowed in this context" error when used inside [[Scheduler#Unscheduled_Environment|non-scheduled]] script. For all other uses it must be executed in environment that allows [[Scheduler#Suspension|suspension]] ([[canSuspend]]), such as [[spawn]]ed or [[execVM]]ed code
* Avoid doing <sqf inline>waitUntil { time > 20 };</sqf> and use <sqf inline>sleep 20;</sqf> instead!
* If you can, add a [[sleep]] to the condition to save some cpu cycles <sqf inline>waitUntil { sleep 1; !alive player };</sqf>


|x3= <code>[[waitUntil]] {[[sleep]] 0.1; [[not]] [[alive]] [[player]] };</code> |= Example 3
{{Feature|arma3|Since {{arma3}} v1.94, a ''condition'' returning anything other than [[true]] or [[false]] '''will''' result in an appropriate type error.}}


|x4= An on-the-fly custom ''[[Arma_3:_Event_Handlers|event handler]]'':
|pr= For some unknown reason if you have [[waitUntil]] loop active and game is '''saved/loaded''', some variables in the expression may appear undefined for a short time. As a workaround, assign expression to a variable and make sure it is defined before [[waitUntil]] checks it:
<code>_myEH = ["ZoomIn"] [[spawn]] {
<sqf>waitUntil { private _expression = someBooleanVar && (someNumberVar > 10); !isNil "_expression" && { _expression } };</sqf>
    [[while]] { [[true]] } [[do]] {
        [[waitUntil]] {
            [[inputAction]] ([[_this]] [[select]] 0) == 1;
        };
        [[diag_log]] [[format]] ["%1 @ %2", [[_this]] [[select]] 0, [[diag_tickTime]]<nowiki>]</nowiki>;
    };
};</code>
Although perhaps better to use [[BIS_fnc_addStackedEventHandler|onEachFrame]], depending on the application. |= Example 4
____________________________________________________________________________________________


| [[Control Structures]], [[while]] |= See also
|s1= [[waitUntil]] condition


}}
|p1= condition: [[Code]] - the expression that '''must''' return a [[Boolean]], [[true]] to finish waiting or [[false]] to continue waiting


<h3 style="display:none">Notes</h3>
|r1= [[Anything]] - the value the condition evaluates to when the wait is over (normally [[true]])
<dl class="command_description">
<!-- Note Section BEGIN -->


<dd class="notedate">Posted on September 20, 2013
|x1= <sqf>waitUntil { not alive player };</sqf>
<dt class="note">'''[[User:Killzone_Kid|Killzone_Kid]]'''
<dd class="note">In case you have more complex code inside [[waitUntil]] loop, to be on the safe side '''always''' return boolean at the end of the scope:


<code>[[player]] [[addEventHandler]] ["Fired", {
|x2= <sqf>_i = 0; waitUntil { _i = _i + 1; _i >= 100 };</sqf>
_null = (_this [[select]] 6) [[spawn]] {
_p = [0,0,0];
[[waitUntil]] {
if ([[isNull]] _this) [[exitWith]] {[[true]]};
_p = [[getPos]] _this;
[[false]] //<-- boolean at the end of the scope
};
[[hint]] [[str]] _p;
};
}];</code>


<dd class="notedate">Posted on December 20, 2006 - 19:55
|x3= [[waitUntil]] can lead to performance loss if used improperly:
<dt class="note">'''[[User:CrashDome|CrashDome]]'''
<sqf>
<dd class="note">
waitUntil { not alive player }; // bad
waitUntil suspends both SQF functions and SQF scripts. In functions, the calling script is still in suspension due to waiting for a return from the [[call]] command. The game engine will continue, however. See [[Function]] for more detail.
waitUntil { sleep 1; not alive player }; // good - checks every 1 second
player addEventHandler ["Killed", {  }]; // best - don't forget about Event Handlers
</sqf>


|x4= An on-the-fly custom [[Arma 3: Event Handlers|event handler]]:
<sqf>
_myEH = ["ZoomIn"] spawn {
while { true } do
{
waitUntil { inputAction (_this select 0) == 1 };
diag_log format ["%1 @ %2", _this select 0, diag_tickTime];
};
};
</sqf>
Although it may be better to use [[onEachFrame]] ([[BIS_fnc_addStackedEventHandler|stacked]]) [[Arma_3:_Mission_Event_Handlers#EachFrame|mission Event Handler]], depending on the application.


<dd class="notedate">Posted on April 2, 2010 - 17:10
|x5= Use [[getVariable]] with default value to prevent unexcepted script errors:
<dt class="note">'''[[User:Roehre|Roehre]]'''
<sqf>
<dd class="note">
waitUntil { bank getVariable ["money", 0] > 0 };
If WaitUntil uses an undefined [[call]] code, WaitUntil won't release, even when this code is separated from other conditions through [[or]]. Be warned that this won't cause an error message.
waitUntil { missionNamespace getVariable ["isready", false] };
</sqf>


|x6= Always return [[Boolean]]:
<sqf>
waitUntil { sleep 1; if (not alive player) exitWith {}; _time = _time + 1 }; // bad
waitUntil { sleep 1; if (not alive player) exitWith { true }; _time = _time + 1; false }; // good
waitUntil { sleep 1; not alive player }; // perfect
</sqf>


<dd class="notedate">Posted on Jan 07, 2011
|seealso= [[sleep]] [[uiSleep]] [[canSuspend]] [[spawn]] [[execVM]] [[while]] [[Control Structures]]
<dt class="note">'''[[User:kju|kju]]'''
}}
<dd class="note">
By default the cycle time for the condition check is per frame. Look at the example 3, how to set it at a lower rate yourself.
Often times one does not need per frame checking. Saves a lot CPU checks; especially when the condition is complex to compute.




<!-- Note Section END -->
{{Note
</dl>
|user= CrashDome
|timestamp= 20061220195500
|text= waitUntil suspends both SQF functions and SQF scripts. In functions, the calling script is still in suspension due to waiting for a return from the [[call]] command. The game engine will continue, however. See [[Function]] for more detail.
}}


<h3 style="display:none">Bottom Section</h3>
{{Note
 
|user= RoehrenRadio
[[Category:Scripting Commands|WAITUNTIL]]
|timestamp= 20100402171000
[[Category:Scripting Commands ArmA|WAITUNTIL]]
|text= Prior to {{arma3}} v1.94 if [[waitUntil]] uses an undefined [[call]] code, [[waitUntil]] won't release, even when this code is separated from other conditions through [[or]]. Be warned that this won't cause an error message.
[[Category:Scripting Commands ArmA2|{{uc:{{PAGENAME}}}}]]
}}
[[Category:Scripting Commands Arma 3|{{uc:{{PAGENAME}}}}]]
[[Category:Scripting_Commands_Take_On_Helicopters|{{uc:{{PAGENAME}}}}]]


<!-- CONTINUE Notes -->
{{Note
<dl class="command_description">
|user= Commy2
<dd class="notedate">Posted on December 13, 2014 - 23:25 (UTC)</dd>
|timestamp= 20141213232500
<dt class="note">[[User:Commy2|Commy2]]</dt>
|text= If you want to use [[waitUntil]] together with [[exitWith]], remember that the loop only exits if the code block returns true.<br>
<dd class="note">
If you want to use waitUntil together with exitWith, remember that the loop only exits if the code block returns true.<br>
<br>
<br>
It should look like this:
It should look like this:
<code>
<sqf>
waitUntil {
waitUntil {
  // exit loop if the unit gets deleted
// exit loop if the unit gets deleted
  if (isNull _unit) exitWith {true}; // has to return true to continue
if (isNull _unit) exitWith { true }; // has to return true to continue


  !alive _unit;
!alive _unit;
};
};
</code>
</sqf>
}}


</dd>
{{Note
</dl>
|user= AgentRev
<!-- DISCONTINUE Notes -->
|timestamp= 20220419060501
|text= It's a good idea to include a timeout with the condition if there's any possibility that it never becomes true:
<sqf>
disableUserInput true;
player moveInDriver _vehicle; // this command is asynchronous and can fail sometimes
_time = time;
waitUntil {vehicle player == _vehicle || time - _time > 3};
disableUserInput false;
</sqf>
}}

Latest revision as of 10:49, 8 April 2024

Hover & click on the images for description

Description

Description:
Suspends execution of scheduled script until the given condition satisfied.
  • This command will loop and call the code inside {} mostly every frame, depends on complexity of the condition and the overall engine load, until the code returns true
  • If the very first execution of the code returns true the command will exit immediately, therefore it will not produce any "Suspending not allowed in this context" error when used inside non-scheduled script. For all other uses it must be executed in environment that allows suspension (canSuspend), such as spawned or execVMed code
  • Avoid doing waitUntil { time > 20 }; and use sleep 20; instead!
  • If you can, add a sleep to the condition to save some cpu cycles waitUntil { sleep 1; !alive player };
Arma 3
Since Arma 3 v1.94, a condition returning anything other than true or false will result in an appropriate type error.
Problems:
For some unknown reason if you have waitUntil loop active and game is saved/loaded, some variables in the expression may appear undefined for a short time. As a workaround, assign expression to a variable and make sure it is defined before waitUntil checks it:
waitUntil { private _expression = someBooleanVar && (someNumberVar > 10); !isNil "_expression" && { _expression } };
Groups:
Program Flow

Syntax

Syntax:
waitUntil condition
Parameters:
condition: Code - the expression that must return a Boolean, true to finish waiting or false to continue waiting
Return Value:
Anything - the value the condition evaluates to when the wait is over (normally true)

Examples

Example 1:
waitUntil { not alive player };
Example 2:
_i = 0; waitUntil { _i = _i + 1; _i >= 100 };
Example 3:
waitUntil can lead to performance loss if used improperly:
waitUntil { not alive player }; // bad waitUntil { sleep 1; not alive player }; // good - checks every 1 second player addEventHandler ["Killed", { }]; // best - don't forget about Event Handlers
Example 4:
An on-the-fly custom event handler:
_myEH = ["ZoomIn"] spawn { while { true } do { waitUntil { inputAction (_this select 0) == 1 }; diag_log format ["%1 @ %2", _this select 0, diag_tickTime]; }; };
Although it may be better to use onEachFrame (stacked) mission Event Handler, depending on the application.
Example 5:
Use getVariable with default value to prevent unexcepted script errors:
waitUntil { bank getVariable ["money", 0] > 0 }; waitUntil { missionNamespace getVariable ["isready", false] };
Example 6:
Always return Boolean:
waitUntil { sleep 1; if (not alive player) exitWith {}; _time = _time + 1 }; // bad waitUntil { sleep 1; if (not alive player) exitWith { true }; _time = _time + 1; false }; // good waitUntil { sleep 1; not alive player }; // perfect

Additional Information

See also:
sleep uiSleep canSuspend spawn execVM while Control Structures

Notes

Report bugs on the Feedback Tracker and/or discuss them on the Arma Discord or on the Forums.
Only post proven facts here! Add Note


CrashDome - c
Posted on Dec 20, 2006 - 19:55 (UTC)
waitUntil suspends both SQF functions and SQF scripts. In functions, the calling script is still in suspension due to waiting for a return from the call command. The game engine will continue, however. See Function for more detail.
RoehrenRadio - c
Posted on Apr 02, 2010 - 17:10 (UTC)
Prior to Arma 3 v1.94 if waitUntil uses an undefined call code, waitUntil won't release, even when this code is separated from other conditions through or. Be warned that this won't cause an error message.
Commy2 - c
Posted on Dec 13, 2014 - 23:25 (UTC)
If you want to use waitUntil together with exitWith, remember that the loop only exits if the code block returns true.

It should look like this:
waitUntil { // exit loop if the unit gets deleted if (isNull _unit) exitWith { true }; // has to return true to continue !alive _unit; };
AgentRev - c
Posted on Apr 19, 2022 - 06:05 (UTC)
It's a good idea to include a timeout with the condition if there's any possibility that it never becomes true:
disableUserInput true; player moveInDriver _vehicle; // this command is asynchronous and can fail sometimes _time = time; waitUntil {vehicle player == _vehicle || time - _time > 3}; disableUserInput false;