Control bug?
|
|
Haravikk Mistral
Registered User
Join date: 8 Oct 2005
Posts: 2,482
|
11-15-2006 16:42
Okay, here's a simplified version of my script: integer controlMask;
default { state_entry() { controlMask = CONTROL_UP | CONTROL_DOWN | CONTROL_FWD | CONTROL_BACK; llRequestPermissions(llGetOwner(), PERMISSION_TAKE_CONTROLS); } run_time_permissions(integer x) { llTakeControls(controlMask, TRUE, TRUE); } control(key id, integer held, integer change) { if ((held & CONTROL_UP) && (held & CONTROL_DOWN)) { change = change & held; if (change & CONTROL_FWD) llOwnerSay("Pressed forward"); else if (change & CONTROL_BACK) llOwnerSay("Pressed back"); } } } Hopefully I didn't make any mistakes in reproducing that. Basically, with llTakeControls set to accept 1 and pass-on 0, it works fine, but I want the controls to remain functional, so set it to 1 and 1, which does not work at all (control() is not triggered for anything). This is for an object that an avatar will sit on (ignore the fact my example doesn't handle that). Am I doing something wrong? Also, surely where I have: if ((held & CONTROL_UP) && (held & CONTROL_DOWN)) if I replaced it with: if (held & (CONTROL_UP | CONTROL_DOWN)) it should still work? But it doesn't, it will trigger for either UP or DOWN. Thanks for any help!
_____________________
Computer (Mac Pro): 2 x Quad Core 3.2ghz Xeon 10gb DDR2 800mhz FB-DIMMS 4 x 750gb, 32mb cache hard-drives (RAID-0/striped) NVidia GeForce 8800GT (512mb)
|
|
Ziggy Puff
Registered User
Join date: 15 Jul 2005
Posts: 1,143
|
11-15-2006 17:17
I can answer one part of this. An if() check only checks for true or false. And any non-zero value evaluates to true. So: if (held & (CONTROL_UP | CONTROL_DOWN)) Will be true if any of the two bits are set. What you want is: if (held & (CONTROL_UP | CONTROL_DOWN) == (CONTROL_UP | CONTROL_DOWN)) That checks to make sure both bits are set. In general, it's a good idea to do that for bitmask constants, because you don't always know that SOME_CONSTANT is a single bit.
|
|
Thanto Usitnov
Lord Byron wannabe
Join date: 4 Aug 2006
Posts: 68
|
11-15-2006 20:27
I'm confused. Why are you checking to see that up or down are being pressed as a condition of checking forward or backward? And why are you changing the value of change, a variable passsed through the event handler? If I had any idea what you were trying to do, I could tell you whether or not you're doing it right, but at the moment, I'm completely confused.
|
|
Haravikk Mistral
Registered User
Join date: 8 Oct 2005
Posts: 2,482
|
11-16-2006 01:52
The aim is to have a control system that ONLY works when page-up and page-down are both pressed (since they negate each other), this allows the keys to remain functional and should prevent commands being triggered by accident while the user moves the camera. Thus it will first check to see if page-up and page-down are pressed, if so it will then look to see what else is being pressed. For example, pretend this is for a levitating builder's chair. As a builder you want your keys to remain functional so you can reposition the camera, but the levitation could be controlled by holding page-up and page-down, then pressing up to move the chair up, or down to move down. The value of change is bitwise ANDed with held, this returns a number that represents only the controls that changed, and are being held down (this means they were pressed, since changed only occurs for a key when a key-press is different from before). The actual controls though aren't really the important part, it's the fact that llTakeControls() doesn't seem to work with both flags set to TRUE  From: Ziggy Puff In general, it's a good idea to do that for bitmask constants, because you don't always know that SOME_CONSTANT is a single bit. Ah, that won't work in my case then, thanks though! Here's me doing Computer Architecture and completely forgetting how a bitwise AND works 
_____________________
Computer (Mac Pro): 2 x Quad Core 3.2ghz Xeon 10gb DDR2 800mhz FB-DIMMS 4 x 750gb, 32mb cache hard-drives (RAID-0/striped) NVidia GeForce 8800GT (512mb)
|
|
Haravikk Mistral
Registered User
Join date: 8 Oct 2005
Posts: 2,482
|
11-16-2006 03:55
For anyone that wants to test this script, here's a slightly modified version that should just drop into a cube and work: integer controlMask; vector moveAmt = <0.0, 0.0, 0.2>;
default { state_entry() { controlMask = CONTROL_UP | CONTROL_DOWN; llSitTarget(<0.0, 0.0, 0.05>, ZERO_ROTATION); } changed(integer x) { if (x & CHANGED_LINK) { if (llAvatarOnSitTarget() != NULL_KEY) llRequestPermissions(llAvatarOnSitTarget(), PERMISSION_TAKE_CONTROLS); } } run_time_permissions(integer x) { if (x & PERMISSION_TAKE_CONTROLS) llTakeControls(controlMask, TRUE, TRUE); else if (llAvatarOnSitTarget() != NULL_KEY) llRequestPermissions(llAvatarOnSitTarget(), PERMISSION_TAKE_CONTROLS); } control(key id, integer held, integer change) { vector pos = llGetPos(); if (held & CONTROL_UP) pos += moveAmt; if (change & CONTROL_DOWN) pos -= moveAmt; llSetPos(pos); } } This script should just drop into a simple cube, reset it to be sure it set the sit-target correctly. Now just sit on the cube, it will take your controls, now when you press page-up, you should go up, and when you press page-down you will go down. Please note, I wrote the above from a uni lab where I can't access SL to be sure this works exactly, but it's simple enough that it should be fine. This is basically what I have in the script I'm working with, except it controls a few other things (which I disabled during my testing), the results I found were that it simply ignored user input, as though the settings were FALSE and TRUE (ignore input and pass-through), but it should not be doing this  If you get the same thing and change the llTakeControls flags to TRUE and FALSE (accept but don't pass-on) then it will work, but the controls won't do anything anymore.
_____________________
Computer (Mac Pro): 2 x Quad Core 3.2ghz Xeon 10gb DDR2 800mhz FB-DIMMS 4 x 750gb, 32mb cache hard-drives (RAID-0/striped) NVidia GeForce 8800GT (512mb)
|
|
Ziggy Puff
Registered User
Join date: 15 Jul 2005
Posts: 1,143
|
11-16-2006 08:25
Did you try sticking an llOwnerSay in the control handler to see if it's being triggered at all, and if it is, what values you're getting? I've used controls where the script gets them and they're passed on, and it's worked fine. Maybe there's a bug in what combination of controls you try to do that with.
|
|
Haravikk Mistral
Registered User
Join date: 8 Oct 2005
Posts: 2,482
|
11-16-2006 08:29
Try the script in my last post (just corrected the one tiny mistake). It works fine if you change llTakeControls(controlMask, TRUE, TRUE) to llTakeControls(controlMask, TRUE, FALSE), apart from the fact that of course now page-up and page-down don't tilt the camera as they should. It simply doesn't trigger AT ALL with both as TRUE.
If you have any scripts that use this, please try copy/pasting them into a new script and saving, see if they still work. Because this do not seem like correct behaviour at all.
_____________________
Computer (Mac Pro): 2 x Quad Core 3.2ghz Xeon 10gb DDR2 800mhz FB-DIMMS 4 x 750gb, 32mb cache hard-drives (RAID-0/striped) NVidia GeForce 8800GT (512mb)
|
|
Ziggy Puff
Registered User
Join date: 15 Jul 2005
Posts: 1,143
|
11-16-2006 09:33
I'll try it out tonight, can't get in-game until then. Though, here's an idea. I've seen odd camera behavior when sitting on sit-targetted prims. And I've used this function on attachments. So maybe there's something there, i.e. it works differently for the two cases *shrug*
|
|
Haravikk Mistral
Registered User
Join date: 8 Oct 2005
Posts: 2,482
|
11-16-2006 10:11
Hmm, it's possible, as when you are in sit mode by default the page-up/page-down keys don't do anything (you have to alt-click on something else first and then tilt the camera), but that doesn't give a reason for it not detecting it. Really it should still move the camera, but irrespective of camera behaviour a key-press is being ignored, I've bug-reported this though. It's really annoying though, I like the idea for the control system since IMO it's more intuitive, but if it won't work, bah 
_____________________
Computer (Mac Pro): 2 x Quad Core 3.2ghz Xeon 10gb DDR2 800mhz FB-DIMMS 4 x 750gb, 32mb cache hard-drives (RAID-0/striped) NVidia GeForce 8800GT (512mb)
|
|
Tiarnalalon Sismondi
Registered User
Join date: 1 Jun 2006
Posts: 402
|
11-17-2006 05:43
If someone has a hard-coded camera setting in the script that coded the sit target (most do) then the camera will be locked into position unless you move it manually off your AV.
Now I personally just use the mouse to move my camera...much more precise and intuitive, but that's just me.
If you want to still be able to control the camera with the keys plus then be able to use them to move the block as well..the easiest method would be to set a touch event to take controls, and then a repeated touch releases controls.
To free the camera, just put the camera offset commands in with zero vectors and rotations and just like with sittargets, this should change them back to the default (free camera)
|
|
Haravikk Mistral
Registered User
Join date: 8 Oct 2005
Posts: 2,482
|
11-17-2006 06:59
Thanks for the suggestion, but the object is touch to sit so that won't work for me. I'll just have to go with disabling page-up/page-down and using them, the thread is mainly just to find out if this is a universal bug or not.
Has anyone tried the script to be sure it's not just me, or maybe even a Mac specific control glitch?
_____________________
Computer (Mac Pro): 2 x Quad Core 3.2ghz Xeon 10gb DDR2 800mhz FB-DIMMS 4 x 750gb, 32mb cache hard-drives (RAID-0/striped) NVidia GeForce 8800GT (512mb)
|
|
Tiarnalalon Sismondi
Registered User
Join date: 1 Jun 2006
Posts: 402
|
11-17-2006 10:03
I don't think it's a bug or a mac issue. If there's a camera preset that was put in the seat (if your camera snaps into the same locked position after you sit, then this is the case) then the only way to move the camera would be to mouse it off yourself.
If there isn't a camera preset built in then there wouldn't be a 'snap' and you would be able to move the camera all around yourself using just the keys.
|
|
Haravikk Mistral
Registered User
Join date: 8 Oct 2005
Posts: 2,482
|
11-17-2006 10:15
I haven't touched the camera settings in any way though, unless you're suggesting there's one by default?
_____________________
Computer (Mac Pro): 2 x Quad Core 3.2ghz Xeon 10gb DDR2 800mhz FB-DIMMS 4 x 750gb, 32mb cache hard-drives (RAID-0/striped) NVidia GeForce 8800GT (512mb)
|
|
Tiarnalalon Sismondi
Registered User
Join date: 1 Jun 2006
Posts: 402
|
11-17-2006 12:10
There can be if you took the prim from something that had a preset sittarget and camera....things like this are persistent..meaning even if the script is taken out the settings will remain like a property of the prim itself I'm a bit lazy to look up the exact lines, but puttings something like llSetCameraAtOffset(ZERO_VECTOR); and llSetCameraEyeOffset(ZERO_VECTOR); in the state entry should clear any preset camera settings and put it back to free camera.
|
|
Haravikk Mistral
Registered User
Join date: 8 Oct 2005
Posts: 2,482
|
11-17-2006 12:45
Ah, no, the prims are newly rezzed. As I say, try it for yourself, rez a fresh cube, stick the script in my most recent script post into the cube and sit on it. The script is very simple, and just as simply doesn't work.
The thing I was referring to is that normal behaviour when sitting on an object is that the tilt (page-up/page-down) keys are ignored anyway, but you can still use the arrows to rotate and zoom, you have to alt-click before tilting works. However, if you take control of page-up/page-down with script and don't enable pass-through, then if you alt-click something then try to tilt the camera using page-up/page-down, it will reset your view.
_____________________
Computer (Mac Pro): 2 x Quad Core 3.2ghz Xeon 10gb DDR2 800mhz FB-DIMMS 4 x 750gb, 32mb cache hard-drives (RAID-0/striped) NVidia GeForce 8800GT (512mb)
|
|
Nynthan Folsom
Registered User
Join date: 29 Aug 2006
Posts: 70
|
12-02-2006 02:36
I've tested your code and can verify that setting pass_on to true seems to prevent CONTROL_ events from being generated when used with sit objects. However, I've also noticed that even when you set pass_on to false, you can still control the camera by holding down the option key (I'm on a Mac) and using the nav-keys: w, s, a, d, e, c as well as the up, down, left, right arrows and the page-up/down keys. Events are not generated when you hold down the option key, but when you release it, controls are restored to the script. I think that pass_on was intended for taking controls from attached objects (e.g. animation/walk overrides, weapons, etc). Here is a test script that reports the keys pressed. Even with pass_on set to true, events still are reported. integer sFlags = 0x33f; // CONTROL_FWD | CONTROL_BACK | CONTROL_ROT_LEFT | CONTROL_LEFT | CONTROL_ROT_RIGHT | CONTROL_RIGHT | CONTROL_UP | CONTROL_DOWN;
// If set to FALSE, your av will not receive control messages and will not move. // But regardless, the script will still receive events. integer sPassOn = TRUE;
default { state_entry() { if(llGetPermissions() & PERMISSION_TAKE_CONTROLS) { llTakeControls(sFlags, TRUE, sPassOn); } else { llRequestPermissions(llGetOwner(), PERMISSION_TAKE_CONTROLS); } } on_rez(integer iParam) { llResetScript(); } run_time_permissions(integer iPerms) { if(iPerms & PERMISSION_TAKE_CONTROLS) { llTakeControls(sFlags, TRUE, sPassOn); } } control(key iId, integer iDown, integer iChanged) { if(iDown & CONTROL_UP && iChanged & CONTROL_UP) { llOwnerSay("CONTROL_UP pressed"); } if(iDown & CONTROL_DOWN && iChanged & CONTROL_DOWN) { llOwnerSay("CONTROL_DOWN pressed"); } if(iDown & CONTROL_FWD && iChanged & CONTROL_FWD) { llOwnerSay("CONTROL_FWD pressed"); } if(iDown & CONTROL_BACK && iChanged & CONTROL_BACK) { llOwnerSay("CONTROL_BACK pressed"); } if(iDown & CONTROL_LEFT && iChanged & CONTROL_LEFT) { llOwnerSay("CONTROL_LEFT pressed"); } if(iDown & CONTROL_RIGHT && iChanged & CONTROL_RIGHT) { llOwnerSay("CONTROL_RIGHT pressed"); } if(iDown & CONTROL_ROT_LEFT && iChanged & CONTROL_ROT_LEFT) { llOwnerSay("CONTROL_ROT_LEFT pressed"); } if(iDown & CONTROL_ROT_RIGHT && iChanged & CONTROL_ROT_RIGHT) { llOwnerSay("CONTROL_ROT_RIGHT pressed"); } } } Interestingly, when you strafe left or right, (shift-a or shift-d), two key down events are generated. Can someone else verify that this is supposed to happen?
|
|
Strife Onizuka
Moonchild
Join date: 3 Mar 2004
Posts: 5,887
|
12-02-2006 04:39
From: Nynthan Folsom ...However, I've also noticed that even when you set pass_on to false, you can still control the camera by holding down the option key (I'm on a Mac) and using the nav-keys: w, s, a, d, e, c as well as the up, down, left, right arrows and the page-up/down keys. Events are not generated when you hold down the option key, but when you release it, controls are restored to the script.
I think that pass_on was intended for taking controls from attached objects (e.g. animation/walk overrides, weapons, etc). Here is a test script that reports the keys pressed. Even with pass_on set to true, events still are reported.
...
Interestingly, when you strafe left or right, (shift-a or shift-d), two key down events are generated. Can someone else verify that this is supposed to happen? 1) you are correct, when the user moves the camera via camera controls (option key on Mac or Alt on windows & linux?; or the camera controls window) the camera is not in the normal camera mode and subsequently is not under script control even if permission for such control have been granted (which is quite annoying if you want to know the camera position). 2) the pass_on is to stop avatar movement; it is intended to stop the bubbling of the movement event. 3)that does sound interesting. I'm not inworld at the moment would you mind testing with this script? You may have found a bug. The script below is a modified version of your script (and has been modified to be a bit easier to understand & give better debug info). integer sFlags = 0x33f; // CONTROL_FWD | CONTROL_BACK | CONTROL_ROT_LEFT | CONTROL_LEFT | CONTROL_ROT_RIGHT | CONTROL_RIGHT | CONTROL_UP | CONTROL_DOWN;
// If set to FALSE, your av will not receive control messages and will not move. // But regardless, the script will still receive events. integer sPassOn = TRUE; integer iEventCounter = 0;
default { state_entry() { if(llGetPermissions() & PERMISSION_TAKE_CONTROLS) { llTakeControls(sFlags, TRUE, sPassOn); } else { llRequestPermissions(llGetOwner(), PERMISSION_TAKE_CONTROLS); } } on_rez(integer iParam) { llResetScript(); } run_time_permissions(integer iPerms) { if(iPerms & PERMISSION_TAKE_CONTROLS) { llTakeControls(sFlags, TRUE, sPassOn); } } control(key iId, integer iDown, integer iChanged) { integer iStart = iChanged & iDown;//just started being held down // integer iEnded = iChanged & ~iDown;//just ended being held down string sCount = (string)(++iEventCounter); if(CONTROL_UP & iStart) { llOwnerSay(sCount + ": CONTROL_UP pressed"); } if(CONTROL_DOWN & iStart) { llOwnerSay(sCount + ": CONTROL_DOWN pressed"); } if(CONTROL_FWD & iStart) { llOwnerSay(sCount + ": CONTROL_FWD pressed"); } if(CONTROL_BACK & iStart) { llOwnerSay(sCount + ": CONTROL_BACK pressed"); } if(CONTROL_LEFT & iStart) { llOwnerSay(sCount + ": CONTROL_LEFT pressed"); } if(CONTROL_RIGHT & iStart) { llOwnerSay(sCount + ": CONTROL_RIGHT pressed"); } if(CONTROL_ROT_LEFT & iStart) { llOwnerSay(sCount + ": CONTROL_ROT_LEFT pressed"); } if(CONTROL_ROT_RIGHT & iStart) { llOwnerSay(sCount + ": CONTROL_ROT_RIGHT pressed"); } } }
_____________________
Truth is a river that is always splitting up into arms that reunite. Islanded between the arms, the inhabitants argue for a lifetime as to which is the main river. - Cyril Connolly
Without the political will to find common ground, the continual friction of tactic and counter tactic, only creates suspicion and hatred and vengeance, and perpetuates the cycle of violence. - James Nachtwey
|
|
Haravikk Mistral
Registered User
Join date: 8 Oct 2005
Posts: 2,482
|
12-02-2006 05:16
From: Nynthan Folsom I've tested your code and can verify that setting pass_on to true seems to prevent CONTROL_ events from being generated when used with sit objects. However, I've also noticed that even when you set pass_on to false, you can still control the camera by holding down the option key (I'm on a Mac) and using the nav-keys: w, s, a, d, e, c as well as the up, down, left, right arrows and the page-up/down keys. Events are not generated when you hold down the option key, but when you release it, controls are restored to the script.
I think that pass_on was intended for taking controls from attached objects (e.g. animation/walk overrides, weapons, etc). Here is a test script that reports the keys pressed. Even with pass_on set to true, events still are reported. Ah, thanks for the info! I really wish LL would better document things, because to me "pass on" has no relevance whatsoever to movement of an avatar rather than the camera. And I didn't know that holding alt allowed you to move the camera, all these hidden or not obvious features =(
_____________________
Computer (Mac Pro): 2 x Quad Core 3.2ghz Xeon 10gb DDR2 800mhz FB-DIMMS 4 x 750gb, 32mb cache hard-drives (RAID-0/striped) NVidia GeForce 8800GT (512mb)
|
|
Strife Onizuka
Moonchild
Join date: 3 Mar 2004
Posts: 5,887
|
12-02-2006 08:44
From: Haravikk Mistral Ah, thanks for the info! I really wish LL would better document things, because to me "pass on" has no relevance whatsoever to movement of an avatar rather than the camera. And I didn't know that holding alt allowed you to move the camera, all these hidden or not obvious features =( Someone skipped the Orientation Island Tutorials 
_____________________
Truth is a river that is always splitting up into arms that reunite. Islanded between the arms, the inhabitants argue for a lifetime as to which is the main river. - Cyril Connolly
Without the political will to find common ground, the continual friction of tactic and counter tactic, only creates suspicion and hatred and vengeance, and perpetuates the cycle of violence. - James Nachtwey
|
|
Haravikk Mistral
Registered User
Join date: 8 Oct 2005
Posts: 2,482
|
12-02-2006 09:40
Well I signed up with the referral program so didn't go via Orientation Island, but still, when you hit alt you get a zoom/focus icon, to me that doesn't imply I can now use my keys to change camera without affecting anything else.
_____________________
Computer (Mac Pro): 2 x Quad Core 3.2ghz Xeon 10gb DDR2 800mhz FB-DIMMS 4 x 750gb, 32mb cache hard-drives (RAID-0/striped) NVidia GeForce 8800GT (512mb)
|
|
Strife Onizuka
Moonchild
Join date: 3 Mar 2004
Posts: 5,887
|
12-02-2006 10:01
From: Haravikk Mistral ...when you hit alt you get a zoom/focus icon, to me that doesn't imply I can now use my keys to change camera without affecting anything else. A very good point. (Since you missed the OI, you may want to look up a few places that have the OI content; you might find other bits of instruction you missed & would be useful)
_____________________
Truth is a river that is always splitting up into arms that reunite. Islanded between the arms, the inhabitants argue for a lifetime as to which is the main river. - Cyril Connolly
Without the political will to find common ground, the continual friction of tactic and counter tactic, only creates suspicion and hatred and vengeance, and perpetuates the cycle of violence. - James Nachtwey
|
|
Tyken Hightower
Automagical
Join date: 15 Feb 2006
Posts: 472
|
12-02-2006 10:43
From: Ziggy Puff I can answer one part of this. An if() check only checks for true or false. And any non-zero value evaluates to true. So: if (held & (CONTROL_UP | CONTROL_DOWN)) Will be true if any of the two bits are set. What you want is: if (held & (CONTROL_UP | CONTROL_DOWN) == (CONTROL_UP | CONTROL_DOWN)) That checks to make sure both bits are set. In general, it's a good idea to do that for bitmask constants, because you don't always know that SOME_CONSTANT is a single bit. It's noteworthy here that all the control constants (as well as virtually all other LL constants that I'm aware of) are single bits. Furthermore, the reason if (stuff & (constant1 | constant2)) doesn't evaluate like he expects is because those two single-bit constants become one multi-bit constant for the & operation.
|
|
Nynthan Folsom
Registered User
Join date: 29 Aug 2006
Posts: 70
|
12-02-2006 21:46
The modification you provided is indeed more efficient, thanks. A snippet of the output from it follows. [17:24] Object: 1: CONTROL_ROT_RIGHT pressed [17:24] Object: 8: CONTROL_ROT_RIGHT pressed [17:24] Object: 26: CONTROL_LEFT pressed [17:24] Object: 29: CONTROL_LEFT pressed [17:24] Object: 41: CONTROL_RIGHT pressed [17:24] Object: 43: CONTROL_RIGHT pressed [17:24] Object: 54: CONTROL_ROT_RIGHT pressed [17:24] Object: 63: CONTROL_ROT_RIGHT pressed [17:24] Object: 68: CONTROL_ROT_LEFT pressed [17:24] Object: 71: CONTROL_FWD pressed Perhaps a more useful debugging tool would be one that prints out the states of all the controls at once like this: [21:19] Object: 1 fwd back left right up down rot_left vROT_RIGHT [21:19] Object: 2 fwd back left right up down rot_left _ROT_RIGHT [21:19] Object: 11 fwd back left right up down rot_left ^rot_right [21:19] Object: 12 fwd back left right up down vROT_LEFT rot_right [21:19] Object: 13 fwd back left right up down _ROT_LEFT rot_right [21:19] Object: 18 fwd back left right up down ^rot_left rot_right [21:19] Object: 19 vFWD back left right up down rot_left rot_right [21:19] Object: 20 _FWD back left right up down rot_left rot_right [21:19] Object: 65 ^fwd back left right up down rot_left rot_right Here's the code to do this: // This script will llOwnerSay the status of all the following controls. // Unpressed controls are lowercase. Pressed controls are uppercase. // Controls that have just been pressed are preceeded by a ^ symbol. // Controls that have just been released are preceeded by a v zymbol.
integer sFlags = 0x33f; // CONTROL_FWD | CONTROL_BACK | CONTROL_ROT_LEFT | CONTROL_LEFT | CONTROL_ROT_RIGHT | CONTROL_RIGHT | CONTROL_UP | CONTROL_DOWN;
list sCtrlNames;
// If set to FALSE, your av will not receive control messages and will not move. // But regardless, the script will still receive events. integer sPassOn = TRUE; integer sEventCounter = 0; integer sLastFlags;
default { state_entry() { sCtrlNames = [ "fwd ","back ","left ","right ","up ","down ","","","rot_left ","rot_right " ]; if(llGetPermissions() & PERMISSION_TAKE_CONTROLS) { llTakeControls(sFlags, TRUE, sPassOn); } else { llRequestPermissions(llGetOwner(), PERMISSION_TAKE_CONTROLS); } } on_rez(integer iParam) { llResetScript(); } run_time_permissions(integer iPerms) { if(iPerms & PERMISSION_TAKE_CONTROLS) { llTakeControls(sFlags, TRUE, sPassOn); } } control(key iId, integer iDown, integer iChanged) { string tName; string tStatus; integer tBit; integer tMask = 1; integer tDownFlags = iChanged & iDown; integer tUpFlags = iChanged & ~iDown; tStatus = ((string) (++sEventCounter)) + " "; integer tCurrentFlags; tCurrentFlags = (0xFFFF & iDown) | ((0xFFFF & iChanged) << 16); if(tCurrentFlags != sLastFlags) { for(tBit = 0; tBit < 10; tBit++) { if(tDownFlags & tMask) { tStatus += "v"; } else if(tUpFlags & tMask) { tStatus += "^"; } else if(sFlags & tMask) { tStatus += " "; } tName = llList2String(sCtrlNames, tBit); if(iDown & tMask) { tName = llToUpper(tName); } tStatus += tName; tMask = tMask << 1; } llOwnerSay(tStatus); } sLastFlags = tCurrentFlags; } } So looking at the output it's clear that the CONTROL_LEFT and CONTROL_RIGHT control down events ARE sometimes sent twice. When I press and hold shift-A or shift-D, a down event, followed by an up event followed by another down event happens in quick succession before settling on a hold event: Pressing and hold shift-A sometimes results in: [21:35] Object: 946 fwd back vLEFT right up down rot_left rot_right [21:35] Object: 947 fwd back ^left right up down rot_left rot_right [21:35] Object: 948 fwd back vLEFT right up down rot_left rot_right [21:35] Object: 949 fwd back LEFT right up down rot_left rot_right
Pressing and hold shift-D sometimes results in: [21:33] Object: 674 fwd back left vRIGHT up down rot_left rot_right [21:33] Object: 675 fwd back left ^right up down rot_left rot_right [21:33] Object: 676 fwd back left vRIGHT up down rot_left rot_right [21:33] Object: 677 fwd back left RIGHT up down rot_left rot_right
|
|
Nynthan Folsom
Registered User
Join date: 29 Aug 2006
Posts: 70
|
12-02-2006 23:37
From: Tyken It's noteworthy here that all the control constants (as well as virtually all other LL constants that I'm aware of) are single bits. This is untrue. PI, TWO_PI, etc... DEBUG_CHANNEL, NULL_KEY, EOF, all the constants to llSet/GetPrimParameters (just to name a few) ARE NOT flag constants. From: Tyken Furthermore, the reason if (stuff & (constant1 | constant2)) doesn't evaluate like he expects is because those two single-bit constants become one multi-bit constant for the & operation. Well, binary arithmetic is not for everyone. To clarify: bitwise OR basically slaps all the bits from two integers together. The resulting value has 1s where there is a 1 in the corresponding bits of either (or both) of the operands. Some examples: 01010101 | 10101010 -------- 11111111
00010101 | 10101010 -------- 10111111
00100100 | 00100000 -------- 00100100 Bitwise AND generates a 1 IF AND ONLY IF both operands have 1s in the corresponding positions. 01010101 & 10101010 -------- 00000000
00010101 & 10101010 -------- 00000000
00100100 & 00100000 -------- 00100000 Havarikk essentially wants to check to see if two separate bits are BOTH 1 in the same integer. So lets say we have a variable, A, with a value of 1100. We want to test whether the first bit and the third bit (from the right) are 1. The most straightforward way to do this would be if((A & 0001) && (A & 0100)) { ... }(Why use && rather than & in the middle? && returns true as long as both operands are non-zero. If we'd used & instead, even if both bit 1 and bit 3 [u C gurus please don't slam me for 1 based bit referencing] were 1, look what happens when you perform (0001 & 0100) -- you get (0000)! Which is NOT what we want.) However, some programmers who are either obsessed with optimization (which is a good thing when dealing with LSL) or who want to show off their knowledge of binary arithmetic look at the above code and say "Hey! I could eliminate a WHOLE operation by doing it like this:" if((A & 0101) == 0101) { ... }Hmmm, why is the extra == operation necessary? Remember the value of A? It's 1100. What happens when you AND 1100 and 0101? You get 0100, a non-zero which means that the condition would result in a TRUE. But we wanted it to be true IF AND ONLY IF both bits 1 and 3 were 1. Ok, so we need the == operation. But why can't we eliminate the &? Ok. Say at some other point in time A's value becomes 1101. So both bits 1 and 3 are 1 -- what we're testing for. We don't care what bit 4 is. However, 1101 is not equal to 0101 and will cause our condition statement to fail. This is why some people call the & operation a "filter" or a "mask" because it filters or masks out all the bits except the ones you want.
|
|
Nynthan Folsom
Registered User
Join date: 29 Aug 2006
Posts: 70
|
12-02-2006 23:54
From: Tyken It's noteworthy here that all the control constants (as well as virtually all other LL constants that I'm aware of) are single bits. This is untrue. PI, TWO_PI, etc... DEBUG_CHANNEL, NULL_KEY, EOF, all the constants to llSet/GetPrimParameters (just to name a few) ARE NOT flag constants. From: Tyken Furthermore, the reason if (stuff & (constant1 | constant2)) doesn't evaluate like he expects is because those two single-bit constants become one multi-bit constant for the & operation. Well, binary arithmetic is not for everyone. To clarify: bitwise OR basically slaps all the bits from two integers together. The resulting value has 1s where there is a 1 in the corresponding bits of either (or both) of the operands. Some examples: 01010101 | 10101010 -------- 11111111
00010101 | 10101010 -------- 10111111
00100100 | 00100000 -------- 00100100 Bitwise AND generates a 1 IF AND ONLY IF both operands have 1s in the corresponding positions. 01010101 & 10101010 -------- 00000000
00010101 & 10101010 -------- 00000000
00100100 & 00100000 -------- 00100000 Havarikk essentially wants to check to see if two separate bits are BOTH 1 in the same integer. So lets say we have a variable, A, with a value of 1100. We want to test whether the first bit and the third bit (from the right) are 1. The most straightforward way to do this would be if((A & 0001) && (A & 0100)) { ... }(Why use && rather than & in the middle? && returns true as long as both operands are non-zero. If we'd used & instead, even if both bit 1 and bit 3 [u C gurus please don't slam me for 1 based bit referencing] were 1, look what happens when you perform (0001 & 0100) -- you get (0000)! Which is NOT what we want.) However, some programmers who are either obsessed with optimization (which is a good thing when dealing with LSL) or who want to show off their knowledge of binary arithmetic look at the above code and say "Hey! I could eliminate a WHOLE operation by doing it like this:" if((A & 0101) == 0101) { ... }Hmmm, why is the extra == operation necessary? Remember the value of A? It's 1100. What happens when you AND 1100 and 0101? You get 0100, a non-zero which means that the condition would result in a TRUE. But we wanted it to be true IF AND ONLY IF both bits 1 and 3 were 1. Ok, so we need the == operation. But why can't we eliminate the &? Ok. Say at some other point in time A's value becomes 1101. So both bits 1 and 3 are 1 -- what we're testing for. We don't care what bit 4 is. However, 1101 is not equal to 0101 and will cause our condition statement to fail. This is why some people call the & operation a "filter" or a "mask" because it filters or masks out all the bits except the ones you want. In code cited previously, optimization would only occur if we converted it from if(held & (CONTROL_UP | CONTROL_DOWN) == (CONTROL_UP | CONTROL_DOWN)) { ... }to if(held & 0x30 == 0x30) { ... }This saves two OR operations because we are doing it manually. In any other programming language, this might not be so critical because a) most other platforms aren't quite this slow, and b) compilers in other languages are often intelligent enough to optimize for us. That being said. IF you anticipate that this condition will be tested thousands of times a second, then by all means optimize as much as possible. However, if it's just a simple test that happens with every key-press (which is eons between on the CPU time scale) the only reason to write code like this is obfuscation, whether for security (pffft) reasons, or to impress noobs. My advice though? KISS. Keep It Stupid Simple. (I know the last two words are normally reversed, but I don't really want to insult anyone.)
|