Miranda Umino
-
Posts
411 -
Joined
-
Last visited
Content Type
Forums
Blogs
Knowledge Base
Posts posted by Miranda Umino
-
-
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.
- 1
-
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}
-
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() ])); }}
-
@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.
-
in LSL : no
in a media on prim : i am not sure .
On the web , some flash/shockwave application can access to your microphone and camera . But there is a specific dialog box for the user to allow it . And the QT webtoolkit doesn t give the focus to the buttons of this dialog box .
Probably a bug of the QT webtoolkit
-
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
-
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(); } }- 1
-
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
-
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
-
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 .
// C see http://ideone.com/gErnA1#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//C# see http://ideone.com/pGfUbUusing 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 .
-
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
-
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
-
Hi , Qie .
I have noticed that Mestro has brought some cralrifications of explanations in the wiki about llHttpRequest
http://wiki.secondlife.com/w/index.php?title=LlHTTPRequest&action=history
Did you get more informations inside your JIRA ?
-
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 errors5-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
-
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
-
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 )
-
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
-
Some people from 2006 have told already this.
Probably it s better to change our logic of scripts than to wait the birth of an hypothetical perfect webservice
-
You assume than vwsrsearch was perfect .. it didn t ...you had already some wrong results
Prove : your own post was criticizing vwrsearch :
https://lists.secondlife.com/pipermail/secondlifescripters/2011-October/006390.html
-
"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
-
-
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; } } } -
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 tototal 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
-
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); } }
List array question
in LSL Scripting
Posted
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