ParcelChatRelay
Parcel Chat Relay
Description:
Communicate on your land in general chat regardless of distance between avatars. Useful when building, in clubs, for roleplay, etc.
Messages will be intelligently relayed - a listener will never hear a message twice! It will either be heard normally, or relayed. Using the new llRegionSayTo() api, chat messages are only relayed to avatars that are out of range.
How to use:
- Rez 1 or more relays on your parcel, in a way that you could hear each avatar (<20m). Do not worry overlapping, but don't overdo it either - less relays will still be less lag.
- If you rez a relay on its' final position, it will immediately be 'tuned' and part of the network.
- If you move or remove a relay, it might take up to 10 minutes for the network to catch up.
Features:
- Muliple relays can be rezzed to cover each part of your parcel.
- Dedoubling without any overhead
- Low lag - relays do not have to communicate to dedouble messages
Limitations:
- Works only per parcel (by design). Agents on neighboring land will not receive relayed messages.
- Receivers have to be within radar range (96m) of the receiving relay
- Scripts cannot distinguish normal say, whispering and shouting. Normal say is assumed. Shouts may be heard double by the receiver
- Moving avatars might experience 'border' cases - where a message sometimes accidentally is not relayed or double relayed. Due to the fast response time unlikely
- The displayed ('faked') name is the official linden name, and chat is colored like objects, not avatars. Also depends on viewer settings.
Remarks on the parcel limitation.. Other options (sim wide, range based) would be easily possible, but i like the item to be zero-config ('just works'). Feel free to mod the script at your demands.
License:
Modified BSD / public domain
This script is also available at marketplace for your convenience: https://marketplace.secondlife.com/p/Parcel-Chat-Relay/3157725
Notes:
Possible easy-to-adjust modifications: do not use parcel key but owner key as handle, allowing cross parcel-but-same-owner chat, or specifying a fixed key for region-wide that.
<lsl> //2011-2012 Tano Toll - TSL License//
//Short summorization: //Relays will know of eachothers existance //Relays listen to public chat //The relay _closest_ to sending agent is responsible for relaying the message //Messages will only be relayed to agents further than 20 meter away from the speaker //Messages will only be relayed to agents on the same parcel
//list of detected nearby agents:
list insim;
//just a hash. change to use several systems on a single parcel. string tag="+-/";
//key of the parcel where we are rezzed key parcelkey;
//chat channel handle made with key as base integer parcelhandle;
//list of detected nearby relays list repeaters;
announce() {
llRegionSay (parcelhandle, tag+(string)parcelkey);
}
default {
state_entry() { llSetText("Chat Relay started...",ZERO_VECTOR,1); if (llGetAttached()) { //owner relay only mode //redundant in this script. //llListen (0, "", "", ""); } else { //relay all agents llListen (0, "", "", ""); } //scan for nearby agents llSensorRepeat ("", "", AGENT, 65, TWO_PI, 20); //make up a inter-relay channel, so they can find eachother parcelkey=llList2Key(llGetParcelDetails(llGetPos(), [PARCEL_DETAILS_ID]),0); parcelhandle=-10909-(integer)("0x"+llGetSubString(parcelkey,1,5)); llListen(parcelhandle, "", "", tag+(string)parcelkey); //broadcast our existance about every 5 minutes llSetTimerEvent(290.0+llFrand (20.0)); //about each 300 seconds, not all at once announce(); } on_rez(integer n) { //simply reset llResetScript(); }
timer() { //announce self announce(); //and clear list. repeaters with an too old timestamp will be removed. integer n=llGetListLength(repeaters)-1; integer t=llGetUnixTime(); while (n>0) { if ((t-llList2Integer(repeaters, n))>390) { //time out repeaters=llDeleteSubList(repeaters, n-2, n); } n-=3; } llSetText ("Node(s): "+(string)(1+llGetListLength(repeaters)/3), <1,1,1>, 1); } sensor (integer n) { //add detected agents to our list while (~--n) { key id=llDetectedKey(n); if (!~llListFindList(insim, [id])) insim+=id; } //clean up agents that are no longer in sim n=llGetListLength(insim); while (~--n) if (llGetAgentSize(llList2Key(insim,n))); else insim=llDeleteSubList(insim,n,n); } no_sensor() { insim=[]; /* //clean up agents that are no longer in sim integer n=llGetListLength(insim); while (~--n) if (llGetAgentSize(llList2Key(insim,n))); else insim=llDeleteSubList(insim,n,n); */ } listen (integer channel, string name, key id, string m) { if (!channel) { //channel 0 //only relay agents, not objects if (llGetAgentSize(id));else return; //see if another relay is more nearby integer n=0; vector senderpos=llList2Vector(llGetObjectDetails(id, [OBJECT_POS]), 0); float d=llVecDist(senderpos, llGetPos()); while (n<llGetListLength(repeaters)) { if (d>llVecDist(senderpos, llList2Vector(repeaters, n+1))) return; n+=3; } //We are nearest repeater. Our job to relay. //relay to everyone in range. that's fixed to minimum 20 mins maximum 60. //get position of chatter vector o=llList2Vector(llGetObjectDetails(id, [OBJECT_POS]), 0); n=llGetListLength(insim); string oname=llGetObjectName(); llSetObjectName(name); while (~--n) { vector t=llList2Vector(llGetObjectDetails(llList2Key(insim, n), [OBJECT_POS]), 0); float d=llVecDist (o,t); if (d>=20/* && d<=60*/) { //same parcel? if (parcelkey==llList2Key(llGetParcelDetails(llList2Vector(llGetObjectDetails(llList2Key(insim,n), [OBJECT_POS]),0), [PARCEL_DETAILS_ID]),0)) llRegionSayTo (llList2Key(insim,n), 0, m); } } llSetObjectName(oname); } else if (channel==parcelhandle) { //there's another repeater.. vector pos=llList2Vector(llGetObjectDetails(id, [OBJECT_POS]),0); integer p=llListFindList(repeaters, [id, pos]); if (~p) repeaters=llDeleteSubList(repeaters, p, p+2); repeaters += [id, pos, llGetUnixTime()]; } }
}
</lsl> --Tano Toll 19:54, 11 May 2012 (PDT)