Welcome to the Second Life Forums Archive

These forums are CLOSED. Please visit the new forums HERE

Code Bounty: Fun w/ Rez Integers

Burke Prefect
Cafe Owner, Superhero
Join date: 29 Oct 2004
Posts: 2,785
11-21-2006 08:10
Sup?
Okay, so I'm looking down the pipeline of Stuff I Want To Make, and looking at pieces I'll need. One of them is using a rez integer as a bitfield and parsing that out.

Application: A multi-tool rezzer (like a utility belt) that saves settings of the tools it rezzes (that are usually temp_on_rez that self-attach to the right hand).
The belt rezzes the tool, and passes the settings via rez integer to save on chat lag. This is for simple preferences like on/off or 0/1/2/3/4, simple stuff.

What I know how to do:
Take preferences from the tool and store it in memory.
Stick the preferences into the rez integer.

What I don't know how to do:
Parse the rez integer and match each digit to a preference.
Like 013531 would be Safe,Single,Blister,Silencer,Scope,Laser,Pie

If you can shine any light on how to do that, I'll pay you L$1000.
_____________________
Stephen Zenith
Registered User
Join date: 15 May 2006
Posts: 1,029
11-21-2006 08:25
From: Burke Prefect
Sup?
Okay, so I'm looking down the pipeline of Stuff I Want To Make, and looking at pieces I'll need. One of them is using a rez integer as a bitfield and parsing that out.

Application: A multi-tool rezzer (like a utility belt) that saves settings of the tools it rezzes (that are usually temp_on_rez that self-attach to the right hand).
The belt rezzes the tool, and passes the settings via rez integer to save on chat lag. This is for simple preferences like on/off or 0/1/2/3/4, simple stuff.

What I know how to do:
Take preferences from the tool and store it in memory.
Stick the preferences into the rez integer.

What I don't know how to do:
Parse the rez integer and match each digit to a preference.
Like 013531 would be Safe,Single,Blister,Silencer,Scope,Laser,Pie

If you can shine any light on how to do that, I'll pay you L$1000.


Assuming the integer always has leading zeros, you could just convert it to a string and then use llGetSubString ().

A more robust way would be to repeatedly divide by 10 and take the remainder, that remainder being the preference. So for example:

013531 divided by 10 is 1353, remainder 1. The 1 is the last preference.
Then divide that by 10 again, giving 135 remainder 3. The 3 is the next preference.
Keep doing it for every flag you know about.

The benefit of this method is that it doesn't need leading zeros. I'm at work right now so not in a position to help you with actual code. If you still need help, im me in world.
Ordinal Malaprop
really very ordinary
Join date: 9 Sep 2005
Posts: 4,607
11-21-2006 09:15
If you're going to just use on/off flags you can use a bitfield, which has the advantage that it's (a) quick and (b) will already be familiar to you from other functions.

Basically, it's an integer with certain set flag values. You can set those up into global variables, e.g.
CODE
integer OPTION_SIGHT = 1;
integer OPTION_FLAMETHROWER = 2;
integer OPTION_SHIELD = 4;
integer OPTION_PIE = 8;
// doubling for each one

and then use them to construct the value of the integer to send:
CODE
llRezObject("thing", ...blah..., OPTION_SIGHT | OPTION_PIE);

and then use them in the object's code:
CODE
if (gOptions & OPTION_PIE) {
rez_pie();
}

Of course you'll have to declare them in both scripts and make sure they're the same. As I said this should be familiar syntax.

For a bitfield you can also use functions which will set or remove specific bits, something like:
CODE
// Sets the specified bit
integer set_bit(integer var, integer bit)
{
return (var | (integer)llPow(2.0, (float)bit));
}

// Unsets the specified bit
integer remove_bit(integer var, integer bit)
{
return (var & ~(integer)llPow(2.0, (float)bit));
}

// Returns the value of the specified bit
integer check_bit(integer var, integer bit)
{
integer bitval = (integer)llPow(2.0, (float)bit);
return ((var & bitval) == bitval);
}

default
{
state_entry()
{
integer n = 0;
llOwnerSay((integer)n);
n = set_bit(n, 5);
n = set_bit(n, 3);
llOwnerSay((integer)n); // should be 2^5 + 2^3 = 20
if (check_bit(n, 5)) {
llOwnerSay("Bit 5 is checked");
}
if (check_bit(n, 1)) {
llOwnerSay("Bit 5 is checked"); // which it shouldn't be
}
}
}

