scripting

You are currently browsing articles tagged scripting.

In OpenSim you’re not just restricted to using LSL for scripting, it’s also possible to use c#. This opens up the possiblilities for far more powerful scripts that can access c# in built libraries.

For example I’ve previously mentioned that the string processing methods in Second Life are not very flexible when it comes to reading formatted data. Thus the reason I implemented the osParseJSON method to make Web APIs easier to use.

Obviously another common data format is XML, in this case I don’t have to implement any new OpenSim script functions because the XML capabilities are available natively in c#.

Here is a simple example of reading the RSS feed for my blog, and reading out the entries in chat.


//c#
// displays the contents of an RSS 2.0 feed

string URL = “http://robsmart.co.uk/feed”;
System.Xml.XmlDocument xDoc = new System.Xml.XmlDocument();
LSL_Types.LSLString requestID;

public void default_event_state_entry()
{
llSay(0,”RSS reader current Feed is ” + URL);
getFeedContent();

}

public void getFeedContent()
{
requestID = llHTTPRequest(URL, new LSL_Types.list(), “” );
}

public void default_event_touch_start(LSL_Types.LSLInteger total_number)
{
// read out the RSS feed.
displayFeed();

}

public void displayFeed()
{
System.Xml.XmlNodeList items = xDoc.GetElementsByTagName(”item”);

for(int i=0;i < items.Count ; i++)
{
string title = items[i].SelectSingleNode(”title”).InnerXml;
string link = items[i].SelectSingleNode(”link”).InnerXml;

string description=”no description available”;

if(items[i].SelectSingleNode(”description”)!=null)
description = items[i].SelectSingleNode(”description”).InnerXml;

llSay(0,title + “\n” + description + “\n”);
}
}

public void default_event_http_response(LSL_Types.LSLString request_id, LSL_Types.LSLInteger status, LSL_Types.list metadata, LSL_Types.LSLString body)
{
if (requestID == request_id)
{
// store the xml
xDoc.LoadXml(body);

// process the xml
llOwnerSay(”loaded feed”);
}
}

OpenSim Web 2.0 contribution

As described over on Eightbar I have made my first contribution to the OpenSim opensource project. The contribution is in the form of a new scripting function called osParseJSON. This function allows a c# script in OpenSim to consume the JSON notation provided by many of the major Web 2.0 APIs provided by services such as Flickr and Google translation.

The following example is a script that uses the Google Translate API to let an OpenSim avatar translate ther conversations between 23 different languages.

(disclaimer - please read the terms of conditions of the Google translate API and abide by them)

//c#
// This script is written as an example use of the osParseJSON method
// it uses the Google translate API
// ensure you have read the terms and conditions of the Google translate API
// http://code.google.com/apis/ajaxlanguage/documentation/

LSL_Types.key requestID;
string sourceLang = "en";
string targetLang = "fr";

public void default_event_state_entry()
{
     llSay(0,"translator running say '/1 sentence' to translate something");
     llSay(0,"translator running say '/2 source langage' to change target language e.g. '/2 fr'");
     llSay(0,"translator running say '/3 target langage' to change source language e.g. '/3 en'");
     llSay(0,"translator running say '/4 help', to list languages");
     llListen(1, "", NULL_KEY, "");
     llListen(2, "", NULL_KEY, "");
     llListen(3, "", NULL_KEY, "");
     llListen(4, "", NULL_KEY, "");
}

public void default_event_touch_start(LSL_Types.LSLInteger total_number)
{
     llSay(0,"translator running say '/1 sentence' to translate something");
     llSay(0,"translator running say '/2 source langage' to change target language e.g. '/2 fr'");
     llSay(0,"translator running say '/3 target langage' to change source language e.g. '/3 en'");
     llSay(0,"translator running say '/4 help', to list languages");
}

