User:Daemonika Nightfire/Scripts/linkset data example

From Second Life Wiki
Jump to navigation Jump to search

Vorwort

Grundsaetzlich war ich immer schon dagegen mit Texture Changern die UUIDs ueber einen Channel beispielsweise an ein Kleidungsstueck zu senden. Die abenteuerlichsten Huds werden verbreitet, wo die UUIDs mal verschluesselt und mal unverschleusselt versendet werden. Das wirkt auf mich halt wie gewollt und nicht gekonnt. Viel besser ist es die UUIDs fuer Texturen im Empfaenger zu speichern. Bisher habe ich dazu immer eine Liste im Empfaenger genutzt und mittels HUD lediglich die Zahl fuer den index uebermittelt. Da muss dann auch nichts mehr entschluesselt werden und spart eine ganze menge Script-Code / Memory. Ein weiterer und wahrscheinlich der essentielle Vorteil des LinksetData ist, dass man das Script resetten kann, ohne das die Daten verloren gehen, weil sie naemlich im Object gespeichert sind.

llLinksetData Setup

Dieses Beispiel ist nur ein einfaches Hilfsmittel das LinksetData zu fuellen. Bei einigen Experimenten ist uns aufgefallen, das die Eintraege alphabetisch sortiert werden. In dieser Variante wird das LinksetData mit Texturen fuer ein Texture Changer Menue vorbereitet. Mit hilfe der Passwort Variante kann auch niemand ohne dem richtigen Passwort die UUIDs aus dem Linkset auslesen.

Nachdem die Schluesselnamen im Chat ausgegeben wurden, entfernt sich das Script selbst aus dem Inhalt.
string password = "n3H49sd";

default
{
    state_entry()
    {
        llLinksetDataReset();
        
        llLinksetDataWriteProtected("red", "81cc70a7-2d3f-bf21-50b5-ba129cd070c9", password);
        llLinksetDataWriteProtected("blue", "a7faeca8-dcad-2429-75a8-0afd1fd3d983", password);
        llLinksetDataWriteProtected("green", "2cb4e61d-9e2e-9c74-c636-62fba90bde57", password);
        
        llOwnerSay(llDumpList2String(llLinksetDataListKeys(0, -1), " | "));
        llRemoveInventory(llGetScriptName());
    }
}

llLinksetData Texture Changer

Dieses Script ist das entgueltige Texture Changer Menue Exsample. Die Menue Button tragen die selben Namen wie die Schluesselnamen im LinksetData. Wird nun einer dieser Namen im Menue ausgewaehlt, uebernimmt das Object automatisch den eingetragenen Wert dahinter.

Wenn du das Script ohne die ganzen Kommentare speicherst, wirst du sehen wie klein es eigentlich ist. 
string password = "n3H49sd";

// Bedenke das ein einfacher Dialog nur 12 Button auf einmal anzeigen kann.
// Alternativ kann man auch einen HUD erstellen, womit dann dien Namen der einzelnen Button (links) gesendet werden.
list menu_buttons = ["red","green","blue"];

// Dynamischer menue Channel
/*
    In dieser globalen funktion wird bei jedem oeffnen des Menues der aktuelle Channel geloescht und ein neuer zufaelliger Channel erzeugt.
    Am Ende wird der Timer gestartet, der nach Ablauf den timer beendet und den Channel loescht.
*/
integer menu_handler;
integer menu_channel;
menu(key user,string title,list buttons)
{
    llListenRemove(menu_handler);
    
    menu_channel = (integer)(llFrand(1) * -DEBUG_CHANNEL);
    menu_handler = llListen(menu_channel,"","","");
    llDialog(user, title, buttons, menu_channel);
    
    llSetTimerEvent(30);
}

