Scripting Tutorial 02

From Osgrid Wiki
Jump to: navigation, search
   [12:08]  Fu Barr: last week we did an intro session, which when I think about it might have jumped the gun just slightly, so we're going to do a fast recap and them move forwards.
 [12:09]  abaddon Debevec: btw your ok ?
 [12:09]  Fu Barr: so here's the fast recap
 [12:09]  Fu Barr: 1. scripts live in the content tab of a prim
 [12:09]  Jeff Hall has entered shout range.
 [12:10]  Fu Barr: if it's a linkset it can live in any prim, but usually you'll be putting it into the root prim.
 [12:10]  Fu Barr: 2. we talked about states, events and event handlers
 [12:11]  Fu Barr: states are 'states' a script can be in. event are things like touch a prim, listen with a prim, move a prim
 [12:11]  Fu Barr: and event handlers are functions that 'take care of business' when events happen
 [12:11]  Fu Barr: 3. we talked a bit about functions
 [12:11]  Fu Barr: functinos are bits of code/script that 'do things'
 [12:12]  Fu Barr: and all functions have a 'signature' or 'parameter list'
 [12:12]  Fu Barr: there might be 'no parameters' or 5 parameters... it just depends on the function and the info it needs to do its thing
 [12:13]  Fu Barr: 4. there are lots and lots of functions.
 [12:13]  Fu Barr: the ones in LSL invented by linden lab start with ll
 [12:13]  Fu Barr: the ones added by opensim in OSSL start with os
 [12:13]  Fu Barr: and the OSSL functions need to be activated by the region owner
 [12:14]  Fu Barr: from what i remember that's more or less what we covered wrt concepts in the first class.
 [12:14]  Fu Barr: we also tried a little example of getting two prims to talk to each other
 [12:15]  Fu Barr: as an example of how functions work and I mentioned that the LSL wiki is your friend :)
 [12:15]  Fu Barr: so far so good
 [12:15]  Fu Barr: any questions that you guys bumped into when you spent the last week working on trying out the llListen() fn and the listen event *evil grin*
 [12:16]  Fu Barr: nope good then i shall continue with my dastardly plan of confusion and confumbulation!
 [12:16]  abaddon Debevec: hear hear
 [12:16]  Koni Lanzius: hehe
 [12:17]  Fu Barr: so today we're going to spend some time in a single prim messing with the notion of variables, global variables and 'state'
 [12:18]  Fu Barr: now, dont forget, the first thing to do when you rez your code prim is to change llSay() into llOwnerSay() - and dont forget to remove the 0 channel parameter - go , rez a prim and lets get the show on the road.

 [12:19]  Object: Script running
 [12:19]  Fu Barr: okay so this is what i have now:
 default {
  state_entry() {
  llOwnerSay("Script running quietly.");
  }
 }
 [12:19]  Fu Barr: you should all have something similar
 [12:19]  Primitive: Script running
 [12:19]  Object: Script running
 [12:19]  Fu Barr: now i;m going to add a new state....
 [12:20]  Fu Barr: like so:
  default {
  state_entry() 
  llOwnerSay("Script running quietly.");
  }
 }
  state new {
 }
 [12:21]  Fu Barr: i could have called the state something like 'theNewOne'
 [12:21]  Fu Barr: or 'verylongpointlessname'
 [12:21]  Fu Barr: i just called it 'new'
 [12:21]  Koni Lanzius: :)
 [12:21]  Fu Barr: now is you save your new script - nothing will happen
 [12:21]  Fu Barr: *if
 [12:21]  Fu Barr: or it will just give you your message
 [12:22]  Fu Barr: here's why
 [12:22]  Fu Barr: any script you put into a prim will automatically start the 'default' state
 [12:23]  Fu Barr: that why when you create a new script it doesn;t start with your Say(0, "some message); - but that stuff is wrapped in the default state boiler plate.
 [12:23]  Foxx Bode has entered shout range.
 [12:23]  Fu Barr: this is an important idea
 [12:23]  Fu Barr: because the coder - that's you lot
 [12:23]  Fu Barr: can CHANGE the state
 [12:23]  Fu Barr: like so:
 [12:24]  Fu Barr: pasting code:
 default {
 state_entry() {
 llOwnerSay("Script running quietly."); 
 state new;
  }
 }
 state new {
 }
 [12:24]  Fu Barr: the first 'state' is a function call to switch from the default state to the 'new' state.
 [12:24]  Fu Barr: the second 'state' is the boilerplate that will wrap the code of the 2nd state
 [12:25]  Fu Barr: now if you run this you'll get an error
 [12:25]  Fu Barr: is everybody getting an error?
 [12:25]  Jodi Dancer: yes
 [12:25]  You silently accept New Note from dan banner.
 [12:25]  Fu Barr: cool
 [12:26]  Fu Barr: now - who can guess/tell me why this 'syntax error' is appearing?
 [12:26]  Koni Lanzius: yes
 [12:26]  abaddon Debevec: same state name ?
 [12:26]  Fu Barr: nope
 [12:26]  Fu Barr: but good try
 [12:26]  Fu Barr: we're missing some boilerplate!
 [12:26]  Fu Barr: here's the 'working' code
 default {
  state_entry() {
  llOwnerSay("Script running quietly.");
  state new;
  }
 }
 state new {
 state_entry() {
  }
 }
 [12:27]  Fu Barr: see how the second state 'new' also need the 'state_entry()' stuff?
 [12:27]  Koni Lanzius: yes
 [12:27]  Fu Barr: that's because each state has it's own state_entry event handler
 [12:27]  Fu Barr: entering a state is an event
 [12:28]  Fu Barr: now i;m going to try and explain this with a metaphor
 [12:28]  Fu Barr: here we go
 [12:28]  Fu Barr: running a script is like entering a house
 [12:29]  Fu Barr: in our case it's a house with only one outside door
 [12:29]  Fu Barr: that door opens into a 'room' called 'default'
 [12:29]  Fu Barr: room in our case == state
 [12:29]  Fu Barr: but i can move from the default room into another room
 [12:30]  Fu Barr: in this example we moved from room default to room new
 [12:30]  Fu Barr: so what happens to the FLOW of your script....
 [12:30]  Fu Barr: 1. you enter the script, it move to the default room.
 [12:30]  Fu Barr: 2. the state_entry event is fired
 [12:30]  Fu Barr: 3. the functions and stuff in the state_entry event is executed
 [12:31]  Fu Barr: that means it does your llOwnerSay()
 [12:31]  Fu Barr: and then find the state new command - and moves to the next 'room' or state
 [12:31]  Fu Barr: once you enter the new state.... what happens?
 [12:32]  Fu Barr: well, it's a new state - so of course the state_entry event of _that_ state fires
 [12:32]  dan banner: mine has another llOwnerSay to tell me the state its in
 [12:32]  Fu Barr: yeah - we're getting to that dan :)
 [12:32]  Fu Barr: the point is that what you need to understand is that a script can be in one of many available 'states' or rooms
 [12:33]  Arielle.Delamerlibre @phaandoria.de:8002 is Online
 [12:33]  Fu Barr: and entering or exiting a state is in itself an event
 [12:33]  Fu Barr: and thus has an event handler
 [12:33]  Fu Barr: any questions so far?
 [12:33]  Fu Barr: there should be one
 [12:33]  Fu Barr: BIG one
 [12:33]  Fu Barr: lol
 [12:33]  Koni Lanzius: uhhh
 [12:33]  George Equus: big and small letter importance...
 [12:34]  Koni Lanzius: ohh
 [12:34]  Fu Barr: yea,, but on a more conceptual level george
 [12:34]  abaddon Debevec: how to get from ste to state
 [12:34]  George Equus: State new gave error but state new not
 [12:34]  abaddon Debevec: it set the event but then
 [12:34]  Fu Barr: well how to get from state to state is simple - you just call 'state theNextState'
 [12:35]  Fu Barr: no the real wuestion is - why do i need states at all
 [12:35]  Fu Barr: it just seems a little confusing
 [12:35]  Fu Barr: why cant i just write a long list of functions and boom the prim does it's thing
 [12:35]  abaddon Debevec: think states can keep the state in memory
 [12:36]  Fu Barr: well - you can. an MANY scripts do just that, but as your scripts get longer and more complicated it turns out that states are really good at helping you manage complexity of your code
 [12:36]  Fu Barr: so here's an example
 [12:36]  Fu Barr: no code just the underlying idea
 [12:37]  Fu Barr: say you have this brilliant idea of making a locking door
 [12:37]  Fu Barr: nobody has made such a thing evvah.
 [12:37]  Fu Barr: all new
 [12:37]  Fu Barr: so you start working on this
 [12:37]  Fu Barr: you cut your .375/.875 prim
 [12:37]  Fu Barr: you do all the fun studd make it look like a wooden castle door etc etc
 [12:38]  Fu Barr: then you start on the script
 [12:38]  Fu Barr: you find a line of code that makes the prim rotate on it's axis etc. all good.
 [12:38]  Fu Barr: but then you get to the locking part
 [12:38]  Fu Barr: how do you you keep track of the loked/unlocked position of the door?
 [12:39]  Fu Barr: well you could use a 'variable'
 [12:39]  Fu Barr: which is basically a little bag you can stick data in
 [12:39]  Fu Barr: you'd do something like 'locked = "yes"'
 [12:40]  Fu Barr: again - dont mind the systax etc. it's just about the idea
 [12:40]  Fu Barr: *syntax
 [12:40]  Fu Barr: but then you run into a problem
 [12:40]  Fu Barr: everytime somebody touches the door, youh ave to start testing
 [12:40]  Fu Barr: testing if the door is open or closed or locked
 [12:41]  Fu Barr: this starts to make you code very ugly
 [12:41]  Fu Barr: lots of if... then, and more if..then all one inside the next.
 [12:41]  Fu Barr: it'll start hurting your pixel head :(
 [12:41]  Fu Barr: so all of a sudden the lightbuld goes off
 [12:41]  Fu Barr: *bulb
 [12:42]  Fu Barr: you realise you can use state to keep track if everything in a much more sensible fashion
 [12:42]  Fu Barr: *of
 [12:42]  Koni Lanzius: ahh
 [12:42]  Fu Barr: so your default state is say 'closed'
 [12:42]  Fu Barr: then when the door is opened...
 [12:43]  Fu Barr: you switch to the 'open' state
 [12:43]  Fu Barr: all of a sudden no more testing - or much less testing
 [12:43]  Fu Barr: for example in the open state you dont need to test for 'locked' becuase... well 'duh'
 [12:43]  Fu Barr: it's open so obviously not locked
 [12:44]  Fu Barr: the notion of moving through various 'states' is very powerful
 [12:44]  Fu Barr: and will help you greatly when your scripts start to become 'interesting' - but also for simple stuff....
 [12:45]  Fu Barr: now, I'm going to modify the state switching script to move from one state to another when you click on the prim.... gimme 20 secs to write it...
 [12:47]  Fu Barr: right
 [12:47]  Fu Barr: have a look at this:
 default {
  state_entry() {
  llOwnerSay("default: Script running quietly.");
  }
   touch_end(integer num_detected) {
  state newThing;
  }
 }
 state newThing {
  state_entry() {
  llOwnerSay("newThing: new state entered safely.");
  }
  touch_end(integer num_detected) {
  state default;
  } 
 }
 [12:48]  Fu Barr: basically what this should now do is wiat for a click on the prim, then the thouch event gets fired.
 [12:49]  Fu Barr: if the prim is in the default state, the touch_end handler in THAT STATE is called and it switched to the other state.
 [12:49]  Object: Script running
 [12:49]  Fu Barr: the script is now the 'newThing' state, and fired the state_entry event
 [12:50]  Object: Script running
 [12:50]  Fu Barr: then it sit around waiting for a touch event, when that happens it goes back to the default state
 [12:50]  Object: Script running
 [12:50]  Fu Barr: in other words...
 [12:50]  Fu Barr: only HALF of this script is 'active'
 [12:50]  Fu Barr: and any given time
 [12:50]  Fu Barr: *at
 [12:51]  Fu Barr: if the prim is in the 'default' state then all that code is relevant... but the stuff for 'state newThing' is completely IGNORED
 [12:51]  Fu Barr: when the state switches.... etc. etc. etc.
 [12:51]  Fu Barr: so eventhough the code lives in the same scipt...
 [12:51]  Fu Barr: it's not always relevant....
 [12:52]  Fu Barr: what is important is the STATE the prim or linkset is in
 [12:52]  Fu Barr: so, any questions about the concept of state and how we go from one state to another and that each state will have it's own set of event handlers relevant to that state?
 [12:53]  Fu Barr: i'll give one more example just to try and make it all super clear
 [12:53]  abaddon Debevec: does naming states work ?
 [12:53]  Fu Barr: i dont understand your question
 [12:53]  abaddon Debevec: like if then state = bla bla
 [12:53]  Fu Barr: no
 [12:53]  Fu Barr: state is funcction call
 [12:54]  Fu Barr: you might see stuff like this:
 [12:54]  Fu Barr: if(player == "dead") { state gone_to_heaven; }
 [12:54]  Fernanda Abreu is Offline
 [12:54]  Fu Barr: there is no value assignment to state
 [12:55]  Fu Barr: you cant so state = blabla
 [12:55]  Fu Barr: *do
 [12:55]  Fu Barr: so back to my final state example stoey
 [12:55]  Fu Barr: story
 [12:55]  Fu Barr: so our door
 [12:55]  Fu Barr: we've discovered that havin an open and a closed state for the door is a good thing
 [12:56]  Fu Barr: two states nice
 [12:56]  Fu Barr: but... lets look at the events we need
 [12:56]  Fu Barr: in the open state it's all good.
 [12:56]  Fu Barr: the door is open so of course it's unlocked.
 [12:57]  Fu Barr: but in the closed state - we need to deal with the unlocking of the door
 [12:57]  Fu Barr: and i've deceded that this is a MAGIC door...
 [12:57]  Fu Barr: so no keys, but you have to say the right words to unlock it
 [12:57]  Fu Barr: so here's the new twist...
 [12:58]  Fu Barr: in the CLOSED state i need to setup the state in such a way that it listens on the public channel for the right phrase, and then when the listen event fires i need to make sure the event handler for the listen checks the phrase and unlocks the door when/if it's correct.
 [12:59]  Fu Barr: so in the closed state i need a listen, in the open state i really dont.
 [12:59]  Fu Barr: the idea being that each state is SEPERATE, and has to only deal with the events relevant to it.
 [13:00]  Fu Barr: that's really the core of states
 [13:00]  Fu Barr: no - any questions about states so far?
 [13:00]  Fu Barr: *so
 [13:00]  Fu Barr: seems not
 [13:00]  Fu Barr: nice!
 [13:00]  Fu Barr: so many shy people in the sandbox
 [13:00]  Fu Barr: *chuckle*
 [13:01]  abaddon Debevec: wonder where that BIG rock stay i wished for
 [13:01]  Koni Lanzius: heheh
 [13:01]  Fu Barr: okay so the one thing left to explain is how to deal with the elephant in the room
 [13:02]  Fu Barr: the elephant is - damn you fu, how do I get information i had in one state, into the other state.
 [13:02]  Fu Barr: you see in our door example the 'closed' state knew the status of the lock
 [13:02]  abaddon Debevec: nice line
 [13:02]  Jeff Hall: use global variables
 [13:02]  Fu Barr: but once the prim state moved to 'open'
 [13:03]  Fu Barr: all the date in the previous state is lost.
 [13:03]  Fu Barr: *data
 [13:03]  Fu Barr: and the simplest solution is as jeff mentioned, 'Global variables'
 [13:04]  Fu Barr: so to explain this - i;m going to post two versions of our simple script. the first one is the problem situation - the one where our information is not available to the second state. here we go:
 default {
 state_entry() {
 string locked = "YES";
 llOwnerSay("default: Script running quietly." + locked);
 }
 touch_end(integer num_detected) {
 state newThing;
  }
 }
 state newThing {
 state_entry() {
 llOwnerSay("newThing: new state entered safely.");
 }
 touch_end(integer num_detected) {
 state default;
   } 
  }
 [13:05]  Fu Barr: try running this in your cubes
 [13:05]  Fu Barr: it should work nice.
 [13:06]  Koni Lanzius: yep
 [13:06]  Fu Scripting class examples: Script running
 [13:06]  Fu Barr: i've left out the whole listen and opening logic as it's not needed to explain the point
 [13:06]  Object: Script running
 [13:06]  Fu Barr: now if you try and use the 'locked' value in state newThing - the whole things stats to go horribly wrong
 [13:07]  Fu Barr: it'll complain give you syntax errors etc. not good.
 [13:07]  Fu Barr: the reason is that the 'locked' variable is furniture if you will, that only exists in the default room
 [13:08]  Fu Barr: if you are in the newThing room, you cant open a drawer in the default room
 [13:08]  Fu Barr: you'd have to go back into the default room
 [13:08]  Fu Barr: but your in the newThing room
 [13:08]  Fu Barr: meddening
 [13:08]  Fu Barr: *maddening
 [13:09]  scripts3: Script running
 [13:09]  Fu Barr: so you need to stick the variable in a place that both room have 'access' to... if we stretch the house metaphor we'll stick the locked variable outside the house in the garden
 [13:09]  Fu Barr: and both room have a view into the garden and can 'see' the locked variable from there
 [13:09]  Fu Barr: this is what it would look like in code:
 [13:10]  Fu Scripting class examples: Script running
 string locked = "YES"
 default {
 state_entry() 
 llOwnerSay("default: Script running quietly." + locked);
 }
 touch_end(integer num_detected) {
 state newThing;
  }
  }
 state newThing {
 state_entry() {
 llOwnerSay("newThing: new state entered safely. + locked");
  }
  touch_end(integer num_detected) {
 state default;
  } 
 }
 [13:10]  Fu Barr: notice how in the code i've lifted the string declaration OUT OF THE STATE
 [13:11]  Fu Barr: the string locked = "YES";
 [13:11]  Fu Barr: part now lives in NO state.
 [13:11]  Fu Barr: it's ut in the 'garden'
 [13:11]  Fu Barr: *out
 [13:11]  Fu Barr: this is an important thing to understand - if something lives outside of a single state - it can be 'seen' from any state
 [13:12]  Fu Barr: now i;m going to add one more item to this script just to complete the ideas... we're going to fake the locking mechanism
 [13:13]  Fu Barr: here we go:
 string locked = "YES"
 default {
 state_entry() {
 llOwnerSay("default: Script running quietly." + locked)
 }
 touch_end(integer num_detected) {
 locked = "NO";
 state newThing;
 }
 }
 state newThing {
 state_entry() {
 llOwnerSay("newThing: new state entered safely. + locked");
 }
 touch_end(integer num_detected) {
 locked = "YES";
 state default;
  } 
 }
 [13:14]  Fu Scripting class examples: Script running
 [13:14]  Fu Barr: oops there's an error
 [13:14]  abaddon Debevec: lol not here
 [13:14]  Fu Barr: move the " in the second state llOwnerSay,
 [13:14]  Fu Barr: the line should be:
 [13:14]  Fu Barr: llOwnerSay("newThing: new state entered safely." + locked);
 [13:15]  Fu Barr: now it will YES/NO when you move through the two states
 [13:15]  Fu Barr: i trust you all understand what's happening here
 [13:15]  Jeff Hall: right
 [13:15]  Fu Barr: the states change the one grlobal variable
 [13:16]  Fu Barr: in the first state the variable is set to yes.
 [13:16]  Fu Barr: oopes no
 [13:16]  Fu Barr: and then when the new state is entered that value is shown
 [13:16]  Fu Barr: because it's stored in the global variable it has access too
 [13:16]  Fu Barr: -o
 [13:16]  Fu Barr: the variable inthe 'garden' so to speak
 [13:17]  Wizard Atazoth received your inventory offer.
 [13:17]  George Equus: Think I am with you Fu...
 [13:17]  Fu Barr: then when the touch event is handled in the second state, the lock is flipped... the locked value is set back to YES and when the default state is called.... and the state_entry handler fires.... hey presto - the global variable now shows 'YES'
 [13:18]  Fu Barr: so the two states both have access to the locked variable, and set it as is relevant and use it as is needed
 [13:18]  Fu Barr: that's how you share data between states
 [13:18]  Jeff Hall: global variables are a mus have
 [13:18]  Jeff Hall: *must
 [13:18]  Fu Barr: well, there's another more involved way of doing it
 [13:18]  Fu Barr: but best we keep that for another day :)
 [13:19]  Jeff Hall: read data i guess Fu?
 [13:19]  Fu Barr: actually there are several ways... but this will do for now :)
 [13:19]  Koni Lanzius: :)
 [13:19]  Jodi Dancer is Online
 [13:20]  Fu Barr: okay - i leave it to you guys as homework to actually add the listen part to our 'door'. don't bother with the rotation etc. just send me your versions of the scripts that has a listen event handler and 'works'
 [13:20]  Koni Lanzius: ;p
 [13:21]  Fu Barr: so the thing it needs to do is listen for a pass phrase, check if the pass phrase is correct, and if correct it should 'open' the door
 [13:21]  Fu Barr: send it to me say before 10am next saturday
 [13:22]  Fu Barr: that way i have time to have a look at the scripts
 [13:22]  abaddon Debevec: as note card ?
 [13:22]  Fu Barr: or as a script - just set perms so i can open it :)
 [13:22]  Koni Lanzius: ok
 [13:23]  abaddon Debevec: o do i :) lol
 [13:23]  Jeff Hall: dont send him as a print screen
 [13:23]  Koni Lanzius: hehe
 [13:23]  Fu Barr: if you want to add bells and whistles... be my guest but if i think you're an idiot - i will be merciless in class *Evil Grin*
 [13:23]  Koni Lanzius: eep
 [13:23]  Wizard Atazoth: lol
 [13:23]  Jeff Hall: no one is idiot here Fu
 [13:24]  abaddon Debevec: if reviever is FU then door = closed
 [13:24]  Fu Barr: OMG. Jeff have you SEEN some of the LSL out there... :)
 [13:24]  Koni Lanzius: hehe
 [13:24]  Jeff Hall: im talking about audience here
 [13:24]  Fu Barr: right - i have bored you all long enough. Thus endeth class nr. 2 of my scripting 101