Jump to content

Miranda Umino

Resident
  • Posts

    411
  • Joined

  • Last visited

Posts posted by Miranda Umino

  1. You have talked about a scrabble game .

    So , i guess every elements of your lists are only one-char length ?

    Maybe your data format is not very adapted :

    as the length of your elements are fixed-size , they can be concatenated in a string and accessed easily with the size of the element  

     

    list list1 = ["ABC", "DEF"];integer int = 1; // or 2string str;default{    touch_end(integer total_number)    {	str = llGetSubString(llList2String(list1, int-1 ),0,0);       }}

     

  2. Your URL is wrong :

    http://localhost/DBConn.php '>http://localhost/DBConn.php 

    It can only work when you call the URL from your computer , but it can t be called from the other computers .

    Ask a friend to call http://localhost/DBConn.php on Internet explorer , Chrome , Opera , Firefox, Safari  ...He will fail .

     

     

    Call the Url with the public DNS name of your computer or your internet IP adress.

     

     

    • Like 1
  3. Use one state with a money event .

    When the player has paid ,  save his key, and go to an another state. The player can start to play in the another state.

    After the game , or a timeout because the player has left , go back to the state default , to listen other players ( or the same player with a new game)

     

    key player;integer priceToPlay = 5;default{    state_entry()    {        llSetClickAction(CLICK_ACTION_PAY);        llSetPayPrice(PAY_HIDE, [ priceToPlay ,PAY_HIDE,PAY_HIDE,PAY_HIDE]);    }    money(key id, integer amount)       {        if ( amount >= priceToPlay )        {            player = id; state playing;        }            }}state playing{// your game starts here}

     

  4. By experience :

    with non-physical prims , use llSetRegionPos and not llSetPos to trigger moving_start and moving end events .

    Even with a velocity of ZERO_VECTOR , it works . Nevertheless, you ll get only the final position  when you check llGetPos() inside moving_start and moving_end events .

    So in fact , it useless to catch the two  both events moving_start and moving_end  at the same time , if you use llSetRegionPos

     If you call several llSetRegionPos in the same current event ( for instance you several llSetRegionPos in a timer event , touch_end event ) , only the last llSteregionPos will be triggered

     

    vector shift = <0, 0, 1.0>; default{    state_entry()    {        llSetTimerEvent(2.0);           }    timer()    {        shift = -shift;        llSetRegionPos(llGetPos() + shift);    }    moving_start()    {        llOwnerSay(llList2CSV( [ "moving_start", "shift", shift, "pos", llGetPos() ]));    }    moving_end()    {        llOwnerSay(llList2CSV( [ "moving_end", "shift", shift, "pos", llGetPos() ]));    }}

     

  5. @leprekhaun : It doesn t need an external program . It can be recorded on the web without need to install programs 

    For instance 

    http://justflash.byethost12.com/microphone/microphone_recandsave1.html

     

    If you go to this URL with an external browser ( Internet explorer , chrome , firefox, opera , safari  etc ..)  , click on the button "record" , you ll get a dialog box "settings adobe flash player" .

    If you don t refuse and grant the access to the microphone , the flash will record your microphone . Talk , click on the "stop record" button , click on the play button , click on the save button .

    But as i have said , with an external browser you can confirm and give acces in the dialog box "settings adobe flash player" . SO you can record yourself on the web . Now , to save the file , you can of course save it locally on your computer . But  you can send binary datas since HTML5 to a webserver to store on it  ( it s not done by this demo , but it can be done )

    You can see it s possible to store on a webserver  with this following demo http://www.videomessageonline.com/video-message-online-test  . When it saves the file , it gives you a link where the wave/mp3 file is stored 

    With the internal browser of second life , you can t confirm the  dialog box "settings adobe flash player" because the internal browser sucks and has too many bugs . It s not a bug of media on prim , but it s  a bug of internal browser. If you use the internal browser, you couldn t confirm the authorization dialog box. 

     

     

  6. I assume you are talking about an object on the ground  , not an attachement :

     

    If you want the direction of the move of the avatar ( to know if the avatar goes closer or not)

    You will need the velocity vector of the avatar :
    you may use llDetectedVel ( if you use a sensor ) or llGetObjectDetails(key_avatar, [OBJECT_VEL]) ( if you don t use it)

    f you want the direction of the avatar even when he turns on himselfwithout changing his position, use llDetectedRot or llGetObjectDetails(key_avatar, [OBJECT_ROT]) . You will need to divide by the rotation of your prim or your object . ( if you want the direction of the avatar relative to the object or prim)

     

    If you want the direction of the avatar of his position ( to know if the avtar has crossed your door or not )

    The same with llDetectedPos or llGetObjectDetails(key_avatar, [OBJECT_POS]) .

    Substract the position of the prim or object

    Divide eventually by the rotation o the object if you want a relative position

  7. An another way without timer could to be :

    - not use touch_start and touch_end events ( or use them only for your loopsound and stopsound)

    - use touch event to scale and move your object

    - do one iteration of your loop inside the touch event , not the whole loop

    - use a conditionnal  to know if you ahve reached the limits of your loop

     

    So , while the user lets his mouse button clicked it opens/close the door  ( until a maximum/minimum)  of course.

     

     

    Instance : ( with llSetLinkPrimitiveParamsFast , it should be smoother )

     

    vector psize;vector pposition;integer counter;float startwidth = 0.25;integer isopen;integer fullopen = 10;integer finished;default{    state_entry()    {        psize = llGetScale();        pposition = llGetPos();            }    touch_start(integer total_number)    {        finished = FALSE;        llLoopSound("Blind Moving",15.0);    }    touch(integer n)    {        if ( ! finished )        {            if (isopen == FALSE)            {                if ( counter >= fullopen )                {                    isopen  = TRUE ;                    finished = TRUE;
    counter = 0; } else { counter++; psize.z = psize.z + startwidth; //psize local to object pposition.z = pposition.z - (startwidth / 2); //pposition is global llSetPrimitiveParams([PRIM_SIZE,psize,PRIM_POSITION,pposition]); } } else { if ( counter >= fullopen ) { isopen = FALSE ; finished = TRUE;
    counter = 0; } else { counter++; psize.z = psize.z - startwidth; pposition.z = pposition.z + (startwidth / 2); llSetPrimitiveParams([PRIM_SIZE,psize,PRIM_POSITION,pposition]); } } } } touch_end(integer total_number) { llStopSound(); } }

     

     

     

    • Like 1
  8. It will give wrong negatives ( negative tests not negative numbers) :

     

    string data ="+3"; // worths 3 who is valid and the cast returns 3if ( (string) ( (integer) data) == data)llOwnerSay("'" + data + "' contains a valid integer");elsellOwnerSay("'" + data + "' doesn t contain a valid integer");

     Output : '+3' doesn t contain a valid integer

     

    You will need to add an additional test :

    if ( ( (string) ( (integer) data) == data) || ( "+" + (string) ( (integer) data) == data) )

     

    And probably other tests if your input can be in hexadecimal form :

    string data ="0x0045AB12"; // worths 4565778 who is valid and the cast returns 4565778

     Output : '0x0045AB12' doesn t contain a valid integer 

     

    Third problem : you will need to trim left-zeros

    string data ="03"; // worths 3 who is valid and the cast returns 3

      Output : '03' doesn t contain a valid integer

     

  9. Nevertheless an exception system  in LSL will be great !  ( as too a collection system, a customized event system, a "library" system, a reference system, nested types ... )

    But i doubt we ll get one soon  . I even doubt we ll get one , in the future . ( because of the compatibilty with old outdated user contents)

    It s hopeless and very depressing

     

  10. Yes , it s the expected behaviour 

     

    It looks be the same comportement than the C function atoi : 

    i quote http://www.cplusplus.com/reference/cstdlib/atoi/

     

    1) The function first discards as many whitespace characters (as in isspace) as necessary until the first non-whitespace character is found. Then, starting from this character, takes an optional initial plus or minus sign followed by as many base-10 digits as possible, and interprets them as a numerical value.2) The string can contain additional characters after those that form the integral number, which are ignored and have no effect on the behavior of this function.3) If the first sequence of non-whitespace characters in str is not a valid integral number, or if no such sequence exists because either str is empty or it contains only whitespace characters, no conversion is performed and zero is returned.

     

    With a test in world , we get

    integer x  =  (integer)"   123" =>  x value is 123 as in C with atoi function (1st point of the quote )

    integer y  =  (integer)"123hello" =>  y value is 123 as in C with atoi function (2nd point of the quote )

    integer z  =  (integer)"hello" =>  z value is 0 as in C with atoi function (3rd point of the quote )

     

     

    Note : strangely it looks closer to the C atoi function than the Int32.TryParse C# function .

     
    #include <stdio.h>      /* printf, fgets */#include <stdlib.h>     /* atoi */ int main (){  int x = atoi ("  123");  int y = atoi ("123hello");  int z = atoi ("hello");  printf ("%d %d %d.\n",x,y,z);  return 0;}
    Output :
    123 123 0
     
    using System; class Program{    static void Main()    {        int x; int y ; int z;        Int32.TryParse("  123", out x);        Int32.TryParse("123hello", out y);        Int32.TryParse("hello", out z);         Console.WriteLine("{0} {1} {2}", x, y, z);  // Converted to -3            }}
    Output : 123 0 0

     

    Probably for historic reasons  because the lsl VM was done in C .

     

  11. Requests inside objects from llHTTPRequest will fill the IP of of the sim where is the the prim .

    Not the IP of the avatar who wears it .   In this case , your object is a client

     

    If your object hosts an URL via llRequestURL , this URL is unique .( I mean :  two avatars wearing one object : the URLs of the objects will have two different URLS )

     In this case , your object is a server

     

    By the way , i don t understand where is the "cheat"  and you do a so complicated process .

    In fact , you even don t need to have a webserver. 

    And you don t need to make your object servers with llRequestURLs , because your objects are already unique. 

    And why this pre-registration on your website ? What is the goal of this pre-registration ? A player won t like a complicated process just to be able to play some minutes

    And even if you wanted to register some scores in a website , the key of the object is enough , no ? ( llGetKey ) 

    Can your object be modified by the users ?

    Can your objects be transfered to alts ?

    If it can , why not use llGenerateKey to create an unique UUID ?Or why not to use llAttactToAvatarTemp  ?

    You didn t tell how an alt in normal situation can cheat your game 

     

     

  12. It depends what you want to monitor : monitor the people entering and leaving a sim , i guess .

    Monitoring a sim where your script is running , yes . It s even too much easy . In LSL.

    Monitoring a sim where you are not and where are not your scripts , of course , no 

  13. When you deal with 1 million keys , 1000 accounts are acceptable . You don t work in military sectors or energetic sectors or health sector or other critical sectors . You work in second life .

    You tell yourself

    I regularly get huge lists in the tens of thousands of avatar legacy names to import into my system, 
    and almost always there is a good 5-10% accounts that no longer exist, are incorrectly capitalized,
    or just plain spelled wrong via manual copy and paste errors

    5-10 % is 50 times more than 1 per 1000 . So , your main problems is to find a solution for these 5-10% . Not for the 1 per 1000 .  

     

    I am not surprised you could found them easily if you do a manual search :

    it s because you have run a search with few letters .  If i search "AA" in people , i would have several thousand of pages . But your process to verify UUID will in practice use the length of the name . And people with only two letters and who can t be found with their family name ( for instance they are "aa resident" "ba resident" "ca resident" )  are very rare in the SL population 

    There are more names with few letters when the users are not "Resident" family , but the name of their family allow to be more efficient in the search . (   For instance http://search.secondlife.com/client_search.php?q=aa.keng&s=People gives a list with only one element

    To add , it s not because when you get a long list with a searched name , an another search with a name from this list will give many results . 

    For instance , tula88 resident was in the result of tula  resident . Tula27 resident too . Tula30 resident too . 

    Tula( display name)  petulalake resident too

    But if you search tula88 resident , you won t find tula resident , and the majority of names you got with tula resident :

    http://search.secondlife.com/client_search.php?q=tula88&s=people will give only 1 name..

    http://search.secondlife.com/client_search.php?q=tula27&s=people  will give only 1 name..

     http://search.secondlife.com/client_search.php?q=tula30&s=people will give only 1 name

    http://search.secondlife.com/client_search.php?q=petulalake&s=people&mat=7 will give only 1 name

    And finally , when you have searched , you didn t fill a second name . Your script will fill it and so the results of the serach will be smaller 

     

    In fact , you have searched randomly the  characters of a name before to find tula . But you have not searched randomly the length of the name ( you didn t pay attention your inputs were always small ) . So it was not a correct random 

    So it s only specific to particular people and it explains why it s easier to find someone manually who won t be in the forst page than to check some random names with a "real" name stored in your script , or database

  14. No i ve missed nothing .

     

    But you , you are totally wong :

     

    Firstly , you assume than you can t store keys in notecards  . I don t see why .

    Notecards can store keys without problem

     

    Secondly , you assume than the instance from Susan happens significantly .

     

    But in reality , it happens very rarely .

    Your searched name has  more than 99.9% chance to be in the first page .

    It s logic : even if the name is not th first name returned in the top of the list , they are few chances , they are not displayed in the rest of the list .

     

    And to meet the case of "Tila resident" from susan , the conditions should met :

    - there are more than 20 names returned ( low probability  who decreases exponentially with the length of the 1st name +1 for the Resident family or with the length of the 1st name + 2nd name for the names with familes other than Resident  )

    - the name really searched is after the 20th and not before. For Instance with a list of 21 names , the name searched has 1/21 to be in the second page so 5% .

     

    To test it , i have picked up 1700 uuids/names randomly from a groupe .

    I have created an application to call search.secondlife.com . 

    When the result doesn t give "sorry , no result found" , i parse the page . Parsing is easily and quickly done with a Regexp . If i have not found the name i am searching in the 1st page of results  , i send an error message . 

    I have checked with these 1700 names . What i get ?  ZERO cases like the "tila resident" from susan

     

    I have told myself that the samples from a group can be different from samples from in_world . Indeed , some memebers of group can be very old .

    So , i went in several region , collecting keys vi llGetAgentList , their names via llKey2name , and doing a search with their names to verify if the key returned in the search is the correct key .

     

    I have checked around 500 names . What i get ? ZERO cases like the "tila resident" from susan .

    So yes , the case of Tila resident exists , but is not signficant . the observed probability ( or the frequency as you wish ) is inferior to 1 /2200

    How much are there people in the same case as "tila resident" , ( can t be fetched in the fist page of search.second.life.com, but could be fectched in the other pages )  compared to the 35 millions database users, or evn compared to the 1 millions users connected per month   ? Very few .

     

     It s neglectible compared to other possible errors you can get , or you can create yourself in your process

     

     So yes , your argues have nothing convincing

     

  15. Thank you to share .

     

     

    But how large can my second burst be if I wait just 20 seconds after the first burst, for different sizes of that first burst?

     


    Your second burst/bucket can have 25 requests in 20 seconds ... But not at the 1st second of the burst/bucket
    ( it will be hot to try to send the 25th request because you will need to send it at the last moment of the second burst/bucket)
    example :
    time t = 0 : i send 25 requests .. my quota is 25 .. my first bucket is full . so i can t send anymore
    time t = 20 : my second bucket starts .. my quota is 0 ( for the second bucket ) + % time to left = 100% * 25 ( number of request in the last bucket ) = 25 
    So i can t send
    time t = 20.8 : my quota is 0 (2nd bucket ) + (20-0.8)/20 ( time to left ) * 25 ( number of requests in the last bucket )
    = 24 . i can send one request 
    time t = 21.6 : quota is 1 (2nd bucket) + (20 -1.6) / 20 ( time to left ) * 25 ( number of requests in the last bucket )
    = 24 . i can send one another request 
    and so on every 0.8 seconds ( well with the imprecision of floats and timers it can be a bit less , but it works )
    time t = 40 .. i will have sent 25 requests too , but spaced of 0.8 seconds between every each request .


    So , you can send 25 requests per 20 seconds every time , but you need to respect the distribution of requests.

    Of course , i could have done nothing between t=20 and t= 39 and send all the 25 at the last second , but it s slower

    if my first bucket i have sent only 16 requests :
    so at t = 20 my quota is 0 ( for the second bucket ) + % time to left = 100% * 16( number of request in the last bucket ) = 16
    i can already send some requests ( i couldn t at t=20 when i had 25 requests in the first burst) . i send 9
    at t = 21.3 my quota is 9 + % time to left = (20-1.3)/20 * 16 = 9+14.96 = 23.96 .. i can send only one for now
    at t = 22.5 my quota is 10 + % time to left = (20-2.5)/20 * 16 = 10+14 = 24 .. i can send one another
    at t = 23.75 my quota is 11 + % time to left = (20-3.75)/20 * 16 = 11+13 = 24 .. i can send one another
    you notice i must space the following requests more ( 1.25/1.3 second between each ) than when i had 25 requests in my 1st bucket . It s because i have sent already 9 at the start of the bucket .
    Finally the last request could be send at t = 40 - (24 - nb_secondbucket) *20 / nb_firstbucket
    t = 40 - 1 * 20 / nb_firstbucket = 40 - 20 / 16 = 38.75 .

    time t = 40 .. i will have sent 25 requests too , but the 9th firsts at the first second ,and the others spaced  1.25-1.75 seconds between each request . 

     

    In fact , 24 = nb_secondbucket + (20 - t)/20 * 16 => (24 - nb_secondbucket) *20 / 16 = ( 20 - t )
    =>
    t = 40 - (24 - nb_secondbucket) *20 / nb_firstbucket
    t = 60 - (24 - nb_thirbucket) *20 / nb_secondbucket
    t = 80 - (24 - nb_fourthbucket) *20 / nb_thirbucket ....


    In your script , what you do ?
    I have run your script , and dumped and traced at the start of the function "send" the value of llGetTime and the variable "try" :
    i get for instance with REQ_CAP = 16
    [20:44] Object: 100.199501, 0
    [20:44] Object: 100.199501, 1
    [20:44] Object: 100.265244, 2
    [20:44] Object: 100.309822, 3
    [20:44] Object: 100.354858, 4
    [20:44] Object: 100.398628, 5
    [20:44] Object: 100.444237, 6
    [20:44] Object: 100.488426, 7
    [20:44] Object: 100.531960, 8
    [20:44] Object: 100.621796, 9
    [20:44] Object: 100.665428, 10
    [20:44] Object: 100.710594, 11
    [20:44] Object: 100.754433, 12
    [20:44] Object: 100.798767, 13
    [20:44] Object: 100.843872, 14
    [20:44] Object: 100.887810, 15
    [20:44] Object: 120.952583, 0
    [20:44] Object: 120.996490, 1
    [20:44] Object: 121.041954, 2
    [20:44] Object: 121.085426, 3
    [20:44] Object: 121.129906, 4
    [20:44] Object: 121.174728, 5
    [20:44] Object: 121.219597, 6
    [20:44] Object: 121.263458, 7
    [20:44] Object: 121.308586, 8
    [20:44] Object: 121.353378, 9
    [20:44] Object: HTTP REQUEST EXCEEDED THROTTLE (But how?)
    [20:45] Object: 200.198288, 0
    [20:45] Object: 200.243073, 1
    [20:45] Object: 200.286926, 2
    [20:45] Object: 200.331375, 3
    [20:45] Object: 200.421173, 4
    [20:45] Object: 200.464783, 5
    [20:45] Object: 200.509537, 6
    [20:45] Object: 200.553802, 7
    [20:45] Object: 200.598343, 8
    [20:45] Object: 200.643311, 9
    [20:45] Object: 200.687286, 10
    [20:45] Object: 200.731659, 11
    [20:45] Object: 200.775970, 12
    [20:45] Object: 200.821136, 13
    [20:45] Object: 200.865158, 14
    [20:45] Object: 200.887314, 15
    [20:46] Object: 220.985123, 0
    [20:46] Object: 221.030182, 1
    [20:46] Object: 221.074203, 2
    [20:46] Object: 221.118881, 3
    [20:46] Object: 221.207672, 4
    [20:46] Object: 221.252548, 5
    [20:46] Object: 221.296616, 6
    [20:46] Object: 221.340958, 7
    [20:46] Object: 221.385468, 8
    [20:46] Object: 221.431198, 9
    [20:46] Object: HTTP REQUEST EXCEEDED THROTTLE (But how?)
    [20:47] Object: 300.194824, 0
    [20:47] Object: 300.238861, 1
    [20:47] Object: 300.283722, 2
    [20:47] Object: 300.328339, 3
    [20:47] Object: 300.418396, 4
    [20:47] Object: 300.462433, 5
    [20:47] Object: 300.506561, 6
    [20:47] Object: 300.551300, 7
    [20:47] Object: 300.595520, 8
    [20:47] Object: 300.640656, 9
    [20:47] Object: 300.684540, 10
    [20:47] Object: 300.729004, 11
    [20:47] Object: 300.773865, 12
    [20:47] Object: 300.818939, 13
    [20:47] Object: 300.863159, 14
    [20:47] Object: 300.907104, 15
    [20:47] Object: 320.957245, 0
    [20:47] Object: 321.001892, 1
    [20:47] Object: 321.045837, 2
    [20:47] Object: 321.090057, 3
    [20:47] Object: 321.269470, 4
    [20:47] Object: 321.309875, 5
    [20:47] Object: 321.357788, 6
    [20:47] Object: 321.404205, 7
    [20:47] Object: 321.435577, 8
    [20:47] Object: 321.476196, 9
    [20:47] Object: 321.543121, 10
    [20:47] Object: HTTP REQUEST EXCEEDED THROTTLE (But how?)
    [20:49] Object: 400.196381, 0
    [20:49] Object: 400.240814, 1
    [20:49] Object: 400.285400, 2
    [20:49] Object: 400.329742, 3
    [20:49] Object: 400.373627, 4
    [20:49] Object: 400.418335, 5
    [20:49] Object: 400.462921, 6
    [20:49] Object: 400.507050, 7
    [20:49] Object: 400.551971, 8
    [20:49] Object: 400.596039, 9
    [20:49] Object: 400.640686, 10
    [20:49] Object: 400.685944, 11
    [20:49] Object: 400.707397, 12
    [20:49] Object: 400.752594, 13
    [20:49] Object: 400.840515, 14
    [20:49] Object: 400.884888, 15
    [20:49] Object: 420.950500, 0
    [20:49] Object: 420.993469, 1
    [20:49] Object: 421.037964, 2
    [20:49] Object: 421.083130, 3
    [20:49] Object: 421.126831, 4
    [20:49] Object: 421.172058, 5
    [20:49] Object: 421.215820, 6
    [20:49] Object: 421.260223, 7
    [20:49] Object: 421.304657, 8
    [20:49] Object: 421.350037, 9
    [20:49] Object: HTTP REQUEST EXCEEDED THROTTLE (But how?)
    [20:50] Object: 500.186554, 0
    [20:50] Object: 500.231628, 1
    [20:50] Object: 500.275818, 2
    [20:50] Object: 500.320129, 3
    [20:50] Object: 500.365234, 4
    [20:50] Object: 500.409027, 5
    [20:50] Object: 500.453461, 6
    [20:50] Object: 500.497833, 7
    [20:50] Object: 500.543243, 8
    [20:50] Object: 500.587036, 9
    [20:50] Object: 500.631561, 10
    [20:50] Object: 500.675812, 11
    [20:50] Object: 500.720551, 12
    [20:50] Object: 500.765320, 13
    [20:50] Object: 500.809723, 14
    [20:50] Object: 500.853729, 15
    [20:51] Object: 520.918762, 0
    [20:51] Object: 520.963440, 1
    [20:51] Object: 521.007629, 2
    [20:51] Object: 521.052307, 3
    [20:51] Object: 521.142212, 4
    [20:51] Object: 521.185791, 5
    [20:51] Object: 521.229919, 6
    [20:51] Object: 521.274475, 7
    [20:51] Object: 521.319153, 8
    [20:51] Object: 521.363892, 9
    [20:51] Object: HTTP REQUEST EXCEEDED THROTTLE (But how?)

     

    In fact your bust without wait between the requests , so it s normal you reach the throttle at the 9th/10th request

    And for REQ_CAP = 24 :

    [20:51] Object: HTTP REQUEST EXCEEDED THROTTLE (But how?)
    [20:54] Object: 100.170074, 0
    [20:54] Object: 100.170074, 1
    [20:54] Object: 100.170074, 2
    [20:54] Object: 100.259094, 3
    [20:54] Object: 100.303963, 4
    [20:54] Object: 100.348213, 5
    [20:54] Object: 100.392548, 6
    [20:54] Object: 100.436928, 7
    [20:54] Object: 100.482468, 8
    [20:54] Object: 100.525726, 9
    [20:54] Object: 100.571022, 10
    [20:54] Object: 100.614716, 11
    [20:54] Object: 100.659210, 12
    [20:54] Object: 100.704185, 13
    [20:54] Object: 100.725914, 14
    [20:54] Object: 100.770264, 15
    [20:54] Object: 100.859398, 16
    [20:54] Object: 100.903938, 17
    [20:54] Object: 100.948051, 18
    [20:54] Object: 100.992622, 19
    [20:54] Object: 101.037277, 20
    [20:54] Object: 101.082329, 21
    [20:54] Object: 101.126045, 22
    [20:54] Object: 101.170570, 23
    [20:54] Object: 121.228386, 0
    [20:54] Object: 121.273964, 1
    [20:54] Object: 121.317383, 2
    [20:54] Object: HTTP REQUEST EXCEEDED THROTTLE (But how?)
    [20:55] Object: 200.164917, 0
    [20:55] Object: 200.210037, 1
    [20:55] Object: 200.254532, 2
    [20:55] Object: 200.298782, 3
    [20:55] Object: 200.342606, 4
    [20:55] Object: 200.388046, 5
    [20:55] Object: 200.431793, 6
    [20:55] Object: 200.477722, 7
    [20:55] Object: 200.520660, 8
    [20:55] Object: 200.565811, 9
    [20:55] Object: 200.654144, 10
    [20:55] Object: 200.700470, 11
    [20:55] Object: 200.744278, 12
    [20:55] Object: 200.789200, 13
    [20:55] Object: 200.833374, 14
    [20:55] Object: 200.878555, 15
    [20:55] Object: 200.923676, 16
    [20:55] Object: 200.967773, 17
    [20:55] Object: 201.012344, 18
    [20:55] Object: 201.056641, 19
    [20:55] Object: 201.101532, 20
    [20:55] Object: 201.145615, 21
    [20:55] Object: 201.190277, 22
    [20:55] Object: 201.279678, 23
    [20:56] Object: 221.326843, 0
    [20:56] Object: 221.371201, 1
    [20:56] Object: 221.415955, 2
    [20:56] Object: HTTP REQUEST EXCEEDED THROTTLE (But how?)

    Normal too : 

    at t = 20 my quota is 0 ( for the second bucket ) + % time to left = 100% * 24( number of request in the last bucket ) = 24

    i can send one but only one 

    at t = 221.41 , my quota is 2 ( for the second bucket ) + % time to left =  (20-1.41)/20* 24( number of request in the last bucket ) = 24.308

    i can reach the throttle if i send an another ; it s what is happened


    In fact , your script confirms the formula of Kelly Linden 

     

     ( i m sorry for your JIRA , i don t have acces to it )

     

  16. Personnaly , i am uing at the most the keys. because even if they are longer than names they can be better compressed, and because nearly every functions requires a key in parameter.

     

    And it s faster to index in a database, too

    I m storing the couples in my side the couple names,keys. Because it allows me when i want to fetch some keys , to call my private url with several names in parameters and fetch in one http call , several keys .

    I don t care to store every keys . Only the keys from my most important groups are enough . The testclient program from libomv and the command groupmember  gives me the keys . And it can fetch some thousands of keys quickly

     

    Even if Linden would create a "perfect webservice" , there are great chances it will allow only one name in parameter, and not a list

     

     

     

  17. "Tula resident" doesn t exist ... ( or had been purged after a delete of her account)

    So it s normal that the sort by relevance gives something else for the 1st name of the list

     

    So you don t need to parse every pages

     

    Anyway vwrsearch could not check if an avatar has been purged or not. And you needed a proxy to use vwrsearch

  18. If you don t want to modify the settings , you can try to make your script with the two contitions from Kelly linden above .

     

    I have tried to make a version based on your script .

    I  have not tested it intensively , but  the first hour is ok

     

    Probably there is something to change when the URL doesn t answer , but i don t know what

     

    Have a look on the timer event in the state "running" below

     

    integer NEW_URL_MSG = -9955;float REQ_INTERVAL = 900; // 20 seconds * 45 FPSinteger REQ_CAP = 25;string sendToURL;key urlRequestID;integer isFirstBucket = TRUE;integer numberInOldBucket;integer numberInNewBucket;integer numberBuckets;integer numberRequests;integer startTime;integer referenceFrame;integer currentFrame;integer COUNTERMAX = 40 ;integer counter  ; // time in second before to clean and to start the scriptdefault{    state_entry()    {        llOwnerSay("Be warned : if you reset the script you should wait 40 seconds        to clean the buckets . If you don t clean them you could have wrong results");            }    touch_end(integer n)    {        if ( llDetectedKey(0) == llGetOwner())        {            counter = COUNTERMAX;            llSetTimerEvent(1.0);        }                  }    timer()    {        llSetLinkPrimitiveParamsFast(LINK_THIS , [ PRIM_TEXT, "The requests will start in "+ 
    (string)(counter--) +" seconds ", <1,1,1>,1]); if ( counter <= 0) { llSetTimerEvent(0.0); state running; } }}state running{ state_entry() { llReleaseURL(urlRequestID); urlRequestID = llRequestURL(); } http_request(key id, string method, string body) { if (id == urlRequestID) { if (method == "URL_REQUEST_GRANTED") { llOwnerSay(body); // llResetTime(); referenceFrame = (integer)llGetEnv("frame_number"); sendToURL = body; llSetTimerEvent(1/45.0); startTime = llGetUnixTime(); numberBuckets =0; numberRequests =0; } else llOwnerSay("Request for URL failed with method = "+ method); } else llHTTPResponse(id, 200, "if you say so"); } timer() { // I wont mesure time with llGetTime , llGetUnixTime , because they are real world time . // I ll prefer to measure time in Frames of sim . If the sim lags , the script is dilated ,
    // but the throttle is maybe dilated too // llSetTimerEvent(llFrand(0.5)); // Way too fast currentFrame = (integer)llGetEnv("frame_number") - referenceFrame; if (currentFrame > REQ_INTERVAL) { referenceFrame = (integer)llGetEnv("frame_number"); isFirstBucket = FALSE; numberInOldBucket = numberInNewBucket; numberInNewBucket = 0; numberBuckets++; return; } // this is the formula from Kelly Linden // In fact i don t know if KellyLinden counts the current request when it hits the throttle // I prefer count it and add one to the variables numberInNewBucket and numberInOldBucket // To add , to be safer , i prefer to limit my throttle to 24 requests and not 25 requests // It can be safer when time to left in the bucket is low , and the numberInNewBucket
    //and numberInOldBucket are high ( because of rounding float 32 bits approximations) // As i don t know how round Kelly Linden his percent of time to left , i prefer
    // to keep a little margin . if ( (numberInNewBucket + 1 + llCeil((REQ_INTERVAL - currentFrame ) / REQ_INTERVAL * (numberInOldBucket+1)) >= REQ_CAP - 1)) { return; } else if ( isFirstBucket && (numberInNewBucket < REQ_CAP )) { numberInNewBucket++; } else if ( isFirstBucket && (numberInNewBucket >= REQ_CAP )) { return; } else if ( !isFirstBucket && (numberInNewBucket >= REQ_CAP )) { return; } else if ( !isFirstBucket && (numberInNewBucket < REQ_CAP )) { numberInNewBucket++; } else { return; } key reqID = llHTTPRequest(sendToURL, [ HTTP_METHOD, "PUT" , HTTP_VERBOSE_THROTTLE, FALSE // remove this to see the script error ], ""); numberRequests++; list rules = [ PRIM_TEXT , "numberRequests : " + (string)numberRequests + "\n" + "numberBuckets : " +(string) numberBuckets + "\n" + "realtime : " + (string)(llGetUnixTime()-startTime ) , <1,1,1>, 1 ]; llSetLinkPrimitiveParamsFast(LINK_THIS , rules); if (NULL_KEY == reqID) { llOwnerSay("HTTP REQUEST EXCEEDED THROTTLE (But how?)"); // llSetTimerEvent(llFabs(now - REQ_INTERVAL)); llOwnerSay(llList2CSV( [ "numberRequests", numberRequests, "\n", "numberBuckets", numberBuckets, "\n", "time", llGetUnixTime()-startTime, "\n", "new", numberInNewBucket, "\n", "old", numberInOldBucket, "\n", "frame", currentFrame, "\n", "test", numberInNewBucket + llCeil((REQ_INTERVAL - currentFrame ) / REQ_INTERVAL * (numberInOldBucket+1)) , "\n" ])); llSetTimerEvent(0.0); state default; } } }

     

  19. I think :

    there is a throttle of 25/ request per 20 seconds .

    When an llhttprequest is called :

    - it fills a stack or a queue .with a timestamp

    - it tests if the size of this queue is > 25 ( if TRUE  trigges the throttle , , if false call the URL )

    - it deletes the elements of the queue older than 40 seconds

     

     *** correction : see below

     

     

     

     

    So .. Your script should work with parameters :

    integer REQ_INTERVAL = 40;
    integer REQ_CAP = 25;

     

    Wel , i have tried your script with these setting and changed too by

    endSustainedInterval = llGetUnixTime()+500;

    to watch longer .

    It looks work wthout trigger the throttle

     

     

    ***edit ***

     

    Oh .. in fact the old answer of Kelly Linden from http://forums-archive.secondlife.com/139/2c/109571/1.html  seems always right . But we need just to replace 100 seconds by 20 seconds and 20 requests by 25 requests . 

    So it gives

     

    Long answer: The throttle uses a moving window to continue to block things that don't slow down. Starting with the first request, requests are counted in 20 second buckets. For 20 seconds from the first request all requests go into a single bucket, 20  seconds later a new bucket is started ... but the last bucket is kept around.

    condition 1 :

    If the current bucket has more than the throttle limit (25 ) then requests will be blocked.

    condition 2 :

    If the current total + (% of time remaining in this bucket * total from last bucket) is more than the throttle (25) then requests are blocked.

     


    Of course , after 40 seconds , the old bucket is empty . so the second condition is equivalent  to

    total from current bucket  + (  %time  * 0 ) < 25  ; so it s equivalent to the first condition

    Thats why i have found with REQ_INTERVAL = 40 and  REQ_CAP = 25 , your script doesn t trigger throttle . 

     

    Normally your script could use only two conters , you shouldn t  need to use lists of timestamps

  20. You need to sequence the comportment of your script .

     

    To sequence , use the states 

    For instance :

    one state ( the default ) to manage the touch

    one state to manage the option menu

    one state to manage the avatars menu

     

    list listOptions = [ "banana", "egg", "cheese" , "pizza" ];list listAvatarsSensor;integer channelDialog ;integer handleListener;string choicedOption ;string avatarNameHavingMenu;key avatarKeyHavingMenu;float timerDialog = 15.0;float range = 10.0;default{    // We dont want several users using at the same time the menu    touch_end(integer total_number)    {        // lets s store the avatar havaing the menu to be able to dialog with him in teh other states        avatarNameHavingMenu = llDetectedName(0);        avatarKeyHavingMenu =llDetectedKey(0);        state firstDialog;     }}// This state starts to display the menu of option to the user // After his choice , this state will scan the avatars around the prim// and  go to the next state ( display the second menu )state firstDialog{    state_entry()    {        channelDialog= (integer)(llFrand(-1000000000.0) - 1000000000.0);        handleListener = llListen(channelDialog, avatarNameHavingMenu , avatarKeyHavingMenu  , "");        llDialog(avatarKeyHavingMenu, "Choose an option" , listOptions, channelDialog );        llSetTimerEvent(timerDialog);     }    listen( integer i, string n , key k, string m)    {        // the user having the menu has answered his choice of option .        // let s scan the avatars to be able to build the second menu        choicedOption = m;        llSensor("",NULL_KEY,AGENT,range,PI);    }    sensor(integer n)    {        integer i ;        listAvatarsSensor = [];        do        {            listAvatarsSensor += llGetSubString(llDetectedName(i), 0, 23) ;            i++;        } while ( i < n);        state secondDialog;    }    timer()    {        // the user doesn t answer . Ok . Let s give up and we return in the default state         state default;    }     state_exit()    {        // normally we don t need to release the listener . It s released automatically after change states        llListenRemove(handleListener);
    llSetTimerEvent(0.0); }} state secondDialog{ state_entry() { channelDialog= (integer)(llFrand(-1000000000.0) - 1000000000.0); handleListener = llListen(channelDialog, avatarNameHavingMenu, avatarKeyHavingMenu , ""); llDialog( avatarKeyHavingMenu, "Choose an avatar" , listAvatarsSensor, channelDialog ); llSetTimerEvent(timerDialog); } listen( integer i, string n , key k, string m) { // the user having the menu has answered his choice of avatar . // let s do our action "llownerSay" and let s go back at the default state to be able to detect other touch events llOwnerSay( choicedOption + " for " + m ); state default; } timer() { // the user doesn t answer . Ok . Let s give up and we return in the default state state default; } state_exit() { // normally we don t needd to release the listener . It s released automatically after change states llListenRemove(handleListener);
    llSetTimerEvent(0.0); } }

     

×
×
  • Create New...