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 1819 days.

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

Recommended Posts

Scripting is about solving problems. Syntax has surprisingly loose rules sometimes. What kind of code have you written that made you surprised that it even worked at all? (Or maybe it was just something you discovered by accident or never thought about before.)

I was inspired to post this because of something I was implementing. For context, I was trying to select the closest avatar within a sensor that was not in the same group as the object. The first line is what I originally did, and the lines after it are changes I made to it to see if I could shorten it without breaking anything. All of these lines are valid and have the exact same result.

integer i = -1; do { ++i; } while(llSameGroup(llDetectedKey(i)));

integer i = -1; do ++i; while(llSameGroup(llDetectedKey(i)));

integer i = -1; do; while(llSameGroup(llDetectedKey(++i)));

integer i = -1; while(llSameGroup(llDetectedKey(++i)));

// Final i is then used for other llDetected* functions.
Edited by Wulfie Reanimator
Link to comment
Share on other sites

I use many of the shortcuts that Void Singer and Strife Onizuka taught us  decade ago ( and have abandoned others ), but I don't consider them "hacks".  They are perfectly legitimate ways to shorten code.  For example, writing

if ( !~llListFindList(My_list, [ message ] ) )

instead of writing 

if ( llListFindList(My_list, [ message ] )  == -1 )

I consider scripting primarily as a logic challenge, so I am most pleased by those times when I have managed to solve a complex logic problem in a novel way.  One that I have always been quietly proud of is the multipage dialog code that I described in 

The heart of that short script is in one compact  for loop

// This bizarre test does the important work ......        
        for(b = gMenuPosition + len + Last - 1 ; (len < 12)&&(b < All); ++b)

that took me the better part of a day to work through.  There are loads of multipage dialog systems out there, but I've never found another that does it this way.

Edited by Rolig Loon
  • Like 1
Link to comment
Share on other sites

I wouldn't say I have clever hacks so much but

 

-Using a single variable for multiple flags-

integer c;
toggleBit(integer b){
    c=c^b;
}

toggleBit(0x01);
toggleBit(0x02);

