Jump to content

Variables getting reset on inventory change


FridayAfternoon
 Share

You are about to reply to a thread that has been inactive for 70 days.

Please take a moment to consider if this thread is worth bumping.

Recommended Posts

I am pulling my hair out trying to figure out what is going on with a script I am working on. The script is in a HUD and it runs animations with some config settings read in from notecards. When the inventory changes the config cards get reread. I am trying to anticipate the case where a new card gets added with the HUD attached and the animations are running. I have a Boolean variable AnimationsRunning as well as a list of the running animations. I have no issues starting and stopping the animations using the routines I have written.

The idea is within the changed event I check these values and if animations are running I stop them, but what is happening is both the Boolean and list variables are getting reset to 0 when the inventory changes and I have no idea why. I have checked my code and the only places I change the AnimationsRunning variable is within the start and stop animations routines I’ve written. I don’t have anyplace where I might have stuck in a = instead of an == for comparison purposes …I just use if(AnimationsRunning)…

I’ve added debug statements to chat out the values of the variables and all is good up until the point where the inventory changes, and then those variables get reset. Is this normal? If so, I guess storing them in prim data would be the answer?
 

thanks to anyone who offers advice.
 

 

 

 

 

Link to comment
Share on other sites

2 minutes ago, FridayAfternoon said:

but what is happening is both the Boolean and list variables are getting reset to 0 when the inventory changes and I have no idea why.

If the variables are being defined (declared) within your changed() event or a user function, they will get reset every time the event or function is run.

You would need to define (declare) the variables outside of the default{} state, not within any function - then they would be global variables and only "reset" if the script is reset (or if you change the value in a function/event, etc).

 

  • Thanks 1
Link to comment
Share on other sites

7 minutes ago, FridayAfternoon said:

if animations are running I stop them,

It doesn't answer the wording of your problem, but perhaps a better way of going about it would be to use llGetAnimationList() to check which animations are running rather than a global variable. Or, you could just stop all the animations you may be running; AFAIK there is no penalty for stopping an animation that was never started.

Edited by Quistess Alpha
Link to comment
Share on other sites

 

32 minutes ago, Love Zhaoying said:

If the variables are being defined (declared) within your changed() event or a user function, they will get reset every time the event or function is run.

You would need to define (declare) the variables outside of the default{} state, not within any function - then they would be global variables and only "reset" if the script is reset (or if you change the value in a function/event, etc).

 

I should have clarified, the variables in question are Global variables.

 

29 minutes ago, Quistess Alpha said:

It doesn't answer the wording of your problem, but perhaps a better way of going about it would be to use llGetAnimationList() to check which animations are running rather than a global variable. Or, you could just stop all the animations you may be running; AFAIK there is no penalty for stopping an animation that was never started.

LlGetAnimationsList() returns UUIDs no, and I thing you need the animation name to stop it right?

stopping any which might be running I suppose is an option, very potentially could be an extremely long list though. I’ve gotten error messages before when trying to stop an animation when it wasn’t running, but I think that was actually because the animation didn’t exist. I suppose this can be my fall back option.

  • Like 1
Link to comment
Share on other sites

9 minutes ago, FridayAfternoon said:

I thing you need the animation name to stop it right?

llGetInventoryKey("animation name"); will give you the key of "animation name" if it's in the object's inventory, unless there are some permission issues I've forgotten about. You can in-fact start and stop an animation with its key rather than its name, but if you try and stop an animation with its key and it's neither a built-in animaiton nor in the prim's inventory, I think that makes a pop-up error.

Edited by Quistess Alpha
  • Like 1
Link to comment
Share on other sites

5 minutes ago, FridayAfternoon said:

I should have clarified, the variables in question are Global variables.

even with global variables, I think what Love's saying is that you might have accidentally done something like:

string name = "Bad Value";
default
{   state_entry()
    {   string name = "Good value"; // by writing 'string' at the begining of the line, we cause the global copy of name to not be written to.
    }
    touch_start(integer n)
    {   llSay(0,name); // will say 'bad value' because of error in state_entry()
    }
}

Which is allowed in LSL, but almost never intended.

  • Thanks 1
Link to comment
Share on other sites

I do appreciate the efforts at helping!

Hard to do a code snippet since the script is over 700 lines long, but:

