Welcome to the Second Life Forums Archive

These forums are CLOSED. Please visit the new forums HERE

llDialog problems...

Strangel Bade
Omnomnomnivore
Join date: 27 Apr 2007
Posts: 231
07-14-2007 17:17
Okay, I have a basic script with two options--on and off.

The script works fine right after I save and then click on the item while wearing it, but if I detach and re-attach, the "OFF" function seems to break. I've tried adding in an llResetScript underneath the llDialog command, but it didn't make any difference.

I know I'm missing something very, very simple, but I have no idea yet what it might be.

Here's the code:

CODE

integer CHANNEL = 9999;
list MENU_MAIN = ["ON", "OFF"];

default {
state_entry() {
llListen(CHANNEL, "", NULL_KEY, "");
}

touch_start(integer total_number)
{
llDialog(llDetectedKey(0), "ON/OFF", MENU_MAIN, CHANNEL);
}

listen(integer channel, string name, key id, string message)
{
if (message == "ON") {
llSay(0, "This is the ON button...");////DEBUG
llTargetOmega(<-1,0,0>,PI,1.0);
llLoopSound("soundfile", 0.20);
}
else if
(message == "OFF") {
llSay(0, "This is the OFF");////DEBUG
llStopSound();
llTargetOmega(<0,0,0>,0,0);
}
}
}
Qie Niangao
Coin-operated
Join date: 24 May 2006
Posts: 7,138
07-14-2007 20:00
Had to get in-world to try this: the Off condition is reached, it just doesn't stop the spinning. I've encountered that before, and just decided that llTargetOmega(), among its many splendid eccentricities, is easily confused when used in attachments. I finally gave up on it for such uses and resorted to a bunch of slave scripts doing llSetRot or something like that, which is server-side and absurdly laggy, but works. There's a whole list of jira entries for llTargetOmega() but I wouldn't know how to make anything coherent of them for a developer to try to fix. (But maybe somebody else can make this work.)

One little comment on the script: I'd move the llListen() out of the state_entry handler, and into the touch_start, where you can be specific about listening just to llDetectedKey(0)... and then remove the handle returned by llListen, later, in the listen() event handler. Yes, it means opening and closing the channel, but it removes the listen between touches, as well as tightening the filter. It's listening on an obscure channel anyway, so this won't save much, but just a small tweak.