public void default_event_http_response(LSL_Types.LSLString request_id, LSL_Types.LSLInteger status, LSL_Types.list metadata, LSL_Types.LSLString body)
{
        if (requestID == request_id)
        {
            // the Google JSON string returned wil be of the format
            //  {"responseData": {"translatedText":"Bonjour"}, "responseDetails": null, "responseStatus": 200}
            // call the osParseJSON method so we can read the contents 
            System.Collections.Hashtable response = (System.Collections.Hashtable) osParseJSON(body);
            System.Collections.Hashtable responsedata = (System.Collections.Hashtable) response["responseData"];

            llSay(0,(string)responsedata["translatedText"]);
        }
}

public void default_event_listen(LSL_Types.LSLInteger channelIn, LSL_Types.LSLString name, LSL_Types.LSLString id, LSL_Types.LSLString message)
{
    if(channelIn==1)
    {
        string toTranslate = (string) message;
        requestID = llHTTPRequest( "http://ajax.googleapis.com/ajax/services/language/translate?v=1.0&q="+toTranslate+"&langpair="+sourceLang+"%7C"+targetLang, new LSL_Types.list(), "" );  

    }
    else if(channelIn==2)
    {
        sourceLang = (string) message;
    }
    else if(channelIn==3)
    {
        targetLang = (string)message;
    }
    else if(channelIn==4)
    {
        llOwnerSay("LANGUAGE (CODE)");
        llOwnerSay("*  Arabic (ar)");
        llOwnerSay("* Bulgarian (bg)");
        llOwnerSay("* Chinese (zh)");
        llOwnerSay("* Croatian (hr)");
        llOwnerSay("* Czech (cs)");
        llOwnerSay("* Danish (da)");
        llOwnerSay("* Dutch (nl)");
        llOwnerSay("* English (en)");
        llOwnerSay("* Finnish (fi)");
        llOwnerSay("* French (fr)");
        llOwnerSay("* German (de)");
        llOwnerSay("* Greek (el)");
        llOwnerSay("* Hindi (hi)");
        llOwnerSay("* Italian (it)");
        llOwnerSay("* Japanese (ja)");
        llOwnerSay("* Korean (ko)");
        llOwnerSay("* Norwegian(no) ");
        llOwnerSay("* Polish (pl)");
        llOwnerSay("* Portuguese (pt-PT)");
        llOwnerSay("* Romanian (ro)");
        llOwnerSay("* Russian (ru)");
        llOwnerSay("* Spanish (es)");
        llOwnerSay("* Swedish (sv)"); 

    }
}

Second Life hidden video secrets

There is a very little known feature of Second Life to do with showing video in world, this is the ability to show different videos to individual avatars on the same land parcel. I’ve mentioned this to a quite a few people now and all have been in disbelief, even some of the Lindens seem to be unaware of this feature.

The method to do this however is not a hack and has in fact been documented in the LSL API for as long as I know.

The method in question can be discovered by looking at the documentation for llParcelMediaCommandList if you have a close look at the parameters there is one called

PARCEL_MEDIA_COMMAND_AGENT

the description for which is “Applies the media command to the specified agent only.”

So lets look at a quick simple example.

We need a screen that can listen for urls over chat and then set the url for the person speaking. ( The screen must be owned by someone who has media permission on the land )

The script for the screen is …

integer listen_handle;

default
{
state_entry()
{
listen_handle = llListen(10, “”, “”, “”);
}

touch_start(integer total_number)
{
llSay(0, “talk on channel 10 to set your personal video for this land”);
}

listen( integer channel, string name, key id, string message )
{
llSay(0, “Setting Video play back to ” + message);
llParcelMediaCommandList( [
PARCEL_MEDIA_COMMAND_URL, message,
PARCEL_MEDIA_COMMAND_AGENT, id,
PARCEL_MEDIA_COMMAND_TEXTURE, (key) llGetTexture(0) ] );
}

}

Here’s a quick side by side screenshot of two AVs watching a different movie at the same time on the same parcel of land.

secondlife yoss videozeki video

Extra points for guessing what movie trailers they are watching :P