Jump to content

KT Kingsley

Resident
  • Posts

    1,072
  • Joined

  • Last visited

Everything posted by KT Kingsley

  1. It goes something like this: if (im_message) // is there anything to report? { status_request_count = llGetListLength (im_recipients); // how many recipients? im_recipient = llList2Key (im_recipients, --status_request_count); // for the first one, get their key status_request_id = llRequestAgentData (im_recipient, DATA_ONLINE); // and find out if they're online } Note that the variables being assigned values must be declared globally, so that they are preseved across to the dataserver events. Then in the dataserver event: dataserver (key id, string data) { if (id == status_request_id) { if ((integer) data) llInstantMessage (im_recipient, im_message); // if the recipient is online send the IM if (status_request_count) // any more recipients? { im_recipient = llList2Key (im_recipients, --status_request_count); // if so, get their key status_request_id = llRequestAgentData (im_recipient, DATA_ONLINE); // and find out if they're online } } }
  2. Will URIs will work with IMs to email? Though I don't know whether the OP wants those or not (I'm expecting a post asking how to stop them sometime soon ). The (integer)("0x" + avatar_key) is handy to know. Presumably the conversion stops at the first non-hex-digit character that's encountered.
  3. Ah! But I forgot about llListSort, which does make MD5 hashes useful here.
  4. Well, I can answer my first question myself here. No. So because "There is no guaranteed understandable order or randomness to the list returned" by llGetAgentList, and because the sensor will return agents in the order of their proximity – which will change as they move about – you'd have to use some other hash method. XORing the first eight characters of the key, while simplistic and crude, does seem to work, and would likely be adequate in an application like this. (Bit of an overhead creating the hash in the first place, though.) default { state_entry () { string md5_1 = llMD5String (llList2CSV ([NULL_KEY, llGetOwner (), llGetKey ()]), 1); string md5_2 = llMD5String (llList2CSV ([llGetOwner (), llGetKey (), NULL_KEY]), 1); llOwnerSay (md5_1); llOwnerSay (md5_2); llOwnerSay ((string) (md5_1 == md5_2)); integer hash1 = (integer) ("0x" + llGetSubString ((string) NULL_KEY, 0, 7)) ^ (integer) ("0x" + llGetSubString ((string) llGetOwner (), 0, 7)) ^ (integer) ("0x" + llGetSubString ((string) llGetKey (), 0, 7)); integer hash2 = (integer) ("0x" + llGetSubString ((string) llGetKey (), 0, 7)) ^ (integer) ("0x" + llGetSubString ((string) llGetOwner (), 0, 7)) ^ (integer) ("0x" + llGetSubString ((string) NULL_KEY, 0, 7)); llOwnerSay ((string) hash1); llOwnerSay ((string) hash2); llOwnerSay ((string) (hash1 == hash2)); } } Also, if anyone knows of a ghost avatar anywhere (preferably on a script enabled parcel), could they please let me know. I'd like to experiment with it.
  5. Will llMD5String return the same value if llGetAgentList (or llSensorRepeat, which the OP has opted for) return the same keys, but in a different order? Does llGetAgentList (or llSensorRepeat) sometimes return the same ghost as NULL_KEY and sometimes as the correct key on successive calls? Also, is memory fragmentation an issue for local list variables? My (probably flawed) understanding is that local variables are created on the stack, and that's cleared when a function or event is completed. I can see how it could cause problems with a global list variable in the heap, though.
  6. What would be the best way to generate the hash? Something like string list_hash = llMD5String (llList2CSV (current_visitors), 0);? Or a custom hash, maybe like successively XORing part of the key? (Hmm, I guess MD5 wouldn't work here because the list may have the same contents, but in a different order?) I don't think I understand the problem with ghosts. Surely once they're detected as being present, they'll continue being detected as present until they are actually exorcised?
  7. Ah, yes, the departure with no name can happen because llGetDisplayName tries to get the name from the simulator, but that data is deleted from the simulator soon after an avatar leaves the region. One way around that would be to save the names in a list running parallel to the visitors list, another would be to use llRequestDisplayName which queries the database but returns the info in a dataserver event, which would involve extra steps to accommodate. There's no need to use both the timer and a repeating sensor: you can move the code from the timer event into the sensor event. Also, remember that when there's no one in sensor range it'll be the no_sensor event that's triggered, not an "empty" sensor event.
  8. As this is something I've already done myself, here's a simplified version that might help. I hope nothing got mangled in the transcription. list im_recipients = []; // a list of the keys of the people who will get IMed float timer_interval = 30.0; // how often to scan the area list previous_visitors; // a list of the people who were in the area for the last scan, a global value to preserve it between scans default { state_entry () { im_recipients += llGetOwner (); // add yourself on the messaging list. llSetTimerEvent (timer_interval); // start the timer (and wait for it to trigger) } timer () { list arrivals; list departures; list current_visitors = llGetAgentList (AGENT_LIST_PARCEL, []); // get the list of who's here now integer count = llGetListLength (current_visitors); while (count) // for each current visitor (if any), working backwards through the list (beacuse it's easier) { key visitor = llList2Key (current_visitors, --count); // decrement the counter (to convert it to a list index, and also set it up for the while loop test next iteration) and get the visitor's key if (llListFindList (previous_visitors, [visitor]) == -1) // are they in the list of people who were here last time? { arrivals += llGetDisplayName (visitor); // if not, add their name to the list of new arrivals } } count = llGetListLength (previous_visitors); while (count) // for each visitor who was here last time { key visitor = llList2Key (previous_visitors, --count); if (llListFindList (current_visitors, [visitor]) == -1) // are they still here? { departures += llGetDisplayName (visitor); // if not, add their name to the list of departures } } string im_message; if (arrivals) im_message += "\nArrivals: " + llList2CSV (arrivals); // if there are any new arrivals, add their names, seperated by commas, to the IM message if (departures) im_message += "\nDepartures: " + llList2CSV (departures); // if there are any departures, add their names to the message if (im_message) // is there anything to report? { count = llGetListLength (im_recipients); while (count) // for each im recipient { key recipient = llList2Key (im_recipients, --count); llInstantMessage (recipient, im_message); // note that this function imposes a 2 second delay on the script and is subject to throttling } } previous_visitors = current_visitors; // save the list of current visitors for next time; } } But be warned: spamming yourself with IMs, especially if they go to email when you're offline, gets old pretty quickly. As it stands, you may run into issues with the length of the IM text if there's large numbers of people coming and going.
  9. Adeon, try SL viewer: Me/Hide all controls Alt+Shift+U; Firestorm: Avatar/Show User Interface Alt+Shift+U SL viewer: Me/Show HUD Attachments Ctrl+Shift+H; Firestorm: Avatar/Show HUD Attachments Alt+Shift+H Both are toggles. And even with the UI hidden you can summon up various windows using the keyboard shortcuts, Skell, from the gear icon at the bottom left of the SL viewer inventory window "Close all folders". In Firestorm, it's also a button, "Collapse", at the top left of the inventory window. (There's also an "Expand" button there. I haven't been able to figure out why I'd want to open every single folder and sub-folder in my inventory, though.) Also, don't forget that EEP settings will likely make Windlight redundant sometime this year.
  10. Blimey! That was painless! Many thanks! And yeah, occlusion and llCastRay did come into it, but that part was easy, seein' as how there's no angles involved. (By the way, you want ZERO_ROTATION in that llAngleBetween call, not ZERO_VECTOR.)
  11. Given the position and rotation of an object, how do I determine if another object is in front of it? Also, how would I determine if the other object is within a given angle of the first object's forward axis? I guess those are both the same question, in that in the first case the angle would be 90°, though I suspect that calculation can be simplified.
  12. The changed event is being triggered by the changed textures and changed colours. You can be more selective about which changes you want to have trigger the script reset. For example: changed (integer changes) { if (changes & CHANGED_INVENTORY) llResetScript (); } See the wiki for a description of all the changes the changed event is triggered by: http://wiki.secondlife.com/wiki/Changed.
  13. This basic script illustrates one way of doing that: integer steps = 25; float delay = 0.01; integer texture; default { state_entry () { llSetTimerEvent (5.0); } timer () { integer fade_step = steps; while (fade_step--) { float fade = (float) fade_step / (float) steps; llSetColor (<fade, fade, fade>, ALL_SIDES); llSleep (delay); } llSetTexture (llList2Key (["e417f443-a199-bac1-86b0-0530e177fb54", "3ccd6876-dce0-4974-aede-22aa15ad38af"], texture = !texture), ALL_SIDES); while (++fade_step <= steps) { float fade = (float) fade_step / (float) steps; llSetColor (<fade, fade, fade>, ALL_SIDES); llSleep (delay); } } }
  14. The region is called Serenity. There's no visible evidence of the Drune build there on the world map now.
  15. Might it make sense to have the target message whatever's controlling the user's camera whenever it rotates, rather than use a timer? Might the CAMERA_POSITION_LAG parameter help smooth the camera movement?
  16. Also, I wonder if the OP might work around their problem by using llGetAnimationList and looping through that and stopping all the animations it contains except for the one they want to use?
  17. Does stopping the basic built-in default sit, as in llStopAnimation ("sit") – which used to be a standard practice when animating an avatar that's sat on something – extend to stopping the overridden default sit animation set by llSetAnimationOverride?
  18. Looking at the developer's web page for that app, there are SLURL links to their in-world store where you can buy the optional server. But maybe what you're after is the URL of the simulator wherever you're based. You can find that by looking at the Help menu/About... The server URL is the bit that begins with something like "sim9999.agni...".
  19. Firestorm, in it's last release, introduced a feature where you could limit the distance your LookAt would point at. It was flawed, in that enabling it would make your eyes go weird, just like you've described. Did Niran include that code in the Black Dragon viewer? Have you enabled it in Black Dragon but not in Firestorm? Otherwise, no idea.
  20. So I guess that means QAvimator is out of the question. I suppose I'll have to dig out my ancient version of Avastar for Blender and see if I can figure something out. Thanks.
  21. And here's a way to do it using KFM: vector TARGET_POS_LOCAL = <0.0, 0.0, 2.0>; //the distance to move vector TARGET_ROT_LOCAL = <0.0, 0.0, 90.0>; //the angle to rotate, degrees float duration = 2.5; //the time to take float direction = 1.0; integer active; vector start_pos; vector start_rot; default { touch_end (integer count) { if (!active) { //save the start pos and rot for use in the sanity check later start_pos = llGetPos (); start_rot = llRot2Euler (llGetRot ()); llSetKeyframedMotion ([ TARGET_POS_LOCAL * direction, llEuler2Rot (TARGET_ROT_LOCAL * direction * DEG_TO_RAD), duration ], []); //set the timer to clean up after the KFM llSetTimerEvent (duration); active = TRUE; } } timer () { llSetTimerEvent (0.0); //now for a sanity check: stop the KFM and set the object to the //actual target in case KFM didn't quite get it right llSetKeyframedMotion ([], [KFM_COMMAND, KFM_CMD_STOP]); llSetRegionPos (start_pos + (TARGET_POS_LOCAL * direction)); llSetRot (llEuler2Rot (start_rot + (TARGET_ROT_LOCAL * direction * DEG_TO_RAD))); active = FALSE; direction = -direction; } } Ok, so I'm only stumbling my way through KFM, It's not something I've done very much of. This is primarily an example so people can compare KFM with stepped motion.
  22. Which part of the animation skeleton affects avatar physics? I've tried a few things in QAvimator, but nothing seems to get my avatar physics going. Any suggestions?
  23. Regarding the 512 byte memory difference, I understand that mono LSL aligns user functions on 512 byte boundaries, so inline code tends to use less memory than a function, at least up to the point where the inline code is repeated often enough to overtake the function's memory usage. Which way to go depends on which you value more: your sanity or your script's memory usage.
  24. Like I said, you don't have to be a participant to get dragged into having to fend off the bloody thing.
  25. I'd suggest that because whatever Bloodlines may claim to be or not be, it's an intrusion that frequently spills over from its participants to those of us who have no interest in participating. At the very least it involves you clicking on a "**** off" button, at the worst you have to get stuff from the marketplace, visit an external website or set up systems to exclude its users from your SL experience.
×
×
  • Create New...