Mantis Bug Tracker

View Issue Details Jump to Notes ] Issue History ] Print ]
IDProjectCategoryView StatusDate SubmittedLast Update
0007040opensim[REGION] Script Functionspublic2014-02-27 12:522014-07-29 13:42
ReporterMata Hari 
Assigned ToMata Hari 
PrioritynormalSeverityfeatureReproducibilityN/A
StatusclosedResolutionfixed 
PlatformIntel i7 930 quad coreOSWindows .NETOS VersionWin7 x64
Product Versionmaster (dev code) 
Target VersionFixed in Versionmaster (dev code) 
Summary0007040: request for function osUpdateObject(key object)
DescriptionCurrently if the position or rotation of an object is changed by script (for example using llSetLinkPrimitiveParamsFast() and the change is quite small, the simulator does not send the updated position/rotation of that object to the viewer. The new position/rotation data is applied/stored but until the aggregate movement is sufficiently large this isn't transmitted to the viewers of anyone currently in the region (presumably this is to prevent excessive traffic). Even the console command "force update" doesn't do this (whether sent by script or by manually typing it)...the only way a viewer will receive the update is for the user to leave the region and return.

For many purposes this is fine, but for making a script to adjust position of a seated avi (for instance while fine-tuning a sit target position) it's important to be able to see "real time" update of the actual avi position even if the change is small.

The only work-around currently available (and one that is used in SL as a work-around) is to temporarily move the avi a greater distance (~0.25m is usually enough) using the non-fast llSetLinkPrimitiveParams() function; and while the script sleeps for 0.2sec the update is sent; and then subsequently use the llSetLinkPrimitiveParamsFast() function to move it to the actual location you want (and since this move is another 0.25m it will trigger a viewer update). This method doesn't work if the "fast" function is used for both moves.

Needless to say this is a very ugly work-around when trying to position someone. Moving a different child prim won't cause the viewer to update either...the other child will update (if you move it far enough) but the avi won't. If the object isn't an avi this can also be accomplished by making some other change (color, alpha, etc) but again the change has to be made using the non-fast version that makes the script sleep for 0.2 sec.

So my request is for a script method to force the sim to send the updated position even if it's small. I'd propose something like:

osUpdateObject(key object)

where "object" is the UUID of a prim or agent (function would fail silently if it's anything else) and would have the effect of forcing the sim to send the updated position/rotation even if the change from the last sent data is small. It would probably make sense for this to have a small throttle (maybe 0.1 sec?) to prevent too much excessive traffic if the adjustments are being made with control keys.
Steps To ReproduceThis script demonstrates the failure to update and is part of a test script I was working on today. Even at its "medium" setting it won't update the viewer until a number of control events have been processed. Using "fine" setting will force the update using the ugly "move it away and then back again".

To use: drop this into a prim, sit on it, then touch it.

// Main body of script
integer ctrlMask;
integer ctrlLink;
key user=NULL_KEY;
list sitters;
integer channel;
integer handle;
float diaTimeout=30.0;
float ctrlTimeout=10.0; // actually times out at double this time
integer ctrlInactive=TRUE;
integer ctrlInUse=FALSE;
string adjType="Position"; // Position || Rotation
string adjScale="Coarse"; // Coarse || Medium || Fine
list adjPosScales=["Coarse","Medium","Fine",0.1, 0.01, 0.001]; // amount to step each position change in m
list adjRotScales=["Coarse","Medium","Fine",5.0, 0.1, 0.01]; // amount to step each roation change in degrees

showControlDialog()
{
    list butDia=["Coarse","Medium","Fine","Position","Rotation","DONE"];
    string txtDia="Select location or rotation depending on what you want to adjust\n"
                + "Select one of the three scales to control how much to adjust\n"
                + "Click DONE when you are finished and with to regain key controls\n\n"
                + "Currently adjusting "+adjType+" at scale "+adjScale+"\n\n"
                + "Use up/down/left/right/shift+left/shift+right arrow keys to adjust";
    handle=llListen(channel, "", user, "");
    llDialog(user, txtDia, butDia, channel);
}
selectTarget()
{
    sitters=[];
    integer links=llGetNumberOfPrims();
    if (!links)
    {
        llRegionSayTo(user,0,"Unable to detect any seated avatars");
        return;
    }
    while (links)
    {
        if (llGetAgentSize(llGetLinkKey(links))!=ZERO_VECTOR) sitters+=[llGetLinkName(links),llGetLinkKey(links),links];
        links--;
    }
    sitters=llListSort(sitters,3,TRUE);
    sitters=["name","key","link num"]+sitters;
    integer l=llGetListLength(sitters)/3;
    if (l<2)
    {
        llRegionSayTo(user,0,"Unable to detect any seated avatars");
        return;
    }
    if (l==2)
    {
        // only one avatar seated so we don't need to ask who to control....go directly to perm request
        ctrlLink=llList2Integer(sitters,5);
        llRequestPermissions(user,PERMISSION_TAKE_CONTROLS);
        return;
    }
    string txtDia="Select the avatar to position:\n";
    list butR1;
    list butR2;
    list butR3;
    list butR4;
    list butDia;
    integer i;
    while (++i<l)
    {
        txtDia+="\n"+(string)i+". "+llList2String(sitters,3*i);
        if (i<4) butR1+=[(string)i];
        else if (i<7) butR2+=[(string)i];
        else if (i<10) butR3+=[(string)i];
        else butR4+=[(string)i];
    }
    while (i<12)
    {
        if (i<4) butR1+=["-"];
        else if (i<7) butR2+=["-"];
        else if (i<10) butR3+=["-"];
        else butR4+=["-"];
        i++;
    }
    butR4+=["CANCEL"];
    butDia=butR4+butR3+butR2+butR1;
    while (llListFindList(butDia,["-","-","-"])!=-1)
    {
        integer del=llListFindList(butDia,["-","-","-"]);
        butDia=llDeleteSubList(butDia,del,del+2);
    }
    handle=llListen(channel,"",user,"");
    ctrlInUse=FALSE;
    ctrlInactive=TRUE;
    llDialog(user, txtDia, butDia, channel);
    llSetTimerEvent(diaTimeout);
}

default
{
    state_entry()
    {
        ctrlMask=(CONTROL_FWD | CONTROL_BACK | CONTROL_LEFT | CONTROL_RIGHT | CONTROL_ROT_LEFT | CONTROL_ROT_RIGHT);
        llSitTarget(<0,0,0.000001>,ZERO_ROTATION);
        channel=0x80000000 | (integer)("0x"+(string)llGetKey());
    }
    timer()
    {
        if (!ctrlInactive)
        {
            ctrlInactive=TRUE;
            return;
        }
        if (user!=NULL_KEY) llRegionSayTo(user,0,"Timed out. Please touch me again to reactivate");
        user=NULL_KEY;
        if (ctrlInUse)
        {
            // return controls back to avi
            ctrlInUse=FALSE;
            llReleaseControls();
        }
        llSetTimerEvent(0.0);
        llListenRemove(handle);
    }
    touch_start(integer num)
    {
        if ((user!=NULL_KEY) && (user!=llDetectedKey(0))) llRegionSayTo(llDetectedKey(0),0,"Sorry, the controller is already in use");
        else user=llDetectedKey(0);
        selectTarget();
    }
    listen(integer channel, string name, key id, string message)
    {
        // always remove listen
        llListenRemove(handle);
        if (ctrlInUse)
        {
            // handle dialog responses while controls are active
            // this counts as an action so reset flag so ctrl timer doesn't time out
            ctrlInactive=FALSE;
            // now handle the message
            if (message=="DONE")
            {
                // finished adjusting so stop
                llSetTimerEvent(0.0);
                ctrlInUse=FALSE;
                llReleaseControls();
                // Probably want to have an option here to store for some applications (or autostore)
                return;
            }
            // otherwise we are selecting on of the type buttons so update and redisplay
            if (message=="Coarse" || message=="Medium" || message=="Fine") adjScale=message;
            else if (message=="Position" || message=="Rotation") adjType=message;
            showControlDialog();
            return;
        }
        else
        {
            // controls are inactive so this is a response for who to control
            // clear timer
            llSetTimerEvent(0.0);
            // handle possible messages
            // *** TO DO ***
            if (message=="-") selectTarget();
            else if (message=="CANCEL") return;
            else
            {
                // anything else should be the index multiplier for the selection
                integer ind=(integer)message;
                ctrlLink=llList2Integer(sitters,3*ind+2);
                llRequestPermissions(user,PERMISSION_TAKE_CONTROLS);
            }
        }
    }
    run_time_permissions(integer perm)
    {
        if (perm & PERMISSION_TAKE_CONTROLS)
        {
            ctrlInUse=TRUE; // set flag that controls are in use
            ctrlInactive=FALSE; // set flag for timer (so control events don't keep resetting the timer)
            llTakeControls(ctrlMask,TRUE,FALSE); // take controls and while in control mode do not allow the keys to perform their normal function
            showControlDialog(); // show the control dialog
            llSetTimerEvent(ctrlTimeout); // set timer to monitor if anything has been done recently
        }
    }
    control (key id, integer level, integer edge)
    {
        // a key was pressed so clear timer flag
        ctrlInactive=FALSE;
        // adjust based on key(s) pressed: CONTROL_FWD | CONTROL_BACK | CONTROL_LEFT | CONTROL_RIGHT | CONTROL_ROT_LEFT | CONTROL_ROT_RIGHT
        // list avData=llGetLinkPrimitiveParams(ctrlLink,[PRIM_POSITION,PRIM_ROTATION]);
        list avData=llGetLinkPrimitiveParams(ctrlLink,[PRIM_POS_LOCAL,PRIM_ROT_LOCAL]);
        vector avPos=llList2Vector(avData,0); // relative
        avPos=avPos*llGetRot()+llGetPos(); // convert to region
        rotation avRot=llList2Rot(avData,1); // relative but leave it this way
        vector adjPos=ZERO_VECTOR;
        vector adjRot=ZERO_VECTOR; // handle this as vector for x,y,z rotation then convert to quat
        float amountPos=llList2Float(adjPosScales,llListFindList(adjPosScales,[adjScale])+3); // the amount to apply to a step in m
        float amountRot=llList2Float(adjRotScales,llListFindList(adjRotScales,[adjScale])+3); // the amount to apply to a step in degrees
        if (level & CONTROL_FWD) // up arrow key
        {
            if (adjType=="Position") adjPos.z+=amountPos;
            else adjRot.y+=amountRot;
        }
        else if (level & CONTROL_BACK) // down arrow key
        {
            if (adjType=="Position") adjPos.z-=amountPos;
            else adjRot.y-=amountRot;
        }
        else if (level & CONTROL_LEFT) // shift + left arrow key
        {
            if (adjType=="Position") adjPos.x-=amountPos;
            else adjRot.x-=amountRot;
        }
        else if (level & CONTROL_RIGHT) // shift + right arrow key
        {
            if (adjType=="Position") adjPos.x+=amountPos;
            else adjRot.x+=amountRot;
        }
        else if (level & CONTROL_ROT_LEFT) // left arrow key
        {
            if (adjType=="Position") adjPos.y-=amountPos;
            else adjRot.z-=amountRot;
        }
        else if (level & CONTROL_ROT_RIGHT) // right arrow key
        {
            if (adjType=="Position") adjPos.y+=amountPos;
            else adjRot.z+=amountRot;
        }
        else return;
        // calculate new position and rotation
        vector newAvPos=avPos+adjPos; // this is region so convert to relative
        newAvPos=(newAvPos-llGetPos())/llGetRot(); // now relative
        rotation newAvRot= avRot*llEuler2Rot(adjRot*DEG_TO_RAD); // was always relative
        // unfortunately small changes won't result in a viewer update so at fine level of adjustment there has to be an interim position set using non-fast method
        if (adjScale=="Fine") llSetLinkPrimitiveParams(ctrlLink,[PRIM_POS_LOCAL,newAvPos+<0,0,0.1>]);
        llSetLinkPrimitiveParamsFast(ctrlLink,[PRIM_POS_LOCAL,newAvPos,PRIM_ROT_LOCAL,newAvRot]);
    }
}
Additional InformationNote that the above script will only work with r/24384 where the function is fixed
TagsNo tags attached.
Git Revision or version number
Run Mode Grid (Multiple Regions per Sim)
Physics EngineBulletSim
Environment.NET / Windows64
Mono VersionNone
Viewer
Attached Files

- Relationships

-  Notes
(0025470)
justincc (administrator)
2014-03-18 18:10
edited on: 2014-03-18 18:11

Hi Mata. I believe this has been addressed as of git master c9415fd76378af35ff76037d46245f2b95e4264f (March 5th 2014)? This allows llSetPrimitiveParams() and friends to make adjustments smaller than the previous threshold.

(0025471)
melanie (administrator)
2014-03-18 18:12

I can't confirm this. The current core code will send any update, however small.
(0025477)
Mata Hari (reporter)
2014-03-19 04:04

confirmed as fix r/24396

- Issue History
Date Modified Username Field Change
2014-02-27 12:52 Mata Hari New Issue
2014-02-27 12:54 Mata Hari Additional Information Updated View Revisions
2014-03-18 18:10 justincc Note Added: 0025470
2014-03-18 18:10 justincc Status new => feedback
2014-03-18 18:11 justincc Note Edited: 0025470 View Revisions
2014-03-18 18:12 melanie Note Added: 0025471
2014-03-19 04:04 Mata Hari Note Added: 0025477
2014-03-19 04:04 Mata Hari Status feedback => new
2014-03-19 04:04 Mata Hari Status new => resolved
2014-03-19 04:04 Mata Hari Fixed in Version => master (dev code)
2014-03-19 04:04 Mata Hari Resolution open => fixed
2014-03-19 04:04 Mata Hari Assigned To => Mata Hari
2014-07-29 13:42 chi11ken Status resolved => closed


Copyright © 2000 - 2012 MantisBT Group
Powered by Mantis Bugtracker