• Bitte schaltet eure Ad Blocker aus. SLinfo kann nur betrieben werden, wenn es durch Werbung Einnahmen erzielt. Vielen Dank!!
  • Wir freuen uns, wenn du dich in unserem Forum anmeldest. Bitte beachte, dass die Freigabe per Hand durchgeführt wird (Schutz vor Spammer). Damit kann die Freigabe bis zu 24 Stunden dauern.
  • Wir verwenden Cookies, um Inhalte und Anzeigen zu personalisieren, Funktionen für soziale Medien anbieten zu können und die Zugriffe auf unsere Website zu analysieren. Sie geben Einwilligung zu unseren Cookies, wenn Sie unsere Webseite weiterhin nutzen.

Visitor Detector

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:

float ignore_time = 20.; // avatars visiting the parcel less than this time in seconds will be ignored
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)

integer print_method = 1; // 0=llSay, 1=llOwnerSay, 2=llInstantMessage
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)

float loop_time = 2.; // scanner checks every <loop_time> seconds
Die Scan-Rate. mit 2 scannt er alle 2 Sekunden. Schnellere Werte erhöhen den Lag. Alle 5 Sekunden reicht sicher auch.

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 = [];   
    }

}
 
Hallo Ezian,
ich hab das mal probiert, aber ich bekomme da einen Error:
Code:
[17:41]  Object: Scans every 2.0s. Ignores visitors staying less than 20.0s.
[17:41]  Object: Activated: "xxbeliebigerOrtxx", 2008-06-23, 00:41:48 GMT
[17:41]  Object: Touch to stop or start.
[17:41]  Object [script:visitor_detect]: Script run-time error
[17:41]  Object [script:visitor_detect]: Math Error

Kannst Du sagen, woran das liegt ?
Grüße
ST
 
Bei mir genauso, ich habe mal geschaut aber ich finde den Fehler nicht ...ich dachte zuerst ein Variablen Wertigkeit wäre zu niedrig.
 
math

ohne das ich das ganze script jetzt durchgegangen bin,

Math error hört sich nach division by Zero am. Also Teilen durch 0.

Um heraus zu finden an welcher stelle der Fehler aufläuft, ist es hilfreich einige llSay 's unterzubringen. Ich mache das in jeder Funktion und jedem Event. Dann bekommt ihr den Überblick was noch richtig abläuft.

Leider hat Linden [libary:a64cb4b5ca]Synonym für [LindenLab]. Wird im Zusammenhang mit der [Währung] [Lindendollar] oder auch als [Nachname] [Linden] für [Administratoren] in [SecondLife][/libary:a64cb4b5ca] ja den debugger vergessen.
 
Hm. Muss ich mir nochmal anschauen, bei mir läufts natürlich.

Math Error kommt bei Division durch 0 oder Ziehen einer Wurzel durch eine negative Zahl.

Kommentier doch einfach erstmal aus dem state_entry das hier aus: getparcelbounds() aus, indem du zwei Slashes davor schreibst, also "// getparcelbounds();"

getparcelbounds() rechnet ein bisschen, um die optimale Position auszugeben, aber eigentlich ist der Programmteil für die eigentliche Funktion des Visitor Detectors völlig unwichtig.

Und dann sagt mal, ob es ohne getparcelbounds geht, das grenzt dann die Suche ein :)
 
Ezian Ecksol schrieb:
Hm. Muss ich mir nochmal anschauen, bei mir läufts natürlich.

Math Error kommt bei Division durch 0 oder Ziehen einer Wurzel durch eine negative Zahl.

So auf den ersten Blick (ohne testen) ist das Problem in Variable h in Parcelbounds():

float h = llSqrt(llPow(detect_range/2.0,2.0)-c*c) - 0.4,


Das Problem mit dem Mathefehler taucht dann auf, wenn c² > (detect_range/2)² ist.

In diesem Fall (detect_range = 96m), wenn c größer als 48 ist.
 
[Push]

Habe das Script jetzt oben in dem ersten Post korrigiert.

Wie Shirley richtig gesehen hat, war ein Fehler in einer Formel drin, der bei meinem Test auf einem relativ kleinem Parcel nicht zum Tragen kam.

