LSL Style Guide

From Second Life Wiki
Revision as of 17:09, 6 September 2014 by Terk Resident (talk | contribs) (→‎User-Defined States: Nope. Actually fixing it now. Note to self - use show preview and don't just assume an edit fixed the issue.)
Jump to navigation Jump to search

Script Structure

LSL scripts are comprised of expressions, functions, statements, event handlers and states. The LSL compiler mandates a certain structure to scripts:


Global Variables

Global variables define and can contain data which can be written to or read from in multiple events and states within a script. Here's an example of a simple script which uses global variables to store information in a state_entry event and allow it to be used in a second touch event. <lsl> key ownerkey; //Here we start by defining a global variable by the name of "ownerkey" and specify that it stores a key (UUID)

string ownername; //Next we define another global variable which stores the username of the owner of the prim containing this script and specify it is storing a string

integer reportonchannel = 0; //In this case we are defining a global variable which stores the numerical channel we will be using later, but in this case we give it a value at the start. //As with the last 2, this can be written to but will revert to the specified value when the script is reset.


default { state_entry() //This event is triggered when entering the default state (When the script first runs or if moving to the default state from a user state) { ownerkey = llGetOwner(); //Stores the key of the owner of the prim containing this script to the "key ownerkey" global variable

ownername = llGetUsername(ownerkey); //Here we use that newly stored key to find the username of the account associated with the key in "key ownerkey" //Note that since we have already defined ownerkey and ownername as a key and string respectively, we do not need to specify what type of data they store, unlike local variables }

touch_start(integer num_detected) //This event is triggered when someone click the prim this script contains (If it's on click action is set to touch in the build floater) { string ownerkeyasastring = (string)ownerkey; //Let's prepare the key for use in a chat message. llSay requires strings but ownerkey is currently a string. //Note that this is an inefficent method of preparing data stored in a variable to another type of data. //Typically this would be done with typecasting in the intended function it is to be used in, but for the purpose of keeping this example easy to follow, I'll use this method.

llSay(reportonchannel,"I am owned by "+ownername+" and their UUID is "+ownerkeyasastring); //When clicked, the prim will speak on the channel specified in "integer reportonchannel" and say the information we found in the previous event. } } </lsl>

User Defined Functions

User defined functions follow imediatly after global variables in a script and before the default state. User Defined Functions allow for chunks of code that are repeated often throughout a script to be replaced with a one line function that acts in the same way as standard functions (Linden Library Functions). These are useful when you want to keep your script bloat to a minimum by only having to write that chunk a single time and substitute other instances of it with a single easy line throughout the script. Here's an example of our earlier script, this time making use of a custom function to replace the functions seen in our state_entry event. <lsl> key ownerkey; string ownername; integer reportonchannel = 0;

RetrieveOwnerData() //Here we create the user-defined function with the name "RetrieveOwnerData". { ownerkey = llGetOwner(); ownername = llGetUsername(ownerkey); //Notice how we took the contents of our earlier state_entry() and placed it in a function. //When the new function is called, this code will be ran. }


default { state_entry() { RetrieveOwnerData(); //Here we call the function just like we would a normal LL function. //Using a user-defined variable only once in a script is inefficient and shouldn't be used in place of just putting the code in normally if not being used multiple times. //As for the point at which you deem it necessary? That's personal preference, but personally I go with if I am repeating code 3 or more times in a script. }

touch_start(integer num_detected) { string ownerkeyasastring = (string)ownerkey; llSay(reportonchannel,"I am owned by "+ownername+" and their UUID is "+ownerkeyasastring); } } </lsl>

Default State

Next up we create our first state. This comes after user-defined functions and global variables. In LSL, a state refers to a the container of events that trigger functions in the script. A script when it first starts will always exist in the initial default state which is a prerequisite for any LSL script. Scripts can contain multiple states, but only one can be active at any one time and only events that are handled in the active state will trigger functions in the script. A state can only contain one of each (such as Touch_start or State_entry). See below for an example of a simple script which says hello when clicked for an example of the default state: <lsl> default //All LSL scripts must contain a state named "default" and this must be the first state defined in your script. { touch_start(integer num_detected) { llSay(0,"I was clicked! I'm in the default state!"); } } </lsl>

User-Defined States

Lastly, we include any additional states we want in a script. User-Defined states allow for multiple instances of an while effectively turning off other undesired events. It should be noted that in most cases, you would want to use conditionals or timers in place of a state but the occasional use still does show up time to time. Below is our previous script used in the default state example with a user-defined state added. <lsl> default { state_entry() //This event is triggered when we are entering from another state { llSay(0,"I have entered the default state!"); } touch_start(integer num_detected) { llSay(0,"I was clicked!"); state two; // This instructs the script to switch to "state two" and stop processing events in the default state. }

state_exit() //This event is triggered when we are changing to another state { llSay(0,"I am leaving the default state!"); } }

state two { state_entry() //This event is triggered when we are entering from another state { llSay(0,"I have entered state two!"); }

touch_start(integer num_detected) { llSay(0,"I was clicked! I'm in the second state!"); state default; // This instructs the script to switch back to the default state and stop processing events in "state two". }

state_exit() //This event is triggered when we are changing to another state { llSay(0,"I am leaving state two!"); } } </lsl>

Take great care when changing states in a script! Changing a state during an if or some loops can have adverse effects! Make sure to read up on states for more information.