Object to object HTTP communication

From Second Life Wiki
Jump to: navigation, search

This script allows you to communicate between objects without using an external server. It is a much simplified version of the communication system used by SLGI Trains and SLGI Fleet in case of emergency. I found it to be less lag then communications to outside servers, but still it might create some problems. So, try not to send more then 10 messages per second.

Feel free to use this script in any way you want.

Basics

There are two scripts. The first one, named GIVE, is sending messages. The second one, RECEIVE, is the receiver. Place each one in a different object, but not too far, for the first moments.

Then, touch the object containing RECEIVE. It will say in chat the http and the url that GIVE will need to use. GIVE will listen those things, on channel 88225.

Then, touch GIVE anytime you want. It will send a message to RECEIVE. Now, you can take, wear or rezz GIVE wherever you need.

Limitations

This communication method has some major problems. You are unable to send a string from GIVE to RECEIVE. What you can do, is to send some limited information, that can be read with llGetHTTPHeader, like object position, object name and a few other features. Also, since URLs are temporary, it is very hard (nearly impossible) to communicate to an object that crosses sim borders.

As long as no url has dropped, communication channel is safe. I sent 30 test messages and all of them reached the target.

It is useful to get object location (sim, position) and object name (you can change the name to encode other useful data inside it, see below).

The code

GIVE code is:

//Created by Ana Imfinity
integer KANAL = 88225; 
//communication channel used by the two scripts
string url; 
string body; 
key req; 
default
{
    state_entry()
    {
        llListen(KANAL,"","",""); 
    }
    touch_start(integer ana) //this sends a message on touch
    {
        key aaa = llHTTPRequest(body,[],text); 
        llReleaseURL(body); 
    }
    listen(integer ch, string nm, key id, string ms) //this allows GIVE to get http & url codes
    {
        string dict = llGetSubString(ms,0,3); 
        string exec = llGetSubString(ms,4,100); 
        if (dict == "<><>")
        {
            url = (key)(exec); 
        }
        else if (dict == "><><")
        {
            body = exec; 
            llSay(0,"HTTP communication is now possible"); 
        }
    }
}

RECEIVE code is

//Created by Ana Imfinity
key url; 
string http; 
integer KANAL = 88225; 
default
{
    state_entry()
    {
    }
    touch_start(integer ana) //this sends the URL & http addresses to GIVE
    {
        llReleaseURL(http); 
        url = llRequestURL(); 
        llSay(0,"URL transmitted"); 
    }
    http_request(key req, string met, string body)
    {
        if (req == url) //this gets RECEIVE's url & http addresses
        {
            http = body; 
            string t4 = "<><>"+(string)(url); 
            string t5 = "><><"+body; 
            llSay(KANAL, t4); 
            llSleep(1); 
            llSay(KANAL, t5); 
        }
        string head = llGetHTTPHeader(req,"x-secondlife-region"); //the next part receives info from GIVE
        string name = llGetHTTPHeader(req,"x-secondlife-object-name"); 
        llSay(0,head); 
        llSay(0,name); 
    }
}

Please note that if you touch again RECEVE, it will request new http & url. Old address will be useless. The script can be modified so that this will not happen.

Uses

There are two HTTP headers that can be useful.

x-secondlife-region tells in what sim at at what global coordinates GIVE is located. By using llGetSubString you can separate the sim name from coordinates. This way, you will get a string like Achemon, (257024, 260608). An useful script to extract sim name and global position is this one:

        string head = llGetHTTPHeader(req,"x-secondlife-region"); 
        string name = llGetHTTPHeader(req,"x-secondlife-object-name");
        string nm = "<??>"+name; 
        llMessageLinked(LINK_SET,1,nm,NULL_KEY); 
        integer hd = llStringLength(head); 
        integer i; 
        for (i=0; i<hd; i++)
        {
            string digit = llGetSubString(head,i,i); 
            if (digit == "(")
            {
                string sim = llGetSubString(head,0,i-2); 
                string coord = llGetSubString(head,i,-2); 
                string cor = "<"+coord+", 0>"; 
                vector ps = (vector)(cor); 
                vector pos = ps/256; 
                string posa = (string)(pos); 
                llSay(0,sim); 
                llSay(0,posa); 
            }
        }

x-secondlife-object-name tells object's name. This is very useful. By using llSetLinkPrimitiveParams you can set the name of the prim hosting the script. Actually, object's name is not important, just the name of the prim hosting GIVE. Take a look at the following example:

    {
        llSetTimerEvent(100); 
    }
    timer()
    {
        vector pos = llGetPos() + llGetRegionCorner(); 
        string text = (string)(pos); 
        float x = pos.x; 
        float y = pos.y; 
        float z = pos.z; 
        integer xx = (integer)(x); 
        integer yy = (integer)(y); 
        integer zz = (integer)(z); 
 
        string name = nm+"<"+(string)(xx)+","+(string)(yy)+","+
        (string)(zz)+">"; 
        llSetLinkPrimitiveParams(LINK_THIS,[PRIM_NAME,name]); 
        key aaa = llHTTPRequest(body,[],text); 
        llReleaseURL(body); 
    }
 
//the string 'nm' is a string made of a few letters, encrypting vehicle's name, 
//if it is on schedule, if it has passengers and other details.

In this example, the prim hosting GIVE changes its name. The name includes a first indicative (nm) that includes data like object status (vehicle name, status, avatars seated, if it's moving according to schedule). Take a look at this example:

integer prim = 28; //default number of prims
string bbb = "s2"; //code name for SLGI Train ONSR
string ddd = "1"; //code if the vehicle is on schedule
string nm; //message to be sent to the relay
 
//the following is how nm is made
 
    link_message(integer sn, integer mn, string ms, key id)
    //another script compares time with schedule, informing the script of any delays
    {
        if (ms == "!@#$+")
        {
            ddd = "0"; //vehicle is late
        }
        else if (ms == "!@#$-")
        {
            ddd = "2"; //vehicle is in advance
        }
        else if (ms == "!@#$=")
        {
            ddd = "1"; //vehicle is on schedule
        }
    }
    timer()
    {
        string aaa "="; //no seated avatar
        integer pr = llGetNumberOfPrims(); 
        if (pr<prim)
        {
            aaa = "+"; //seated avatars
        }
        string ccc = "1"; 
        float alfa = llGetAlpha(0); 
        if (alfa<0.5)
        {
            ccc = "0"; //vehicle using partial invisibility
        }
        vector pos = llGetPos(); 
        float z = (pos.z)/50; 
        integer zz = (integer)(z); 
        string eee = (string)(zz); 
        nm = aaa+bbb+ccc+ddd+eee; //this is the script to be incorporated in prim name

Lifetime

If the object containing an URL crosses a sm border, the URL is lost. So, it is almost impossible to keep contact between two objects wandering throughout the grid. This is not a problem for GIVE, but RECEIVE must be fixed inside one sim.

Sim restart processes will disable any existing URL.

See also

llGetHTTPHeader - a way to decode inworld HTTPs

llHTTPRequest - makes a script listen to HTTPs

llHTTPResponse - send a HTTP

http_request & http_response - events, needed by the functions

LSL HTTP server - a good place to start learning

LSL HTTP server/examples - many useful examples