(above code not tested, I'm at work) which is perhaps more flexible, but not as nice to look at or intuitive for an LSL scripter to use.

If you need more than just on or off flags I'd say it was probably easier to read the integer as a string and use llSubString. Remember that it will probably have to be the same length each time so you should start the first option counting from 1, which will give you 0s in the other positions.
_____________________
http://ordinalmalaprop.com/forum/ - visit Ordinal's Scripting Colloquium for scripting discussion with actual working BBCode!

http://ordinalmalaprop.com/engine/ - An Engine Fit For My Proceeding, my Aethernet Journal

http://www.flickr.com/groups/slgriefbuild/ - Second Life Griefbuild Digest, pictures of horrible ad griefing and land spam, and the naming of names
Joannah Cramer
Registered User
Join date: 12 Apr 2006
Posts: 1,539
11-21-2006 09:19
From: Burke Prefect
If you can shine any light on how to do that, I'll pay you L$1000.

CODE

integer SCOPE = 1; // powers of 2
integer SILENCER = 2; // for each
integer LASER = 4; // of the
integer PIE = 8; // toggles

on_rez( integer Parameter ) {

if( Parameter & SCOPE ) show_scope();
if( Parameter & SILENCER ) show_silencer();
if( Parameter & LASER ) show_laser();
if( Parameter & PIE ) eat_pie();
}


edit: curse Ms.Malaprop and her nimble fingers... ;s
Newgate Ludd
Out of Chesse Error
Join date: 8 Apr 2005
Posts: 2,103
11-21-2006 09:25
I f you are actually using bit fields then its just a case of defining a set of constants and then combining then, either by addition or by ORing.

derefencing would be by AND'ing ,

Its exactly the same as we currently use for permissions etc.

CODE

integer const_SAFE = 0x0001;
integer const_LASER = 0x0002;
integer const_PLASMA = 0x0004;
integer const_GRENADE = 0x0008;
integer const_AUTO = 0x0010;
integer const_SILENCER = 0x1000;
integer const_SCOPE = 0x2000;

integer myvalue = const_ARMED + cosnt_LASER + const_SILENCER;

integer isSafe = (myvalue & cosnt_SAFE);
integer isLaser = (myvalue & cosnt_LASER);



EDIT: Curses Malaprop & Joannah
Jesse Barnett
500,000 scoville units
Join date: 21 May 2006
Posts: 4,160
11-21-2006 09:59
EDIT: Curse Joannah, Newgate and Ordinal. You didn't even leave me any scraps.

Burke, could you still send me $L1 for at least posting in your thread????????????
_____________________
I (who is a she not a he) reserve the right to exercise selective comprehension of the OP's question at anytime.
From: someone
I am still around, just no longer here. See you across the aisle. Hope LL burns in hell for archiving this forum
Stephen Zenith
Registered User
Join date: 15 May 2006
Posts: 1,029
11-21-2006 10:37
If you do actually need multiple values for a preference, ie not just an on/off setting, then the following will do the trick. It's based on my original comment, repeatedly dividing by 10 and looking at the remainder.

CODE

integer PREF_PIE = 0;
integer PREF_SIGHT = 1;
integer PREF_BARREL = 2;
integer PREF_BLISTER = 3;
integer PREF_REPEAT = 4;
integer PREF_SAFE = 5;

integer pie = 0;
integer sight = 0;
integer barrel = 0;
integer blister = 0;
integer repeat = 0;
integer safe = 0;


parsePrefs (integer prefs)
{
integer pos = 0;
integer value = 0;

while (prefs > 0)
{
value = prefs % 10;
prefs = prefs / 10;

if (pos == PREF_PIE)
{
llOwnerSay ("Pie preference is " + (string)value);
pie = value;
}
else if (pos == PREF_SIGHT)
{
llOwnerSay ("Sight type is " + (string)value);
sight = value;
}
else if (pos == PREF_BARREL)
{
llOwnerSay ("Barrel preference is " + (string)value);
barrel = value;
}
else if (pos == PREF_BLISTER)
{
llOwnerSay ("Blister preference is " + (string)value);
blister = value;
}
else if (pos == PREF_REPEAT)
{
llOwnerSay ("Repeat preference is " + (string)value);
repeat = value;
}
else if (pos == PREF_SAFE)
{
llOwnerSay ("Safe is " + (string)value);
safe = value;
}
++pos;
}

}


Obviously you don't need to set variables - you could call functions or append to a list, depending on how you want to use it. Just modify the relevant if blocks.
Nynthan Folsom
Registered User
Join date: 29 Aug 2006
Posts: 70
12-01-2006 23:46
You can pack and unpack non-binary values in bitfields without slow multiplication, division or modulo ops.

An integer has 32 bits and those bits can be isolated in any way you want.

So lets say you have 16 integer parameters (a thru p), all of which you can guarrantee will be between the values of 0 and 3 (inclusive). You can pack all 16 parameters into a single integer using bitfield operations. Here's how you'd pack them:

CODE
integer packed;
packed = ((a & 3) << 30) | ((b & 3) << 28) | ((c & 3) << 26) ... etc

((a & 3) << 30) basically masks out everything but the least significant 2 bits, and then shifts them up 30 bits into the highest 2 bit positions. ((b & 3) << 28) shifts the lowest 2 bits up 28 bits. Then when you OR the two values together, this packs them together in one integer.

In other words: the decimal value of 3 is equivalent to the binary value

00000000000000000000000000000011b

ANDing it with another integer will isolate the lowest two bits

CODE
    xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxb
AND 00000000000000000000000000000011b
---------------------------------------------------
000000000000000000000000000000xxb

Shift right by 30 bits to get

CODE
xx000000000000000000000000000000b

Repeat with the next value but this time shift right by 28 bits to get
CODE
00yy0000000000000000000000000000b

Then you OR the two results together to get
CODE
    xx000000000000000000000000000000b
OR 00yy0000000000000000000000000000b
--------------------------------------------------
xxyy0000000000000000000000000000b


You can then unpack them like this:

CODE
on_rez(integer packed)
{
a = ((packed >> 30) & 3);
b = ((packed >> 28) & 3);
c = ((packed >> 26) & 3);
// etc ...
}

You could even use a list and a loop to achieve this, although I suspect that unrolling the loop would in fact be faster and more memory efficient given what we know about list operations.

There is nothing to say that you can't use different sized bit fields if you have parameters that have other precision requirements.