Was bin ich immer wieder froh, dass es von Flugzeug-Software keine Release Candidates gibt. Sondern es Leute gibt, die Test-Software für die Flugtzeug-Software schreiben, und Dritte, die Test-Software für die Test-Software schreiben :) (eine rmeiner Bekannten).
 
Eine Anmerkung: Es waere eventuell hilfreich abzufragen, ob der eingetroffene Gast der Eigner des Grundstuecks oder der Owner des Prims ist, in dem der script laeuft. Ich seh ja selber, ob ich mich auf meinem Grundstueck aufhalte oder nicht und muss nicht noch per script davon informiert werden.

Auf die schnelle habe ich nichts finden koennen, wo eine Abfrage guenstig zu platzieren waere. Eventuell in der Funktion console, aber dorthin wird nur der komplette auszugebende Text uebergeben und nicht der key des Besuchers, den man dann mit getowner oder getlandowner vergleichen koennte.
 
Ja klar, das wa zu Testzwecken natürlich unpraktisch, und dann hab ich's vergessen :)

Such mal diese Zeile im senso event:
Code:
if (llOverMyLand(llDetectedKey(i))) {

und ersetze sie hierdurch:
Code:
if ((llOverMyLand(llDetectedKey(i)) && (owner != llDetectedKey(i))) {

Ungetestet, sieht aber gut aus.
 
Hihi, genau an der Stelle hatte ich es inzwischen selbst geaendert. Ich habe nur llDetectedKey(i) einer Variablen zugewiesen, um den Doppelaufruf zu vermeiden.

Und "parcel" und alle Ausgaben desbetreffend habe ich auch entfernt. Parcel ist bei mir leer, weil Parcelgroesse gleich Sim. Einen "Untertitel" habe ich gar nicht vergeben. Es wurden nur die "" ausgegeben.

Aber sonst, gute Arbeit, Ez. Keep going.
 
Eine Klammer fehlt, aber sonst läuft die Änderung:

Code:
if ((llOverMyLand(llDetectedKey(i))) && (owner != llDetectedKey(i))) {

Super Teil !
Grüße
ST
 
statt mit llsay oder llInstantMessage arbeite ich gerne mit llEmail.

Das hat den Vorteil das die Nachrichten immer ankommen, egal ob man on oder offline ist.

man kann es natürlich auch kombinieren.
 
Kottos Sperber schrieb:
Ich habe nur llDetectedKey(i) einer Variablen zugewiesen, um den Doppelaufruf zu vermeiden.

Mach ich eigentlich auch normalerweise, hab das vorhin eben nur auf die Schnelle so hingeschrieben.

Übrigens bin ich mir inzwischen ga nicht mehr sicher, ob der "Doppelaufruf" von llDetectedKey(bla) Zeit kostet, denn soweit ich irgendwo neulich gelesen habe, ist es so: Wir haben ja in LSL leider keine Arrays, nur diese beknackten Listen. Die einzigen Arrays sind diese llDetected...-Variablen. Die Werte, die da z.B. im Sensor-Event reinlaufen, werden in den Speicher der Virtual Machine des Scripts geschrieben, man kann man auch mit llGetFreeMemory gut beobachten. D.h. für mich, dass die llDetected...-Aufrufe nix kosten, sondern genauso wie Variablen-Zugriffe einfach nur auf den Stack der VM zugreifen. Ist aber nur so meine Theorie, und das nur mal am Rande.

Doktor Schnyder schrieb:
statt mit llsay oder llInstantMessage arbeite ich gerne mit llEmail.

Ja, kann ja jeder gerne in diese Funze "console" reinbasteln. Ist ja OpenSource, d.h. darf gerne weiterentwickelt werden oder als Basis für irgendwas andres.
 
Hallo,

ich hab mal den besuchermelder probiert. Kann es sein, das der auf Gruppen-Land nicht funktioniert?

Ich habe auch probiert den der Gruppe zu deeden, auch scheinbar erfolglos.

Oder was mache ich evtl. falsch?
 
Habt ihr mal
Code:
integer print_method = 0; // 0=llSay
ausprobiert ?
Weil llOwnerSay und llInstantMessage können nicht funktionieren,
beides schickt die Nachricht an den Besitzer, wenn das Object gedeedet ist,
dann schickt es die jeweilige Gruppe(nicht Gruppen IM) und da "verschwindet" die Nachricht dann im Datennirvana.
 

Users who are viewing this thread

Zurück
Oben Unten