Difference between revisions of "User:SuzannaLinn Resident/ScriptingClasses/Basics 1"

From Second Life Wiki
Jump to navigation Jump to search
Line 213: Line 213:
llOwnerSay needs a string as parameter, but some of the parameters are not of string type.
llOwnerSay needs a string as parameter, but some of the parameters are not of string type.


We can change one type to another with the name of the new type between parentheses before the name of the parameter, for instance:  (script)channel
We can change one type to another with the name of the new type between parentheses before the name of the parameter, for instance:  (string)channel


In line 14 we say the name, the text "has said" and the message, all in one llSay. We can add together several strings with the + sign.
In line 14 we say the name, the text "has said" and the message, all in one llSay. We can add together several strings with the + sign.

Revision as of 23:32, 11 October 2024

Basics 1

Monday class

Touch

-> Object 1 Touch (a red box) -> Script 1 Touch

Right-click your red box and edit it.

Go to the contents tab. There is a script there: "script 1 Touch".

Double-click the "script 1 Touch" to open it. We are going to look at it in detail.

Keep the script opened, and close the edit window.

There are several check boxes and buttons in the script windows. Let's look at them:

- Running. If it is checking the script is executing its code. Usually we will have it checked. Sometimes, if there is an error in the script, it gets unchecked automatically. If our script doesn't work at all, look at this box, perhaps the script is not running.

- Mono: it refers to the version of the scripting language. "Mono" is the modern version. It has more memory and it is faster. This option is kept for compatibility with the older scripts. We will always have "Mono" checked.

- Experiences: when it is checked, it means that we are using the script with an experience in the sim, if the sim has any experience configured. It allows more interactions with the avatars who have accepted the experience and with the environment. This is advanced scripting, for now we will leave it unchecked.

- "reset" button. This button stops the script, no matter what it is doing, and restarts it again. Touch the "reset" button to reset your script. It says "Hello, Avatar!".

- "save" button. To save the script. It will tell if our code is ok or tell us an error message.

Now we are going to look at the script.

It's the most basic script. It reacts to touches. Touch your red box and it says "Touched.".

In this script we want to know when somebody touches the box, and SL tells it to our script.

When there is a touch on the object, SL triggers an event in our script, and we can receive this event and do something, like saying "touched".

Think of an event as a heads-up that the script gets when something occurs to the object or around it, like when someone touches it.

These events are like signals that let us write code in our script to respond to different things, such as when users interact with the object, avatars move or chat, the environment changes, when timers reach a certain point, etc.... There are lots of events, around 40, and we'll be learning many of them in this course.

The name of the event that is triggered when our object is touched is "touch_start". We have it in our script in lines 7-10 (in the viewer with yellow background).

Events' names are always followed by parentheses, "(" and ")". They can be empty or have one or several values separated by commas.

These values are additional information that comes with the event. They are called "parameters".

touch_start has one parameter, called "total_number" and it is an integer number.

Each parameter has a "type", specifying the kind of information that the parameter can hold.

total_number is of type "integer", the type for whole numbers, positive or negative, without decimals.

The events, with their parameters in parentheses, are always followed by curly brackets, "{" and "}", containing our code to answer to the event.

Parentheses are used to know where our parameters start and end, and curly brackets are used to know where our code starts and ends.

In lines 2-5, state_entry is another event.

state_entry is triggered when the script starts (or after it is reset). Our script says "hello avatar" as we have seen after using the "reset" button.

Now let's look to the code inside the events, the lines with the messages that our red box is saying.

Both lines start with "llSay".

llSay is a function of the language.

Functions are predefined set of instructions that we can use in our code, they are built-in tools to perform specific tasks.

All the functions that the linden script language provides to us start with "ll" (2 letters "l" of linden).

The language has several hundreds of functions. We will be learning many of them along this course.

The function "llSay" is used to make the object say something in the public chat.

Functions, like events, are followed by their parameters between parentheses, or by empty parentheses if there are no parameters.