// Script-Anfang
default
{
    // Aufrufen/setzen der Werkseinstellung
    /*
        Der folgende Event wird nur dann ausgefuehrt, wenn das Script gespeichert oder resettet wird.
        Im aktuellen Beispiel ist mir nichts besonderes eingefallen was ich da nutzen kann.
    */
    state_entry()
    {
        llSay(0, "bla bla bla bla");
    }
    
    // klicken erkennen
    /*
        Als erstes wird geprueft, wer das object klickt.
        Jetzt wo der Agent bekannt ist oeffnet sich fuer ihn das einfache menue.
    */
    touch_start(integer total_number)
    {
        key agent = llDetectedKey(0);
        menu(agent, "Bla bla bla bla.", menu_buttons);
    }
    
    // Kommunikation im Chat/Channel
    /*
        Grundsaetzlich empfaengt der listen Event alles was im Chat / Channel gesendet wird.
        Wenn es nicht schon im Befehl llListen(... vorgesehen ist, muss man hier filtern.
        
        Das aktuelle Beispiel filtert nur die Button aus dem menue heraus und nutztdiese Message um den Schluesselnamen im LinksetData zu finden.
        Wird ein Schluesselname gefunden, verwendet der befehl llSetLinkPrimitiveParamsFast(... dessen Wert um die Textur zu veraendern.
        
        ImAnschluss wird das Menue ganz einfach wieder geoeffnet.
    */
    listen(integer channel, string name, key id, string message)
    {
        if(~llListFindList(menu_buttons, [message]))
        {
            llSetLinkPrimitiveParamsFast(LINK_THIS, [PRIM_TEXTURE, ALL_SIDES, llLinksetDataReadProtected(message, password), <1,1,0>, <0,0,0>, 0.0]);
            
            menu(id, "Bla bla bla bla.", menu_buttons);
        }
    }
    
    // Zeitgesteuerte Funktionen
    /*
        Mit dem timer lassen sich bestimmte Funktionen nach Zeit wiederholen oder einfach beenden.
        In diesem Fall wird lediglich der timer angehalten und der Listener entfernt.
    */
    timer()
    {
        llSetTimerEvent(0.0);
        llListenRemove(menu_handler);
    }
    
    // Veraenderungen im LinksetData erkennen
    /*
        Dieser Event aehnelt zwar dem Changed Event, erkennt jedoch nur 3 Veraendeungen die das LinksetData betreffen.
        Fuer veraenderungen am LinkSet (Object) selbst ist der changed(integer change) Event erforderlich.
        In diesem Beispiel wird lediglich geprueft ob ein vorhandener Eintrag veraendert wurde.
        
        Pruefen lassen sich zusaetzlich noch: LINKSETDATA_DELETE & LINKSETDATA_RESET
    */
    linkset_data(integer action, string name, string value)
    {
        if(action == LINKSETDATA_UPDATE)
        {
            llOwnerSay("Linkset Data for " + name + " has been successfully updated.");
        }
    }
    
    // Hallo Welt
    /*
        Ja, die Ueberschrift habe ich mit absicht so gewaehlt.
        Der on_rez Event wird naemlich immer dann ausgeloest, sobald das Object das Licht der Welt erblickt.
        Dazu gehoeren:
        ➤ Vom Inventar auf den Boden ziehen.
        ➤ Inworld kopieren (Kopie ziehen).
        ➤ Mittels Tools rezzen (Rezzer).
        ➤ Am Avatar anziehen.
        ➤ Du traegst es beim Einloggen.
        
        Selbstverstaendlich kann man in diesem Event vielseitige Funktionen ausfuehren.
        Einen Reset sollte man an dieser Stelle jedoch nur dann ausfuehren,
        wenn keine anderen Funktionen davon abhaengig sind vorherige Aufgaben auszufuehren oder temporaere Variablen bei zu behalt
    */
    on_rez(integer Dae)
    {
        llResetScript();
    }
}

llLinksetData Updater

Bei diesem Beispiel handelt es sich um ein LinksetData Updater. Weil das LinksetData Schluesselnamen basiert ist, kann man diverse Eintraege direkt auswaehlen. Dazu ist es nicht notwendig irgend welche langen listen zu parsen. Wenn dieses Script im Object durchgelaufen ist, wurden die Eintraege fuer "red" & "blue" ignoriert.

Auch dieses Script loescht sich selbst nach beendigung.
string password = "n3H49sd";

default
{
    state_entry()
    {
        llLinksetDataWriteProtected("green", "68d790ff-5c41-0a98-c9a9-46fcca48e125", password);
        llRemoveInventory(llGetScriptName());
    }
}