• 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.

Skript erkennt, dass Textur auf Objekt gezogen wird.

Kelith Resident

Aktiver Nutzer
Hallo zusammen,
ich suche eine Möglichkeit zu erkennen, ob eine Textur aus dem Inventar auf ein Objekt gezogen und losgelassen wurde. Das Skript soll dann eine bestimmte Fläche mit der Textur belegen. Ziel ist, das Objekt soll not modify sein und per Skript gewährleisten, dass immer nur die eine Fläche die Textur abbekommt, egal wo man die Textur auf dem Objekt tatsächlich hinzieht.
Mit einem Touch Event geht das nicht, oder? Ich hatte mal was gefunden um eine Textur UUID per drag and drop in ein HUD zu bekommen, kann das aber leider nicht mehr finden. Mit einem gerezzten Objekt wie im aktuellen Fall müsste das doch dann auch gehen?
 
Hier sind Beispiele dazu:
http://wiki.secondlife.com/wiki/Llallowinventorydrop

Das würde dann z.B. so aussehen in deinem speziellen Fall:

Code:
integer iTextureFace = 1; //Seite des Prims, auf die die Textur gegeben werden soll.
default
{
  state_entry()
  {
   llAllowInventoryDrop(TRUE); //Das Ablegen von Inventar erlauben.
  }
  changed(integer change)
  {
    integer iNumberTextures = llGetInventoryNumber(INVENTORY_TEXTURE);
    key kTexture;
    if (change & (CHANGED_ALLOWED_DROP | CHANGED_INVENTORY))
    { //Der Owner (oder jemand mit Mod-Rechten: CHANGED_INVENTORY) oder jemand ohne Modify-Rechte (CHANGED_ALLOWED_DROP) hat das Inventar verändert.
      if (llGetInventoryNumber(INVENTORY_TEXTURE) > iNumberTextures)
      { //Es gibt eine neue Textur.
        kTexture = llGetInventoryKey(INVENTORY_TEXTURE, llGetInventoryNumber(INVENTORY_TEXTURE)-1); //Den Key der zuletzt eingefügten Textur auslesen.
        llSetTexture(kTexture, iTextureFace); //Die 'neue' Textur verwenden (falls jemand mit Modify-Permissions das Inventar verändert hat, wird die zuletzt eingefügte Textur verwendet).
      } //else: nichts tun.
    }
  }
}
 
Zuletzt bearbeitet:
Hallo Kellith

Wenn die Textur auf ds Objekt gezogen wird, wird immer der changed() Ereignis ausgelöst.

Wenn die Textur im Inventar des Objekt erscheint, dann wird CHANGED_INVENTORY aktiv sein, falls Du das Objekt bearbeiten kannst und die Textur ins Baufenster wirfst. Wenn die Textur bei der gedruckten STRG Taste geworfen wird (Objekt rot umrandet) dann CHANGED_ALLOWED_DROP. Und wenn die Textur direkt auf eine Fläche geworfen wurde und diese texturiert hat, ohne im Objektinventar zu erscheinen, dann CHANGED_TEXTURE. Im letzten Fall kannst du die Textur verwerfen und neu texturieren.

Damit CHANGED_ALLOWED_DROP ausgelöst werden kann, must Du das via llAllowInventoryDrop() erlauben, auf die Weise können ADBoards die Bilder, Karten und andere Sachen aufnehmen.

LG
 
hmmm, mal resümieren:

Objekt = nomod -> textur per maus auf die gewünschte fläche ziehen nicht möglich
was möglich ist mit allowdrop, ist die textur ins inventar des nomod objektes zu schieben
das muss ein skript im inneren dem face die neue textur zuweisen (inventory-changed -> settexture)
dazu muss die textur fullperm sein, damit man die uuid der fremdtextur auslesen kann
 
Hallo, vielen Dank für die Antworten so schnell :)