As we see in the script, llSay has two parameters, the first parameter is 0 in both cases, and the second parameter is the text to be said, enclosed in quotes, " and ".

The first parameter, the 0, is the channel. A "channel" is a way for different objects to communicate with each other, a line of communication agreed by both objects. We will use channels again in a while.

The channel 0 is a special channel that says the messages to the public chat.

It's a parameter of the type integer.

The second parameter is the text to be said.

We must write the text between quotes. This way we can use anyting in the message (like "()", "{}", names of events or functions...) and avoid confusions in the script.

This parameter is of another type, the type "string".

The type "string" can contain any kind of text, numbers, or symbols.

And at the end of each of both llSay() lines there is a semicolon, a ;.

The semicolon must be added at the end of each instruction of the block of code inside the curly brackets. It's used by the script to know when the instruction ends.

A new line is not enough, because we can write a long instruction in several lines. A instruction only ends at the semicolon.

And, summarizing, what are the differences between events and functions?

  • events are called by something happening outside the script.
  • functions are called by the script.
  • events send parameters to the script.
  • the script sends parameters to the function.
  • we write code in the script to answer to the events.
  • the function code is already written and it answers to the script.
  • events' parameters are written with its type and name (like integer total_number). We need a type and a name for each parameter to use them in our script.
  • functions' parameters are written with its value (like 0 or "message"). We send the values of the right types.

Events come to us. Functions go from us.

Let's look at the "default" keyword at the start.

"default" is the name of the section in the script where we place all the event, all enclosed between { and }.

When a script starts after a reset or after being modified, it look for this "default", and then for the event "state_entry" inside the default { }.

We must have a default { } in all our scripts.

It's possible to add other groups of events, with other names instead of default. They are called "states" and we will see them in future classes.

Now we can do some practices with our script.

For instance, edit the script and change the messages in the script to any other messages that you like.

Save the script using the "Save" button and touch the object.

We are getting plenty of messaging from all the red boxes. Let's do it a bit more quiet.

We will change the script to make that it says the message only to the owner of the object.

Instead of the function llSay( 0, "message" ) we will use the function llOwnerSay( "message" ).

llOwnerSay() sends the message to the object owner only. There is no way to send to a channel using this function, so it hasn't a parameter for the channel. llOwnerSay() has one parameter, the message,

Everything in the script (events, functions, parameters,...) is case sensitive. We must write it exactly with the right caps, otherwise we will get an error when saving. llOwnerSay() has the "O" and the "S" in caps.