(By the way, as it is, anybody can touch this attachment, not only the owner, just in case that wasn't the intent.)
Strangel Bade
Omnomnomnivore
Join date: 27 Apr 2007
Posts: 231
07-23-2007 18:35
From: Qie Niangao
Had to get in-world to try this: the Off condition is reached, it just doesn't stop the spinning. I've encountered that before, and just decided that llTargetOmega(), among its many splendid eccentricities, is easily confused when used in attachments. I finally gave up on it for such uses and resorted to a bunch of slave scripts doing llSetRot or something like that, which is server-side and absurdly laggy, but works. There's a whole list of jira entries for llTargetOmega() but I wouldn't know how to make anything coherent of them for a developer to try to fix. (But maybe somebody else can make this work.)


*headdesk* So it's not just me, at least? Hm. I'd rather do it this way, but then again... I'd also rather it actually worked. *laugh* Beggers, choosers, all that jazz. I'll keep at it, and thanks for the notes--I'll adjust those bits, too.

Is there any way at all to stop this thing rotating using llDialog, though? In an attachment?
Learjeff Innis
musician & coder
Join date: 27 Nov 2006
Posts: 817
07-24-2007 06:01
From: Qie Niangao
One little comment on the script: I'd move the llListen() out of the state_entry handler, and into the touch_start, where you can be specific about listening just to llDetectedKey(0)... and then remove the handle returned by llListen, later, in the listen() event handler. Yes, it means opening and closing the channel, but it removes the listen between touches, as well as tightening the filter. It's listening on an obscure channel anyway, so this won't save much, but just a small tweak.


Qie, if we do that, don't we also need to use a timer to cancel the listen in case the toucher clicks the "ignore" button? Otherwise, you end up with lots of listens registered, which I suspect is worse than leaving a listen open on a relatively unused channel.

I would like to see some actual data showing the runtime costs for open listens on a specific channel.

And if it's a mistake that anyone can click the attachment (turning the wearer!), then

(a) the touch should ignore all but owner, and
(b) the listen should listen for owner only

In this case the listen is sufficiently restricted that I doubt whether installing a listen on touch is more efficient.
Learjeff Innis
musician & coder
Join date: 27 Nov 2006
Posts: 817
07-24-2007 06:04
BTW, since it works when it's just been reset, consider calling llResetScript() on rez (or perhaps, attach). Might be a workaround, if it's OK to always come up in the same state when you wear it.
Boss Spectre
Registered User
Join date: 5 Sep 2005
Posts: 229
07-24-2007 06:52
From: Learjeff Innis
Qie, if we do that, don't we also need to use a timer to cancel the listen in case the toucher clicks the "ignore" button? Otherwise, you end up with lots of listens registered, which I suspect is worse than leaving a listen open on a relatively unused channel.

Yes, I think a timer is prudent here. The timer can be removed as well, the first time it fires. I like to use a sensor as the timer, that way if they poof early the listen can be removed even sooner. In the case of an attachment this is not necessary.

From: Learjeff Innis
I would like to see some actual data showing the runtime costs for open listens on a specific channel.

I believe that depends on the volume of traffic on that channel. I'd randomize the channel to spread things out.

From: Learjeff Innis
And if it's a mistake that anyone can click the attachment (turning the wearer!), then

(a) the touch should ignore all but owner, and
(b) the listen should listen for owner only

In this case the listen is sufficiently restricted that I doubt whether installing a listen on touch is more efficient.

Maybe so, for one script. But multiply it by all the others making the same assumption. And I suspect it will spend more time idle than listening (especially with a timer). It's got to be more efficient to turn off a listen when you're not using it. This also will allow the script to listen for the current owner when touched, preventing the future problem of a new owner who hasn't reset the script, without the need to reset the script or install a changed() event. This allows the script to remember its "state" if needed.

As for the llTargetOmega not stopping, I find it works better to use a 0 in the rate instead of a 0 gain to stop it.

CODE

integer CHANNEL = -9999;
integer listen_handle;

list MENU_MAIN = ["ON", "OFF"];
float timeout = 60.0; // 60 seconds to respond to the dialog

string status = "OFF";

default {
state_entry() {
}

touch_start(integer count)
{
while (count--) {
key owner = llGetOwner();
if (llDetectedKey(count) == owner) {
CHANNEL = -9999 - (integer)llFrand(9999);
llListenRemove(listen_handle);
listen_handle = llListen(CHANNEL, "", owner, "");
llDialog(owner, "Current state = " + status + ".", MENU_MAIN, CHANNEL);
llSetTimerEvent(timeout);
}
}
}

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

listen(integer channel, string name, key id, string message) {
if (message == "ON") {
llOwnerSay("This is the ON button...");////DEBUG
llTargetOmega(<-1.0, 0.0, 0.0>, PI, 1.0);
llLoopSound("soundfile", 0.20);
}
else if
(message == "OFF") {
llOwnerSay("This is the OFF");////DEBUG
llStopSound();
llTargetOmega(<-1.0 ,0.0 ,0.0>, 0.0, 1.0);
}
status == message;
llListenRemove(listen_handle);
llSetTimerEvent(0.0);
}
}
Qie Niangao
Coin-operated
Join date: 24 May 2006
Posts: 7,138
07-24-2007 08:09
From: Boss Spectre
Yes, I think a timer is prudent here. ...As for the llTargetOmega not stopping, I find it works better to use a 0 in the rate instead of a 0 gain to stop it.
On the timer, yes, Boss and Learjet, quite right. And somewhere in recent posts to this forum there was a brief discussion about the rudeness of "hanging up the phone" with an llListenRemove() on an open dialog, just cuz a timer expired (which I do all the time), so in a simple case like this it probably would be better to just use a single llListen() and declare victory. (I probably obsess o'ermuch about listens anyway, given that half the avatars in world are wearing multiple attachments that wait on bated breath for their owner to utter "bling off" on channel 0. ;) )

And thanks, Boss, for the tip about 0 rate vs 0 gain--that just might help with some other llTargetOmega() "erratica" I've had, too.
Learjeff Innis
musician & coder
Join date: 27 Nov 2006
Posts: 817
07-24-2007 08:47
A scan to avoid a listen? I think that's counterproductive unless the object is rarely used, and it complicates the script more than is justified.

Without any hard data on the impact of various kinds of listens, though, it's a guessing game as to what's the most effective path, and your guess is as good as mine!

The cost of a listen on a channel without any chat is unknown, but I suspect it is very low, nearly zero.

I agree that using a negative random chat channel is best. Given there are 2G of these, the chances of a collision are vanishingly small, and leaving the listen open should cause no measurable lag. Plus, it's very simple, so the script is more efficient whenever it's actually used. Multiply that by the number of all such objects and I suspect it's a significant net gain.

I use something like this (not checked for syntax, so might have errors)

MenuChannel = 0 - (integer) llFrand(DEBUG_CHANNEL);

The zero may not be needed. At one time there was a parser bug involving unary negation, and might not even have applied to this case.

Simplest way to make this work is to put the statement above in the default state entry handler, and on rez, go to default state. Don't stay in the default state, always transition to another state right after entry. (If you're in default state and use "state default", it's a no-op, so copied objects would all continue to use the same channel.)
Learjeff Innis
musician & coder
Join date: 27 Nov 2006
Posts: 817
07-24-2007 09:19
I think this is simpler and more efficient, because I believe that the run-time cost of a listen on a channel with no chat is insignificant. With 2 billion channels, a collision is unlikely.

I modified the channel assignment a bit to remove the 1 in 2-billion chance of it winding up on channel zero.

CODE

integer CHANNEL;
list MENU_MAIN = ["ON", "OFF"];
string status = "OFF";


default
{
state_entry() {
CHANNEL = -1 - (integer) llFrand(DEBUG_CHANNEL-1);
state active;
}
}

state active
{
state_entry() {
llListen(CHANNEL, "", llGetOwner(), "");
}

touch_start(integer count)
{
key toucher = llDetectedKey(0);
if (toucher == llGetOwner()) {
llDialog(toucher, "Currently " + status, MENU_MAIN, CHANNEL);
}
}

listen(integer channel, string name, key id, string message) {
{
if (message == "ON") {
llOwnerSay("This is the ON button...");////DEBUG
llTargetOmega(<-1.0, 0.0, 0.0>, PI, 1.0);
llLoopSound("soundfile", 0.20);
} else if (message == "OFF") {
llOwnerSay("This is the OFF");////DEBUG
llStopSound();
llTargetOmega(<-1.0 ,0.0 ,0.0>, 0.0, 1.0);
}
status = message;
}

on_rez(integer arg) {
state default;
}
}
Boss Spectre
Registered User
Join date: 5 Sep 2005
Posts: 229
07-25-2007 00:11
A bit too efficient, I think, that isn't listening for anything at all. You'll need a state_entry for state "active" to start a listen:

state_entry() {
llListen(CHANNEL, "", llGetOwner(), "";);
}
Learjeff Innis
musician & coder
Join date: 27 Nov 2006
Posts: 817
07-25-2007 06:57
Haha, thanks! I did have that but must not have copied the latest version correctly. I've fixed it above.