Jump to content

Profaitchikenz Haiku

Resident
  • Posts

    2,836
  • Joined

  • Last visited

Everything posted by Profaitchikenz Haiku

  1. One other thought: check your parcel object numbers and possibly also the whole region figures: if you are setting out lots of extra objects for an event and go over the region or parcel limits it is possible some of your objects are being returned. Look in your Lost and Found folder for such items.
  2. Get a visitor recording script to monitor your parcel and log the names and times of all visitors to try and identify the actual culprits. Be wary of just blindly firing off names to Linden Lab in Abuse reports, you are going to have to spend some time tracking down exactly what is going on. Make sure that only the land group has rezzing rights in your parcel. The path-cut issue is strange, it suggests the object in question allows group members to move or change it. The other explanation is that you have given somebody else edit rights to your objects. Go through your group list and friends looking for any such rights or permissions. ETA Regarding the comments above about re-opening an old thread: this can cause a lot of fuss on the forums and it is possibly that some of the recent replies are going to be removed by a moderator on the basis that your problem is not directly related to the original subject or far too large a gap has elapsed for your post to add relevance. Don't despair, take a deep breath, and open a new topic under the heading of something like "Unknown persons interfering with my parcel". I would also suggest you try something else: In the about land information, turn off the option that allows avatars n adjacent parcels to see into and chat with residents on your parcel, and also turn off the option to allow object entry. This does mean that visitors to your club cannot drive/fly in from adjacent areas but have to walk or TP in via a landmark, but it will give you back a little more control over who comes into your club and what they can bring with them.
  3. we need an emoticon for "claps hand over face"
  4. I too logged in this morning to find Ms Moose had come a-calling. Heatfelt thanks to whom it might be, it's a wonderful way to liven people up.
  5. Time dilation: I have been asked why I am not applying the current region time dilation to the timeout periods I am using to look for moving_end or at_target failures. I looked at them when I was experimenting with the timer test. In the worst of the regions I was examining, the time dilation was typically 0.995. This means that instead of setting a timer interval of 1.0 seconds, applying the current time dilation figure would have meant setting a timer interval of 1.005 seconds. From the post by Kelly Linden back in 2011, this would have been outside the minimum discrimination of a frame, 1/45 of a second. In the case of the moving_end timeout for a ten second journey, applying the time dilation figure of 0.995 to a ten-second movement would have resulted in a value of 10.05 seconds. As you will have seen in the script, I ended up having to use an over-run of 15% in order to avoid having constant moving_end timeouts. If I were to have achieved that figure via the time-dilation I would have needed to see 0.85 as the current value. There is no sign that it is time dilation causing KFM and moveToTarget journeys to take longer than expected, it seems more likely that the region is busy with lots of other things, (or is being lightly idled or somehow having resource shifted from it to another region), as the physics FPS figures and Region FPS figures for the worst case region were also good most of the time. (Sitting typing this whilst watching the stats monitor out of the corner of my eye, I saw the figures drop from the steady 45 and 44.5 to 36 for a second or so, possibly somebody arriving with a Hud or four?). So the time dilation figures as presented by the stats floater are not bad enough to explain the need to apply a 0.15 correction factor to a 10 second interval, but interestingly enough, that region had 120 seconds drift from a total of 86340 wallclock seconds, and as a percentage, that comes out to 0.14 ....Maybe the time test isn't so useless after all? ETA Ah but.... in the best region I am monitoring there is zero drift, and in the premium sandbox where I derived the 0.15 overrun empirically, there was also zero drift.
  6. /me now can't stop humming "Chim-chimiinee, chim-chiminee, chim-chim-cherree"
  7. The KFM tests have been throwing up some results that are counter-intuitive to say the least This next test is a slight variation to use llMoveToTarget instead of Keyframed motion, and it threw up something unexpected immediately. When you issue a command to move to a target "critically damped in n seconds" the initial assumption is that it will reach the target in that many seconds. Watching the object in motion showed that it began to slow down as it moved, and as it got nearer to the target, it slowed more and more. After a lot of fiddling I determined empirically that the time "t" seconds for "damping" gave an actual time to reach the specified range around the target of 3,33 * t, provided the range was 1 metre. Trying to get to within half a metre of the target was going to take even more time so I settled on a range of 1 metre. That then threw up yet another problem. The sphere steadily made shorter and shorter journeys because each time it triggered at_target, it was a metre less than the actual destination, and this metre drift accumulated until I could see eventually the sphere would be traveling across or around a square one metre along the side. Here is a script set up in a premium sandbox with few present to achieve the best ratio of successful journeys to timeouts and late ones. I suggest rezzing it to be one metre higher than the KFMM sphere, since this will be a physical object when in motion and most definitely doesn't want to be colliding with anything. // Test moves to a target position in a region by repeated moves along known paths // since the distances are known and the speed is specified the journey time can be computed // and compared with the actual times of moving_end // the course is across the diagonals and along two sides of s 20m x 20 square path. // rezz a sphere at the Low-X low_y corner of the intended square and it will compute the corners key owner; integer debug = 0; integer myChan = -17; // let's not get confused with the KFM test if that's nearby integer cHandle; list points = []; integer maxPoints; integer thisPoint; vector startPos; vector thisPos; vector nextPos; float dist; // distance to be moved from current point to next point integer tHandle; // target handle for the move float moveTime; // to be in whole seconds of 5 or 10 seconds chosen at randomn float timeOut; // movetime + extra to test for no moving_end float fiddleFactor = 0.35; // adjustments for the way llMoveToTarget uses x seconds to actually get to within 1 metre, // think Zeno's paradox of motion but instead of halving the remaining distance, // use 0.35 as the distance reduction float startTime; float endTime; float timeDiff; integer running; // non-zero when running the test string timerAction; // records what is to be done when the timer fires integer journeys = 0; // count of journeys made integer noEnd = 0; // count of at_target timeouts integer tooLong = 0; // count of journey time longer than optimum (will include timeouts) Dout(string message) { llOwnerSay(message); } announce(string message) { llSetText(message,<1.0,1.0,1.0>,1.0); } setPoints() { vector pos = startPos; llOwnerSay("Start from " + (string) startPos); points = [pos]; pos += <20.0, 20.0, 0.0>; // move across diagonal llOwnerSay("Move diagonally to " + (string) pos); points += pos; pos += <0.0, -20.0, 0.0>; // move back along on side llOwnerSay("Move back along side to " + (string) pos ); points += [pos]; pos += <-20.0, 20.0, 0.0>; // move along the other diagonal llOwnerSay("Move diagonally to " + (string) pos); points += [pos]; // next point is back to the start pos += <0.0, -20.0, 0.0>; llOwnerSay("Start and positions " + (string) startPos + " , " + (string) pos); maxPoints = llGetListLength(points); } nextMove() { announce("Journeys " + (string) journeys + "\nend timeout " + (string) noEnd + "\nLate " + (string) tooLong); thisPoint += 1; if( thisPoint >= maxPoints) thisPoint = 0; thisPos = llGetPos(); nextPos = llList2Vector(points, thisPoint); dist = llVecDist(thisPos, nextPos); if( debug) Dout("Next Point " + (string) thisPoint + " From " + (string) thisPos + " to " + (string) nextPos + " dist " + (string) dist); float ranVal = llFrand(1.0); if( ranVal > 0.5 ) moveTime = 10.0; else moveTime = 5.0; timeOut = moveTime * (fiddleFactor * 10); // speed is reduced as the target is approached resulting in the final 1/3 distance // taking perhaps as long as the other 2/3rd? timerAction = "moving"; if( debug) Dout("MoveToTarget " + (string) nextPos + " " + " time " + (string) moveTime); llSetTimerEvent(timeOut); // test for moving_start startTime = llGetTime(); ++journeys; llSetStatus(STATUS_PHYSICS, TRUE); tHandle = llTarget(nextPos, 1.0); // trying to get to 0.5 was a nightmare llMoveToTarget(nextPos, moveTime); } default { on_rez(integer n) { llStopMoveToTarget(); // kill any residual motion if taken back into inventory whilst moving llSetStatus(STATUS_PHYSICS, FALSE); llTargetRemove(tHandle); llSetTimerEvent(0.0); llResetScript(); } state_entry() { owner = llGetOwner(); llSetTimerEvent(0.0); timerAction = ""; running = 0; if( points == []) { startPos = llGetPos(); setPoints(); } cHandle = llListen(myChan, "", owner, ""); llSetRegionPos(startPos); thisPoint = 0; if( maxPoints > 0) { announce("Ready"); llOwnerSay("Touch to start the test, touch to end it, or say \"stop\" on channel " + (string) myChan); } } listen(integer chan, string name, key id, string msg) { if( msg == "stop" || msg == "reset" ) { llSetTimerEvent(0.0); timerAction = ""; llStopMoveToTarget(); llTargetRemove(tHandle); llSetStatus(STATUS_PHYSICS, FALSE); running = 0; if( msg == "reset") { llOwnerSay("Last Journeys " + (string) journeys); llOwnerSay("Last End timeouts " + (string) noEnd); llOwnerSay("Last late " + (string) tooLong); llSetRegionPos(startPos); thisPoint = 0; journeys = 0; noEnd = 0; tooLong = 0; } announce("Journeys " + (string) journeys + "\nend timeout " + (string) noEnd + "\nLate " + (string) tooLong); } else if( msg == "report") { llOwnerSay("Journeys " + (string) journeys); llOwnerSay("End timeouts " + (string) noEnd); llOwnerSay("late " + (string) tooLong); } else if( msg == "debug") { debug = ~debug; } } touch_start(integer touches) { key toucher = llDetectedKey(touches - 1); if( toucher == owner) { if (!running) { running = 1; nextMove(); } else { llSetTimerEvent(0.0); timerAction = ""; llStopMoveToTarget(); llTargetRemove(tHandle); llSetStatus(STATUS_PHYSICS, FALSE); running = 0; announce("Journeys " + (string) journeys + "\nend timeout " + (string) noEnd + "\nLate " + (string) tooLong); } } } at_target(integer thisTarget, vector targetPos, vector ourPos) { llSetTimerEvent(0.0); endTime = llGetTime(); if( debug) Dout("at_target"); llStopMoveToTarget(); llSetStatus(STATUS_PHYSICS, FALSE); // calculate times timeDiff = endTime - startTime; // Actual time if( timeDiff > moveTime) { float diff = timeDiff - (moveTime*3.0); if( diff > (moveTime * fiddleFactor)) tooLong +=1; // movement using llMoveToTarget is not at all linear } timerAction = ""; llTargetRemove(tHandle); llSetRegionPos(targetPos); // because at_target is only within 1 metre of the position, over time the square will shrink // unless we correct the position each time if( running) nextMove(); } timer() { llSetTimerEvent(0.0); if( debug) Dout("Timeout for " + timerAction); if( timerAction == "moving") { llStopMoveToTarget(); llTargetRemove(tHandle); llSetStatus(STATUS_PHYSICS, FALSE); timerAction = ""; ++noEnd; if( running) nextMove(); else announce("Journeys " + (string) journeys + "\nend timeout " + (string) noEnd + "\nLate " + (string) tooLong); } } }
  8. Except those who have bought the homes, houses, mesh clothes, bodies... There's a gambling term pot-committed, where the player has put in so much they cannot bring themselves to get up and leave the table, even though they may end up losing it all
  9. well, you'll not get a bezier out of that, surely the best thing to do is halt the Bezier curve early when a collision is imminent and find a new curve that avoids the obstacle?
  10. Here is a stab at a pseudo-code (text flowchart) descrption of what I think you need to do Set up initial conditions (range, parcel boundaries), kill any residual KFM set b_i to 0 set bi_limit to frames When touched, enter a move routine if b_i == 0 call coeffirst, increment b_i and if( b_i < bi_limit) calculate a point on the bezier curve , clip it to parcel boundaries, initiate KFM when moving_end occurs, go back into the increment b_i process to calculate the next point and move to it
  11. Here is a version of your routine that does actually make a move. I commented out targets coding through the code because it wasn't being used in a comprehensible way: (a target was being set then removed before even calling the routine that was going to try and move to that target), and also there is currently no means at the at_target event of stepping through the parts of the bezier curve. Instead, I used moving_end. However, it won't work in the way you want because at the moment, you don''t go through each incremental part of the calculated bezier curves from one to the next. I can't see a quick and easy easy for me to add a kick-off in moving_end to the next point on the bezier curve because you re using local variable-controlled do_loops inside the touch_event, and no obvious coding anywhere else to increment b_i from 1 to liN, which is what you must do to get all the points along the bezier As I read your code at present, you call nextCoordinates to generate a bezier point according to global b_i b_i needs to increment from 1 to liN to generate a set of points along the bezier Therefore each time you finish a short move you need somewhere to increment b_i, call next_coordinates again, and pass the new coordinates back into __loadCoordinates to then make the next keyframed move. I think you need to make something like a flow chart to work out where you are doing the important calculation parts and in what order the routines are to be called. But hopefully the fact that you can see this code actually working and moving a prim will inspire you to rework the code. integer target_wander_id= 0; integer on_ground_not_flying =0; vector WANDER_RANGE = <20.0,20.0,0.0>; // I HAVE SET Z to 0.0 FOR TESTING ON THE GROUND Set ranges to wander vector iPos; vector pos; vector vLastRelPos; float TARGET_AFFINITY = .4; // How fast will the primitive try to reach the list lCoordinate=[]; rotation lastRot; vector my_home; integer TYPE_FLIGHT; float timer_wander; vector nex_pos; float FUDGE = 0.1; // random delay in flight speed float SPEED = 1.0; // speed of flight. //integer target; Dout( string s) { llOwnerSay(s); } Debug( string s ) { llSetText( s, <1,1,1>, 1.0 ); //llSetText( "", <1,1,1>, 1.0 ); } rotation NormRot(rotation Q) { float MagQ = llSqrt(Q.x*Q.x + Q.y*Q.y +Q.z*Q.z + Q.s*Q.s); return <Q.x/MagQ, Q.y/MagQ, Q.z/MagQ, Q.s/MagQ>; } vector range = < 5.0, 5.0, 5.0 >; rotation homeRot; vector LEFT=< 0.0, 1.0, 0.0 >; rotation refFrame=<0,0,-0.71,0.71>; vector P1; vector P2; vector P3; vector Q1; vector Q2; vector Q3; integer b_i=0; integer liN = 5; // was 24 rotation newrot =ZERO_ROTATION; vector randomP() { return llGetPos() + < WANDER_RANGE.x*(llFrand( 2.0)-1.0), WANDER_RANGE.y*(llFrand( 2.0)-1.0), WANDER_RANGE.z*(llFrand( 2.0)-1.0) > * homeRot; } coefisFirst() { P0 = llGetPos(); Po0 = P0; // why? P3 = randomP(); P2 = randomP(); P1 = randomP(); Po1 = P1; // why? Q1 = 3.0*P1-3.0*P0; Q2 = 3.0*P0-6.0*P1+3.0*P2; Q3 = 3.0*P1-P0+P3-3.0*P2; Dout("coefisFirst P1 " + (string) P1 + " P2 " + (string) P2 + " P3 " + (string) P3); Dout(" and Q1 " + (string) Q1 + " Q2 " + (string) Q2 + " Q3 " + (string) Q3); } coefisNext() { P0 = P3; P1 = 2.0*P3-P2; P3 = randomP(); P2 = randomP(); Q1 = 3.0*P1-3.0*P0; Q2 = 3.0*P0-6.0*P1+3.0*P2; Q3 = 3.0*P1-P0+P3-3.0*P2; } vector Bez( float x ) { // Dout("Bez with x = " + (string) x); return P0 + (Q1 + (Q2 + Q3*x)*x)*x; } // note if you pass in 0.0 you will get back P0 !!!! vector dBez( float x ) { // Dout("dBez with x = " + (string) x); return Q1 + (2.0*Q2 + 3.0*Q3*x)*x; } // note if you pass in 0.0 you will get back Q1 !!! rotation Vec2Rot( vector FWD ) { FWD = llVecNorm( FWD ); vector UP = < 0.0, 0.0, 1.0 >; if ( llFabs(FWD.z) < 1.0 ) LEFT = llVecNorm(UP%FWD); UP = llVecNorm(FWD%LEFT); return refFrame*llAxes2Rot(FWD, LEFT, UP); } //integer __llTargetRemove(integer _id){ // llTargetRemove(_id); // return 0; //} integer checkInside2(vector bottomLeftCorner, vector topRightBack, vector pos) { if (topRightBack == ZERO_VECTOR || bottomLeftCorner == ZERO_VECTOR || pos.x < bottomLeftCorner.x || pos.y < bottomLeftCorner.y || pos.x > topRightBack.x || pos.y > topRightBack.y || pos.z > topRightBack.z ) { return FALSE; // If weare outside area } return TRUE; } vector Po0; vector Po1; vector P0; integer _llObtainLinkFromKey(key l_key) { integer l_i = llGetNumberOfPrims(); if(llGetLinkKey(l_i ) == l_key) return l_i; for(; l_i--;) if(llGetLinkKey(l_i ) == l_key) return l_i; return -1; } vector clipRegion(vector bot, vector top, vector pos) { Dout("clipRegion bot " + (string) bot + " top " + (string) top + " position " + (string) pos); if (pos.x < bot.x) pos.x = bot.x; else if (pos.x > top.x) pos.x = top.x; if (pos.y < bot.y) pos.y = bot.y; else if (pos.y > top.y) pos.y = top.y; if (pos.z < bot.z) pos.z = bot.z; else if (pos.z > top.z) pos.z = top.z; Dout("clipRegion result is " + (string) pos); return pos; } vector nextCoordinates(integer p_TYPE) { vector myNewPos; Dout("nextCoordinates b_i = " + (string) b_i); if (b_i == liN || b_i == 0) { b_i = 1; coefisFirst();} // START FROM 1 not 0 myNewPos = Bez( b_i/ (float) liN); // trivial point but it is a float in my one-shot newrot = Vec2Rot(dBez( b_i/ (float) liN)); b_i++; Dout("nextCoordinates result myNewPos:"+(string)myNewPos+", newrot:"+(string)newrot+", TYPE:" +(string)p_TYPE+" b_i:"+(string)b_i); return myNewPos; } integer __loadCoordinates(vector l_pos ,vector l_dest,rotation l_rot, float time , integer target) { //Debug("Load Points..."); Dout("__loadCoordinates lpos:"+(string)l_pos+", lDest:"+(string)l_dest); // time = distance/velocity time = (float)llVecDist(l_pos,(l_pos+l_dest))/TARGET_AFFINITY; if(time < 0.2) time = .3; lCoordinate = []; lCoordinate +=l_dest; lCoordinate += l_rot; // * any new rot relative to current position. lCoordinate +=time; pos = l_pos+l_dest; vLastRelPos =pos; lastRot = llGetRot(); //iStartTimer = TRUE; // target = __llTargetRemove((integer)target); WHY REMOVE IT BEFORE YOU EVEN TRY TO GO TO IT ? Dout( "__loadCoordinates result At " + (string) llGetPos() + " KIFM to " + llDumpList2String(lCoordinate, ",") ); llSetKeyframedMotion(lCoordinate, [KFM_DATA, KFM_TRANSLATION|KFM_ROTATION, KFM_MODE, KFM_FORWARD]); //iStartTimer = FALSE; return llTarget(pos, 50.0); } _llWanderWithinKeyframe (vector home, vector range, list c) { pos = llGetPos(); iPos = llGetPos(); // THIS IS WHERE WE are, do not change it! Dout("Wander within key frame from " + (string) iPos); list TYPE = [9] ; // ,16,32,64,128,126]; integer vAreaParcelsqm = llList2Integer(llGetParcelDetails(iPos,[PARCEL_DETAILS_AREA]),0); vector area = < vAreaParcelsqm -.25, vAreaParcelsqm -.25,vAreaParcelsqm -.25>; vector bot = my_home-WANDER_RANGE/2.0; vector top = my_home+WANDER_RANGE/2.0; //llInstantMessage(llGetOwner(),"bot:"+(string)bot+"top:"+(string)top); // if(TYPE_COUNT++ > 1) { TYPE_COUNT = 0; TYPE_FLIGHT = // (integer)(llFrand(7.0)); iPos = llGetPos();} TYPE_FLIGHT = 0; if( TYPE_FLIGHT == 10) {TYPE_FLIGHT == 0; iPos = llGetPos();} integer i = liN; // was 20, should be the number of frames the curve is divided into; //timer_wander = llGetUnixTime(); do { nex_pos = clipRegion(bot,top,nextCoordinates(llList2Integer(TYPE,TYPE_FLIGHT) )); //Dout("_llWanderWithinKeyframe:Process point:"+(string)nex_pos); Dout( "wanderwithin i = " + (string) i + " next_pos " + (string) nex_pos); } while(checkInside2(bot,top,nex_pos) == FALSE && i-- >0); // this is the wrong place to decrement i if(nex_pos != ZERO_VECTOR && i!=0) { Dout("_llWanderWithinKeyframe: Moving from ipos: "+(string)iPos+" to next "+ (string)nex_pos); if(TYPE_FLIGHT != 9) newrot = llGetRot(); target_wander_id = __loadCoordinates(iPos,(nex_pos-iPos),newrot, llFrand(FUDGE)+ (nex_pos.z)/SPEED,target_wander_id); } else Dout("Wander within no movewment because nex_pos = " + (string) nex_pos + " and/or i = " + (string) i); // and now decrement I and repeat the loop } key owner; default { state_entry() { owner = llGetOwner(); pos = llGetPos(); iPos = pos; my_home = llGetPos(); llSetLinkPrimitiveParamsFast(LINK_THIS, [PRIM_PHYSICS_SHAPE_TYPE, PRIM_PHYSICS_SHAPE_CONVEX]); llSetKeyframedMotion([],[]); // IMPORTANT, KILL ANY PRIM_PROERTY KFM } touch_start(integer total_number) { integer i = 3; // 10; do { _llWanderWithinKeyframe (llGetPos(),WANDER_RANGE, []); } while(i-- > 0); } //at_target(integer tnum, vector targetpos, vector ourpos) { // Dout("At target"); // if(tnum == target_wander_id) { // llSetKeyframedMotion([],[]); // IMPORTANT otherwise it won't stop moving // //iStartTimer = FALSE; // target_wander_id = __llTargetRemove(target_wander_id); // } // } moving_end() { llOwnerSay("We have arrived"); llSetKeyframedMotion([],[]); // IMPORTANT otherwise it won't stop moving // AND NOW add code to go and calculate the nextr series of moves } }
  12. Security orbs will often show a blue popup giving you a warning of imminent ejection then throw you out, but when you are ejected by a landowner you receive a message after you are TP-ed home or moved to outside the parcel.
  13. Did you simply get thrown across the region, or did you see a blue popup or get a text message saying you were getting ejected? For future reference, look under "help" for "Bumps pushes and hits and see if t reports anybody pushing you.
  14. No, but that wasn't the situation described by the OP, it sounded much more like a push.
  15. I'm going to watch Mr CanIdoIt and Mr Crashstappen sort out who's the top hot-dog, then I'll have another look at thhis.
  16. If they are already wearing the Hud when they enter the parcel they don't need permission. You can turn off things like all residents run scripts but there are methods to keep AOs and Huds running even in such conditions. Stay seated all the time.
  17. Yes, I also gt more vertical movement than horizontal but I didn't have a lot of time. Once I get the region monitoring project sorted I'll have another look. Regarding the vertical movement, chat out the two vectors frrom which you derive the KFM delta, which are the current position and the result of clipping the generated bezier position to region coordinates, and look at the delta produced. Is all the difference in the Z coordinates?
  18. That sounds more like they just pushed you with a script. In confrontations such as those, stay seated on anything convenient. A seated avatar can't be pushed.
  19. Tell me all about it. My partner has a degree in maths and physics, she views the universe as duty-bound to obey the rules she thinks it ought to. I am an engineer, I know there's a lot of compromise, trickery and gaffer-tape required to coexist in the actual world.
  20. The previous three tests have been largely pointless: 1) Messages : I have yet to detect any instances of llSay and llRegionSay messages on channels other then 0 being delayed or dropped. (Chat-lag on channel 0 is something else, as explained by Oz Linden at a Server User Group meeting it is a rendering issue, all the letters put up in the chat floater are drawn there pixel by pixel, so if there's a mass of drawing to be done, they get put in the queue). 2) Times : There has been drift measured in the tests but not enough to be considered significant (45 seconds lost in 34185 in the worst-affected region is less than 0.2%) Some of the lost seconds can be explained by the momentary hit each time an avatar with scripted attachments enters the region. 3) Prime number-crunching: Although this does show that the worse the region performance the more time is required to compute, this is hardly a surprise, and in addition, SL is not intended to be a heavy-computational platform. The next test is closer to measuring some of the visible degradation that people have complained about; starting to move, moving, and stopping movement of scripted objects. It uses Keyframed Motion to send a sphere along several paths of two distinct lengths, using one of two definite times for the motion. It uses timers to detect for two particular problems that have been observed in the past: a) Keyframedmotion does not start promptly enough (if at all) and so moving_start was not received. b) Keyframed motion took much longer than expected and moving_end was not raised (instancees were seen of the object stopped just a few metres from the intended destination apparently frozen). In addition, the script records how often the journey took more than 5% longer than expected (this count includes the above moving_end failures but also those where moving_end was received but after the 5% point). Reports of the runs in various regions will follow in a few days, here is the test for those wishing to try it for themselves. Note that, as was mentioned in the time test, an avatar with heavy scripts entering a region may well account for some of the failures for moving_end, or the extended journey time. ETA Typical, mistakes seem to only become visible some time after publication: The moving_end count includes all of the late counts, not vice-versa as I stated // Test Keyframed motion in a region by repeated moves along known paths // since the distances are known and the desired time is specified the journey time can be computed // and compared with the actual times of moving_end // the course is across the diagonals and along two sides of s 20m x 20 square path. // rezz a sphere at the Low-X low_y corner of the intended square and it will compute the corners // move the square and reset the script to get the desired figures // for parcels with not enough room for a 20x20 square amend xOffset and yOffset as appropriate // Set Z hieght to try and avoid any collisions with avatars and objects, KFM ignores collisions except // with physical objects but we don't want to add more to the region load than is absolutely necessary // // Touch to start, then issue commands on channel /-13 // report - chats out the collected stats // debug - toggles debug on or off for a more detailed view of what is happening when // stop - ceases action // reset - ceases action, clears the counters, and goes back to the start+ // // Reported stats are // Journeys made - each separate KFM move is a journey // Start timeout - number of times moving_start failed to be raised withing 0.5 seconds of starting movement // End timeout - number of times moving_end failed to be raised after the expected movement time plus 15% // Late - number of times the journey took more than 5% longer than expected (includes the moving_end instances obviously) key owner; integer debug = 0; integer myChan = -13; integer cHandle; float xOffset = 20.0; // adjust these for the size of square/rectangle to be created float yOffset = 20.0; // starting from the initial position // no need to amend further portions list points = []; integer maxPoints; integer thisPoint; vector startPos; // thge low-X low-Y corner of a rectangle vector thisPos; vector nextPos; float dist; // distance to be moved from current point to next point float moveTime; // to be in whole seconds of 5 or 10 seconds chosen at randomn float timeOut; // movetime + extra to test for no moving_end float startTime; float endTime; float timeDiff; integer running; // non-zero when running the test, used to prevent residual KFM when rezzing or stopping string timerAction; // records what is to be done when the timer fires integer journeys = 0; // count of journeys made integer noStart = 0; // count of moving_start timerouts integer noEnd = 0; // count of moving_end timeouts integer tooLong = 0; // count of journeys taking more than 5% of expected time Dout(string message) { llOwnerSay(message); } announce(string message) { llSetText(message,<1.0,1.0,1.0>,1.0); } setPoints() { vector pos = startPos; llOwnerSay("Start from " + (string) startPos); points = [pos]; pos += <xOffset, yOffset, 0.0>; // move across diagonal llOwnerSay("Move diagonally to " + (string) pos); points += pos; pos += <0.0, -yOffset, 0.0>; // move back along on side llOwnerSay("Move back along side to " + (string) pos ); points += [pos]; pos += <-xOffset, yOffset, 0.0>; // move along the other diagonal llOwnerSay("Move diagonally to " + (string) pos); points += [pos]; // next point is back to the start pos += <0.0, -yOffset, 0.0>; llOwnerSay("Start and positions " + (string) startPos + " , " + (string) pos); maxPoints = llGetListLength(points); } nextMove() { announce("Journeys " + (string) journeys + "\nStart timeouts " + (string) noStart + "\nend timeout " + (string) noEnd + "\nLate " + (string) tooLong); thisPoint += 1; if( thisPoint >= maxPoints) thisPoint = 0; thisPos = llGetPos(); nextPos = llList2Vector(points, thisPoint); dist = llVecDist(thisPos, nextPos); if( debug) Dout("Next Point " + (string) thisPoint + " From " + (string) thisPos + " to " + (string) nextPos + " dist " + (string) dist); float ranVal = llFrand(1.0); if( ranVal > 0.5 ) moveTime = 10.0; else moveTime = 5.0; timeOut = moveTime + (moveTime * 0.15); // allow 15% extra time to settle at moving_end timerAction = "starting"; if( debug) Dout("KFM " + (string) (nextPos - thisPos) + " " + (string) ZERO_ROTATION + " time " + (string) moveTime); llSetTimerEvent(0.5); // test for moving_start startTime = llGetTime(); ++journeys; llSetKeyframedMotion([nextPos - thisPos, ZERO_ROTATION, moveTime],[]); } default { state_entry() { owner = llGetOwner(); llSetTimerEvent(0.0); timerAction = ""; running = 0; llSetPrimitiveParams([PRIM_PHYSICS_SHAPE_TYPE, PRIM_PHYSICS_SHAPE_CONVEX]); llSetKeyframedMotion([],[]); `// stop any motion if rezzing a previously-moving item taken back to inventory if( points == []) { startPos = llGetPos(); setPoints(); } cHandle = llListen(myChan, "", owner, ""); llSetRegionPos(startPos); // restore to start if reloading from inventory thisPoint = 0; if( maxPoints > 0) { announce("Ready"); llOwnerSay("Touch to start the test, touch to end it, or say \"stop\" on channel " + (string) myChan); } } listen(integer chan, string name, key id, string msg) { if( msg == "stop" || msg == "reset" ) { llSetTimerEvent(0.0); timerAction = ""; llSetKeyframedMotion([],[]); running = 0; if( msg == "reset") { llSetRegionPos(startPos); thisPoint = 0; journeys = 0; noStart = 0; noEnd = 0; } announce("Journeys " + (string) journeys + "\nStart timeouts " + (string) noStart + "\nend timeout " + (string) noEnd + "\nLate " + (string) tooLong); } else if( msg == "report") { llOwnerSay("Journeys " + (string) journeys); llOwnerSay("Start timeouts " + (string) noStart); llOwnerSay("End timeouts " + (string) noEnd); llOwnerSay("More than 5% late " + (string) tooLong); } else if( msg == "debug") { debug = ~debug; } } touch_start(integer touches) { key toucher = llDetectedKey(touches - 1); if( toucher == owner) { if (!running) { running = 1; nextMove(); } else { llSetTimerEvent(0.0); timerAction = ""; llSetKeyframedMotion([],[]); running = 0; announce("Journeys " + (string) journeys + "\nStart timeouts " + (string) noStart + "\nend timeout " + (string) noEnd + "\nLate " + (string) tooLong); } } } moving_start() { if( running) // ignore edit and setting up moves { llSetTimerEvent(timeOut); // now make the whole journey timerAction = "moving_end"; if( debug) Dout("Moving_start"); } } moving_end() { llSetTimerEvent(0.0); llSetKeyframedMotion([],[]); endTime = llGetTime(); if( debug) Dout("Moving_end"); // calculate times timeDiff = endTime - startTime; // Actual time if( timeDiff > moveTime) { float diff = timeDiff - moveTime; if( diff > (moveTime *.05)) tooLong +=1; // we over ran by 5% or more } //llOwnerSay("Expected Time = " + (string) moveTime + " actual time " + (string) (endTime - startTime) ); if( running) nextMove(); // but if we touched to stop, do nothing } timer() { llSetTimerEvent(0.0); if( debug) Dout("Timeout for " + timerAction); //running = 0; if( timerAction == "moving_start") { ++noStart; timerAction = "moving_end"; llSetTimerEvent(timeOut); // we can live in hope } else if( timerAction == "moving_end") { llSetKeyframedMotion([],[]); ++noEnd; if( running) nextMove(); else announce("Journeys " + (string) journeys + "\nStart timeouts " + (string) noStart + "\nend timeout " + (string) noEnd + "\nLate " + (string) tooLong); } } }
×
×
  • Create New...