02-06-2005 14:14
A post I just made in another thread reminded me of a technique I use often in LSL... But I haven't seen any posts talking about it. So, of course, I figured I'd share this with everyone to either use, or flame me about. :p

In LSL, we all know that sending messages between objects (either with MessageLinked() or llWhisper() calls) consumes a lot of time and resources. So it makes sense to use as few as possible.

Some mechanisms exist already for helping transfer data between objects - like the "start_param" in the on_rez() event. But this is just one parameter.

The same is true with actual llWhisper() calls as well - you only have 1 text string to pass information with.

There are ways, however, to "condense" information; and pass multiple parameters at the same time. These can be a bit tricky - but if you plan them out and implement them consistently, you can decrease memory usage and increase performance on your multi-object scripts!

The first, and most straight-foward way to "stack" parameters, is to combine several strings into 1 - for use in MessageLinked() and llWhisper() calls. The easy way to do this, is to concatenate your strings together with a "seperator" character; and then use the llParseString2List() function on the receiving end. I personally use the "pipe" character "|" a lot - its the "SHIFT" + "\" key-combination on most keyboards. Note that the comma is not usually a good seperator, since it is already used as a seperator inside vectors & rotations! This is also why I don't think that llList2CSV() should be used very often.

Take this example- which can pass many commands and parameters in 1 string:

CODE

//------------------------------------------------------
//Main Script Code Here:

SetSomeValues(integer listenChannel)
{
//These first lines are just making up some values to pass to an object
vector myPosition = <0.0, 0.0, 0.0>;
vector myColor = <1.0, 1.0, 1.0>; //White
vector eulerRotation = <0.0, 0.0, (90 * DEG_TO_RAD) >; //Rotate 90 degrees

//Set a color, a position, and a rotation all in one call:
llWhisper(listenChannel, "set_color|" + myColor + "|set_pos|" + myPosition +
"|set_rot|" + eulerRotation);
}

//------------------------------------------------------
//Receiving Object's Script Code Here:

vector g_myPosition;
vector g_myColor;
rotation g_myRotation;

listen(integer channel, string name, key id, string message)
{
//Convert our big string into a list of commands and values...
list parsedMessage = llParseString2List(message,["|"],[]);

integer i;

//Set up a loop to check all of the commands we were passed.
//Since the format is "command|value", we only need to check
//every 2nd entry, so "i += 2" is correct.
for(i = 0; i < llGetListLength(parsedMessage); i+= 2)
{
if(llList2String(parsedMessage, i) == "set_pos")
{
g_myPosition = llList2Vector(parsedMessage, i + 1);
}
else if(llList2String(parsedMessage, i) == "set_rot")
{
g_myRotation = llEuler2Rot(llList2Vector(parsedMessage, i + 1));
}
else if(llList2String(parsedMessage, i) == "set_color")
{
g_myColor = llList2Vector(parsedMessage, i + 1);
}
}
}


Note, however, that llWhisper() and its cousins are limited to 255 characters in length, for the string parameter! MessageLinked() does not have this restriction, as far as I know.

Strings can be complex, long, and time-consuming to parse. When you are passing simple data, it is a bit faster and easier to use small numbers to represent data - and then "stack" the numbers using addition and multiplication. Remember that with integers you can store numbers in the "1's" digit, the "10's" digit, and so forth - all the way up to the Billions!

For example, let's say I'm making a game; and I want to Rez a game-piece. I have the "start_param" to work with - but its only 1 integer. Somehow, I need to communicate the channel I want the piece to "listen" on, the piece's color, and the piece's location in the game-grid. There are 5 colors, so I can track that with a single digit. Since the game-grid is list of 100 spaces, the grid number will be between 0 and 99. If I make the "listen" channel evenly divisible by 1000, I can "stack" all 3 parameters into one value.

Here's how I'd go about doing that:

CODE

//Put this list into both object’s scripts, to track the colors:
//Colors are ordered: White, Red, Green, Blue, Black
list COLOR_LIST = [<1.0, 1.0, 1.0>,<1.0, 0.0, 0.0>,<0.0, 1.0, 0.0>,
<0.0, 0.0, 1.0>,<0.0, 0.0, 0.0>];

//------------------------------------------------------
//Main Script Code Here:

RezNextPiece()
{
//Randomly get a color index for the next piece.
integer pieceColor = llRound( llFrand( llGetListLength(COLOR_LIST) - 1 ) );

//Figure out what spot on the board this piece will be at.
integer pieceSpot = g_lastOpenSpace++;

//Set the listen channel. In real code, I would use a random num. for security…
integer listenChannel = 50000;

//Start Combining all numbers together… Doing this on multiple lines for clarity

//Since "listenChannel" only involves the "thousands" digits, it can be safely
//combined with "pieceSpot" without interfering with each other.
integer startParam = listenChannel + pieceSpot;

//Since “pieceSpot” is between 0 and 99, “listenChannel” is in the thousands,
//and “pieceColor” is a single digit; use the “hundreds” digit for the color…
startParam += (pieceColor * 100);

llRezObject(“Some Object”, somePosition, ZERO_VECTOR, someRotation, startParam);
}

//------------------------------------------------------
//Rezzed Object Script Code Here:

default()
{
on_rez(integer start_param)
{
//First break out the lowest digits – the “pieceSpot”
integer myPieceSpot = start_param % 100;

//Now remove that value from the parameter
start_param -= myPieceSpot;

//Repeat with the hundreds digit
integer myColor = start_param % 1000;

//Set the listen channel with the remaining value
integer listenChannel = start_param – myColor;
}
}


I hope these examples have helped you think about different ways to pass your data between objects and scripts. Just be sure to be careful and consistent, when you do so. Happy coding!

Take care,

--Noel "HB" Wade
(Tread Whiplash)