Unofficial LSL Reference

[[language:state]]


Unofficial LSL reference

User Tools

Login

You are currently not logged in! Enter your authentication credentials below to log in. You need to have cookies enabled to log in.

Login

Forgotten your password? Get a new one: Set new password

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

language:state [2018-10-11 02:42 SLT]
sei created
language:state [2020-06-15 12:58 SLT] (current)
sei more wording
Line 9: Line 9:
 state <​state_name>​ state <​state_name>​
 { {
-   <​event_declaration>​+    ​<​event_declaration>​
  
-   <​event_declaration>​+    ​<​event_declaration>​
  
-   ...+    ​...
 } }
 </​code>​ </​code>​
  
-where `<​state_name`>​ is the identifier that will be used in $kw[switch] statements. As an exception, when declaring state $kw[default] we don't add the keyword $kw[state] in front of it. Additionally,​ the $kw[default] state must always appear before any other state declaration.+where `<​state_name`>​ is the identifier that will be used in $kw[state] statements. As an exception, when declaring state $kw[default] we don't add the keyword $kw[state] in front of it. Additionally,​ the $kw[default] state must always appear before any other state declaration.
  
-For the `<​event_declaration`>​ syntax see [[Events]]. ​States can't be empty; ​there must be at least one event declaration ​inside of each state. There can be as many event declarations as necessary, but there can't be two declarations of the same event inside ​the same state.+States can't be empty; ​each state must contain ​at least one event declaration. There can be as many event declarations as necessary, but there can't be two declarations of the same event within ​the same state. 
 + 
 +No globals may appear between states; globals are only allowed before the $kw[default] ​state.
  
 ==== state statement ==== ==== state statement ====
Line 29: Line 31:
 </​code>​ </​code>​
  
-where `<​state_name`>​ can be $kw[default] or the name of any existing state.+where `<​state_name`>​ can be $kw[default] or the name of any existing state. This statement causes a state switch, interrupting execution of the current function or event.
  
