Accessing Prim Properties/de
From OpenSimulator
(→Writing accessors) |
(→Beispiel: Ein Replikator) |
||
Line 68: | Line 68: | ||
Fügen Sie dieses Skript zusammen mit einem Single-Prim-Objekt namens „seed“ in eine Box ein. Es iteriert auf jedem Prim eines benannten Objekts, das Sie in der Szene besitzen, und rezerrt dann ein identisches Prim mit einem bestimmten Offset, wodurch das Quellobjekt, sogar die Netze, perfekt repliziert wird. Sleeps sind zur Demo hier. Entfernen Sie sie für eine schnelle Replikation. Mit der CLEANUP-Option werden gelöschte Prims entfernt. | Fügen Sie dieses Skript zusammen mit einem Single-Prim-Objekt namens „seed“ in eine Box ein. Es iteriert auf jedem Prim eines benannten Objekts, das Sie in der Szene besitzen, und rezerrt dann ein identisches Prim mit einem bestimmten Offset, wodurch das Quellobjekt, sogar die Netze, perfekt repliziert wird. Sleeps sind zur Demo hier. Entfernen Sie sie für eine schnelle Replikation. Mit der CLEANUP-Option werden gelöschte Prims entfernt. | ||
<source lang="lsl"> | <source lang="lsl"> | ||
− | string targetName = "Example"; // | + | string targetName = "Example"; // Name des Zielobjekts, das dupliziert werden soll |
− | string seedName = "seed"; // Name | + | string seedName = "seed"; // Name des Ausgangs-Prims, der dupliziert werden soll |
− | vector offset = <5,0,0>; // | + | vector offset = <5,0,0>; // Versatz für die Duplikate |
− | |||
− | |||
− | |||
+ | integer primcnt; // Anzahl der Prims im Wurzelobjekt | ||
+ | integer primnum; // Aktuelle Nummer des zu kopierenden Prims | ||
+ | key rootKey; // Schlüssel des Wurzelobjekts | ||
+ | |||
+ | // Funktion zur Bestimmung der Länge eines Tupels basierend auf dem Parameter | ||
integer TupleLength (integer param) | integer TupleLength (integer param) | ||
{ | { | ||
Line 90: | Line 92: | ||
} | } | ||
+ | // Funktion zum Iterieren durch die Seiten (Faces) eines Prims und Rückgabe der Parametertupel für jede Seite | ||
list IterateFaces (list p, integer param) | list IterateFaces (list p, integer param) | ||
{ | { | ||
Line 106: | Line 109: | ||
} | } | ||
+ | // Funktion zum Kopieren der Parameter eines Prims von einer Quelle zu einem Ziel | ||
CopyParams (key srcprim, key dstprim, integer param) { | CopyParams (key srcprim, key dstprim, integer param) { | ||
if (TupleLength(param) == 0) | if (TupleLength(param) == 0) | ||
Line 122: | Line 126: | ||
} | } | ||
+ | // Funktion zum Erstellen eines neuen Prims | ||
RezAPrim () | RezAPrim () | ||
{ | { | ||
Line 128: | Line 133: | ||
} | } | ||
+ | // Funktion, die aufgerufen wird, wenn ein Prim rezisiert wurde | ||
+ | // Kopiert die Parameter des ursprünglichen Prims auf den rezisierten Prim | ||
PrimRezed (key dstkey) | PrimRezed (key dstkey) | ||
{ | { | ||
Line 150: | Line 157: | ||
} | } | ||
− | + | // Funktion zum Abrufen des Besitzers eines Objekts anhand der Objekt-ID | |
key OwnerOf (key id) | key OwnerOf (key id) | ||
{ | { | ||
Line 162: | Line 169: | ||
state_entry() | state_entry() | ||
{ | { | ||
+ | // Initialisierung des Skripts | ||
llSetText ("READY", <0,1,0>, 1.0); | llSetText ("READY", <0,1,0>, 1.0); | ||
} | } | ||
Line 167: | Line 175: | ||
touch_start (integer n) | touch_start (integer n) | ||
{ | { | ||
+ | // Wenn das Objekt berührt wird, wechselt der Zustand in den Dialog-Modus | ||
state dialog; | state dialog; | ||
} | } | ||
Line 178: | Line 187: | ||
state_entry() | state_entry() | ||
{ | { | ||
+ | // Initialisierung des Dialog-Modus | ||
llSetText ("LISTENING", <0,1,0>, 1.0); | llSetText ("LISTENING", <0,1,0>, 1.0); | ||
llDialog (llGetOwner(), "Action?", ["CLEANUP", "REPLICATE"], dlgchan); | llDialog (llGetOwner(), "Action?", ["CLEANUP", "REPLICATE"], dlgchan); | ||
Line 184: | Line 194: | ||
} | } | ||
+ | // Abhören von Dialognachrichten und Auslösen entsprechender Aktionen | ||
listen (integer chan, string name, key id, string msg) | listen (integer chan, string name, key id, string msg) | ||
{ | { | ||
Line 192: | Line 203: | ||
timer () | timer () | ||
{ | { | ||
+ | // Timer-Ereignis zum Zurückkehren in den Standardzustand nach einer bestimmten Zeit | ||
state default; | state default; | ||
} | } | ||
Line 197: | Line 209: | ||
state_exit () | state_exit () | ||
{ | { | ||
+ | // Aufräumen beim Verlassen des Dialog-Modus | ||
llSetTimerEvent (0.0); | llSetTimerEvent (0.0); | ||
llListenRemove (dlglistener); | llListenRemove (dlglistener); | ||
Line 207: | Line 220: | ||
state_entry() | state_entry() | ||
{ | { | ||
+ | // Zustand für die Bereinigung von Prims | ||
llSetText ("CLEANUP", <0,1,0>, 1.0); | llSetText ("CLEANUP", <0,1,0>, 1.0); | ||
llSensor (seedName, NULL_KEY, PASSIVE|SCRIPTED, 100, PI); | llSensor (seedName, NULL_KEY, PASSIVE|SCRIPTED, 100, PI); | ||
Line 212: | Line 226: | ||
sensor (integer num) { | sensor (integer num) { | ||
+ | // Ereignis, das ausgelöst wird, wenn Sensoren aktiv sind | ||
llOwnerSay ("Garbage collecting "+(string)num); | llOwnerSay ("Garbage collecting "+(string)num); | ||
for (integer i=0; i<num; i++) osDie (llDetectedKey(i)); | for (integer i=0; i<num; i++) osDie (llDetectedKey(i)); | ||
Line 218: | Line 233: | ||
no_sensor() { | no_sensor() { | ||
+ | // Ereignis, das ausgelöst wird, wenn keine Sensoren aktiv sind | ||
llOwnerSay ("All clean."); | llOwnerSay ("All clean."); | ||
state default; | state default; | ||
Line 228: | Line 244: | ||
state_entry() | state_entry() | ||
{ | { | ||
+ | // Zustand für die Replikation von Prims | ||
llSetText ("REPLICATE", <0,1,0>, 1.0); | llSetText ("REPLICATE", <0,1,0>, 1.0); | ||
llSensor (targetName, NULL_KEY, PASSIVE|SCRIPTED, 100, PI); | llSensor (targetName, NULL_KEY, PASSIVE|SCRIPTED, 100, PI); | ||
Line 233: | Line 250: | ||
sensor (integer num) { | sensor (integer num) { | ||
+ | // Ereignis, das ausgelöst wird, wenn Sensoren aktiv sind | ||
rootKey = llDetectedKey (0); | rootKey = llDetectedKey (0); | ||
Line 246: | Line 264: | ||
no_sensor() { | no_sensor() { | ||
+ | // Ereignis, das ausgelöst wird, wenn keine Sensoren aktiv sind | ||
llOwnerSay ("Object "+targetName+" was not found."); | llOwnerSay ("Object "+targetName+" was not found."); | ||
} | } | ||
object_rez (key uuid) { | object_rez (key uuid) { | ||
+ | // Ereignis, das ausgelöst wird, wenn ein Objekt rezisiert wird | ||
PrimRezed (uuid); | PrimRezed (uuid); | ||
} | } |
Revision as of 00:18, 3 March 2024
Ein wenig Geschichte
Zuerst gab es llSetColor.
Dann gab es llSetLinkColor. Das war ein großer Fortschritt, da es Sie von der Last befreit hat, jedes einzelne Prim in Ihrem Haar zu skripten. Lache nicht. Möglicherweise finden Sie solche offensichtlich veralteten Skripte immer noch auf dem Hypergrid. Tun Sie uns einen Gefallen. Verbreiten Sie sie nicht. Mach sie kaputt. Schreiben Sie sie um.
Später erkannte man, dass die Möglichkeit, über ein Masterskript auf jede Eigenschaft eines Prims in einem Linkset zuzugreifen, eine gute Sache war. Dadurch wird Ihre Anwendung einfacher zu verstehen und zu warten und die Anzahl der Skripte wird reduziert. llSetLinkPrimitiveParams war geboren.
Schließlich hat OpenSimulator seine eigene Note hinzugefügt. Warum nicht Prims outside des Linkset von einem Masterskript aus manipulieren? Und wir hatten osSetPrimitiveParams.
llGet/SetLinkPrimitiveParams, osGet/SetPrimitiveParams sind das Arbeitstier der Prim-Manipulationen. Sie können von einem zentralen Ort aus auf alle vorhandenen Eigenschaften eines Prims zugreifen. Optimierter, schnellerer Code. Kein Chat oder LinkedMessages zwischen Prims mehr erforderlich.
Ein besonderer Hinweis zu llGetObjectLinkKey : Diese Funktion wurde im September 2022 eingeführt und ist der Kleber, den Sie benötigen, um auf Prims außerhalb des Linksets zuzugreifen. Sobald Sie die ID eines externen Objekts erhalten haben (vielleicht mit llSensor), können Sie llGetObjectPrimCount aufrufen (bedenken Sie auch osGetPrimCount, das sitzende Avatare nicht zählt) und dann mit llGetObjectLinkKey iterieren, um die ID jedes Prims im Remote-Objekt zu erhalten. Wenden Sie abschließend osGet/SetPrimitiveParams an.
In den folgenden Tabellen wird versucht, die zur Manipulation von Prims verfügbaren Funktionen für jede Adressierungsmethode zu sortieren.
Target is script's host (prim containing the script) |
Target is link number (inside the linkset) |
Target is prim id (any prim you own in the scene) |
---|---|---|
llGetOwner | ||
llGetKey | llGetLinkKey(num) | |
llSetText | ||
llGetRot / llSetRot | ||
llGetScale / llSetScale | ||
llGetAlpha / llSetAlpha | llSetLinkAlpha(num) | |
llGetColor / llSetColor | llSetLinkColor(num) | |
llGetPos / llSetPos | ||
llGetObjectName / llSetObjectName | llGetLinkName(num) | |
llGetObjectDesc / llSetObjectDesc | ||
llGetNumberOfSides | llGetLinkNumberOfSides(num) | |
llGetTexture / llSetTexture | llSetLinkTexture(num) | |
llSetTextureAnim | llSetLinkTextureAnim(num) | |
llParticleSystem | llLinkParticleSystem(num) | |
llSetPrimMediaParams | llSetLinkMedia(num) | |
llGetObjectPrimCount(uuid) | ||
llGetObjectDetails(uuid) | ||
llGetObjectLinkKey(uuid,num) | ||
"Universal" access (list of rules) | ||
llGet/SetPrimitiveParams | llGet/SetLinkPrimitiveParams(num) | osGet/SetPrimitiveParams(uuid) |
Beispiel: Ein Replikator
Fügen Sie dieses Skript zusammen mit einem Single-Prim-Objekt namens „seed“ in eine Box ein. Es iteriert auf jedem Prim eines benannten Objekts, das Sie in der Szene besitzen, und rezerrt dann ein identisches Prim mit einem bestimmten Offset, wodurch das Quellobjekt, sogar die Netze, perfekt repliziert wird. Sleeps sind zur Demo hier. Entfernen Sie sie für eine schnelle Replikation. Mit der CLEANUP-Option werden gelöschte Prims entfernt.
string targetName = "Example"; // Name des Zielobjekts, das dupliziert werden soll string seedName = "seed"; // Name des Ausgangs-Prims, der dupliziert werden soll vector offset = <5,0,0>; // Versatz für die Duplikate integer primcnt; // Anzahl der Prims im Wurzelobjekt integer primnum; // Aktuelle Nummer des zu kopierenden Prims key rootKey; // Schlüssel des Wurzelobjekts // Funktion zur Bestimmung der Länge eines Tupels basierend auf dem Parameter integer TupleLength (integer param) { if (param == PRIM_GLOW) return 1; if (param == PRIM_COLOR) return 2; if (param == PRIM_TEXGEN) return 1; if (param == PRIM_TEXTURE) return 4; if (param == PRIM_NORMAL) return 4; if (param == PRIM_SPECULAR) return 7; if (param == PRIM_BUMP_SHINY) return 2; if (param == PRIM_FULLBRIGHT) return 1; return 0; // Not a by-side parameter } // Funktion zum Iterieren durch die Seiten (Faces) eines Prims und Rückgabe der Parametertupel für jede Seite list IterateFaces (list p, integer param) { integer tuplelength = TupleLength (param); integer numsides = llGetListLength(p) / tuplelength; // Une seule face, retourner [ param, ALL_SIDES, p ] if (numsides == 1) return [ param, ALL_SIDES ] + p; list result = [ ]; for (integer s=0; s<numsides; s++) { list tuple = llList2List (p, s*tuplelength, (s+1)*tuplelength-1); result += [ param, s ] + tuple; } return result; } // Funktion zum Kopieren der Parameter eines Prims von einer Quelle zu einem Ziel CopyParams (key srcprim, key dstprim, integer param) { if (TupleLength(param) == 0) { list p = osGetPrimitiveParams (srcprim, [ param ]); if (param == PRIM_POSITION) p = [ llList2Vector (p,0) + offset ]; osSetPrimitiveParams (dstprim, [ param ] + p); } else { list p = osGetPrimitiveParams (srcprim, [ param, ALL_SIDES ]); p = IterateFaces (p, param); osSetPrimitiveParams (dstprim, p); } llSleep (0.1); } // Funktion zum Erstellen eines neuen Prims RezAPrim () { if (++primnum > primcnt) llResetScript(); llRezObject (seedName, llGetPos()+<0,0,1>, ZERO_VECTOR, ZERO_ROTATION, 0); } // Funktion, die aufgerufen wird, wenn ein Prim rezisiert wurde // Kopiert die Parameter des ursprünglichen Prims auf den rezisierten Prim PrimRezed (key dstkey) { llOwnerSay ("Processing link "+(string)primnum+" of "+(string)primcnt); key srckey = llGetObjectLinkKey (rootKey, primnum); llSleep (0.1); CopyParams (srckey, dstkey, PRIM_POSITION); CopyParams (srckey, dstkey, PRIM_ROTATION); CopyParams (srckey, dstkey, PRIM_TYPE); CopyParams (srckey, dstkey, PRIM_SIZE); CopyParams (srckey, dstkey, PRIM_COLOR); CopyParams (srckey, dstkey, PRIM_TEXTURE); CopyParams (srckey, dstkey, PRIM_NORMAL); CopyParams (srckey, dstkey, PRIM_SPECULAR); CopyParams (srckey, dstkey, PRIM_TEXGEN); CopyParams (srckey, dstkey, PRIM_BUMP_SHINY); CopyParams (srckey, dstkey, PRIM_FULLBRIGHT); CopyParams (srckey, dstkey, PRIM_PHYSICS_SHAPE_TYPE); RezAPrim (); } // Funktion zum Abrufen des Besitzers eines Objekts anhand der Objekt-ID key OwnerOf (key id) { list l = llGetObjectDetails (id, [ OBJECT_OWNER ]); return llList2Key (l, 0); } default { state_entry() { // Initialisierung des Skripts llSetText ("READY", <0,1,0>, 1.0); } touch_start (integer n) { // Wenn das Objekt berührt wird, wechselt der Zustand in den Dialog-Modus state dialog; } } integer dlgchan = 99; integer dlglistener; state dialog { state_entry() { // Initialisierung des Dialog-Modus llSetText ("LISTENING", <0,1,0>, 1.0); llDialog (llGetOwner(), "Action?", ["CLEANUP", "REPLICATE"], dlgchan); dlglistener = llListen (dlgchan, "", llGetOwner(), ""); llSetTimerEvent (10); } // Abhören von Dialognachrichten und Auslösen entsprechender Aktionen listen (integer chan, string name, key id, string msg) { if (msg == "CLEANUP") state cleanup; if (msg == "REPLICATE") state replicate; } timer () { // Timer-Ereignis zum Zurückkehren in den Standardzustand nach einer bestimmten Zeit state default; } state_exit () { // Aufräumen beim Verlassen des Dialog-Modus llSetTimerEvent (0.0); llListenRemove (dlglistener); } } state cleanup { state_entry() { // Zustand für die Bereinigung von Prims llSetText ("CLEANUP", <0,1,0>, 1.0); llSensor (seedName, NULL_KEY, PASSIVE|SCRIPTED, 100, PI); } sensor (integer num) { // Ereignis, das ausgelöst wird, wenn Sensoren aktiv sind llOwnerSay ("Garbage collecting "+(string)num); for (integer i=0; i<num; i++) osDie (llDetectedKey(i)); state default; } no_sensor() { // Ereignis, das ausgelöst wird, wenn keine Sensoren aktiv sind llOwnerSay ("All clean."); state default; } } state replicate { state_entry() { // Zustand für die Replikation von Prims llSetText ("REPLICATE", <0,1,0>, 1.0); llSensor (targetName, NULL_KEY, PASSIVE|SCRIPTED, 100, PI); } sensor (integer num) { // Ereignis, das ausgelöst wird, wenn Sensoren aktiv sind rootKey = llDetectedKey (0); if (OwnerOf(rootKey) != llGetOwner()) { llOwnerSay ("I don't own "+targetName+". Aborting."); state default; } primcnt = llGetObjectPrimCount (rootKey); primnum = 0; RezAPrim (); } no_sensor() { // Ereignis, das ausgelöst wird, wenn keine Sensoren aktiv sind llOwnerSay ("Object "+targetName+" was not found."); } object_rez (key uuid) { // Ereignis, das ausgelöst wird, wenn ein Objekt rezisiert wird PrimRezed (uuid); } }
Schreibzugriffsmethoden
Die Funktionsfamilie Get/SetPrimitiveParams ist unglaublich leistungsstark. Es ist auch ziemlich geheimnisvoll zu schreiben und zu entschlüsseln. Eine Möglichkeit, diese langen Parameterlisten loszuwerden, die Ihren Code überladen, besteht darin, Get/SetPrimitiveParams in einzelne get/set-Accessoren zu kapseln und so tatsächlich die Lücken in der obigen Tabelle zu füllen. Obwohl dies sehr angenehm zu lesen ist, beachten Sie, dass dies die Leistung beeinträchtigen kann, wenn Sie viele Eigenschaften auf einmal ändern möchten, was SetPrimitiveParams in einem Aufruf tun kann. Als Beispiel wird die folgende Bibliothek angeboten.
// Index of properties for PRIM_TYPE_BOX, PRIM_TYPE_CYLINDER, PRIM_TYPE_PRISM integer INDEX_TYPE = 0; integer INDEX_HOLE = 1; integer INDEX_CUT = 2; integer INDEX_HOLLOW = 3; integer INDEX_TWIST = 4; integer INDEX_TAPER = 5; integer INDEX_SHEAR = 6; // Index of properties for PRIM_TEXTURE integer INDEX_TEXTURE = 0; integer INDEX_REPEATS = 1; integer INDEX_OFFSETS = 2; integer INDEX_ROTATION = 3; // client script // +---------------+------------+ // Taper | -1.0 0 +1.0 | 2.0 0.0 | // Shear | -0.5 0 +0.5 | -0.5 +0.5 | // Twist | -180 0 +180 | -1.0 +1.0 | // +---------------+------------+ // // Set accessors // mySetLinkName (integer link, string text) { llSetLinkPrimitiveParamsFast (link, [PRIM_NAME, text]); } mySetLinkDesc (integer link, string text) { llSetLinkPrimitiveParamsFast (link, [PRIM_DESC, text]); } mySetLinkText (integer link, string text, vector color) { llSetLinkPrimitiveParamsFast (link, [PRIM_TEXT, text, color, 1.0]); } mySetLinkColor (integer link, vector color, integer face) { llSetLinkPrimitiveParamsFast (link, [PRIM_COLOR, face, color, 1.0]); } mySetLinkBright (integer link, integer bright, integer face) { llSetLinkPrimitiveParamsFast (link, [PRIM_FULLBRIGHT, face, bright]); } mySetLinkGlow (integer link, float glow, integer face) { llSetLinkPrimitiveParamsFast (link, [PRIM_GLOW, face, glow]); } // Les 3 suivants ne marchent pas pour ALL_SIDES mySetLinkTexture (integer link, key texture, integer face) { list l = llGetLinkPrimitiveParams (link, [PRIM_TEXTURE, face]); l = llListReplaceList(l, [texture], INDEX_TEXTURE, INDEX_TEXTURE); llSetLinkPrimitiveParamsFast (link, [PRIM_TEXTURE, face] + l); } mySetLinkRepeat (integer link, vector repeat, integer face) { list l = llGetLinkPrimitiveParams (link, [PRIM_TEXTURE, face]); l = llListReplaceList(l, [repeat], INDEX_REPEATS, INDEX_REPEATS); llSetLinkPrimitiveParamsFast (link, [PRIM_TEXTURE, face] + l); } mySetLinkOffset (integer link, vector offset, integer face) { list l = llGetLinkPrimitiveParams (link, [PRIM_TEXTURE, face]); l = llListReplaceList(l, [offset], INDEX_OFFSETS, INDEX_OFFSETS); llSetLinkPrimitiveParamsFast (link, [PRIM_TEXTURE, face] + l); } mySetLinkPos (integer link, vector pos) { llSetLinkPrimitiveParamsFast (link, [PRIM_POS_LOCAL, pos]); } mySetLinkRot (integer link, rotation rot) { llSetLinkPrimitiveParamsFast (link, [PRIM_ROT_LOCAL, rot]); } mySetLinkSize (integer link, vector size) { llSetLinkPrimitiveParamsFast (link, [PRIM_SIZE, size]); } mySetLinkCut (integer link, vector cut) { list l = llGetLinkPrimitiveParams (link, [PRIM_TYPE]); l = llListReplaceList(l, [cut], INDEX_CUT, INDEX_CUT); llSetLinkPrimitiveParamsFast (link, [PRIM_TYPE] + l); } mySetLinkTwist (integer link, vector twist) { list l = llGetLinkPrimitiveParams (link, [PRIM_TYPE]); l = llListReplaceList(l, [twist], INDEX_TWIST, INDEX_TWIST); llSetLinkPrimitiveParamsFast (link, [PRIM_TYPE] + l); } mySetLinkTaper (integer link, vector taper) { list l = llGetLinkPrimitiveParams (link, [PRIM_TYPE]); l = llListReplaceList(l, [taper], INDEX_TAPER, INDEX_TAPER); llSetLinkPrimitiveParamsFast (link, [PRIM_TYPE] + l); } mySetLinkShear (integer link, vector shear) { list l = llGetLinkPrimitiveParams (link, [PRIM_TYPE]); l = llListReplaceList(l, [shear], INDEX_SHEAR, INDEX_SHEAR); llSetLinkPrimitiveParamsFast (link, [PRIM_TYPE] + l); } mySetLinkHollow (integer link, float hollow) { list l = llGetLinkPrimitiveParams (link, [PRIM_TYPE]); l = llListReplaceList(l, [hollow], INDEX_HOLLOW, INDEX_HOLLOW); llSetLinkPrimitiveParamsFast (link, [PRIM_TYPE] + l); } // // Get accessors // string myGetLinkName (integer link) { list l = llGetLinkPrimitiveParams (link, [PRIM_NAME]); return llList2String (l,0); } string myGetLinkDesc (integer link) { list l = llGetLinkPrimitiveParams (link, [PRIM_DESC]); return llList2String (l,0); } string myGetLinkText (integer link) { list l = llGetLinkPrimitiveParams (link, [PRIM_TEXT]); return llList2String (l,0); } vector myGetLinkColor (integer link, integer face) { list l = llGetLinkPrimitiveParams (link, [PRIM_COLOR, face]); return llList2Vector (l,0); } integer myGetLinkBright (integer link, integer face) { list l = llGetLinkPrimitiveParams (link, [PRIM_FULLBRIGHT, face]); return llList2Integer (l,0); } float myGetLinkGlow (integer link, integer face) { list l = llGetLinkPrimitiveParams (link, [PRIM_GLOW, face]); return llList2Float (l,0); } key myGetLinkTexture (integer link, integer face) { list l = llGetLinkPrimitiveParams (link, [PRIM_TEXTURE, face]); return llList2Key(l,0); } vector myGetLinkRepeat (integer link, integer face) { list l = llGetLinkPrimitiveParams (link, [PRIM_TEXTURE, face]); return llList2Vector(l,1); } vector myGetLinkOffset (integer link, integer face) { list l = llGetLinkPrimitiveParams (link, [PRIM_TEXTURE, face]); return llList2Vector(l,2); } vector myGetLinkPos (integer link) { list l = llGetLinkPrimitiveParams (link, [PRIM_POS_LOCAL]); return llList2Vector (l,0); } vector myGetLinkSize (integer link) { list l = llGetLinkPrimitiveParams (link, [PRIM_SIZE]); return llList2Vector (l,0); } vector myGetLinkCut (integer link) { list l = llGetLinkPrimitiveParams (link, [PRIM_TYPE]); return llList2Vector (l, INDEX_CUT); } vector myGetLinkTwist (integer link) { list l = llGetLinkPrimitiveParams (link, [PRIM_TYPE]); return llList2Vector (l, INDEX_TWIST); } vector myGetLinkTaper (integer link) { list l = llGetLinkPrimitiveParams (link, [PRIM_TYPE]); return llList2Vector (l, INDEX_TAPER); } vector myGetLinkShear (integer link) { list l = llGetLinkPrimitiveParams (link, [PRIM_TYPE]); return llList2Vector (l, INDEX_SHEAR); } float myGetLinkHollow (integer link) { list l = llGetLinkPrimitiveParams (link, [PRIM_TYPE]); return llList2Float (l, INDEX_HOLLOW); }