Jump to content

Stickman Ingmann

Resident
  • Posts

    66
  • Joined

  • Last visited

Posts posted by Stickman Ingmann

  1. So me and several other avatars makers create non-standard "onion skinned" avatars. I've made dragons, gryphons, and wyverns. I'm working with someone who does horses. I have friends who make dinosaurs who use a similar method.

    In order to aid in customization of these creatures, it's common to have a "texture HUD." Select a body part, select a texture, and it gets applied. Pick a decal/tattoo layer, and apply some spots or stripes or a stocking or whatever. The system can get pretty fancy, allowing you to have certain patterns on legs or arms, and different patterns on wings and tails, etc.

    From what I understand of Bakes on Mesh, in order to use this new feature, it would be necessary for the consumer to manually apply textures from inventory, rather than using a HUD to layer and bake the textures. Is that correct?

    If it is, the Bakes on Mesh project asks the question: which is better? A texture HUD with preview images, or a series of folders with various named skins in them? I'd pick the texture HUD every time. So unless I'm mistaken, for now I'll be continuing my onion skinning designs, but hope to hear more developments soon!

  2. I am very interested and excited in this feature. I'd like to thank Linden Lab for listening to input and working on this.

    I would like to argue against the lack of bone translation/positioning via animation. While it does have the traditional legitimate use of animating the facial bones (which rarely use simply rotation to animate the face), there are other non-traditional uses that it would be particularly potent and powerful for.

    Personally, I have been using "animation deformations," the changing of bone positions through the use of animations, in place of mesh skeleton deformations through mesh upload, because the mesh skeletons haven't always loaded to everyone looking at it, and it's much easier to automatically replay an animation than it is to rewear the object that sets the mesh skeleton.

    If LL does not desire unapproved use of this feature, I recommend communication. A good set of tools includes enough rope to hang yourself with. To continue a tool analogy, a nailgun is powerful and useful. Given to someone who doesn't know any better, it can be deadly. The trick here is education. Let us know how to use the tools, and if we're using the tools wrong, tell us how we're using them wrong, and why we shouldn't use them wrong. But don't remove the tool just because it's "dangerous." Second Life has lacked a proper "standards guide" since its inception, and this has resulted in some very wasteful and dangerous creations. However cool.

    Also, a source file for the new skeleton, or at least an explanation including all bone names and which bones are parents to which other bones so we can create our own would be desirable.

    • Like 2
  3. Looking for ways to create what-you-see-is-what-you-get animations in SL.

    The only way to do this is by uploading .anim files, the SL internal animation format. I'm only familiar with two tools that aid with this.

    One is Zwagoth's number-editing tool, AnimMaker. https://code.google.com/p/par/downloads/detail?name=AnimMaker.zip

    The other is Avastar. http://blog.machinimatrix.org/avastar/

    I know Daz3D is used as an SL tool, but I don't even know if it can do animations, let alone export .anim files.

    Are there any other anim related tools that anyone knows about?

    Thanks.

  4. Looking for ways to create what-you-see-is-what-you-get animations in SL.

    The only way to do this is by uploading .anim files, the SL internal animation format. I'm only familiar with two tools that aid with this.

    One is Zwagoth's number-editing tool, AnimMaker. https://code.google.com/p/par/downloads/detail?name=AnimMaker.zip

    The other is Avastar. http://blog.machinimatrix.org/avastar/

    I know Daz3D is used as an SL tool, but I don't even know if it can do animations, let alone export .anim files.

    Are there any other anim related tools that anyone knows about?

    Thanks.

  5. Two methods come to mind.

    One is sending an email, which you can do if you know the UUID of the object. http://wiki.secondlife.com/wiki/LlEmail Note that it has a 20 second delay, and there is a limit to how many/fast you can send them.

    Note that email requires a way to receive the UUID in the first place. You can manually input it, but the object's UUID will change whenever it is rerezzed. Thus, while being fairly simple, this method has some hard-coded or less dynamic methods to it.

    Two is using the http functions. You can use llRequestURL to get a URL that the other object can access. http://wiki.secondlife.com/wiki/Category:LSL_HTTP

    For HTTP communications, you can use some sort of "LSL DNS" system, which requires an external server. There are some free ones set up that you could tap into, I believe. A quick serch shows this page: http://wiki.secondlife.com/wiki/Public_Object_DNS Which, if is not the answer, will lead you towards the answer.

    So HTTP can be entirely automated even after rerezzing things, but setting it up as such is way more involved than just sending an email.

    Hope that helps!

  6. "Name not defined in scope" means that the variable wasn't declared, or wasn't declared within the same event, or otherwise the same "scope."

     

    For example:

    touch_start(integer num) {    if (num) {        string s = "Two or more people touching!";    }    llOwnerSay(s);}

     In this case, the string s is defined within the if block. The if block exits, s becomes undefined. Thus, this would get the error "name not defined in scope."

    A correct version is as follows:

    touch_start(integer num) {    string s;    if (num) {        s = "Two or more people touching!";    }    llOwnerSay(s);}

     In this case, it's defined before the block, and then assigned during, and used afterwards. Since it's defined within the "touch_start()" scope, it's within the same scope.

    Trying to use this variable in another event would require defining it as a global variable, before the state definition. Like so:

    integer i;default {    touch_start(integer num) {        i = i + 1;    }    on_rez(integer a) {        llOwnerSay("We have been touched "+(string)i+" times.");    }}

     Understanding scope and variable definition should help you resolve this problem.

     

     

  7. I recommend doing as suggested above.

    Rather than looping through the inventory each time, you can cache the values in two lists. When you get an on_rez()/state_entry(), loop through all animations and store them in each list, depending on the prefix.

    When you get a changed() with CHANGED_INVENTORY, clear the lists and cache them again.

    I assume you've got some sort of pagination working based on looping through inventory count. you can do the same except with your cached lists.

  8. The wiki page mentions that some errors can happen during certain times of day. Could that be the problem?

    http://wiki.secondlife.com/wiki/LlHTTPRequest

    "Requests made at approx 0625 SLT may fail with a 503 status code, with "ERROR: The requested URL could not be retrieved", and "(111) Connection refused" in the body of the response. This has been confirmed as expected behaviour by Kelly, due to the nightly maint & log rotation. It does reliably impact object to object HTTP at that time, and quite probably may impact object to/from web around the same time. The interruption in service is fairly brief, and the precise timing may vary as LL adjust their nightly maint processes, or due to server load."


    Not familiar with the problem you describe, as I don't use the feature enough to encounter problems, but a workaround could be having the object ping its own URL with a request to see if it gets a response, and request a new URL if it doesn't.

  9. Not sure what you're asking for. Alpha swapping? Position changing?

    Alpha swapping could be like this:

    // Swaps prim alpha when flying/landingstring gsOpen = "open";string gsClosed = "closed";list glPrimCacheOpen;list glPrimCacheClosed;float gfTimer = 0.25; // Don't recommend lower.integer gbFlying;cachePrims() {    glPrimCacheOpen = [];    glPrimCacheClosed = [];    integer x = llGetNumberOfPrims();    do {        string sName = llGetLinkName(x);        if (sName == gsOpen) {            glPrimCacheOpen += [x];        }        else if (sName == gsClosed) {            glPrimCacheClosed += [x];        }    } while (--x);}default {    attach(key id) {        if (id != NULL_KEY) {            llSetTimerEvent(gfTimer);            if (!llGetListLength(glPrimCacheOpen)) {                cachePrims();            }        }        else {            llSetTimerEvent(0.0);            gbFlying = FALSE;        }    }    timer() {        integer i = llGetAgentInfo(llGetOwner());        if (i & AGENT_FLYING && !gbFlying) {            gbFlying = TRUE;            i = llGetListLength(glPrimCacheClosed);            while (i--) {                llSetLinkAlpha(i,0.0,ALL_SIDES);            }            i = llGetListLength(glPrimCacheOpen);            while (i--) {                llSetLinkAlpha(i,1.0,ALL_SIDES);            }        }        else if (!(i & AGENT_FLYING) && gbFlying) {            gbFlying = FALSE;            i = llGetListLength(glPrimCacheOpen);            while (i--) {                llSetLinkAlpha(i,0.0,ALL_SIDES);            }            i = llGetListLength(glPrimCacheClosed);            while (i--) {                llSetLinkAlpha(i,1.0,ALL_SIDES);            }        }    }

        changed(integer c) {
            if (c & CHANGED_LINK) {
                cachePrims();
            }
        }
    }

    I wrote the script above without testing, so it may have a bug or two for you to work out. It compiles, though!

    The above script uses "prim caching" so it doesn't have to walk through the linkset every time. (which may not be a bad thing, needs benchmarking) It will only do that when it changed, or if there's no stored data (first wear). It also doesn't work except when worn, since that's always led to problems in everything I've worked on.

    Since it does use caching, and can only detect if the linkset changes, if you rename prims you'll need to manually reset the script for it to detect those changes.

    If you were changing the prims around when flying, physically relocating them, I would recommend storing the position, scale, and rotation values for each state in invisible hovertext and looping thought he linkset to change them. Seems like it'd use less script memory that way, as storing prim properties for two states of all prims could be real expensive on a high prim setup.

  10. The pin scripts are used for actually transferring running scripts between objects. That's a bit more complex than what you're looking to do, I'm sure. Sending a spoken message with llSay(), llWhisper(), llShout(), llRegionSay(), or llRegionSayTo() would be much simpler.

    I'm partial to llRegionSayTo(). In this case, you only need one object to hear what you're saying, so there's no reason to go broadcasting it into a radius. And when you llRezAtRoot() you get the object_rez() event, which tells you the key of what you just rezzed.

    On object_rez(key id) you'll want to have a llGetOwnerKey(id) == llGetOwner() to verify that the object actually rezzed, as it can be used to check for rez failure if the key is invalid. The wiki page probably has more about that, though it may only be listed as a jira bug link.

  11. I was dealing with a problem similar to this myself recently. One of my ideas was to set the rezzed object temporary before putting it into the vendor. This has its own problems, as temporary objects can be deleted unexpectedly. If I recall once every 90 seconds a "cleaning" cycle is executed which deletes all temporary objects, regardless of age. I've had brand new temporary objects get caught after a second or two and wiped.

    If not temporary, you just need some communication between objects to coordinate all the rezzing and derezzing.

    Keep in mind communication instant instant. It may take a frame or two (0.022-ish seconds) for a listen message to get to the object to tell it to delete. So using:

    llRegionSayTo(gkPlaceholder,giChannel,"Delete thyself");llRezAtRoot(gsInventoryTempAttach,llGetPos(),ZERO_VECTOR,ZERO_ROTATION,0);

     one right after the other may still result in "not enough prims." Adding a short sleep, or having the placeholder object reply just before calling llDie(), are a couple ways to be sure the action has been taken.

  12. While it's beyond my realm of knowledge, a bot would have access to the information you require to check these things. If the bot had administrative access over the land, they could then llEjectFromLand or llTeleportAgentHome. Keep in mind a bot requires a running computer with an always-on internet connection in order to exist in Second Life.

  13. llWater just gives you the water height of the region.

    http://wiki.secondlife.com/wiki/LlSetKeyframedMotion

    Using this function to animate it sounds like it would be the easiest solution. Anything else would involve enabling physics, or basically creating a movement system and math that does what this function does.

    Though turning on physics, making it boyant and maybe phantom, and giving it a target or five to weakly travel to might give you the effect you want.

    Look at these for more on that:

    http://wiki.secondlife.com/wiki/LlSetBuoyancy

    http://wiki.secondlife.com/wiki/LlTarget

    http://wiki.secondlife.com/wiki/At_target

    Oh, and this may be useful somehow, too.

    http://wiki.secondlife.com/wiki/Interpolation/Target/Float

     

  14. Google auto-translate used to be used a lot. But the API is now restricted to paying customers. You could try Bing's translate, which doesn't seem to have such restrictions. Just beware of false positives. Easiest way to avoid those (in my guess) would be to make sure X number of words and a total length of Y is used.

    Pulling apart any inworld freebie translator can get you the starting point you need.

  15. Last time I encountered this problem it was very simple. I had to find out if the point x, y was within a 2D rectangle. While I was digging for that, I found several more complex situations, such as finding out if a point is within a 2D polygon, if a line passes through (or just in) an n-sided polygon, etc.

    I'm sure a Google search can help you find the math you're looking for.

    A search led me here:

    http://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html

    This looks like a 2D test. But it could be modified to run multiple times. Four, I think, with two sides of each rectangle making up the L shape would do the job.

    Math is not my strong suit. Especially not 3D math. Something I'm still learning. But the problem you're seeking the answer to is not new, and has been documented countless times. Finding the math for it is just a matter of finding the official terminology used to describe such a situation.

  16. I see a couple potential problems here.

    First, there are three collision events. collision_start(), collision_end(), and collision(). They do what they sound like -- collision_start() is triggered when a collision begins, while the item is colliding (eg, pushing against the prim) the collision() event will fire something like every 0.05 seconds (or 0.1-ish probably), and when the colliding object finally goes away collision_end() will fire. You simply mentioned "collision event", so if you're not certain you're using the right one (or combination thereof), you can outline what it is you're making and we can help with that.

    Second, you're using a (very useful) shortcut, but which can be dangerous in this case. llDetectedType(0), using a zero, assumes that only one item is colliding. If more than one is colliding, you will only be checking against the first item in the list of colliding items. If you're doing something like a touch_start() event in a HUD, you can almost guarantee only one person will ever be touching it, and can save some effort by using this shortcut. However, in this case you probably don't want to do that.

    To find the problem, I recommend outputting some debug information. You can use the following script to see what's actually going on, rather than shooting into the darkness and hoping you hit something. Then use the information to make whatever it is you're trying to make.

    // Debug style output for collision events.string returnType(integer i) {    string s;    if (i & AGENT_BY_LEGACY_NAME) {        s += "AGENT ";    }    if (i & ACTIVE) {        s += "ACTIVE ";    }    if (i & PASSIVE) {        s += "PASSIVE ";    }    if (i & SCRIPTED) {        s += "SCRIPTED ";    }    return s;}// Modified LSL library functionstring int2hex(integer iInt, integer iLen) {    string s;    do {        s = llGetSubString("0123456789ABCDEF", iInt & 0x0000000F, iInt & 0x0000000F) + s;        iInt = iInt >> 4;    } while (iLen = ~-iLen);    return s;}default {    collision_start(integer x) {        llOwnerSay((string)llGetTime()+": collision_start("+(string)x+") triggered.");        while (x--) {            integer iType = llDetectedType(x);            string sName = llDetectedName(x);            string s = returnType(iType);            llOwnerSay((string)x+" ("+sName+") is type "+s+" (0x"+int2hex(iType,4)+")");        }    }    collision(integer x) {        llOwnerSay((string)llGetTime()+": collision("+(string)x+") triggered.");        while (x--) {            integer iType = llDetectedType(x);            string sName = llDetectedName(x);            string s = returnType(iType);            llOwnerSay((string)x+" ("+sName+") is type "+s+" (0x"+int2hex(iType,4)+")");        }    }    collision_end(integer x) {        llOwnerSay((string)llGetTime()+": collision_end("+(string)x+") triggered.");        while (x--) {            integer iType = llDetectedType(x);            string sName = llDetectedName(x);            string s = returnType(iType);            llOwnerSay((string)x+" ("+sName+") is type "+s+" (0x"+int2hex(iType,4)+")");        }    }}

    Third, and this is probably the actual solution now that I think about it, you're mixing comparison and bitwise operations, but not in the right way.

    llDetectedType(0) != (AGENT_BY_LEGACY NAME | ACTIVE) should have worked (for any agent not sitting on something, I think). I'm not sure if the bitwise and (pipe, |) is evaluated before or after the "not equal to" (!=) operator. So when in doubt, add parenthesis. Also add them for readability when it's confusing.

    The following would match any avatar collision:

    llDetecectedType(0) & AGENT_BY_LEGACY_NAME

    Which means this would match any non-avatar collision:

    !(llDetecectedType(0) & AGENT_BY_LEGACY_NAME)

    For more information on how bitwise operators work, check out the entries near the bottom of the table here: http://wiki.secondlife.com/wiki/LSL_Operators and then check out the last section of the page. Understanding how to build your conditions and how to use flags or masks is important.

  17. Thank you for the information, everyone!

    Regarding some worries, this is not an item intended to be publicly released, but is a creation tool used for configuring values another script uses. As such, the intended audience is very limited, competent builders, and in direct contact with me. I'm more concerned with convenience and workflow. Sitting and attaching breaks intended workflow and can complicate things

    Dora's solution sounds like the best option for the situation. It doesn't involve writing extra scripts that need to be managed and maintained and tied into this one.

    If anyone has additional ideas or suggestions, feel free to provide, but I believe I have my answer. Thank you!

  18. I've written up a quick script that lets me "scroll" through a linkset with the movement controls. Forward/back changes the prim number up and down, left/right changes the current face.

    Basic functionality is great, with one problem: The camera reverts back to "over the shoulder" every time I press a control button.

    I've looked around and cannot find a simple solution to this problem. Everything involves special camera controls and equipment. I would like to be able to use this tool without attaching or sitting on a special object, simply by accepting control permission.

    My question is: In this situation, what is the easiest way to prevent the alt-camera from reverting position? Be it simple or not simple.

    A simplified version of the script I'm using is below:

     

    integer giPrimCurrent;
    integer giFaceCurrent;
    
    selectFace(integer iPrim, integer iFace) {
        llSetLinkColor(iPrim,<1.0,0.2,0.2>,iFace);
    }
    
    unselectFace(integer iPrim, integer iFace) {
        llSetLinkColor(iPrim,<1.0,1.0,1.0>,iFace);
    }
    
    default {
        state_entry() {
            llRequestPermissions(llGetOwner(), PERMISSION_TAKE_CONTROLS);
        }
    
        control(key id, integer held, integer change) {
            integer iPrimCount = llGetNumberOfPrims();
            integer iFaceCount = llGetLinkNumberOfSides(giPrimCurrent);
            integer iStart = held & change;
            if (iStart) {
                unselectFace(giPrimCurrent, giFaceCurrent);
            }
            if (iStart & CONTROL_FWD) {
                giPrimCurrent++;
                if (iPrimCount == 1) {
                    giPrimCurrent = 0;
                }
                else if (giPrimCurrent > iPrimCount) {
                    giPrimCurrent = 1;
                }
                giFaceCurrent = ALL_SIDES;
            }
            if (iStart & CONTROL_BACK) {
                giPrimCurrent--;
                if (iPrimCount == 1) {
                    giPrimCurrent = 0;
                }
                else if (giPrimCurrent < 1) {
                    giPrimCurrent = iPrimCount;
                }
                giFaceCurrent = ALL_SIDES;
            }
            if (iStart & CONTROL_ROT_LEFT) {
                if (giFaceCurrent == ALL_SIDES) {
                    giFaceCurrent = iFaceCount-1;
                }
                else {
                    giFaceCurrent--;
                    if (giFaceCurrent < 0) {
                        giFaceCurrent = ALL_SIDES;
                    }
                }
            }
            if (iStart & CONTROL_ROT_RIGHT) {
                if (giFaceCurrent == ALL_SIDES) {
                    giFaceCurrent = 0;
                }
                else {
                    giFaceCurrent++;
                    if (giFaceCurrent >= iFaceCount) {
                        giFaceCurrent = ALL_SIDES;
                    }
                }
            }
    
            if (iStart) {
                selectFace(giPrimCurrent, giFaceCurrent);
                llOwnerSay("Prim "+(string)giPrimCurrent+" and Side "+(string)giFaceCurrent+" selected.");
            }
        }
    
        run_time_permissions(integer p) {
            if (p & PERMISSION_TAKE_CONTROLS) {
                llTakeControls( CONTROL_FWD |
                                CONTROL_BACK |
                                CONTROL_ROT_LEFT |
                                CONTROL_ROT_RIGHT |
                                CONTROL_UP |
                                CONTROL_DOWN,
                                TRUE, FALSE);
            }
        }
    }

     Thank you for any help you can offer.

×
×
  • Create New...