You are currently browsing the category archive for the ‘Blogroll’ category.

One of the wonders of Second Life, the S S Galaxy is a huge and elegant ship build, created by Bill Stirling, which stretches across three sims, and includes accommodation, shops, restaurants, a ballroom, and more.

I’ll let the pictures do the talking, and encourage you to pay a visit.

Links

For even more photos, see my Snapzilla album.

If you have Second Life installed, you can teleport to the S S Galaxy.

Temp-on-rez is a prim setting which will keep a prim ‘alive’ for a fixed amount of time, after which it will be removed. It is a very handy feature with a number of legitimate uses, the most common of which I suppose are bullets and vendor displays (which temporarily rez examples of the items for sale).

Unfortunately it is sometimes used as a way of circumventing Second Life’s prim limits. There are gadgets you can get which will essentially keep temp-on-rez items permanently alive (basically they re-rez the items every time the temp-on-rez reaches its time-out).

If you’ve been tempted by these gadgets, or if you’re actually thinking of trying to create one, please, please don’t.

The prim limits are there for a reason. The more prims there are in a sim, the heavier the load on the Second Life servers. Using the temp-on-rez to bypass the limits simply increases the load, and makes the Second Life experience even worse than it already is, not only for other users but for you (the temp-on-rez abuser!) yourself.

Second Life is struggling enough as it is. Don’t make it worse.

Thank you.

A Little History

Second Life has long had a system for displaying video on a prim. This is the parcel-media system, whereby you can supply a URL for a video feed, and the video will be displayed on an assigned texture (if you have never seen this before, the set-up for it is on the last tab of the About Land dialog). Its main restriction has been (and still is) that only one video can be displayed on each parcel of land. You can have any number of prims displaying the video, but they will all display the same video.

It has always been possible to display output from a web-site to the parcel media stream, although it was never easy. If you are interested, it involves creating a CGI script on a web-site to generate an image. By then pointing the parcel-media URL at this script, the image will be displayed on any prim which uses the parcel-media texture.

I experimented with this myself a little while ago, and got a system up and running which would display text which was ‘chatted’ by an avatar. I had ideas about creating some sort of live broadcast system. Unfortunately, the Quicktime vulnerability then appeared, and for some time anyone with any sense kept parcel-media switched off. I stopped experimenting at that point, and didn’t go back to it even after the vulnerability was fixed.

Recent Changes

The more recent versions of Second Life include the ability to directly display a web-page via the parcel-media. Point the parcel-media URL at a web-page, and the page will be displayed on the parcel-media texture.

This brings us a step closer to the long-promised HTML-on-a-prim, but we aren’t quite there yet. For a start, this system only applies to parcel-media, and hence suffers from the same restrictions that parcel-media suffers from. There are also some quirks in the way in which the web-pages are displayed.

The main problem that I have found is that the pages seem to rendered at a fixed size (it looks to be something like a 1024 x 1024 area). If the webpage is too large to fit this, scroll-bars will appear. Of course, because the page is essentially just displayed as an image, these scroll-bars are inactive in Second Life. It also means that you have to display the page on a fairly sizeable prim in order for a normal web-page to be readable. It would have been nice to have the ability to display only part of the web-page, with it sizing to fit the prim.

Implementing a Broadcaster

So much for the background. Now, how can we make use of this? Obviously, we can just display a web-page, but there other things that can be done, such as creating genuinely active text. That’s what I want to demonstrate in this post. It is going to be rather simplistic and limited, but it should be quite easy to extend the basic idea into something more sophisticated and useful.

To make particular example work, you will need a website that handles PHP, and that you can upload files to. You will also need to own or rent a parcel of land that you can change the parcel-media on (obviously!).

Let’s start with the PHP script (if you are more familiar with other web-page scripting languages, it should not be difficult to adapt this script):

<html>
<head></head>
<style>body { font-size: 64pt; font-family: Verdana, sans-serif }</style>
<body>
<?php