AnimationsArePlaying is declared as a global variable

I've done a find on the variable and looked at every instance it's used in my code, and aside from inside debug statements where I am casting it to a string before chatting out it's value it's only set in two places (posted below). what's weird is the list of current animations is getting cleared too.

Because I couldn't figure it out I was thinking this must be some deal where if you update an item while it's attached it behaves weirdly. I think I'm going to just wait a few days and then look at it again, and if I still can't figure it out I'll get a list of the running animations and compare their UUID's with the one's in the HUD and stop them that way as Quistess suggested I could do.

 

 

PlayAnimations()
{
    debug("PlayAnimations()");
    integer i = 0;
    integer length = llGetListLength(CurrentAnimations);
    debug("CurrentAnimations list length = " + (string)length);
    if(!length)
    {
        say("No animations enabled, enable them using the item config menu.");
    }
    if(length)
    {
        do
        {
            llStartAnimation((string)CurrentAnimations[i] );
            PlayingAanimations[i] = (string)CurrentAnimations[i];
        }
        while(++i < length);
        AnimationsArePlaying = TRUE;
    }
    debug("PlayAnimations(): AnimationsAreplaying (0=false) after play = " + (string)AnimationsArePlaying);
}

and

StopAnimations()
//stops all playing animations
{
    debug("StopAnimations()");
    debug("StopAnimations(): AnimationsAreplaying (0=false) before stop = " + (string)AnimationsArePlaying);
    integer length = llGetListLength(PlayingAanimations);
    debug("from stop animations length of playing animations =" + (string)length);
    if(AnimationsArePlaying)
    {
        integer i = 0;
        integer length = llGetListLength(PlayingAanimations);
        if(length)
        {
            do{
                llStopAnimation((string)PlayingAanimations[i]);
            }
            while(++i < length);
        }
        AnimationsArePlaying = FALSE;
    }
    debug("StopAnimations(): AnimationsAreplaying (0=false) after stop = " + (string)AnimationsArePlaying);
}

 

Link to comment
Share on other sites

15 hours ago, FridayAfternoon said:

When the inventory changes the config cards get reread

The idea is within the changed event I check these values and if animations are running I stop them, but what is happening is both the Boolean and list variables are getting reset to 0 when the inventory changes

be best to begin debugging from the change event. Where in this event are the running animations stopped ? and where in this event are the config cards reread ? If the latter comes first then does the notecard reader set the global variables to 0 ?

 

Link to comment
Share on other sites

This has been mentioned, but a few things can likely occur:
 

  • Your global variable AnimationsArePlaying is set in the state_entry() or changed() events;
  • Your StopAnimations() function is called in the state_entry() or changed() events;
  • There is another function that changes AnimationsArePlaying, such as a function that collects the animations into the CurrentAnimations list

I think the third option is the most likely, but it's hard to guess without seeing your changed(), or state_entry() code.

Link to comment
Share on other sites

8 hours ago, elleevelyn said:

be best to begin debugging from the change event. Where in this event are the running animations stopped ? and where in this event are the config cards reread ? If the latter comes first then does the notecard reader set the global variables to 0 ?

 

 

2 hours ago, Bugs Larnia said:

This has been mentioned, but a few things can likely occur:
 

  • Your global variable AnimationsArePlaying is set in the state_entry() or changed() events;
  • Your StopAnimations() function is called in the state_entry() or changed() events;
  • There is another function that changes AnimationsArePlaying, such as a function that collects the animations into the CurrentAnimations list

I think the third option is the most likely, but it's hard to guess without seeing your changed(), or state_entry() code.

 Note home so can’t post code right now but in the changed event (as well as state_entry) I am first calling StopAnimations, then calling config. The stop animations is failing because somehow the variables have been reset. I was thinking could this be some multi-threading issue where config is running at same time and finishing first? Seems like it would wait for the first routine to finish before running the second, correct?
 

something just occurred to me, I’m actually reading the notecards from a different script, and it re-reads them on its own changed event, but it doesn’t send the info until the first script requests it and I put a timer in that script to allow the first one to run and finish. Maybe there’s something happening there. I will re-write that one so it doesn’t read the cards on changed, instead it re-Reads them only when requested by the first scripts config routine. I think maybe there’s something in this part of the flow messing me up.
 

 

 

 

  • Like 1