if(c&0x01){....etc etc etc

 

-If I need to increment and check an if statement-

if((++ind)==llGetListLength(test))

 

-How I did a multi tap dash system without using a timer-

integer type;
integer timeNow;
integer timeCheck(){
    if((llGetUnixTime()-timeNow)>1){
        timeNow=llGetUnixTime();
        type=0;
        return 1;
    }
    return 0;
}

timeNow=llGetUnixTime();

control(key id, integer level, integer edge){
        integer press=level&edge;
        if(timeCheck()|press){
            type+=press;
            if(press&1&&type&2){
                llOwnerSay("Forward Dashing");
            }
            if(press&2&&type&4){
                llOwnerSay("Back Dashing");
            }
            if(press&260&&type&512){
                llOwnerSay("Left Dashing");
            }

...........etc etc etc 

 

-Long ass winded way thats in need of updating to multi timer with floats-

float timerA=2.0;
float timerB=3.3;
float timerC=7.0;

float decimalPlace(float d, integer p){
    string s=(string)d;
    s=llDeleteSubString(s,llSubStringIndex(s,".")+p,-1);
    return ((float)s);
}

float div(float a, float b){
    return a-b*llFloor(a/b);
}

timer(){
        //Timer A
        if(div(decimalPlace(llGetTime(),2),timerA)==0.0){
            llOwnerSay("TIMER A : "+(string)decimalPlace(llGetTime(),2));
        }

 

-Check for the first entry in a list that is 0-

while(llList2Integer(this,++tempInt)==0);

 

As I said not really hacks just random stuff I do with code to do the things I need to do

Link to comment
Share on other sites

None of them are hacks. They are just different ways to achieve the same result. The issue is whether one is more efficient than another, and whether it is stable. As for LSL syntax it was tightened up with mono and has been several times since. Simple things like nesting 'if' conditionals into relievent blocks rather than twenty lines. Understanding the difference of 'if' and 'else if' conditionals. Not using pointless functions like upper/lower case converstion in stored memory dialog script when it is intended for user created notecards and text messages.  List sorting etc'  Putting events in their priority order because some have higher priority than others. The miss usage of globals when locals are only needed. LSO used more memory with repeat variables, mono does not. The correct usage of listen filtering, the correct usage of targeted agent messaging and not blasting it to everyone with an irrelievent message that they will never see. Understanding that some functions have inbuilt delays etc etc. Many can even get their head around the fact that touch_start, touch and touch_end can be stated in the body of the script stacked and used for different things.

'if ( !~llListFindList(My_list, [ message ] ) )'  i use this, but whether it is more efficient than this ' if ( llListFindList(My_list, [ message ] )  == -1 ) ' is debatable.  Technically it should be more efficient, but SL does not behave in ways that seem logical. I doubt many even understand what this '!~' is even doing.

  • Like 1
Link to comment
Share on other sites

37 minutes ago, steph Arnott said:

None of them are hacks. They are just different ways to achieve the same result.

Quite right.  You said it more succinctly than I did.

13 hours ago, Rolig Loon said:

I use many of the shortcuts that Void Singer and Strife Onizuka taught us  decade ago ( and have abandoned others ), but I don't consider them "hacks".  They are perfectly legitimate ways to shorten code. 

The more scripts we write, the more we each adopt stylistic twists that match the way our brains approach logical challenges.  I doubt that most of us are really optimizing LSL code for bytecode efficiency or speed of execution.  I suspect that most scripters do what I do -- we reach into a toolbox of snippets that make sense to us.  There was some point in the dim past when I finally understood what !~ means, and it made more sense to me than writing == -1.  ( I actually know when that happened.  Dora Gustafson showed me. )  That's not a "hack."  It's my brain saying, "Wow! Now I understand what a bitwise operation means, and it makes more sense to me than visualizing list elements on some sort of a Mobius strip."  You know you are becoming a mature scripter when you have developed a distinctive coding style that matches the way that your own brain approaches logic.

  • Like 1
Link to comment
Share on other sites

It's been so long since i used this, i can't remember if i made it or not lol...

Non Sensor Range Checker:


integer range(vector vec1, vector vec2, float rng)
{  if( vec1.x >= (vec2.x - rng) 
       && vec1.x <= (vec2.x + rng) 
       && vec1.y >= (vec2.y - rng) 
       && vec1.y <= (vec2.y + rng) )
     return TRUE;
    else
     return FALSE;
}

vector target =  <175.0, 32.0, 3023.70508>; 
integer area = 5;  

default
{
    state_entry()
    { llSetTimerEvent(5.0);
    }
    touch_start(integer total_number)
    {
    }
    timer()
    {      
         vector pos = llGetPos();
         if( range( pos, target, area) ) 
         { llOwnerSay("In Range");
         }
         else
         {  llOwnerSay("Not In Range");
         }
    }
}

:P

Edited by Xiija
Reason for Edit: formatting !
  • Like 1
Link to comment
Share on other sites

16 hours ago, steph Arnott said:

None of them are hacks. They are just different ways to achieve the same result. 

The term "hack" has many meanings in different contexts. I was half-expecting someone to wander in and say something like "you can't hack anything with LSL!"

I use the term "hack" in this case to refer to code that does something particularly unusual. Something that doesn't look pretty or is hard to understand when you first read it.
While it is true that "hacks" are just another way to do something, the term usually has a negative connotation because hacks are often undesirable solutions.

Here are some additional examples of code I have written:

// Use a "nonzero" check to toggle another value.
integer multiplier = 3;
integer test = 3 * !!multiplier;
// test will be 3, not 9.
// Multiplier will be used as 1, not 3.
// If multiplier is 0, it stays 0.
// Clamp value with if-check
float test = 1.5;
if((test += 1.5) > 2.5) test = 2.5; // test will be 2.5 instead of 3.
// llList2* functions as ternary-operators
string greeting = llList2String(["Afternoon!", "Morning!"], (llGetGMTclock() / 3600) < 12);

And all together now, just as an example I came up now to illustrate all of these things in practice.

default
{
    state_entry()
    {
        integer score_threshold = 100;
        integer current_score = 95;
        integer current_multiplier = 2;

        integer score_gained = 5; // Final score being added before prize checking.

        integer final = llList2Integer([current_score * current_multiplier, 0],
                        (current_score += score_gained) > score_threshold); // condition

        llOwnerSay(llList2String([
            "Scored too high! Better luck next time!",
            "Your final score is: " + (string)final], !!final));
        // 95 + 5 = 100, not over threshold. The user wins the game with 190 points.
        // If score_gained is 10, the score threshold is exceeded and the user loses with 0 points.
    }
}

 

Or heck, this is some real code I'm using right now (in a timer):

05c830f88f.png

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

If X is greater than 0, decrease it until it is 0.

Else if X is lesser than 0, increase it until it is 0

'hacking' this then :)

default
{
    state_entry()
    {
         integer LOSS = 4;
         
         integer i;
         for (i = -8; i <= 8; i++)
         {
            integer x = i;
            x = (x - ((1 - (2 * (x < 0))) * LOSS)) * (x <= -LOSS || x >= LOSS);
    
            llSay(0, "i = " + (string)i + " x = " + (string)x);
        }
    }     
}

/* break down
   x = (x - ((1 - (2 * (x < 0))) * LOSS)) * (x <= -LOSS || x >= LOSS);
   
   TRUE = 1. FALSE = 0. LOSS = 4.
   
   (x < 0) 
      : when x is < 0 then (x < 0) = TRUE = 1.
      : when x is >= 0 then (x < 0) = FALSE = 0.
   (2 * (x < 0))
      : 2 * 1 = 2
      : 2 * 0 = 0
   (1 - (2 * (x < 0)))
      : 1 - 2 = -1
      : 1 - 0 =  1
   ((1 - (2 * (x < 0))) * LOSS)
      : -1 * LOSS = -4
      :  1 * LOSS =  4
   (x - ((1 - (2 * (x < 0))) * LOSS))
      : when x = -5...
      : -5 - -4  = -1
      : -4 - -4  -  0
      : -3 - -4  =  1
      : when x = 5...
      : 5 - 4 =  1
      : 4 - 4 =  0
      : 3 - 4 - -1
   (x <= -LOSS || x >= LOSS)
      : when (x <= -4 or  x >= 4) then = 1
      : when (x >  -4 and x  < 4) then = 0
      
   altogether:   
      : (-5 - -4 = -1) * (1) = -1
      : (-4 - -4 =  0) * (1) =  0
      : (-3 - -4 =  1) * (0) =  0
      : ( 0 - -4 = -4) * (0) =  0 
      : ( 3 -  4 = -1) * (0) =  0
      : ( 4 -  4 =  0) * (1) =  0
      : ( 5 -  4 =  1) * (1) =  1    
*/

 

  • Haha 1
Link to comment
Share on other sites

12 hours ago, Wulfie Reanimator said:

// llList2* functions as ternary-operators
string greeting = llList2String(["Afternoon!", "Morning!"], (llGetGMTclock() / 3600) < 12);

 

This is what first came to my mind for this thread, but I never would have come up with such a clear and concise label for it. I don't know when I started using this, but I do it all the time now, mostly to avoid a level of conditional and a repeat of the consequence (in this example an assignment).

I do, however, privately fret a bit about its efficiency: consing-up a list just to extract a singleton seems profligate, but so far I've been too lazy to test.

Link to comment
Share on other sites

Would rathe use

5 minutes ago, Qie Niangao said:

This is what first came to my mind for this thread, but I never would have come up with such a clear and concise label for it. I don't know when I started using this, but I do it all the time now, mostly to avoid a level of conditional and a repeat of the consequence (in this example an assignment).

I do, however, privately fret a bit about its efficiency: consing-up a list just to extract a singleton seems profligate, but so far I've been too lazy to test.

Would rather use

integer gAfternoon = 43200; 
integer gEvening   = 64800; 

string sayTimeOfDay()
{
	float timeOfDay = llGetWallclock();
	if(timeOfDay < gAfternoon) return "Good Morning!";
	else if (timeOfDay < gEvening) return "Good Afternoon!";
	else return "Good Evening!";
}

 

Link to comment
Share on other sites

30 minutes ago, Qie Niangao said:

This is what first came to my mind for this thread, but I never would have come up with such a clear and concise label for it. I don't know when I started using this, but I do it all the time now, mostly to avoid a level of conditional and a repeat of the consequence (in this example an assignment).

I do, however, privately fret a bit about its efficiency: consing-up a list just to extract a singleton seems profligate, but so far I've been too lazy to test.

"Ternary operator" (as opposed to unary or binary) is actually a real term in other programming languages, like the C family. The syntax is something like:

condition ? true : false

The LSL version's syntax in general is a little suspect. It's not necessarily less typing and it's definitely more memory-consuming. I can't say anything about its speed though. But it's not something you should worry about. If that line was the slowest part of your whole script, you've got literally nothing to worry about. (speed-wise)

Link to comment
Share on other sites

2 minutes ago, Wulfie Reanimator said:

"Ternary operator" (as opposed to unary or binary) is actually a real term in other programming languages, like the C family. The syntax is something like:


condition ? true : false

The LSL version's syntax in general is a little suspect. It's not necessarily less typing and it's definitely more memory-consuming. I can't say anything about its speed though. But it's not something you should worry about. If that line was the slowest part of your whole script, you've got literally nothing to worry about. (speed-wise)

Right, although now that I think about it, I sometimes select from a list with more options than 0 or 1, so that doesn't exactly fit the ternary operator form.

One place I use it often is constructing a big batch of parameters passed in to llSetLinkPrimitiveParamsFast(). It's either this approach or carrying around a bunch of conditionally-assigned local variables holding values to graft into the parameter list. In those cases it may have an advantage beyond mere aesthetics: conditionally assigning and then accessing all those variables wouldn't be free.

Link to comment
Share on other sites

34 minutes ago, Wulfie Reanimator said:

"Ternary operator" (as opposed to unary or binary) is actually a real term in other programming languages, like the C family. The syntax is something like:


condition ? true : false

 

But that is just basically an 'if else' conditional. Even in C it is weak currying. Well the way you have done it it is.

Link to comment
Share on other sites

I think you are missing the point of the thread Steph. It's not about whether or not something is better or worse than something else it's about posting random little hacks that YOU use to make your coding life easier. It's not about, yet again, proving that your options are somehow superior

  • Thanks 3
Link to comment
Share on other sites

There are all sorts of ways to compress familiar operations into a shorter form.  These don't necessarily save execution time or memory, but may at least save you time typing out things in longer form.  For example, conditional loops like

if ( x > 12)
{
    y = TRUE;
} 
else
{
    y = FALSE;
}

can easily be shortened to

y = ( x > 12 );

and

if (  llGetListLength(my_list)  == 0 )

can be written simply as 

if ( my_list == [] )

If you are a slow typist like me or simply prefer short forms for aesthetic reasons, some of those shortcuts can be appealing.  Admittedly, there are times when you can overdo shortening.  My friend and one-time mentor Void Singer, is famous for writing code that is almost impenetrable, like

integer vIntTtl = -~((~([] != gLstMnu)) / 10); //-- Total possible pages

In her defense, however, I will say that I learned an immense amount about LSL and about coding logic in general by being forced to unpack her code to see how it ticks. Also, as a lifetime puzzle aficionado, I love creating and solving intricate puzzles, just for their sheer beauty.  ;) 

  • Like 2
Link to comment
Share on other sites

8 minutes ago, ItHadToComeToThis said:

I think you are missing the point of the thread Steph. It's not about whether or not something is better or worse than something else it's about posting random little hacks that YOU use to make your coding life easier. It's not about, yet again, proving that your options are somehow superior

But that was not easier. It is actually terrible.

Link to comment
Share on other sites

9 minutes ago, steph Arnott said:

But that was not easier. It is actually terrible.

Quite possibly.  The point is that these "hacks" -- whatever we want to call them -- are personal stylistic oddities that we each use because they have meaning for us.  They might not work for anyone else, but they help us express a coding problem in a way that makes sense to us, a way that matches the quirky way our own mind works.  I rarely care whether a "hack" saves me time or makes my script "better".  It's just the way I choose to do things, like writing English sentences with way too many commas and parenthetical comments.  :)

Link to comment
Share on other sites

1 minute ago, Rolig Loon said:

Quite possibly.  The point is that these "hacks" -- whatever we want to call them -- are personal stylistic oddities that we each use because they have meaning for us.  They might not work for anyone else, but they help us express a coding problem in a way that makes sense to us, a way that matches the quirky way our own mind works.  I rarely care whether a "hack" saves me time or makes my script "better".  It's just the way I choose to do things, like writing English sentences with way too many commas and parenthetical comments.  :)

It is the list that is the issue. Also LSL does not evalute  cond ? a : b; the same as C. If a is logically FALSE it will cause odd behavior.

Link to comment
Share on other sites

12 minutes ago, steph Arnott said:

LSL does not evalute  cond ? a : b; the same as C. If a is logically FALSE it will cause odd behavior.

True.  That's one of the pitfalls that scripters can fall into if they try to apply tricks that worked well in a different language.  A lot of these personal oddities that we build into our scripts really only work in limited conditions.  Some of them only work because they take advantage of a strange feature of LSL.  It's dangerous to just pick up someone else's "hacks" and start applying them in your own coding until you truly understand why they work. 

To make a far-fetched analogy, it's like an American dropping uniquely British terms into conversation without understanding the cultural nuances behind them.  We can make embarrassing mistakes by assuming that we all use the language the same way.

  • Like 3
Link to comment
Share on other sites

non binary toggle...

integer x;
integer num = 9;
default
{
    state_entry()
    {
    }
    touch_start(integer total_number)
    {
        if( x=x^num )
        llOwnerSay("On: " + (string)x); // says ON: 9
        else
        llOwnerSay("Off: " + (string)x); // says Off: 0
    }
}

 

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

integer entry = llGetListLength(mylist);
while(entry--)
{
	if(<something>)
		mylist = llDeleteSubList(mylist,entry,entry);
}

The reverse while iterator, useful when you don't care about the looping order (since it's back to front) or when you are deleting entries since it won't cause re-indexing of the data for future iterations.

  • Like 1
Link to comment
Share on other sites

  • 2 weeks later...

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.)

Link to comment
Share on other sites

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