-When a state switch statement is found, a $kw[return] statement is automatically inserted at that point in the code, and when the currently executed ​event finalizes, the state switch happens. This triggers two events: first, the $lev[state_exit] event for this state; then, the $lev[state_entry] event for the state changed to.+When a state switch statement is found, a $kw[return] statement is automatically inserted at that point in the code, and when the current ​event finalizes, if the state is NOT the current state, the state switch happens. This triggers two events: first, the $lev[state_exit] event for this state; then, the $lev[state_entry] event for the state changed to
 + 
 +A state switch statement that specifies the same state where it is executed, causes the interruption of the current event or function, but does not cause any other effects: neither the $ev[state_exit] nor the $ev[state_entry] events of the current state are executed.
  
 State statements aren't designed to be used within user-defined functions, only within events. It's possible to use state statements in user functions, but with caveats; see [[#hacks]] below. State statements aren't designed to be used within user-defined functions, only within events. It's possible to use state statements in user functions, but with caveats; see [[#hacks]] below.
Line 38: Line 42:
  
 ===== Notes ===== ===== Notes =====
-TODO: Talk about interaction of touch_start and switching states. 
  
-TODO: Talk about the event queue flush.+  * When the left mouse button is pressed in a state that has a $lev[touch/​] event ($lev[touch_start],​ $lev[touch] or $lev[touch_end]),​ and released in a state does not have a touch event, no other $ev[touch_start] event will be generated until the mouse is released in a state that has one of the touch events. This situation persists even after the script is reset. 
 +    * This happens most often when using $ev[touch_start] to change state, and the destination state does not have any touch events. The symptom is that a click is lost. For this reason, it's preferable to use $ev[touch_end] to change state instead of $ev[touch_start]. 
 +  * When changing state, most pending events are cleared from the event queue. This does not include pending responses for $ev[dataserver],​ $ev[http_response],​ $ev[object_rez],​ $ev[transaction_result],​ etc. events that haven'​t been enqueued yet: those may still be processed by the new state when they arrive. Additionally,​ on state change all listeners ($lfn[llListen]) are closed and all repeated sensors ($lfn[llSensorRepeat]) are stopped. $lev[Target/​] detectors ($lfn[llTarget],​ $lfn[llRotTarget]) are kept running. 
 +    * The case of $ev[timer] is special. If there'​s a running timer ($lfn[llSetTimerEvent]),​ it's not stopped by a state change. If there'​s a pending timer event (because of expiry of the timer period), and the current state does not have a $ev[timer] event itself, then that pending timer event won't be cleared by the state change, and will be executed in the new state. If the current state has a $ev[timer] event, however, the state change //will// clear it, without prejudice of the timer events that will be generated in the new state. 
 +  * Executing a state change to a state other than the current one within $ev[state_exit],​ causes the previous state switch to be cancelled, and the new state switch will generate another $ev[state_exit] event. This will cause an infinite loop unless the script is prepared to handle the situation. If the $ev[state_exit] event executes a switch to the current state, the previous state switch will still happen.
  
 ===== Examples ===== ===== Examples =====
Line 82: Line 89:
 ===== Hacks ===== ===== Hacks =====
  
-TODO+State switches are designed to be used only within event declarations. They work by signalling the state change and adding a $lkw[return] statement at the point where the state switch statement is. The signal is checked when the current event terminates. That creates the illusion that the state switch acts as an immediate jump to another state, stopping execution of the current code. 
 + 
 +This $kw[return] trick, however, does not work in user-defined functions, because it would return to the caller, rather that completely interrupting the currently running event. Since it doesn'​t work in these circumstances,​ it can't be properly supported in UDFs easily, and rather than adding the necessary complexity for adding proper support for it, LL chose to not support it in UDFs at all, and implemented a check in the compiler to ensure that there is no state switch statement within a user function. 
 + 
 +However, due to a bug, the check fails when the statement is somewhere within the block associated to: 
 + 
 +  * an $lkw[if] statement that has no $lkw[else] part, 
 +  * a $lkw[for] statement,​ 
 +  * a $lkw[while] statement,​ 
 +  * a $lkw[do] statement. 
 + 
 +thus allowing us to exploit that bug and use state statements even within user functions. 
 + 
 +For example: 
 + 
 +<code lsl2> 
 +my_function() 
 +
 +    // You can't use a switch statement here. 
 +    if (TRUE) 
 +    { 
 +        // You can use any statements here, including 
 +        // state switch statements. 
 +    } 
 +    // You can't use a switch statement here. 
 +
 +</​code>​ 
 + 
 +But note that, against normal expectations,​ this will //not// jump to the specified state directly. Keep in mind that it works by flagging the state switch and inserting a $kw[return] statement; this means that it will return to the caller of the function, which may be another function or an event. Only when the event within which these functions are executed terminates, will the $ev[state_exit] event execute, if it exists, and then the actual state switch will happen. 
 + 
 +To illustrate this, consider the following example: 
 + 
 +<code lsl2> 
 +my_function() 
 +
 +    if (TRUE) 
 +    { 
 +        state another; 
 +        llOwnerSay("​You can't see me"​);​ 
 +    } 
 +
 + 
 +default 
 +
 +    state_entry() 
 +    { 
 +        my_function();​ 
 +        llOwnerSay("​Oops,​ this is visible!"​);​ 
 +    } 
 +
 + 
 +state another 
 +
 +    state_entry() 
 +    { 
 +        llOwnerSay("​Yep,​ it changed state alright"​);​ 
 +    } 
 +
 +</​code>​ 
 + 
 +The output of that script will be "Oops, this is visible!"​ followed by "Yep, it changed state alright"​. The line that displays "You can't see me" isn't executed, because the state statement causes a return before reaching it. The line that displays "Oops, this is visible!",​ however, is executed when the function returns, therefore it will still be executed //after// the state switch statement. When the $ev[state_entry] event finishes, the system will notice that there'​s a state switch pending, and change to ''​state another''​. 
 + 
 +When using this hack, it's best to use it within a function that does not return any values. If the function returns a value, the outcome depends on the virtual machine used and on the type returned. 
 + 
 +Under $Mono, it will return the default value for the corresponding type, that is ''​0''​ for $ty[integer],​ ''​0.0''​ for $ty[float], ''""''​ for $ty[string],​ ''​(key)""''​ for $ty[key], ''​ZERO_VECTOR''​ for $ty[vector],​ ''​ZERO_ROTATION''​ for $ty[rotation] and ''​[]''​ for $ty[list]. 
 + 
 +Under $LSO, attempting to use the return value of a function that returns type $ty[string],​ $ty[key] or $ty[list] and executes a state switch, will cause a $err[Bounds Check Error] and the script will stop. If the return type is $ty[rotation],​ the returned value used will be ''<​0,​ 0, 0, 0>''​ (note that that's not the same as ZERO_ROTATION,​ which is ''<​0,​ 0, 0, 1>''​). For the remaining types, the value returned will be the same as in Mono. 
 + 
 +If two state switch statements are executed as a consequence of this hack (for example, one in a nested function, and one in the caller), only the last one takes effect, unless it's to the current state, in which case the previous one prevails.