Link to comment
Share on other sites

1 hour ago, FridayAfternoon said:

 

 I was thinking could this be some multi-threading issue where config is running at same time and finishing first? Seems like it would wait for the first routine to finish before running the second, correct?
 

something just occurred to me, I’m actually reading the notecards from a different script, and it re-reads them on its own changed event, but it doesn’t send the info until the first script requests it and I put a timer in that script to allow the first one to run and finish. Maybe there’s something happening there. I will re-write that one so it doesn’t read the cards on changed, instead it re-Reads them only when requested by the first scripts config routine. I think maybe there’s something in this part of the flow messing me up.

on the first

you are correct that single script routines execute in order

on the second

coordinating multi-script flow can be a bit involved as events in the second script(s) occur independent of the first script (as you know). So I think your approach (have the first script change event trigger the notecard reader script) will help with the flow

the first script may tho have to wait till the notecard reader script has completed its task. Is a number ways to do this.  One way is to raise a flag accessible to both scripts (linkset_data / object description). The first script raising the flag, the notecard reader script lowering the flag on completion. The first script polling the flag til is lowered. Something like:

in first script

changed (integer change)
{
   if (change & CHANGED_INVENTORY)
   {

       ... stop animations

       ... raise flag  (linkset_data or object description)

       ... link message to notecard reader to start reading
       

       // wait for notecard reader to complete
       // or stop after some_quite_long_time to prevent the script going catatonic 
       // should the notecard reader script fail to complete
       float pause = llGetTime() + some_quite_long_time;
       while ((flag is raised) && (llGetTime() < pause))
       {
           llSleep(1.0); // .. this sleep helps prevent wait from over-thrashing
       }

       if (flag is raised) 
       {
           ... notecard reader script has failed to complete in some_quite_long_time
           ... do something about it
       }
       else
       {
           ... we are good to continue 
       }

       // ... potential catatonic wait method, avoid doing this
       // ... while (flag is raised);
    }
}

in notecard reader script

... on_read_complete, lower flag

 

  • Like 1
Link to comment
Share on other sites

I wanted to thank everyone for offering up help and suggestions, it lead me to explore different paths. I still haven’t figured it out though, lol. But..

I am going to re-write my code in a state oriented manner. Not just because I think it will help with issues like this, but because it will be a bit of a learning experience. 

High level I’ll have an AnimationsRunning state where I start them in state entry and stop them on state exit. And flow can go from there to config state on inventory change or stopped state from touch start. And after config it will transition to stopped.

