E
Ezian Ecksol
Guest
Irgendwo gabs einen Thread, da ging es um einen Besucher-Melder, den find ich allerdings nicht mehr. Mehrere Leute hatten mich per PM nach einem entsprechenden Script gefragt, here we go.
Das Script einfach in ein beliebiges Prim werfen. Funktioniert in der vorliegenden Form für den Eigentümer eines Parcels.
Nach dem Rezzen ist das Script an, und berechnet noch eine optimale Position für das Prim, bei dem der Scan-Kegel von 96m optimal für den Boden ausgenutzt wird - und teilt diese Position beim Start mit. Das Prim also ggf. per Edit einfach auf diese Stelle befördern.
Per Touch kann der Eigentümer das Script aus- bzw. wieder anmachen.
Das Script ignoriert Kurzzeit-Besucher, gibt dann nach Verstreichen der Kurz-Besucher-Zeit eine Meldung aus, die Zeit ist GMT. Beim Verlassen eines Besuchers des Grundstücks meldet sich das Script wieder mit der Verweildauer.
Im Script-Kopf kann man folgende Werte einstellen:
Das Script einfach in ein beliebiges Prim werfen. Funktioniert in der vorliegenden Form für den Eigentümer eines Parcels.
Nach dem Rezzen ist das Script an, und berechnet noch eine optimale Position für das Prim, bei dem der Scan-Kegel von 96m optimal für den Boden ausgenutzt wird - und teilt diese Position beim Start mit. Das Prim also ggf. per Edit einfach auf diese Stelle befördern.
Per Touch kann der Eigentümer das Script aus- bzw. wieder anmachen.
Das Script ignoriert Kurzzeit-Besucher, gibt dann nach Verstreichen der Kurz-Besucher-Zeit eine Meldung aus, die Zeit ist GMT. Beim Verlassen eines Besuchers des Grundstücks meldet sich das Script wieder mit der Verweildauer.
Im Script-Kopf kann man folgende Werte einstellen:
Erst nach dieser Zeit (in Sekunden) kommt eine Meldung , dass jemand aufs Grundstück gekommen ist. Verschwindet er vorher wieder (wie z.B. Grundstück-Überflieger), wird er nicht gemeldet. (Trotzdem wird aber die Gesamt-Zeit beim Verlassen des Grundstücks angezeigt)float ignore_time = 20.; // avatars visiting the parcel less than this time in seconds will be ignored
0: gibt die Meldungen direkt aus dem prim auf den offenen Chat aus. 1: benutzt llOwnerSay an den Prim-Eigentümer. OwnerSay geht verloren, wenn der Benutzer offline ist. 2: gibt die Meldungen per IM an den Eigentümer aus. IM funktioniert im Prinzip auch, wenn man offline ist. (zur Zeit wegen SL-Bugs allerdings manchmal nicht, außerdem können IMs derzeit teilweise erheblich zeitverzögert ankommen, während llOwnerSay eigentlich immer sofort arbeitet)integer print_method = 1; // 0=llSay, 1=llOwnerSay, 2=llInstantMessage
Die Scan-Rate. mit 2 scannt er alle 2 Sekunden. Schnellere Werte erhöhen den Lag. Alle 5 Sekunden reicht sicher auch.float loop_time = 2.; // scanner checks every <loop_time> seconds
Code:
// Visitor-Detector 0.66
// (c) Ezian Ecksol. Use, modify, steal or sale as you like. Keep credits.
// modify these values: /////
float ignore_time = 20.; // avatars visiting the parcel less than this time in seconds will be ignored
integer print_method = 1; // 0=llSay, 1=llOwnerSay, 2=llInstantMessage
float loop_time = 2.; // scanner checks every <loop_time> seconds
//////////////////////////////////
vector parcel0; vector parcel1;
vector parcel_center; vector parcel_size;
float detect_range = 96.;
key owner;
string parcel;
list visitors_long;
list visitors_short;
integer active;
string getparcelname(vector p) {
return llList2String(llGetParcelDetails(p, [PARCEL_DETAILS_NAME]),0);
}
getparcelbounds() {
vector pos = llGetPos();
vector rpos;
pos = <llRound(pos.x), llRound(pos.y), 0.>;
string name = getparcelname(pos);
rpos = pos;
do { rpos.x -= 1.; } while ((getparcelname(rpos) == name) && (rpos.x>=0.));
parcel0.x = rpos.x + 1.;
rpos = pos;
do { rpos.y -= 1.; } while ((getparcelname(rpos) == name) && (rpos.y>=0.));
parcel0.y = rpos.y + 1.;
rpos = pos;
do { rpos.x += 1.; } while ((getparcelname(rpos) == name) && (rpos.x<256.));
parcel1.x = rpos.x;
rpos = pos;
do { rpos.y += 1.; } while ((getparcelname(rpos) == name) && (rpos.y<256.));
parcel1.y = rpos.y;
parcel_center = (parcel1 + parcel0) / 2.;
parcel_size = parcel1 - parcel0;
float c = llPow(parcel_size.x/2.,2.)+llPow(parcel_size.y/2.,2.);
float d = detect_range*detect_range;
if (c > d)
llOwnerSay("Your parcel is to large to be covered by a 96-m-scanner. Place the detector in the middle of the parcel at ground, but the corners are not covered.");
else {
vector dest = <parcel_center.x, parcel_center.y, llGround(parcel_center-llGetPos())+llSqrt(d-c)>;
llOwnerSay("For optimal scanning range at ground, set position of object to: "+Vector2String(dest));
}
}
string format_2dig(integer i) {
if (i<10)
return "0"+(string)i;
else
return (string)i;
}
string format_timestamp(string ts) {
return parcel+", "+llGetSubString(ts, 0, 9)+", "+llGetSubString(ts, 11,18)+" GMT";
}
string format_seconds(integer s) {
integer m = s / 60;
s %= 60;
integer h = m / 60;
m %= 60;
return format_2dig(h)+":"+format_2dig(m)+":"+format_2dig(s);
}
console(string txt) {
if (print_method == 0)
llSay(0, txt);
else if (print_method == 1)
llOwnerSay(txt);
else
llInstantMessage(owner, txt);
}
visitors_left(list v) {
integer j = llGetListLength(v);
if (j) {
integer i;
integer tu = llGetUnixTime();
for (i=0; i<j; i+=3)
console("<< "+llList2String(v, i)+" left "+parcel+" after "+format_seconds(tu-llList2Integer(v, i+1)));
}
}
string Float2String(float num) {
list s = llParseString2List((string)(llRound(num*10.)/10.), ["."], []);
return llList2String(s, 0)+"."+llGetSubString(llList2String(s, 1), 0, 0);
}
string Vector2String(vector v) {
return "<"+Float2String(v.x)+", "+Float2String(v.y)+", "+Float2String(v.z)+">";
}
activate(integer a) {
active = a;
if (a) {
llOwnerSay("Scans every "+Float2String(loop_time)+"s. Ignores visitors staying less than "+Float2String(ignore_time)+"s.");
llOwnerSay("Activated: "+format_timestamp(llGetTimestamp()));
llSensorRepeat("", NULL_KEY, AGENT, detect_range, PI, loop_time);
} else {
llOwnerSay("Deactived.");
llSensorRemove();
}
}
default {
state_entry() {
owner = llGetOwner();
parcel = """+llList2String(llGetParcelDetails(llGetPos(), [PARCEL_DETAILS_NAME]),0)+"""; // +" in "+llGetRegionName();
activate(TRUE);
llOwnerSay("Touch to stop or start.");
getparcelbounds();
}
touch_start(integer n) {
if (llDetectedKey(0) == owner)
activate(!active);
}
on_rez(integer p) {
llResetScript();
}
changed(integer c) {
if (c & CHANGED_OWNER) llResetScript();
}
sensor(integer n) {
integer i; integer j;
integer tu = llGetUnixTime();
string ts = llGetTimestamp();
string dname;
list temp;
list temp_short = visitors_short;
list temp_long = visitors_long;
visitors_short = [];
visitors_long = [];
for (i=0; i<n; ++i) {
if (llOverMyLand(llDetectedKey(i))) {
//vector dpos = llDetectedPos(i);
//if ((dpos.x >= parcel0.x) && (dpos.x < parcel1.x) && (dpos.y >= parcel0.y) && (dpos.y < parcel1.y)) {
dname = llDetectedName(i);
j = llListFindList(temp_long, [dname]);
if (j != -1) {
visitors_long += llList2List(temp_long, j, j+2);
temp_long = llDeleteSubList(temp_long, j, j+2);
} else {
j = llListFindList(temp_short, [dname]);
if (j != -1) {
temp = llList2List(temp_short, j, j+2);
if ((tu-llList2Integer(temp, 1)) >= ignore_time) {
visitors_long += temp;
console(">> "+llList2String(temp, 0)+" entered "+format_timestamp(llList2String(temp, 2)));
} else {
visitors_short += temp;
}
} else {
visitors_short += [dname, tu, ts];
}
}
}
}
visitors_left(temp_long);
}
no_sensor() {
visitors_left(visitors_long);
visitors_short = [];
visitors_long = [];
}
}