Talk:Textbox2Hovertext

From Second Life Wiki
Jump to navigation Jump to search

Listeners:

As your llListen() always has the same arguments (same channel and filtering by owner only) each llListen will be assigned to the same listener handle. So there's no danger of accumulating open listens, and your timer code could be simplified to:-

<lsl>

   timer()
   {
       llListenRemove(listenhandle);
       llSetTimerEvent(0.0);
   }

</lsl>

Unless your object gets handed on to multiple subsequent owners :)

If you want anyone to be able to set the hover text, then you could preclude multiple open listeners by removing the listen at the start of the touch event. It doesn't matter if it's already been removed by the timer code (or has never been assigned):-

<lsl>

  touch_start(integer num)
   {
       llListenRemove(listenhandle);
       key target = llDetectedKey(0);
       llSetTimerEvent(30.0);
       listenhandle = llListen(1, "", target, "");
       llTextBox( target, "Set Hovertext", 1 );
   }

</lsl>

Omei Qunhua 07:01, 29 January 2013 (PST)

Owner vs Toucher

Actually I now see that there is confusion between toucher and the person who gets the textbox. The original code had this line:

<lsl>

       llTextBox( llDetectedKey(0), "Set Hovertext", (listenhandle = llListen(1, "", llGetOwner(), "")) );

</lsl>

Which sends a text box to the person who touched the object, but listens for a reply from the owner only (who is not necessarily the same person, or even online at the time). It also had the confusion between channel number and listener handle as Strife pointed out.

However Strife's revision still has problems in the version intended for owner use only, as it responds to anyone touching the object, but sends the textbox to, and listens to a reply from, the owner.

Better code for owner-only use would be:-

<lsl>

  touch_start(integer num)
   {
       key target = llDetectedKey(0);
       if (target != llGetOwner() )          // remove this 'if' and the 'return' to allow anyone to change the hover text
           return;
       llListenRemove(listenhandle);
       llSetTimerEvent(30.0);
       listenhandle = llListen(1, "", target, "");
       llTextBox( target, "Set Hovertext", 1 );
   }

</lsl>

Omei Qunhua 07:24, 29 January 2013 (PST)

I wanted to make as few changes as possible. As a bit of secret knowledge, listen handles are allocated incrementally, the first to be returned is 1. So even if the script did open multiple handles it would eventually clean them all up with the timer, nor would it clean them up too quickly (just way too slowly). I don't approve of that bit of cleverness, since it relies upon the allocation of listen handles (which I don't recall it ever being specified) but it works so I'm not going to spoil someone else's fun on their userpage. The script wastes CPU time and can run out of listens but again, not my call. You are correct, I forgot to make sure that if you set it to owner that only the owner's click would set it in motion. -- Strife (talk|contribs) 11:03, 29 January 2013 (PST)
Maybe it's one thing putting it on your own user page, but another thing to then link it from the Wiki script library, whose rules say "Your script must be tested and working. This is a list of working, usable scripts."  :)) Omei Qunhua 11:24, 29 January 2013 (PST)
It works exactly as intended: For owners http://community.secondlife.com/t5/LSL-Scripting/SCRIPTING/m-p/1819191#M15173 :) --Ackley Bing 10:28, 13 February 2013 (PST)
Good point. -- Strife (talk|contribs) 22:12, 29 January 2013 (PST)

Thank you for the feedback I really do appreciate it and have decided it's best to keep listening simple so that we don't debate here the best Listening practices i think that debate should be on a Listen page, not this one. This is really just a demonstration of llTextBox. --Ackley Bing 10:56, 13 February 2013 (PST)

Ackley, I felt it wasn't appropriate for me to edit your own script on your own page, but I was concerned about its errors, as you had linked it to an index of "working usable scripts". Hence I added an alternate example. You've now edited yours again, but it is still faulty. Sure, this is not a script to explain listeners, but the script does need to be correct in its handling of listens. May I ask, what is your understanding of what
llListenRemove(1);     
does? Omei Qunhua 15:58, 13 February 2013 (PST)
Why? It does exactly what its supposed to do which is to remove listen callback #1. What is it you really want to know?? --Ackley Bing 10:05, 14 February 2013 (PST)
Unfortunately, due to a quirk in the way listener numbers are allocated, llListenRemove(1), won't work. Your first listener will be #1. You then remove listener #1. BUT ... after the remove, the listen allocation process moves on to #2, and all subsequent listeners (in YOUR example), will be allocated #2 ... NOT number 1. You can test it yourself by putting llSay(0, (string) llListen(-12345, "", llGetOwner(), "") );. So after the first (successful) llListenRemove, your code fails to release any subsequent listener. It won't accumulate open listeners, it just never releases #2. And as for my definition of "faulty" scripts, I am happy to justify all my such descriptions. If a script doesn't compile, or gives wrong results at run-time, then it's faulty. Omei Qunhua 15:44, 14 February 2013 (PST)
Oh! Now I see what you mean. Whats the best way to remove these listens? And the script should remove the listen in case a person closes the textbox without typing anything in. --Ackley Bing 19:40, 15 February 2013 (PST)
-note: And we wonder why there's "bad" scripts in SL. ;) --Ackley Bing 19:55, 15 February 2013 (PST)

The correct approach is to save the listen handle returned by llListen() in a global integer variable, and use this handle in an llListenRemove() or llListenControl(). The shortest code for your owner-only script would do llListenRemove() within the timer code only, as this will catch the expired listener (eventually) whether or not the user responds positively to the textbox. The listener would always remain open for 30 seconds.

If the owner clicks the prim again WITHIN 30 SECS, as the llListen() parameters are identical to the existing still-open listener, llListen() will return that same old listener handle, so this won't result in an additional open listen.

<lsl> integer gListenHandle;

default {

   touch_start(integer num)
   {
       key user = llDetectedKey(0);
       if (user != llGetOwner() )        
           return;
       llSetTimerEvent(30);
       gListenHandle = llListen(-12345, "", user, "");
       llTextBox( user, "Set Hovertext", -12345 );
   }
   listen(integer channel, string name, key id, string message)
   {
       llSetText(message, <1, 1, 1>, 1);
   }
   timer()
   {
       llListenRemove(gListenHandle);
       llSetTimerEvent(0);
   }

} </lsl>

If you don't like the idea of always unnecessarily leaving the listener open for 30 seconds, then add llListenRemove(gListenHandle) in the listen event too.

((I've reduced the ByteCode size of the script by coding integers instead of floats wherever possible, such as llSetText(message, <1, 1, 1>, 1); No doubt some "purists" would object, but ByteCode space is often the most critical aspect of scripts. llSetText(message, <1, 1, 1>, 1) is 12 bytes shorter than llSetText(message, <1.0 ,1.0 ,1.0>, 1.0) in ByteCode)) Omei Qunhua 02:10, 16 February 2013 (PST)