im sure it won’t be quite so simple but the multi notecard reader script I am using is done that way so that should help me (and maybe I just pull that functionality into the main script at the same time.

speaking of that, is there an easy way to know what triggers an inventory change in terms of type of item so I can avoid re reading the notecards if the inventory change was caused by something else? 

Link to comment
Share on other sites

1 hour ago, FridayAfternoon said:

speaking of that, is there an easy way to know what triggers an inventory change in terms of type of item so I can avoid re reading the notecards if the inventory change was caused by something else? 

Not exactly, but I was going to suggest anyway: If a notecard changes, its key changes, so the changed() event can check the current notecard keys in inventory against their keys the last time they were read to determine which if any of them were responsible for triggering this particular changed() event.

(I'm generally skeptical of multi-state scripts unless there are advantages to having only some events active only some of the time—but as a learning experience, go for it!)

Edited by Qie Niangao
assorted typos
Link to comment
Share on other sites

21 minutes ago, Qie Niangao said:

(I'm generally skeptical of multi-state scripts unless there are advantages to having only some events active only some of the time—but as a learning experience, go for it!)

In all my years scripting LSL, I've found really almost zero reason why I really ever needed multiple states!

  • Like 1
Link to comment
Share on other sites

2 hours ago, Love Zhaoying said:

In all my years scripting LSL, I've found really almost zero reason why I really ever needed multiple states!

A few years ago I made a thing that needed a 'guided setup', there were like 5 different things the user needed to do (change permissions, set object description, input an email, etc.) that for the sake of clarity were asked of the user in-order. Implementing it with states for each step had a lot of duplicated code, but was rather easy to write and debug. a while later I had to re-write the system, and decided to use just 2 states (one for setup, and one for when it was running) to see the difference. and it turned out a lot messier, with a lot of checks on the 'state' global variable in each event, which just looked confusing.

Moral of the story I guess, is that states aren't useful most of the time, but when they make sense, they're incredibly useful if only for code clarity.

All the times I can think of using states have been some form of 'setup' state, where the script does things like requesting permissions and reading notecards, (IMO a separate setup state is best practice for anything requesting PERMISSION_DEBIT) and then a state for when it's operating normally. But any time something needs to have radically different reactions to events, states can offer a lot more clarity than global variable checks, even though almost everything a state change can do can be done without one*.

*moving from a state with a touch event to one without can "disable" the mouse hover over effect for an object. CLICK_ACTION_DISABLED might now have the same effect, the wiki doesn't say so though.

Edited by Quistess Alpha
  • Like 2
Link to comment
Share on other sites

13 hours ago, FridayAfternoon said:

 is there an easy way to know what triggers an inventory change in terms of type of item so I can avoid re reading the notecards if the inventory change was caused by something else? 

have a look at the wiki for changed event: https://wiki.secondlife.com/wiki/Changed

look at the first example and how to used the change parameter bitfield to section your code to deal with the different types of changes that can trigger the change event

Edited by elleevelyn
Link to comment
Share on other sites

20 hours ago, FridayAfternoon said:

is there an easy way to know what triggers an inventory change in terms of type of item so I can avoid re reading the notecards if the inventory change was caused by something else? 

store the inventory key of the notecard and check against it, roughly:

key kNC; // notecard's inventory key.
//...
changed(integer c)
{   if(c&CHANGED_INVENTORY)
    {  key k = llGetInventoryKey("Notecard Name")
       if(k!=kNC)
       {   kNC = k;
           handleNotecardRead = llGetNotecardLine("Notecard Name",0);
       }
    }
}

 

  • Like 1
Link to comment
Share on other sites

On 2/20/2024 at 1:07 PM, Quistess Alpha said:

even with global variables, I think what Love's saying is that you might have accidentally done something like:

string name = "Bad Value";
default
{   state_entry()
    {   string name = "Good value"; // by writing 'string' at the begining of the line, we cause the global copy of name to not be written to.
    }
    touch_start(integer n)
    {   llSay(0,name); // will say 'bad value' because of error in state_entry()
    }
}

Which is allowed in LSL, but almost never intended.

That’s what it ended up being, I had a local variable name clash with a global variable, it was just indirectly related so I didn’t see it until I refactored my code to be state oriented (which turned out pretty well although I am now seeing some instances where my HUD isn’t clickable even though I am in a state with touch-start event. Script reset fixes it. I‘ll figure it out :) 

Thanks again to everyone who offered advice, you guys are great.

 

 

 

 

  • Like 1
  • Thanks 1
Link to comment
Share on other sites

11 minutes ago, FridayAfternoon said:
On 2/20/2024 at 4:07 PM, Quistess Alpha said:

even with global variables, I think what Love's saying is that you might have accidentally done something like:

string name = "Bad Value";
default
{   state_entry()
    {   string name = "Good value"; // by writing 'string' at the begining of the line, we cause the global copy of name to not be written to.
    }
    touch_start(integer n)
    {   llSay(0,name); // will say 'bad value' because of error in state_entry()
    }
}

Which is allowed in LSL, but almost never intended.

Expand  

That’s what it ended up being, I had a local variable name clash with a global variable, it was just indirectly related so I didn’t see it until I refactored my code to be state oriented (which turned out pretty well although I am now seeing some instances where my HUD isn’t clickable even though I am in a state with touch-start event. Script reset fixes it. I‘ll figure it out :) 

Thanks again to everyone who offered advice, you guys are great.

Wow, I almost missed that my guess was right! 

YAY ME!!!

@FridayAfternoon, I originally almost asked if you could post more of your script so we could understand better.  We would have caught it for you then! (I realize posting a lot of your script is not always comfortable to do.)

Thanks,

Love

 

Link to comment
Share on other sites

You are about to reply to a thread that has been inactive for 70 days.

Please take a moment to consider if this thread is worth bumping.

Please sign in to comment

You will be able to leave a comment after signing in



Sign In Now
 Share

×
×
  • Create New...