@MartinRJ Fayray: Da ist ein Syntax error in Deinem Skript,
Code:
[COLOR=#494949]kTexture = llGetInventoryKey(INVENTORY_TEXTURE, llGetInventoryNumber(INVENTORY_TEXTURE)-1);[/COLOR]
Das llGetInventoryKey erlaubt nur einen Parameter, es sollte wohl so ähnlich lauten?
Code:
[COLOR=#494949]kTexture = llGetInventoryKey(llGetInventoryNumber(INVENTORY_NAME));[/COLOR]


Trotzdem war Dein Skript und die Anmerkung der anderen sehr hilfreich.
Ich habe das hier gebastelt, so als erste Variante, die aber schon das tut, was sie soll. Eine erste Textur liegt bereits im Auslieferungszustand im Objekt. Deren Name wird gespeichert. Wenn eine zweite Textur hinzukommt (STRG-drag-drop), wird die erste gelöscht und die neue Textur gesetzt.

Code:
string  name;default
{
 state_entry()
    {
         llAllowInventoryDrop(TRUE);                        // Das Ablegen von Inventar erlauben.
         name =  llGetInventoryName(INVENTORY_TEXTURE, 0);  // as default there is already one texture
}
    changed(integer change)
    {
        if (change & (CHANGED_ALLOWED_DROP | CHANGED_INVENTORY))    // if there has been a change to the prim's contents ...
        {
            if (llGetInventoryNumber(INVENTORY_TEXTURE) > 1)        // if there is another texture
            {   
                llRemoveInventory(name);                            // remove last known texture
                if (name = llGetInventoryName(INVENTORY_TEXTURE, 0))  llSetTexture(name,1);  // if a texture exists set it
            }
        }
    }
}
 
Zuletzt bearbeitet:
llGetInventoryKey benötigt den Namen der Datei im Objektinventar um den Key dafür zu ermitteln. So müsste der Befehl funktionieren:

Code:
llGetInventoryKey(llGetInventoryName(INVENTORY_TEXTURE, 0));

Ich würde im Skript die Textur übernehnem und danach wieder löschen, damit wenn jemand eine neue rein tut, sie oben erscheint. Evtl macht es sinn, alle Texturen zu löschen, falls einer einen Haufen reingelegt hat. Dann könnte es passieren, dass die vorhandene Texturen immer noch vorne sind und das Auslesen der Neuen blokieren. Dann legt man eine Textur und der Skript bringt eine andere auf die Vorderseite bis die von vor einer Stunde dran ist und man vielleicht einen Batzen von Texturkopien im Objekt liegen hat. So in etwa:

Code:
string name;

default
{
    state_entry()
    {
        llAllowInventoryDrop(TRUE); // Das Ablegen von Inventar erlauben.

        name =  llGetInventoryName(INVENTORY_TEXTURE, 0);
        while (name != "")
        {
            llSetTexture(name, 1);
            llRemoveInventory(name);
            name =  llGetInventoryName(INVENTORY_TEXTURE, 0);
        }
    }

    changed(integer change)
    {
        if (change & (CHANGED_ALLOWED_DROP | CHANGED_INVENTORY))    // if there has been a change to the prim's contents ...
        {
            name =  llGetInventoryName(INVENTORY_TEXTURE, 0);
            while (name != "")
            {
                llSetTexture(name, 1);
                llRemoveInventory(name);
                name =  llGetInventoryName(INVENTORY_TEXTURE, 0);
            }
        }
    }
}

Kleines Manko, wenn man hier im Seltenen Fall 20 Texturen rein tut, wernden alle 20 nacheinander im Diashow abgespielt und die letzte bleibt angezeigt. Wäre sinnvoll evtl nur die letzte anzuzeigen. Das macht aber den Skript komplizierter.

Wenn man aber fordert, dass da nur fullperm Texturen für den Tafelbesitzer in die Tafel landen, dann könnte man statt Namen den Key abfragen und den letzten Key dann nach der Löschschleife zuweisen.
 
Zuletzt bearbeitet:
Hallo, vielen Dank für die Antworten so schnell :)

@MartinRJ Fayray: Da ist ein Syntax error in Deinem Skript,
Code:
[COLOR=#494949]kTexture = llGetInventoryKey(INVENTORY_TEXTURE, llGetInventoryNumber(INVENTORY_TEXTURE)-1);[/COLOR]
Das llGetInventoryKey erlaubt nur einen Parameter, es sollte wohl so ähnlich lauten?
Code:
[COLOR=#494949]kTexture = llGetInventoryKey(llGetInventoryNumber(INVENTORY_NAME));[/COLOR]


Trotzdem war Dein Skript und die Anmerkung der anderen sehr hilfreich.
Ich habe das hier gebastelt, so als erste Variante, die aber schon das tut, was sie soll. Eine erste Textur liegt bereits im Auslieferungszustand im Objekt. Deren Name wird gespeichert. Wenn eine zweite Textur hinzukommt (STRG-drag-drop), wird die erste gelöscht und die neue Textur gesetzt.

Code:
string  name;default
{
 state_entry()
    {
         llAllowInventoryDrop(TRUE);                        // Das Ablegen von Inventar erlauben.
         name =  llGetInventoryName(INVENTORY_TEXTURE, 0);  // as default there is already one texture
}
    changed(integer change)
    {
        if (change & (CHANGED_ALLOWED_DROP | CHANGED_INVENTORY))    // if there has been a change to the prim's contents ...
        {
            if (llGetInventoryNumber(INVENTORY_TEXTURE) > 1)        // if there is another texture
            {   
                llRemoveInventory(name);                            // remove last known texture
                if (name = llGetInventoryName(INVENTORY_TEXTURE, 0))  llSetTexture(name,1);  // if a texture exists set it
            }
        }
    }
}


Hopple, das sollte heißen:
kTexture = llGetInventoryKey(llGetInventoryName(INVENTORY_TEXTURE, llGetInventoryNumber(INVENTORY_TEXTURE)-1)); // (die zuletzt ins Inventar eingefügte Textur)

Das gesamte Skript sieht dann so aus (ich habe es nicht getestet):

Code:
integer iTextureFace = 1; //Seite des Prims, auf die die Textur gegeben werden soll.
default
{
  state_entry()
  {
   llAllowInventoryDrop(TRUE); //Das Ablegen von Inventar erlauben.
  }
  changed(integer change)
  {
    integer iNumberTextures = llGetInventoryNumber(INVENTORY_TEXTURE);
    key kTexture;
    if (change & (CHANGED_ALLOWED_DROP | CHANGED_INVENTORY))
    { //Der Owner (oder jemand mit Mod-Rechten: CHANGED_INVENTORY) oder jemand ohne Modify-Rechte (CHANGED_ALLOWED_DROP) hat das Inventar verändert.
      if (llGetInventoryNumber(INVENTORY_TEXTURE) > iNumberTextures)
      { //Es gibt eine neue Textur.
        kTexture = llGetInventoryKey(llGetInventoryName(INVENTORY_TEXTURE, llGetInventoryNumber(INVENTORY_TEXTURE)-1)); //Den Key der zuletzt eingefügten Textur auslesen.
        llSetTexture(kTexture, iTextureFace); //Die 'neue' Textur verwenden (falls jemand mit Modify-Permissions das Inventar verändert hat, wird die zuletzt eingefügte Textur verwendet).
      } //else: nichts tun.
    }
  }
}

PS: Dieses Skript nimmt immer die zuletzt eingefügte Textur (was ja schließlich gefragt war), und belässt die vorhandenen im Inventar (man kann problemlos hunderte Texturen im Objekt-Inventar lassen, das stört das Skript nicht).
 
Zuletzt bearbeitet:
Hopple, das sollte heißen:
kTexture = llGetInventoryKey(llGetInventoryName(INVENTORY_TEXTURE, llGetInventoryNumber(INVENTORY_TEXTURE)-1)); // (die zuletzt ins Inventar eingefügte Textur)

Ich probiere das gleich mal aus. Nach meinen Informationen liest llGetInventoryName das Inventar aber alphabetisch, nicht chronologisch. Man erhält mit der oben beschriebenen Methode die Textur, die nach dem Alphabet die letzte ist, nicht zwangsläufig die Textur, die man zuletzt eingefügt hat.
 
@Jenna,
Du löscht eine Textur aus dem Invantar, nachdem Du diese auf eine Fläche gelegt hast.
Code:
[COLOR=#333333]while (name != "")
[/COLOR]{
      llSetTexture(name, 1);
      llRemoveInventory(name);
      name =  llGetInventoryName(INVENTORY_TEXTURE, 0);
[COLOR=#333333]}[/COLOR]
Wie ich nun feststelle, wird dadurch auch die Fläche wieder ohne diese Textur dargestellt, so wie sie zuvor war.
Schlussfolgerung: Wenn man eine Textur im Inventar hat und über deren Namen oder auch UUID (selber getestet) einer Fläche zuweist und dann diese Textur aus dem Inventar entfernt, ist auch die Fläche wieder wie vorher. So, als wäre nichts geschehen.
Darauf wiederrum folgt, die benutzte Textur muss im Inventar verbleiben, nur die anderen Texturen (falls mehrere gleichzeitig gedropt werden) können weg.

Was mich auf das nächste Problem bringt.
Wenn man mehrere Texturen zugleich in das Objekt dropt, läuft das Skript schon mal los, obwohl noch Texturen ins Inventar kommen. Das kann man so kaum vernünftig handhaben. Besonders, weil die Texturen alphabetisch sortiert werden und man ja nie weiß, was da an Texturen noch reinflattert. Wenn man 20 Texturen markiert und zugleich ins Objekt fallen läßt, gehts das drunter und drüber.
 
Ein stabiles Verhalten und Aufräumen des Inventars bei vielen gedropten Texturen bekomme ich so hin: Mit einer 5 sekündigen Pause nach dem CHANGE. Aber 20 Texturen brauchen länger (eben getestet) als 5 Sekunden, bis sie im Inventar des Objekts erscheinen. Das Skript kommt damit aber klar, es werden nur ggf. zwei oder drei Texturen nacheinander angezeigt. Doof ist die Pause schon, ich sehe ungeduldige Anwender vor mir.:wink:

Code:
string  name;default
{
 state_entry()
    {
         llAllowInventoryDrop(TRUE);                        // Das Ablegen von Inventar erlauben.
         name =  llGetInventoryName(INVENTORY_TEXTURE, 0);  // as default there is already one texture
}
    changed(integer change)
    {
        if (change & (CHANGED_ALLOWED_DROP | CHANGED_INVENTORY))    // if there has been a change to the prim's contents ...
        {
            llSleep(5.0);
            if (llGetInventoryNumber(INVENTORY_TEXTURE) > 1)        // if there is another texture
            {   
                llRemoveInventory(name);                            // remove last known texture
                if (name = llGetInventoryName(INVENTORY_TEXTURE, 0))  llSetTexture(name,1);  // if a texture exists set it


                while (llGetInventoryName(INVENTORY_TEXTURE, 1))
                {
                    llRemoveInventory(llGetInventoryName(INVENTORY_TEXTURE, 1));                    
                }
            }
        }
    }
}
 
Ich probiere das gleich mal aus. Nach meinen Informationen liest llGetInventoryName das Inventar aber alphabetisch, nicht chronologisch. Man erhält mit der oben beschriebenen Methode die Textur, die nach dem Alphabet die letzte ist, nicht zwangsläufig die Textur, die man zuletzt eingefügt hat.

Oh ja stimmt - das ist ein Irrtum der mir schon mehrmals passiert ist.
Du wirst dann wohl tatsächlich entweder die Texturen löschen müssen, oder die Namen am Ende des changed-Events in einer Liste speichern, z.B. mit dieser Funktion: list lInventoryList () { list l; integer i; for (i=0; i<llGetInventoryNumber(INVENTORY_TEXTURE); i++) {l += llGetInventoryName(INVENTORY_TEXTURE, i);} return l; }


Und dann im Changed - Event überprüfen welche Texturen schon vorhanden sind: string getNewTexture(list l) { integer i; for (i=0; i<llGetInventoryNumber(INVENTORY_TEXTURE); i++) {if (llListFindList(l, [llGetInventoryName(INVENTORY_TEXTURE, i)]) == -1) {return llGetInventoryName(INVENTORY_TEXTURE, i);}} return "";}
-> aufrufen mit string sTexture = getNewTexture(lGlobalInventoryList);
und gleich danach die neue Liste global speichern: lGlobalInventoryList = lInventoryList();



Das komplette Skript sieht dann so aus:
list lGlobalInventoryList;
list lInventoryList () { list l; integer i; for (i=0; i<llGetInventoryNumber(INVENTORY_TEXTURE); i++) {l += llGetInventoryName(INVENTORY_TEXTURE, i);} return l; }
string getNewTexture(list l) { integer i; for (i=0; i<llGetInventoryNumber(INVENTORY_TEXTURE); i++) {if (llListFindList(l, [llGetInventoryName(INVENTORY_TEXTURE, i)]) == -1) {return llGetInventoryName(INVENTORY_TEXTURE, i);}} return ""; }
default
{
state_entry()
{
lGlobalInventoryList = lInventoryList();
}

changed(integer change)
{

string sTexture = getNewTexture(lGlobalInventoryList);
llSay(0, sTexture);
lGlobalInventoryList = lInventoryList();
}
}


EDIT: Das was du beobachtet hast, dass die Textur verschwindet, passiert sogar bei Fullperm- Texturen (gerade ausprobiert) - das hätte ich nicht gedacht! Ich war der Meinung dass Fullperm-Texturen nicht von der Prim-Oberfläche verschwinden wenn sie aus dem Objekt-Inventar entfernt werden (natürlich reden wir hier von Texturen die mit llSetTexture zusammen verwendet wurden).
 
Zuletzt bearbeitet:
Und ich dachte das passiert nur wenn die einer Oberfläche zugewiesene Textur manuell aus dem Objektinventar gelöscht wird. Dann erscheint da wieder die Holztextur laut meiner Beobachtung.

Wenn es so ist, dann muss man die Übernommene Textur nicht löschen, nur die anderen. Oder den Key der Textur (leider Fullperm benötigt) ermitteln und diesen dann setzen, dann sollte die Textur beim löschen nicht verschsinden. Wenn doch, nach dem Löschvorgang die Textur via key erneut setzen.

Die Texturen in Liste speichern hat den Vorteil, dass die Texturen auch bleiben. Aber dann auch den Speicher über die Liste verbrauchen. Wielange es braucht bis der Speicher überläuft, keine anung, aber ein String verbraucht in einer Liste etwa 18 Bytes + 2 Byte per Zeichen. Geht man von Namen der bilder von etwa 40 Zeichen aus (schon recht lang, aber Snapshots schreiben da alles mögliche, also sollte passen) dann nimmt jeder Name 98 Byte. 60kb reichen dann für 612 Bilder. Könnte also reichen.
 
Wenn es so ist, dann muss man die Übernommene Textur nicht löschen, nur die anderen. Oder den Key der Textur (leider Fullperm benötigt) ermitteln und diesen dann setzen, dann sollte die Textur beim löschen nicht verschsinden. Wenn doch, nach dem Löschvorgang die Textur via key erneut setzen.
Leider wird die Textur tatsächlich auch von der Primoberfläche entfernt, wenn man den Key verwendet. Die Textur nach dem Löschen neu auftragen ist eine praktikable Lösung, man muss dann eben den Key zwischenspeichern, und das Changed-Event überwachen um gegebenenfalls die Textur neu zu setzen (z.B. kann man im Changed-Event vergleichen ob das Face wieder die Default-Textur verwendet, und dann die zwischengespeicherte Textur nochmals auftragen).
 
Wie waers mit der Textbox?

Damit liesse dich das doch ohne Textur einlegen realisieren und das Object muesste nicht modify sein.

  1. Einfach mit der rechten Maustaste im Inventar die Asset-UUID kopieren,
  2. das Object clicken damit sich die Textbox per Menue oeffnet,
  3. die UUID in die Textbox einfuegen und senden,
  4. fertig.
Wenn die Textur Fullperm ist, gibt es mit der UUID ueberhaupt keine Probleme.

LG
Dae
 
Danke nochmal für die vielen guten Vorschläge. Listen zu führen geht mir ehrlich gesagt dann doch zu weit für so ein simples Teil. Mein hier zuletzt gepostetes Skript funktioniert ganz ordendlich. Es wird stumpf die (alphabetisch) erste Textur übernommen bzw. durch eine andere ersetzt. Wer mehr als eine Textur reinschiebt, weiß eh nicht, was er tut, und die fliegen dann alle wieder raus bis auf eine. Bei so Masseninserts ist das Skript schneller als die Objekte ins Inventar plumpsen, daher die 5 Sekunden Pause. Die 5 Sekunden zum Stabilisieren des Inventars überbrücke ich duch einen Hovertext.
Damit das Objekt nicht zur Mülltonne verkommt, in die jeder was reinschmeißt, muss der Owner oder jemand aus der selben Gruppe das Objekt anklicken. Erst dann wird ALLOW_INVENTORY_DROP auf TRUE gesetzt und nach 15 Sekunden per Timer wieder auf FALSE.

Das mit der Textbox habe ich auch in Erwägung gezogen und auch schon mal ausprobiert gehabt. Ist einerseits einfacher, da immer nur eine UUID übergeben werden kann und man das Inventargetue nicht braucht. Andererseits werden auch bei dieser Lösung, ebenso wie bei meiner, Anwender da stehen und nicht wissen, was genau zu tun ist. Ich weiß auch nicht, ob alle Viewer einen Rechtsklick mit der Option Asset-UUID abbieten. Kurz gesagt, jede Lösung hat ihre Vor- und Nachteile.

Das mit dem Löschen einer Textur aus dem Objektinventar ist schon witzig. Ich habe das Objekt normal texturiert, also über das Baumenü eine Textur aus meinem Inventar gewählt. Die Textur war nicht im Objektinventar. So ist das Objekt dann auch wieder gespeichert in meinem Inventar. Wenn ich das Objekt wieder rezze, ist alles normal. Testweise habe ich dann mal die Textur, mit der das Objekt texturiert wurde, in das Objektinventar gelegt und dann daraus wieder gelöscht. Und zack ist das Objekt plötzlich wieder aus Sperrholz.
 

Users who are viewing this thread

Zurück
Oben Unten