Jump to content

Your best/worst "clever hack" in LSL


Wulfie Reanimator
 Share

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

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

Recommended Posts

46 minutes ago, Arduenn Schwartzman said:

Changing states only works from within an event, not from within a function, unless you prefix it with if(TRUE);


uYourFunction(){
  state other_state;
}

Will result in an error message. However,


uYourFunction(){
  if(TRUE)state other_state;
}

Will work. I think this unintended behavior or LL would not have bothered disallowing the first one. (And may therefore qualify as a hack.)

This is the kind of hack I was talking about in its truest form, lol.

Had to test it myself just to witness it. Apparently changing state from within a conditional is possible. (It doesn't have to be TRUE specifically. Any IF-check that evaluates to true allows this.) For example, this would work if the UUID was valid:

function(key uuid)
{
    if(uuid)
    {
        state test;
    }
}

However, "else if" or "else" does NOT allow changing state. You will get the expected "Global functions can't change state" error.

 

On another note, here's a fun fact about variables and scopes.

integer test = 3;

default
{
    state_entry()
    {
        test = 2;
        llOwnerSay( (string)test );

        {
            integer test = 3;
            llOwnerSay( (string)test );
        }

        llOwnerSay( (string)test );
    }
}

What do you think the the output is? Does this even compile?
Spoiler: It compiles just fine. You can nest new scopes without an IF or a function. (That's the point I'm making.)

The output is "2 3 2" because the second variable has a more local scope and it is discarded when execution leaves that scope. The global "test" variable (as well as any other non-global variable) is unaffected by more local scopes.

Edited by Wulfie Reanimator
  • Like 1
Link to comment
Share on other sites

On 4/27/2019 at 4:50 PM, Arduenn Schwartzman said:

Changing states only works from within an event, not from within a function, unless you prefix it with if(TRUE);


uYourFunction(){
  state other_state;
}

Will result in an error message. However,


uYourFunction(){
  if(TRUE)state other_state;
}

Will work. I think this unintended behavior or LL would not have bothered disallowing the first one. (And may therefore qualify as a hack.)

When I saw this I was quite pleased, if so would clean up a number of places where I've had to do some fancy stepping to change the state. As with @Wulfie Reanimator my first reaction was to go in-world and compile a simple script so that I could see it with my own eyes, and yep it did so. Later when sitting down to work on a customisation of my Home Control System, before putting this to use I thought to actually execute some code using this, just to be certain .. and have learned some interesting 'features' of this ... first I tried the code below:

integer gCounter = 0;

integer is_even(integer value)
{
    float fResult = value/2.0;
    integer result = (llFloor(fResult) == fResult);
    llOwnerSay("Result: " + (string)result);
    if (result){state even;}
    return result;
}

default
{
    touch_end(integer total_number)
    {
        if (!is_even(gCounter++)){state odd;}
    }
}

state even
{
    state_entry()
    {
        llOwnerSay("I'm Even!");
        state default;
    }
}

state odd
{
    state_entry()
    {
        llOwnerSay("I'm Odd!");
        state default;
    }
}

The results of this were not what I expected though:

[01:46] Wanda Soulstar: with state call in function
[01:46] Wanda Soulstar: -----------
[01:46] Object: Result: 1
[01:46] Object: I'm Odd!
[01:46] Object: Result: 0
[01:46] Object: I'm Odd!
[01:46] Object: Result: 1
[01:46] Object: I'm Odd!
[01:46] Object: Result: 0
[01:46] Object: I'm Odd!

I then changed the line on the return to touch_end to do an Owner Say instead of going to the odd state:

[02:07] Wanda Soulstar: with owner say instead of state
[02:07] Wanda Soulstar: -------------------
[02:07] Object: Result: 0
[02:07] Object: I am Odd
[02:08] Object: Result: 1
[02:08] Object: I am Odd
[02:08] Object: I'm Even!
[02:08] Object: Result: 0
[02:08] Object: I am Odd
[02:08] Object: Result: 1
[02:08] Object: I am Odd
[02:08] Object: I'm Even!

So what I was seeing here was that the function would return, and finishing the event that had made the call to the function before going into the state called in the function. And it looked that the return from the function, when there was a call to a state in it, was being set to the default value for the type of the function. I confirmed this by changing the return to a string (True/False) and in the instances where state even was called the return was always an Empty String (""). With the code I has was not certain if any code in the function was executed after the state even line .. so I modified my code to the below:

integer gCounter = 0;

string is_even(integer value)
{
    string sResult = "TRUE";
    float fResult = value/2.0;
    integer result = (llFloor(fResult) == fResult);
    llOwnerSay("Result: " + (string)result);
    if (result){state even;}
    
    if (result)
    {
        sResult = "True";
        llOwnerSay("Continue Even");
    } 
    else 
    {
        sResult = "False";
    }
    return sResult;
}

default
{
    touch_end(integer total_number)
    {
        string result = is_even(gCounter++);
        if (result == "False"){llOwnerSay("I am Odd");}
        llOwnerSay("Result in Touch: " + result);
    }
}

state even
{
    state_entry()
    {
        llOwnerSay("I'm Even!");
        state default;
    }
}

And ... the result:

[02:36] Wanda Soulstar: checking if function completes
[02:36] Wanda Soulstar: --------------
[02:36] Object: Result: 1
[02:36] Object: Result in Touch: 
[02:36] Object: I'm Even!
[02:37] Object: Result: 0
[02:37] Object: I am Odd
[02:37] Object: Result in Touch: False
[02:37] Object: Result: 1
[02:37] Object: Result in Touch: 
[02:37] Object: I'm Even!
[02:37] Object: Result: 0
[02:37] Object: I am Odd
[02:37] Object: Result in Touch: False

As you can see, when we call state even in the function it executes no further in the function and returns the default value for the function type.  So something that we need to be aware of when using state in a user-defined function/sub:

  • No code in the function will execute after the state is called .. but...
  • The event code after the call to the function with the state call will execute before the execution moves to the new state ..
  • If there is another state call in said code it will execute and ignore the one called in the function
  • If it is a function and not a sub, the return value when a state is called will be the default value for said type

AS this is a hack, not surprising that strange things happen, but as long as we know the boundaries, can be useful. Next time I'm inworld and have a moment would like to see what happens with nested calls to user functions, i.e. touch to function1 to function2 where the state call resides ... what gets executed and what does not ...

  • Thanks 1
Link to comment
Share on other sites

You are about to reply to a thread that has been inactive for 1837 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...