Change llSay(0,... to llOwnerSay(... and save the script. If you get an error when saving that you can't solve, send the script to me.

Now you will see the messages from your red box only, because you are the owner of it.

You will also see the messages from your red box if someone else touches it, but the toucher will not see the messages. Try touching the cylinders of the students around you.

Touch with comments

-> Object 2 Touch with comments (a yellow tube) ->Script 2 Touch with comments

Now let's talk about a very important thing, commenting our scripts.

We will not only learn to script, but we will learn to script well, following good scripting practices.

And this includes adding comments to our scripts.

We can add a comment at the end of a line, or as a new line, always starting with a double slash, //.

The comments that you write in your script are firstly for yourself. To explain to yourself what the script does and how the script does it. They are meant to help you when you look to the script after some time to modify it, and also while you are writing a long script.

The comments will also help other scripters when you share your scripts.

The comments are not written for the teacher. But the teacher likes a lot to see your scripts and read your comments :)

You can write as many and as long comments as you want. They don't use script memory or any resources.

At the beginning, we will comment most of the lines. Later, we will not repeat the same comments to the same things that, by then, we will have scripted several times, and we will comment what is more important or new.

My suggestion is that later today or during this week, when you study the class notes that you will get at the end of the class, you add the comments to the script.

When you have the script commented, send it to me. It will help me a lot to follow your progress and to know what needs a better explanation.

In this script there is also another event, "on_rez".

"on_rez" is triggered when the object where the script is in is rezzed. Don't worry about the parameter start_param, is for more advanced uses and we will see it in the future.

llResetScript does, just that, resets the script. The same that the "Reset" button in the script window.

Everything is restarted and the event state_entry is called . Usually is good to do it to start clean in each rezzing. We will add this code in most of our scripts.

Listen

-> Object 3 Listen (a green cylinder) -> Script 3 Listen

Now our object is listening to what people tells, but in channel 3, not in public chat.

We could listen to the public chat, channel 0, but then it would be repeating everything that we say.

To write in a channel, type / and the number of the channel before your text, for instance: /3 I'm writing in channel three

When someones chats near our object, SL triggers the event "listen".

This event is a bit more complex than the event "touch", it has four parameters.

These are the parameters: listen( integer channel, string name, key id, string message )

  • channel: the number of the channel in which the message has been said.
  • name: the name of the avatar or the name of the object that has said the message.
  • id: the UUID of the avatar or the object that has said the message.
  • message: the message that has been said.

channel is of the type integer, name and message are of the type string. We already have seen and used these types before.

id is of the type "key". The type "key" is only for the UUIDs.

Keys has numbers, letters and "-"s, so we could use the type string for them. But in LSL script we will be using UUIDs (of people, objects, textures, etc) so often that there is a type for them alone.

The parameter "name", when the the message comes from an avatar, has the legacy name. Legacy names are the usernames in the format "firtname.lastname" or "name.resident".

In lines 9 to 12 we are saying to ourselves the values of the parameters.

llOwnerSay needs a string as parameter, but some of the parameters are not of string type.

We can change one type to another with the name of the new type between parentheses before the name of the parameter, for instance: (string)channel

In line 14 we say the name, the text "has said" and the message, all in one llSay. We can add together several strings with the + sign.

Now we have our event listen ready... but it's not enough for it to work.

The event listen differs from the events touch (and many other events). The problem is that there are more than 4 billions of possible channel numbers.

And the script can't be listening to all of them. So we need to tell to the script what channel or channels we want to listen to.

There is a LSL function to do it: llListen().

llListen() has the same 4 parameters that the event listen, in the same order. We must choose a channel, the first parameter, but we can leave the other 3 parameters empty, with "".

We can use these other 3 parameters, name, id or message, to listen only to a legacy name, or a UUID, or to a specific message.

This is a way to filter the messages to receive only the events with the messages that we are interested in.

If we want to use more than one channel, we will use a function llListen() for each channel.

We have the function llListen() in line 4. We are listening to the channel 3.

We use the function llListen in the event state_entry. This way we are listening since the script starts.

Listen and Touch

-> Object 4 Listen and Touch (a blue sphere) -> Script 4 Listen and Touch

Now we using both events, listen and touch_start, to say messages, but now saying the display name of the person.

We see another ll function: llGetDisplayName( id ).

But there is a difference between llGetDisplayName() and llSay() or llOwnerSay().

llSay() and llOwnerSay() do something: saying.

llGetDisplayName(), instead of doing something, returns us information.

In this case the display name of the avatar who has the UUID that we have given to the function as parameter.

The value returned is a string and we can add with "has said" and the message to say it.

In the event touch_start, to get the UUID of the toucher we use this function:

  • llDetectedKey(0)

llDetectedKey() has one parameter, the number of the toucher, starting with 0.

llDetectedKey(0) returns us the UUID of the first toucher.


Answers to questions

When are scripts "out of range"?

  • If we are editing a script and we take or delete the object where the script is in the title of the script shows the script name and (out of range). This script can't be saved, we will need to copy it and paste to the script in the object.

When are scripts saved with "running" unchecked?

  • "running" gets unchecked, if we save a script with errors, and then we close the script without solving the errors. The script is saved, with the "running" unchecked.

If we get an object that has a script running without the "Mono" checked, should we check it?

  • The old version, LSO, has some differences, and there are a few scripts that use these differences. So if you receive a script that works and has "Mono" not checked, dont touch it.

What are the LSL versions?

  • There are two LSL versions: LSO (the old one) and Mono (the new one)

Could we have the event state_entry with a parameter?

  • No, we can't change the parameters of the events. They are predefined and SL triggers the events with the predefined parameters.
  • We can't change the quantity or the type of the parameters, we can only change its names, if we like, but usually we always use the same names. Using the same names make the code in the event easier to read, since we already know what are the names of the parameters.
  • For instance, the event touch_start has one parameter, of type "integer", we can't change this. But we can use any name for the parameter, touch_start( integer suzanna ), is ok, but not recomended.

Events are the stimulus; functions are the response?

  • Events are the stimulus, and functions are the tools we use to respond to those events.

Must we always have a state_entry event, because the script automatically looks for that?

  • No, we can have scripts without state_entry. SL tirggers the event state_entry when a script starts, and if state_entry is not there, it does nothing.
  • But we must have a "default { }" group of events, or state, with at least one event in it (any event, state_entry or another).

Can avatars chat only on positive channels?

  • No, avatars can chat also on negative channels nowadays. This limitiation existed time ago. To chat in a negative channel type /- and the number of the (negative) channel.

How to listen to only one avatar?

  • using the parameter id with the UUID of the avatar: llListen(0,"","0f16c0e1-384e-4b5f-b7ce-886dda3bce41","");
  • or using the parameter name with the legacy name: llListen(0,"SuzannaLinn Resident","","");

If a script is listening and then saying, in the same channel, does that put the script in an endless loop of talking to itself and responding?

  • No, because the objects can't listen to themselves.


Wednesday class

Review

Let's start with a review of what we studied on Monday.


We studied 4 events:

  • state_entry( )
    • when the script starts (after a reset or after modifying and saving it).
    • we use it to initialize things at the start, like listening to a channel.
  • touch_start( integer total_number )
    • when an avatar touches the object where the script is in.
      • integer total_number: how many touches the object has received, we will use this parameter next week
  • listen( integer channel, string name, key id, string message )
    • when an avatar or an object says something in the channel.
      • integer channel: the number of the channel that the text has been said to.
      • string name: the name of the avatar or the object that has said the text.
      • key id: the UUID of the avatar or the object.
      • string message: the text that has been said.
  • on_rez( integer start_param )
    • when the object where the script is in is rezzed.
    • we can use it to reset the script.
      • integer start_param: thsi is used when a script rezzes other objects, we will use it later in the course.

Scripts stop running when they are derezzed and go on running when they are rezzed again.

They are not reset by taking the object to our inventory and rezzing it again.


And we studied 6 LL functions.

Let's look at them with their internal format, with their predefined types of the parameters. We will never write the type when we call the function, it's only to show you what the types are. Also, if the function returns a value, there is its type in front of the name.

  • llSay( integer channel, string msg )
    • says a message in the channel.
      • integer channel: the number of the channel where the text will be said to.
      • string msg: the text to say.
  • llOwnerSay( string msg )
    • says a message to the owner only.
      • string msg: the text to say.
  • llListen( integer channel, string name, key id, string msg )
    • starts to listen to a channel, it has the same parameters than the event listen.
      • integer channel: the number of the channel to listen.
      • string name: the name of the avatar or the object to listen.
      • key id: the UUID of the avatar or the object.
      • string message: the text to listen.
    • we must provide the channel number, the other parameters can be left empty, "".
    • to receive a message, it has to comply with all the parameters (if we use the name of an avatar and the key of another, we will never receive a message).
  • llResetScript( )
    • resets the script.
  • key llDetectedKey( integer number )
    • returns the UUID of the avatar that has touched the object.
      • integer number: the number 0 is the first toucher, we will use this parameter next week
  • string llGetDisplayName( key id )
    • returns the display name of the avatar.
      • key id: UUID of the avatar.


Practice

Now get your neurons and fingers ready, we are going to do a practice.

The practice has 3 different levels, choose the level that suits you best:

  • For beginner level:
    • rez to new objects.
    • add a new script to both objects.
    • write the script so when any of the objects is touched, the other object says that the first object has been touched
  • For intermediate level:
    • the same and, using scripting knowledge that we haven't seen in class yet:
    • keep track of who has touched the object and how many times.
    • say the touchers and how many times when the owner touches the object.
  • For advanced level:
    • the same and:
    • when the owner touches any of the objects, say all the touchers and total touches added, and sorted by touches from more to less


Answers to questions

How many channels are available?

  • All the possible values of an integer number, from −2,147,483,648 to +2,147,483,647. A total of 4,294,967,294. Or to remember it easily, 9 digits, positive or negative.

Are there dedicated channels?

  • Yes, there are a few dedicated channels:
    • Channel 0 for local chat (avoid that one in your scripts if you can).
    • Debug Channel, accessible in your scripts as DEBUG_CHANNEL = 0x7FFFFFFF.
  • There are also a number of unofficial common channels for things like RLV relays and so forth.
  • Good practices:
    • Reserve the smaller positive numbers for command channels from the users of the object.
    • Use really big random positive or negative numbers for your object communication.
    • Never depend on only your objects speaking or listening to any given channel.

Do I have to rezz the object to see the scripts inside it?

  • Yes, to open the scripts inside an object, the object must be rezzed. An object attached or attach as HUD is also rezzed.

How do we listen for anyone on a specific channel?

  • To listen to everyone we don't choose neither name nor id, leaving them empty: llListen( channel, "", "", "" );

When listening for a specific avatar or object, is it better to use the UUID or the name?

  • It's best to use their UUID. Using names is handy when you want to do something like listen to several objects that have the same name.

What does the function llListen do?

  • llListen starts listening to a channel (in the first parameter) and selects the messages that our script will receive based on the other 3 parameters. The script can't listen to all the channels, there are more than 4 million possible channels, so we need to choose what channels we want to listen to.

Have the people chatting to be in chat range of the object with the listen script?

  • Yes, we will receive messages said in chat up to 20 meters away of the center of the object where the script is in. Objects only listen up to 20 meters for normal chat, 10 meters for whispering and 100 meters for shouting.

Is there a way to make the range bigger?

  • No, we can't change the ranges. We can script repeaters or chat relays, but this will be a topic for a future class.

How is the event listen activated?

  • The event listen is activated when an avatar or an object says something to a channel that we are listening to.
  • We choose the events that we want to listen with the function llListen.
  • The events, listen, touch_start, etc , are always activated by something happening externally to the script.
  • We can listen to several channels, using the function llListen once for each channel, up to 64 channels.

Can a script listen to voice?

  • No, only to text chat.

Can we change the channel that we listen to when the script is running?

  • Yes, we can stop listening to a channel and start listening to another. We will see how to do it in a next class.
  • We can use llListen anywhere, not only in the event state_entry.

Can we write llListen("","","","Hello") to listen for hello in any channel?

  • No, we must always choose a channel. The first parameter can't be empty.

Is the even listen it always listen(integer channel,string name,key id,string message) ?

  • Yes, the quantity of parameters and their types is predefined an never exchange. We could change the name of the parameters.

Can I write listen(5,string name,key id,string message) ?

  • No, we can't use values in the parameters in the events, the values will be sent to us by SL when the event is triggered.

What the parameter start_param does in the event on_rez?

  • It is used for some advanced process related to scripts rezzing objects, we will see this parameter in a future class.

Can the parameters of an event be used elsewhere?

  • No, we can use the names of the parameters only inside the code of the event.

Can events communicate from one event to another event in the same script?

  • No, we can't call an event from another event.
  • Two events can't be executed at the same time. If, while the code of an event is running, another event arrives, the second event is queued to be executed when the first event finishes.

How can I know the UUID of my newly rezzed object?

  • Every object has a unique UUID, whenever we rez a copyable object it gets a new UUID.
  • We have the function llGetKey() that returns the UUID of the object where the script is in.

Is it possible to write a script that listens for the channel 0 and saves the conversations to a notecard (or somewhere else)?

  • Yes, but not to a notecard. LSL doesn't include facilities for notecard writing You would have to use Linkset Data or an external data storage. We will see how to do it in a future class.