// Get the text to display.
$contents = stripslashes($_GET&#91;"contents"&#93;);

// Only works with PHP compiled as an Apache module.
$headers = apache_request_headers();
$ownerKey = $headers&#91;"X-SecondLife-Owner-Key"&#93;;

// Output the text.
echo("<p>".$contents."</p>\n");

?>
</body>
</html>

This script expects to be passed a ‘comments’ parameter containing the text to be displayed. For example, assuming you have saved the script as broadcast.php, the following would be used to call the script:

broadcast.php?contents=This%20is%20a%20test.

This would display a web-page with the line “This is a test.”.

A couple of other points: the code above includes a line to read the owner key, but doesn’t make any use of it. In a real situation you would probably want to use this as the basis for some kind of security (remember that anyone with a browser can call this script!). There are also a number of other headers which are available — see the LSL Wiki for more information about them.

Also note that I have set the font-size to a rather large 64 points! This is so that the line of text will show up at a reasonable size on our display.

Now for the Second Life side.

For this example we will set up a script that will listen on a specified channel, and will use our web-script to display anything which is chatted on that channel. We will also set up a timer that will automatically clear the text and replace it with a default after 30 seconds.

In this example I am using a script on my own website — you should replace the URL with the appropriate path for your own site. You can make use of the script on my website if you want to just try things out, but it will display my own logo, and is not guaranteed to stay on the website for long, as it is only a test.

string text;
string baseUrl = "http://ejournal.cyberias.net/broadcast.php?contents=";
integer anyoneCanUse = TRUE;
key avatar;
integer handle;
integer onChannel = 1234;

init()
{
  text = llEscapeURL("Chat some text on channel /" + (string)onChannel);
  string url = baseUrl + text;
  llParcelMediaCommandList([PARCEL_MEDIA_COMMAND_URL, url, PARCEL_MEDIA_COMMAND_PLAY, PARCEL_MEDIA_COMMAND_LOOP]);
}

send()
{
  string url = baseUrl + text;
  llParcelMediaCommandList([PARCEL_MEDIA_COMMAND_URL, url]);
}

default
{
  state_entry()
  {
    llSetTimerEvent(30.0);
    handle = llListen(onChannel, "", avatar, "");
  }

  listen(integer channel, string name, key id, string message)
  {
    if (channel == onChannel)
    {
      llSetTimerEvent(0.0);
      text = llEscapeURL(message);
      send();
      llSetTimerEvent(30.0);
    }
  }

  timer()
  {
    text = llEscapeURL("Chat some text on channel /" + (string)onChannel);
    send();
  }

  state_exit()
  {
    llListenRemove(handle);
    llSetTimerEvent(0.0);
  }
}

Create a prim, and apply your parcel-media texture to one face. Create a script in the prim, and replace the default contents with the above code.

Anyone who stands near the prim and chats on the specified channel will have the chat displayed on the prim (provided, of course, that they have video switched on).

Here is my own test broadcaster in action:

Text on a Prim!

As with all my script posts, I am assuming here that you already know the basics of how to create and edit prims and scripts.

I’ve already covered the rotation option for animating textures, in my post about creating a simple rippling water texture. In this post, however, I want to look at the other animation options, and give some examples. The only one I’m not going to cover is the scaling option, which works in a similar way to the rotation option, but which I have never found a real use for.

Let’s start with what most people think of in terms of texture animations, which is where the animation displays a series of ‘frames’. As a simple example, here is an alternative way of creating a rippling water effect, this time using an animation. To see this in action, rez a cube, and create a new script for it. Replace the contents of the script with the following:

default
{
 state_entry()
 {
  llSetTexture("349b2fec-0f7e-bd5f-5bcc-7090d27ae0fb", ALL_SIDES);
  llSetTextureAnim(ANIM_ON | LOOP, ALL_SIDES, 3, 3, 1, 9, 12.0);
 }
}

As with all the examples in this post, I am taking the textures from the asset server using their UUID, so they should be available to anyone. Of course, you don’t have to do it this way – you can apply animated textures to the prim in the normal way if you want (in which case you can remove the llSetTexture call in the above example).

The texture in this example is 128 x 128, and has the frames laid out in a 3 x 3 grid (the texture was created using the Gimp drawing package). It is actually rather smaller than is necessary, and hence not very high quality. A 256 x 256 version of the texture would be better quality, and would still load reasonably quickly.

Let’s look at each of the parameters of the llSetTextureAnim function.

The first parameter is a set of flags which are combined together using an OR (the ‘|’ symbol). In my example, only two options are included: ANIM_ON, which switches the animation on (no surprise there!) and the LOOP option, which tells the animation to return to the beginning and start again once it has reached the last frame. The alternative to LOOP is PING-PONG, which still keeps the animation running continuously, but when it reaches the last frame it then plays the frames in reverse until it gets back to the first frame, and so on.

If you don’t specify one or other of LOOP or PING-PONG the animation will play through just once and then stop (it will redisplay the first frame, though). We’ll see a possible use for this later.

The other possible flags for this parameter are SCALE, ROTATE, REVERSE, and SMOOTH. As I said above, I won’t be going in to SCALE and ROTATE in this post. REVERSE simply plays the animation backwards. I’ll come back to the SMOOTH option later.

The next two parameters tell the function how the frames are laid out in the texture. In my example, they are laid out in a 3 x 3 grid, so we set both values to 3. A common alternative would be to have the frames laid out horizontally in a long strip. If this sample texture had been done that way we would have had a strip 9 frames long, so these parameters would be 1, 9.

The next two parameters tell the function which frames to display, from the first frame to the last frame. You can use this if you only want to display part of the animation (possibly you might want to display different parts at different times). In this case we want to use all the frames.

The last parameter is the speed of the animation — the higher the number, the faster the animation. It is approximately (very approximately!) in frames per second, and values between 5 and 15 are usually appropriate, though of course this depends on your animation.

Now, what about that SMOOTH option? Well, this works in a rather different way. Instead of displaying individual frame, the SMOOTH option basically scrolls the entire texture sideways. Because of this, it is possible to use this to scroll a texture which isn’t animated (in other words, a texture which isn’t actually a series of frames).

As an example, let’s create a slowly drifting starfield. Rez a cube, and size it so that it is about 4 m wide and 2 m tall. Create a new script in it, and replace the script contents with the following:

default
{
 state_entry()
 {
  llSetTexture("43019701-cf5c-d484-3b35-3fb59fe895b4", ALL_SIDES);
  llSetTextureAnim(ANIM_ON | LOOP | SMOOTH, ALL_SIDES, 1, 2, 1, 1, 0.02);
 }
}

Notice that although the texture is not animated, we have specified a Y frame count of 2. This might seem rather odd, and needs some explanation. As soon as you apply llSetTextureAnim, the script will override whatever X and Y repeat values that you have specified, and instead will size the texture to match the X and Y frame count that you have specified, stretching it as necessary.

In order to make the texture fill the X direction without stretching, the Y frame-count has been specified as 2, making the script treat the texture as a two-frame animation. Because the start and end frames are both 1, it only displays one frame, which in this case works out as the top half of the texture, with the result that the texture is scaled correctly for us. This is not really an efficient way of doing things! Really, an animated texture needs to have the same X:Y ratio as the prim face that you are going to use it on.

Next, something more useful. Let’s see how to use texture animation with Second Life’s waterfall textures, and create a simple waterfall.

Start by rezzing a cube, and size it so that it is 2 m wide, 4 m tall, and 0.2 m deep. On the Texture tab, set the rotation to 90.0. This is because animations which use SMOOTH, as we are going to do, always slide along the X axis, so we need to rotate the texture to make our water flow vertically.

Create a new script in it, and replace the script contents with the following:

default
{
 state_entry()
 {
  llSetTexture("af8c86bd-c377-c331-7476-58abeb7af8fc", ALL_SIDES);
  llSetTextureAnim(ANIM_ON | LOOP | SMOOTH, ALL_SIDES, 1, 2, 1, 1, 0.5);
 }
}

By itself, this should look reasonably effective. We can make it better, though. Take a copy of this prim, shifting it so that it is a little bit in front of the original prim. Edit the script in this copy, and replace it with the following:

default
{
 state_entry()
 {
  llSetTexture("49649c94-f720-6d0f-2246-49cc1835284f", ALL_SIDES);
  llSetTextureAnim(ANIM_ON | LOOP | SMOOTH, ALL_SIDES, 1, 2, 1, 1, 0.25);
 }
}

This now gives us two waterfall animations, running at different speeds. The result is very effective.

Near the start of this post I mentioned that if you had neither LOOP nor PING-PONG in the animation flags the animation would run through just once. Here is an example of this. It is a ‘LOCKED’ sign which flashes once when somebody touches it.

Rez a new cube, and size it to be 1 m wide, 0.5 m tall, and 0.5 m deep. Create a new script in it, and replace the script contents with the following:

default
{
 state_entry()
 {
  llSetTexture("7392be5b-ce2f-eb64-6a45-a4544ec539a9", ALL_SIDES);
  llSetTextureAnim(ANIM_ON, ALL_SIDES, 1, 2, 1, 2, 5.0);
 }
 touch_start(integer total_number)
 {
  // Curiously, we have to switch the animation off first.
  llSetTextureAnim(0, ALL_SIDES, 1, 2, 1, 2, 0.0);
  // Now run the animation once.
  llSetTextureAnim(ANIM_ON, ALL_SIDES, 1, 2, 1, 2, 5.0);
 }
}

Finally, some useful (I hope!) notes:

Finding the prim face: You’ll notice that in the above scripts I have specified ALL_SIDES as the side to apply the texture and animation. A lot of the time you will want to put the texture and animation on one side only. The easiest way to find out the side number of a prim face is to use the Advanced (or Debug) menu.

To active or deactivate the menu, hold down CTRL+ALT+d on your keyboard. The Advanced menu should appear on the main Second Life menu.

Once this menu is showing, edit the prim you want to investigate. Click the ‘Select Texture’ option, and select the face you want to check. Then hold down CTRL+SHIFT+ALT+t on your keyboard. Details of the texture will appear in the bottom-left of your screen, including the face number.

Switching off animations: If you want to switch off the animation on a texture, simply pass zero as the flag. The other parameters are irrelevant:

llSetTextureAnim(0, ALL_SIDES, 1, 1, 1, 1, 0.0);

Texture Size: remember that a texture with multiple frames can easily be very large indeed, and Second Life still has to load the entire texture (no, it doesn’t load it frame by frame!). Creating an effective animation using a minimum number of frames is a skill in its own right.

The LSL Wiki has additional useful information: http://www.lslwiki.net/lslwiki/wakka.php?wakka=llSetTextureAnim

Yes, I’m finally back. My computer is now healthy and happy again, though Second Life seems to be falling apart. No change there then. I managed to get on-line and stay on-line long enough to collect the pictures for this post, though.

Numbakulla Island has been around for some time, and I first came across it a couple of years ago (I think). I’ve been meaning to blog about it for a while, and have finally got round to it.

What is Numbakulla? Well, at first sight, it is a rather interesting and well-built island sim, and worth looking round just for its own sake. However, that is not its main purpose. In fact, Numbakulla is a Second Life version of a point-and-click adventure.

When you first teleport it, you end on the shore beside a shipwreck. The broken ship is half-sunk in the waters beside you, and books, suitcases, and scraps of paper have been tossed up on the shore or still float on the sea.

Shipwreck

You are greeted by a notecard, which gives you some explanation about the game and how to play it. Beside you is an open chest and a small stand with a  notebook on it. When you click on the notebook, you are given a notebook of your own, which is crucial to the game. You wear this notebook (nothing visible appears, but once you start interacting with things on the island you will get messages from it), and start your exploration.

Chest and notebook

A cave is in front of you, and is the obvious direction to go in, but even as you do so, you come across a scrap of paper on the ground. Click it, and you get your first clue (such as it is) to the game.

Letter

Then it is through the cave, and out onto the main island, with its curious, plant-like buildings.

Main island

It will take a little while before you come across your first real hint of the goal of the game and the explanation of the island’s subtitle The Pot-Healer Adventure. In the meantime it is a case of wandering round the island — there is plenty to see — and looking out for things which can be clicked on and interacted with. Such as this pump, which is near the cave exit.

Village pump

It predictably pours water, and your notebook tells you that you need something to collect the water in…but I won’t say more, and so that I won’t spoil the game for you, I’ll refrain from telling you much more about the island, except to say that there is a lot more than just the area which I have shown here.

More of the island

I’ll confess, too, that I haven’t really begun to solve the game myself, and I intend to go back soon and explore the island properly.

I hope I’ve tempted you to pay a visit yourself. Have fun.

The technology has let me down.

I am suffering computer problems at the moment, which is severely curtailing my on-line activities such as this blog, and indeed Second Life itself. If I’ve been rather silent recently (and I have!), this is the main reason.

I hope to back up and running within a week though.

You go for years waiting for a competitor to Second Life, and suddenly three come along at once.

Ok, that’s a bit of an exaggeration, if not to say completely misleading, but it does kind of sum up how I feel right at the moment. In the last few weeks some open-source versions of Second Life have emerged into the wild. They are still in early stages at the moment (think of them as alpha releases at best), but promise to develop very quickly into something very useable.

They also start to open up the possibility of a truly distributed 3D web (more on that later, but for me it is one of the most exciting aspects of these new developments).

First, a quick introduction to the applications in question, and how they relate to one another.

RealXtend

This one has the potential not just to outdo Second Life, but to knock it out of the ring altogether. At the moment the performance is worse than Second Life on a bad day, and a lot of features are missing or incomplete. It still manages to be breathtaking.

There is both a server and a viewer available. Let’s look at the viewer first, which is so similar to Second Life’s viewer that I’m not even going to bother with a screen shot. One significant point is that the viewer can be used for Second Life itself, and can also be used to connect to other servers/grids, such as the Open Life grid mentioned below.

However, RealXtend comes into its own when you use the ReadXtend server with it. You can download the server and run it on your own computer. Yes, your own local world — and yes, other people can connect to you, provided you tell them the correct IP address and port to use (no, this isn’t straight-forward — I told you this was early days yet).

Run the server, then launch the viewer to connect to it, and this is what you get:

RealXtend island

Let’s take a closer look, and let’s do a bit of creating. Ok, it’s just a simple block with a new texture, but at least it proves it works. Take a look at the surroundings, though, which come as default with the server. Very impressive.

RealXtend island

At the moment, there is no facility to change your own appearance, so you are stuck with the default avatar.

RealXtend default avatar

At least she is slightly more interesting than Second Life’s notorious ‘Ruth’!

OpenLife

As with RealXtend, OpenLife comes with both a viewer and a server (both downloadable for free, again as with RealXtend). They are also providing the ability to buy regions on the OpenLife grid, in a similar fashion to the Second Life model.

The viewer, once again, can be used to connect to the OpenLife grid, or to the main Second Life grid (I assume you could also use it to connect to a RealXtend server, but I haven’t tried this myself).

OpenSim

This is a third entrant in the list of open-source servers (there doesn’t seem to be a browser with this one, instead you use one of the existing browsers to connect). I haven’t investigated this one myself, not even to the extent of downloading it and trying it, but I intend to do so very soon.

Distributed 3D Web

Ok, so much for the programs themselves. There has been quite a buzz around them, and a lot of discussion, but I think that many people miss the point of what is going on here.

The most significant point is that it is possible to host a Second Life type of world on your own computer (you’ll need a decent connection!), and invite your friends to come and visit you, using a free downloadable browser. It looks as if many of the browsers will be cross-compatible, though I do see the scope for a new type of browser-war!

It will also be possible for companies to set up their own grids, and sell regions on it, somewhat like Second Life does at the moment, but instead of one central grid, there will be lots of them. The result will be very much akin to the world wide web, where companies host websites.

Avatars will be able to move between these worlds, taking their inventory with them — this is a crucial point (see the RealXtend website for a more detailed explanation), and makes this whole idea not only work, but actually useable and useful.

As I see it, the one thing missing is the equivalent of hyperlinks, to allow you to jump from one world to another. This would not be particularly difficult to implement — essentially you just restart the browser, pointing at a new location. It could be done in a manner similar to the existing teleport feature in Second Life. The trick is being able to find out where those other worlds are, as easily as you can find websites, a problem that has still to be fully addressed by the existing systems (but not, I think, a particularly knotty problem).

There are other issues that will cause existing Second Lifers problems, partly because of Second Life’s own peculiarities. For example, Second Life has an economy (a completely fake economy, of course, something which many people seem unable to grasp) — this is not going to transfer over to the 3D Web. How can it, when potentially everyone is running their own world, and has complete control over it. If you want to earn money, it will mean using a real-life economy, with real-life cash.

Security might also be an interesting issue, but possibly one that is more easily handled than in Second Life. If someone comes to your world, can they do anything they want, or do you have complete control over what they are allowed to do? I suspect that the latter is easily possible in theory, but has not actually been implemented in practice (the current emphasis has mainly been on recreating Second Life’s features).

Certainly, giving each independent world complete control over security opens the possibility of allowing functionality that has been excluded from Second Life purely because of the potential for abuse. I shall be interested to see how the security issues are tackled in these new worlds.

(On a personal note, I have one quibble. I am primarily a Mac-user these days, and all these browsers and servers are Windows-only.)

It’s a little too soon to declare “Second Life is dead. Long live the Open Web!” but I feel that it won’t be long. Maybe one or two years at the most.

Me, I can’t wait.

Links

RealXtend

OpenLife

OpenSim

Note: I’ve edited this post to remove the remarks about No Mod, No Copy, No Transfer and Mod, No Copy, No Transfer, when it was pointed out by a couple of commenters that these combinations are actually impossible.

I was originally going to write a brief article about the technical details of putting items up for sale, and I will still do that at some point, but as I was writing it I found that I had a lot to say about permissions. As permissions are something you have to give serious thought to if you want to sell things, I’ve decided to devote an entire post to it. I’ll assume that you already know how to set permissions (if you don’t, they are on the General tab of the Build dialog).

Permissions are a thorny subject, with wildly differing views. What I am going to do is to examine the ramifications of each option and (more importantly) of each combination of options. I’ll also give my own opinion on each of various options, but you should realise that there are plenty of merchants out there who will have quite different ideas. Be prepared to give the whole subject some very careful consideration!

First, let’s look at the individual permissions.

Mod means that the purchaser can freely change the object, using the Build tools. No Mod means that the purchaser cannot modify the object in any way other than simply moving or rotating it. They can’t scale it, they can’t change the textures, they can’t break it up (assuming it consists of more than one prim).

For most objects, No Mod is a sensible option. However, if you are selling clothing attachments (for example, hats), you might want to allow modification so that the purchaser can adjust the size of the object to fit their avatar (regrettably there is no way to restrict the types of modification that are allowed — it is all or nothing). In fact, some people might be reluctant to buy such items if they are not moddable.

Copy means that the purchaser can create multiple copies of the item (but only for themselves — they cannot pass these copies on to anyone else). This has some less than obvious effects. When a Copy object is rezzed, the original remains in the Inventory. If the owner deletes the rezzed object, they still have the original. If they mod the object (assuming it is moddable), the original is unchanged, and if they wish they can take a copy of the amended object back into their Inventory — they will then have two copies, both the original and the altered copy.

No Copy means that the purchaser cannot create multiple copies of the item. They will not be able to Copy and Paste the object within their Inventory (although they can move it around in the Inventory), and when they rez the object it will vanish from their Inventory.

Many merchants specify No Copy. Unfortunately, many purchasers (myself amongst them) are reluctant to buy No Copy items. The main reason is Second Life’s notorious flakiness. I have had experience myself of rezzing a No Copy object, seeing it vanish from my inventory, but failing to rez. If you are lucky, it might be returned eventually, sometimes to the Lost and Found folder. More often than not it is gone for good. Or rather, for bad.

The other reason for Copy applies to clothes. I have separate folders for each costume that I wear. In many cases these costumes are customised — I have built them by combining clothes from different merchants. Often I have an item that I want to use in more than one outfit, so I want to create copies in several different folders. From my point of view, it is a convenience for me — with No Copy items I would have to go to different folders in order to put together a specific costume. From the merchant’s point of view, I can only ever wear one copy at a time, so they are not losing out (and I’m not going to buy multiple copies just for convenience).

Nowadays I hardly ever buy clothing that is No Copy.

No Transfer means that the purchaser cannot give or sell the item to someone else. This is a very common option, but there is a catch when the purchaser wants to buy the item as a gift for someone else — this option stops them from doing that. A good solution is to create a special ‘gift’ version of the item, specifying Transfer and No Copy. With this option the purchaser can give the item to someone else, and it will be removed from the purchaser’s inventory. Of course, this goes against what I have said above about No Copy items, but there really isn’t a lot of choice in this case. You probably just need to be prepared to deal with the occasional loss of such gifts, when Second Life fails at the crucial moment of transfer!

But this is starting to get us into combinations of permissions, so let’s take a look at the other possible combinations, and what the implications are. I’ll begin with the probable no-nos:

Mod, Copy, Transfer, and the closely related No Mod, Copy, Transfer. Probably fatal, unless this is a freebie that you don’t mind being copied and given or sold on to any number of other people. For items that you want to make a profit out of, this is a very unlikely combination!

Ok, now for the more useful combinations.

No Mod, No Copy, Transfer. As I mentioned above, you can use this for items which are to be sold as gifts, but be prepared to deal with the occasional fall-out. Only use this combination if you are also selling a version with Copy and No Transfer options.

You could feasibly have Mod, No Copy, Transfer to allow moddable gifts (for the clothing attachments I’ve already mentioned). This is workable, but again be prepared to deal with problems. If the receiver of the gift mods it and breaks it, how generous are you going to be to them when they ask for a replacement?

No Mod, Copy, No Transfer. My favoured set of permissions, both for selling and for buying (except for clothing attachments, where I look for Mod as well).

Oh, while I’m at it, some merchants sell items with different permissions for different prices. Usually this means a No Copy version and a more expensive Copy version. Personally, I think this is a good compromise — I’m certainly prepared to pay a little more (but not too much!) for a Copy version, and I understand and empathise with the motives behind it.

Textures

When it comes to permissions, textures are an oddity. They are only usable by the purchaser if they come with full permissions – Mod, Copy, Transfer. This means that once you have sold the textures, the purchaser can do absolutely anything with them, including passing them on to other people. If you think about it, you can probably see why this is the case — if a texture is used on an object which is going to be sold, the texture has to be transferred along with the rest of the object. In a similar fashion, the texture has to have Copy, otherwise the purchaser could only make and sell one single item with that texture.

Does this mean there is no point in selling textures? Maybe. Personally, I have sold (and still sell) packages of textures, and make a good profit from them, in spite of my inability to restrict the usage of them. You might prefer not to take the risk.

You can, of course, accompany your textures with dire warnings about copyright, and threaten people with DCMAs. It might work, I’ve never tried it. It’s your call.

If you want to make textures your central product (and some people, such as Lauren Fox, seem to have done this successfully) you need to decide how much you are going to worry about people copying your work. If the answer is “a lot”, you might want to reconsider.

One final point. When you are selling your items, make sure that the permissions for them are clearly visible (either in a nearby advert, or on the box, if the items are boxed).

Brief, Opinionated Summary

  • Mod, Copy, Transfer – give-aways/freebies only!
  • Mod, Copy, No Transfer – good for clothing attachments
  • Mod, No Copy, Transfer – for moddable gifts
  • No Mod, Copy, Transfer – give-aways/freebies only!
  • No Mod, Copy, No Transfer – my favoured default
  • No Mod, No Copy, Transfer – for gift

In my previous article, I showed how to set up communication between different scripts in a set of linked prims. In this article I will explore this a little further, and show how to make it more flexible and easier to use.

First, we need a way of finding the link numbers of the prims in a set. Although it is possible to work this out manually, it is tedious and error-prone, and the more prims that are linked, the worse this becomes.

Let’s try an alternative. Give each of the prims a unique name (or at least unique within the link-set). This is probably a useful thing to do anyway.

Once this is done, you can set up variables for the prims that a script is interested in, and then locate the linked prims by name, using llGetLinkName function. Call this when the script is reset or the prim is rezzed.

Here’s a small example:

// This will hold the link number for the prim we
// want to send messages before.
integer LINK_TARGET = -1;
// A function to read the link numbers.
getLinks()
{
    integer i;
    // How many prims are linked?
    integer linkcount = llGetNumberOfPrims();
    // Reset our link target number, just to be
    // safe.
    LINK_TARGET = -1;
    // Work through the prims, looking for our
    // target.
    for (i = 1; i <= linkcount; ++i)
    {
        string str = llGetLinkName(i);
        if (str == "LINK_TARGET_NAME")
        {
            // Found it. Store the link number.
            LINK_TARGET = i;
        }
        // We can obviously extend this to
        // look for and record the link
        // numbers of other prims.
    }
    // If we didn't find our target, report this
    // to the owner.
    if (LINK_TARGET == -1)
    {
        llOwnerSay("Could not find LINK_TARGET_NAME");
    }
}
default
{
    state_entry()
    {
        getLinks();
    }
    on_rez(integer param)
    {
        getLinks();
    }
    touch_start(integer count)
    {
        // Make sure we actually found our target
        // prim.
        if (LINK_TARGET != -1)
        {
            // Send the message to it.
            llMessageLinked(LINK_TARGET, 0, "MESSAGE", NULL_KEY);
        }
    }
}

The only thing to be careful about here is that if you change the link order (by unlinking and re-linking your prims in a different order), you have to make sure that all the scripts are reset.

One convenient way of doing this is to include a RESET command which is sent from the root prim to all the other prims. When they receive this command, they should call llResetScript() to reset themselves:

link_message(integer sender, integer cmd, string param, string id)
{
    // Assume we have defined CMD_RESET somewhere.
    if (cmd == CMD_RESET)
    {
        llResetScript();
    }
}

Now, how about passing different types of parameters, other than simple strings? If you only want to pass a single value, a straight-forward typecast is all that is required. For example, suppose we want to have a message that tells another prim to move to a specific position. To do this, we want to send a vector. We can do this like this:

llMessageLinked(TARGET, CMD_MOVE, (string)<128.0,128.0,128.0>, NULL_KEY);

The receiving prim can convert this back into a vector in a similar way:

link_message(integer sender, integer cmd, string param, string id)
{
    if (cmd == CMD_MOVE)
    {
        vector pos = (vector)param;
        llSetPos(pos);
    }
}

(Of course, I am assuming you have set up a CMD_MOVE variable in both scripts, with the same value in each. It would also be sensible to provide some kind of error-trapping, in case the parameter string does not actually hold a vector. If it doesn’t, you will end up with a vector of .)

What about passing more than one parameter between the scripts? The main trick here is for the sending script to pack the parameters into a string, and then the receiving script uses llParseString2List() to extract the result.

In this example, I am separating the parameters with a semi-colon. Here is the sender’s code:

llMessageLinked(TARGET, CMD_MOVE, "<1.0,1.0,1.0>;Move!", NULL_KEY);

The receiver needs to unpack this, like so:

link_message(integer sender, integer cmd, string params, key id)
{
    if (cmd == CMD_MOVE)
    {
        list parameters = llParseString2List(params, [";"], [""]);
        vector moveBy = (vector)llList2String(parameters, 0);
        string command = llList2String(parameters, 1);
        // Do something with the results
        // ...
    }
}

Note that when extracting the vector, I am extracting the parameter from the list as a string, and then typecasting it to a vector, because the parameter is stored as a string in the list (llParseString2List will extract the contents as string), and llList2Vector will not perform a typecast itself.

By combining the getLinks() function and the ability to pass multiple parameters, you can construct a flexible and fairly robust system for passing information between linked prims.

A final caveat: don’t overdo this. Every script takes up resources. If you have an object with a large number of scripts all communicating with one another you can seriously contribute to lag. If you find yourself doing this, it is worth rethinking how your object is working, and whether there is a simpler way of doing things.

Sooner or later, if you are creating gadgets that do useful things, you will find the need to have some communication between scripts in different prims.

There are two basic methods of doing this. One is to use the llMessageLinked() function, the other is to use a chat channel. In this article I am going to look at using llMessageLinked, but it is important to understand when to use which option.

Let me start, then, by briefly looking at the chat channel option.

The main advantage of this option is that the prims which contain the communicating scripts do not have to be linked. This allows prims to communicate across an entire sim (note that there is no easy way to communicate across different sims short of using an external web-service of some kind).

The main disadvantage, and this is a biggie, is that using a chat channel normally requires the scripts to set up Listeners which are constantly active. This adds to simulator lag, and is something that therefore should be minimised.

If your scripts absolutely need to be run in unlinked prims, or in prims which are in separate objects, however, the chat channel option is probably the only way to go.

However, if your scripts are part of a set of linked prims, the llMessageLinked function is a better option, and it is this option that I am going to cover.

llMessageLinked takes a number of parameters, although you rarely need to make use of all of them. The first parameter is crucial, though, as it is the number of the prim that you are sending the message to. It can also be one of a set of special values, the most useful of which are probably the following:

LINK_ALL_OTHERS – this sends the message to all other prims except the current one.

LINK_ALL_CHILDREN – this sends the message to all prims which are children of the root prim.

LINK_ALL – this sends the message to all the prims in set, including the one that the message is sent from.

The second parameter is an integer. This can be used as an identifier of the type of message. For example, you could set up the following constants in each script:

integer CMD_INIT = 1;
integer CMD_MOVE = 2;	// I'll use this in my examples below

You would then pass the appropriate value to llMessageLinked.

The third parameter is a string. This can be used to pass parameters to the receiving scripts. If you only need one parameter, this is simple. Remember that you can use LSL’s type-casting to let you put (for example) numbers into this parameter. I’ll show an example of this later.

The final parameter is a key.

At the receiving end, the message() function will be called when a message is received from an llMessageLinked() call. It is passed five values, the first of which is the number of the sending prim, and the other four are the four parameters from llMessageLinked().

As an example, lets create a system whereby touching the root prim will move the linked prim. In itself, this isn’t exactly useful, but it could be used as the basis of (for example) some kind of ‘sliding door’ system.

Create two prims, and link them together.

Create a new script in the root prim (note that if you create a script while a link set is selected, the script will automatically be created in the root prim).

In our script, we will have a setting which tells us if the other prim is in its original position. If it is, when the owner touches the root prim, we move the other prim a short distance away. If it is not, we will move it back.

Here is the basic script:

integer hasMoved = FALSE;
float moveBy = 1.25;
// Commands
integer CMD_MOVE = 1;
integer CMD_RESTORE = 2;
default
{
    touch_start(integer count)
    {
        // Only respond to our owner.
        if (llDetectedKey(0) == llGetOwner())
        {
            if (hasMoved)
            {
                // Tell the other prim to restore its original position.
                llMessageLinked(2, CMD_RESTORE, "", NULL_KEY);
                hasMoved = FALSE;
            }
            else
            {
                // Tell the other prim to move by a specified distance. Note
                // that we are type-casting the distance to a string.
                llMessageLinked(2, CMD_MOVE, (string)moveBy, NULL_KEY);
                hasMoved = TRUE;
            }
        }
    }
}

Save the script.

Now, tick the ‘Edit individual prims’ checkbox, and select the other prim. Create a script in this prim. In this script, we will detect the message from the root prim, and respond accordingly:

vector originalPos;
// Commands
integer CMD_MOVE = 1;
integer CMD_RESTORE = 2;
default
{
    state_entry()
    {
        originalPos = llGetLocalPos();
    }
    on_rez(integer param)
    {
        originalPos = llGetLocalPos();
    }
    link_message(integer sender, integer num, string params, key id)
    {
        // Check that this came from the main script.
        if (sender == 1)
        {
            // Find out which command was received
            if (num == CMD_MOVE)
            {
                // Read our local position (i.e. relative
                // to the link-set object)
                vector pos = llGetLocalPos();
                // Adjust it -- note that we can typecast
                // the string parameter to a float.
                pos.x += (float)params;
                // Set the new position
                llSetPos(pos);
            }
            else if (num == CMD_RESTORE)
            {
                // Restore our original position
                llSetPos(originalPos);
            }
        }
    }
}

Save the script, close the Build dialog, and test the object.

You should find that this works, and touching the object will move the second prim. Touching it again will move it back to its original position.

However, there are some problems with this system. For example, we need to know the link number of the prim that we want to send a message to. When there are only two prims (as in our example) this is simple, but if there are a number of prims, it can get difficult to keep track of this (especially if you
unlink and relink the prims while you are building your object, as is quite likely).

Also, the string that we are using to pass a parameter to the linked prim seems a little restrictive.

In the next article I’ll look at both of these issues, and some possible solutions (though as a hint for the parameters, remember that you can typecast a list).