Don't click here unless you want to be banned.

LSL Wiki : FunctionStateChangeHack

HomePage :: PageIndex :: RecentChanges :: RecentlyCommented :: UserSettings :: You are crawl338.us.archive.org
To change state within a function, insert the state change statement within a conditional statment that always evaluates to TRUE.
For example:
stateChange() {
    state foo;
}

default {
    state_entry() {
        stateChange();
    }
}

state foo {
    state_entry() {
    }
}
The above doesn't compile, but the below does:
stateChange() {
    if (TRUE)
        state foo;
}

default {
    state_entry() {
        stateChange();
    }
}

state foo {
    state_entry() {
    }
}

Comparisons

Compared to a "normal" state change, there are no differences between changing states using the "state" statement, and changing states from within a function. The differences occur when viewing where, when and how code runs inside the function changing state.

When a function triggers a state change, it is popped off the stack (the state directive acts like a return statement). Any functions calling the function that changed state are allowed to complete, until focus returns to an event. After all code within the event finishes executing, then state changes normally.

The only difference occurs when comparing precedence of one state directive over another. An event's state change directive has precedence over a function's. That means, if an event executes the state change directive after a function does, the event's directive will be used. If a function executes a state change directive after another function does, then the first directive will be used. The same applies to two (or more) directives within an event; the first will take precedence over the others.

Examples of directive precedence differences:
default {
    state_entry() {
        state foo; // Only this one will work.
        state bar; // Ignored.
    }
}
// Pretend foo and bar are defined below...

changeState() {
    if (TRUE)
        state foo; // Ignored.
}

default {
    state_entry() {
        changeState();
        state bar; // Only this one will work.
    }
}
// Pretend foo and bar are defined below...

changeStateFoo() {
    if (TRUE)
        state foo; // Only this one will work.
}

changeStateBar() {
    changeStateFoo();
    if (TRUE)
        state bar; // Ignored.
}

default {
    state_entry() {
        changeStateBar();
    }
}
// Pretend foo and bar are defined below...

Adverse effects

When changing states from within functions, the main things to watch out for are return values.
string changeState() {
    if (TRUE)
        state foo;
    return "Hello";
}

default {
    state_entry() {
        string result = changeState();
    }
}
state foo {
    state_entry() {

    }
}
Calling changeState, because it returns a string, will trigger a run-time bounds check error. Returning a list triggers the same effect. The bounds check error results when you try to use the value returned from changeState (which we're doing in this case when we assign the result of the function to the variable 'result'). Because changeState changed state, this value does not exist, even though the SL script interpretor believes it should.

When changing state from within functions that return other types of variables, the function returns a null/zero value (0 for integers, 0.0 for floats, <0, 0, 0> for vectors and <0, 0, 0, 0> for rotations).

The point is: Never return a value from a function that changes state.

Hacks
There is no comment on this page. [Display comments/form]