Difference between revisions of "User:Opensource Obscure/FFHUD"

From Second Life Wiki
Jump to navigation Jump to search
(→‎Script: FFHUD 0.7.3)
Line 61: Line 61:
* ...better code
* ...better code


<lsl>// FFHUD 0.7.2
<lsl>// FFHUD 0.7.3
// free for public use
// free for public use
// A project started by Opensource Obscure
// A project started by Opensource Obscure
Line 75: Line 75:
//  "secondlife" -> an unofficial SL room - http://friendfeed.com/rooms/secondlife
//  "secondlife" -> an unofficial SL room - http://friendfeed.com/rooms/secondlife
// Change accordingly the line below:
// Change accordingly the line below:
string room="";  
string room="ffhud";  




Line 101: Line 101:
key texturedefault = "4760a44f-06f7-622e-7429-b01570a598b0";
key texturedefault = "4760a44f-06f7-622e-7429-b01570a598b0";


//{ Combined Library - Copyright (C) 2004-2008, Strife Onizuka (cc-by 3.0) - "Jul 17 2008", "14:03:07"
 
string str_replace(string src, string from, string to)
// let's substitute '&' character with 'and'
{//replaces all occurrences of 'from' with 'to' in 'src'.
string strReplace(string source, string pattern, string replace) {
     integer len = llStringLength(from) - 1;
     while (llSubStringIndex(source, pattern) > -1) {
    if(len >= 0)
         integer len = llStringLength(pattern);
    {
         integer pos = llSubStringIndex(source, pattern);
        string  buffer = src;
         if (llStringLength(source) == len) { source = replace; }
         integer b_pos = -1;
        else if (pos == 0) { source = replace+llGetSubString(source, pos+len, -1); }
        integer to_len = llStringLength(to) - 1;
        else if (pos == llStringLength(source)-len) { source = llGetSubString(source, 0, pos-1)+replace; }
        @loop;//instead of a while loop, saves 5 bytes (and runs faster).
        else { source = llGetSubString(source, 0, pos-1)+replace+llGetSubString(source, pos+len, -1); }
         integer to_pos = 1 + llSubStringIndex(buffer, from);
         if(to_pos)
        {
//            b_pos += to_pos;
//            src = llInsertString(llDeleteSubString(src, b_pos, b_pos + len), b_pos, to);
//            b_pos += to_len;
//            buffer = llGetSubString(src, 1 + (b_pos), 0x40000000);
            buffer = llGetSubString(src = llInsertString(llDeleteSubString(src, b_pos += to_pos, b_pos + len), b_pos, to), 1 + (b_pos += to_len), 0x40000000);
            jump loop;
        }
     }
     }
     return src;
     return source;
}
}
//}
 


// partially redundant (1)
// partially redundant (1)
Line 142: Line 132:
     list lstParcelDesc=llGetParcelDetails(llGetPos(),[PARCEL_DETAILS_DESC]);                 
     list lstParcelDesc=llGetParcelDetails(llGetPos(),[PARCEL_DETAILS_DESC]);                 
     string a = (string)lstParcelDesc;   
     string a = (string)lstParcelDesc;   
     if(a != NULL_KEY)
     if(a != "00000000-0000-0000-0000-000000000000")
     {
     {
         desc = llDumpList2String(llParseString2List(a,[" "],[]),"+") + "+-+";                 
         desc = llDumpList2String(llParseString2List(a,[" "],[]),"+") + "+-+";                 
Line 150: Line 140:
         desc = "";
         desc = "";
     }  
     }  
     return str_replace(desc, "&", "and");   
     return strReplace(desc, "&", "and");   
}
}
   
   
Line 157: Line 147:
string parcelowner()
string parcelowner()
{
{
     return (string)llGetParcelDetails(llGetPos(),[PARCEL_DETAILS_OWNER]);     
     list lstParcelOwner=llGetParcelDetails(llGetPos(),[PARCEL_DETAILS_OWNER]);               
    string uuid = (string)lstParcelOwner;   
    return uuid;     
}
}
   
   
Line 164: Line 156:
string parcelgroup()
string parcelgroup()
{
{
     return (string)llGetParcelDetails(llGetPos(),[PARCEL_DETAILS_GROUP]);
     list lstParcelGroup=llGetParcelDetails(llGetPos(),[PARCEL_DETAILS_GROUP]);            
     return (string)lstParcelGroup=llGetParcelDetails(llGetPos(),[PARCEL_DETAILS_GROUP]);
     string uuid = (string)lstParcelGroup;
    return uuid;
}
}


Line 172: Line 165:
string slurl()
string slurl()
{
{
     string simname = str_replace(llGetRegionName(), " ", "+");
     string simname = llDumpList2String(llParseString2List(llGetRegionName(),[" "],[]),"+");
    string regionname = simname;
     vector detectedPos = llGetRootPosition();         
     vector detectedPos = llGetRootPosition();         
     string sx = (string)llRound(detectedPos.x);
     string sx = (string)llRound(detectedPos.x);
     string sy = (string)llRound(detectedPos.y);
     string sy = (string)llRound(detectedPos.y);
     string sz = (string)llRound(detectedPos.z);
     string sz = (string)llRound(detectedPos.z);
     return "http://slurl.com/secondlife/" + simname + "/" + sx + "/" + sy + "/" + sz;   
     string url = "http://slurl.com/secondlife/"
    url += simname;
    url += "/" + sx + "/" + sy + "/" + sz ;
    return url;   
}
}
   
   
Line 187: Line 184:
     llOwnerSay("parcel desc = " + (string)llGetParcelDetails(llGetPos(),[PARCEL_DETAILS_DESC]));
     llOwnerSay("parcel desc = " + (string)llGetParcelDetails(llGetPos(),[PARCEL_DETAILS_DESC]));
     llOwnerSay("parcel owner = " + "secondlife:///app/agent/" + parcelowner() + "/about");   
     llOwnerSay("parcel owner = " + "secondlife:///app/agent/" + parcelowner() + "/about");   
     llOwnerSay("parcel group = " + "secondlife:///app/group/" + parcelgroup() + "/about");
     llOwnerSay("parcel group = " + "secondlife:///app/group/" + parcelgroup() + "/about");
}
}


Line 197: Line 194:
         request_texture = llHTTPRequest(groupurl + parcelgroup(),[HTTP_METHOD,"GET"],"");             
         request_texture = llHTTPRequest(groupurl + parcelgroup(),[HTTP_METHOD,"GET"],"");             
     }   
     }   
     else // maybe land is set to a group but not group-owned
     else // group may be set, but land is not group-owned
        // single residents have pictures more often than group so we choose them
     {  
     {  
         request_texture = llHTTPRequest(ownerurl + parcelowner(),[HTTP_METHOD,"GET"],"");               
         request_texture = llHTTPRequest(ownerurl + parcelowner(),[HTTP_METHOD,"GET"],"");               
Line 255: Line 253:
     if(request_id == request_ff)  
     if(request_id == request_ff)  
         {
         {
        llOwnerSay(": Message sent.");
        llOwnerSay(": Message sent.");
         }
         }
      
      
Line 278: Line 276:
     changed(integer change)  
     changed(integer change)  
     {  
     {  
     if (change & (CHANGED_TELEPORT | CHANGED_REGION))
     if (change & (CHANGED_TELEPORT|CHANGED_REGION))
     {
     {
         llOwnerSay(": Location changed, restarting.");           
         llOwnerSay(": Location changed, restarting.");           
        state default;
        state default;
     }
     }
     }
     }
      
      
     timer()
      
    {
  timer()
  {
         llOwnerSay(": Time over.");         
         llOwnerSay(": Time over.");         
         state default;
         state default;
    }
  }
 
                      
                      
     touch_start(integer total_number)
     touch_start(integer total_number)
Line 296: Line 297:
         state default;         
         state default;         
     }  
     }  
   
      
      
     listen(integer channel, string name, key id, string message)
     listen(integer channel, string name, key id, string message)
Line 302: Line 304:
         state default;         
         state default;         
     }
     }
   


     // redundant (2)
     // redundant (2)
Line 308: Line 311:
     if(request_id == request_ff)  
     if(request_id == request_ff)  
         {
         {
        llOwnerSay(": Message sent.");
        llOwnerSay(": Message sent.");
         }
         }
      
      
     else if(request_id == request_texture)
     else if(request_id == request_texture)
         {
         {
         textureuuid = (key)llGetSubString(body, llSubStringIndex(body, code1) + llStringLength(code1), llSubStringIndex(body,code2) - 3);
         textureuuid = (key)llGetSubString(body,llSubStringIndex(body, code1)+llStringLength(code1),llSubStringIndex(body,code2)-3);
         llSetTexture(textureuuid, ALL_SIDES);
         llSetTexture(textureuuid, ALL_SIDES);
         }
         }
     }
     }                                                                    
}</lsl>
 
       
}
 
</lsl>

Revision as of 19:07, 29 October 2008

FFHUD

A SIMPLE FRIENDFEED HUD

  • An idea by Opensource Obscure
  • Current release: 0.7.2
  • Features:
    • single, non-obtrusive button
    • quick automatic or custom messages
    • Friendfeed Rooms support
    • Parcel Owner Profile Image support


What does it do

FFHUD lets you publish to the FriendFeed microblogging service from inside Second Life.

You send your posts by writing them in a private chat channel. Posts always include a SLURL link to your actual location. You can send a quick update that automatically includes the parcel description, or write a custom message. If available, the owner or owner-group profile image is also published, accordingly to their privacy settings.

FFHUD is an ideal way to participate on web social networks while you're enjoying Second Life. You can publish a quick review of an interesting place you just found in-world, or share with your friends your random thoughts from your home.

Setup

  • Put the script (see below) in a prim (you may also want to rename it).
  • Edit the script and insert your FriendFeed account data. You may also specify a room.
  • Wear the prim as an HUD. Resize and replace as needed.

How to use FFHUD

Touch it once to get information about the parcel you're in (printed in private chat via llOwnerSay). Then:

  • if you're not publishing a post, just wait until FFHUD resets itself before touching it again;
  • touch it again within 20 seconds to publish a post on FriendFeed that includes available info about the parcel: SLURL, description, owner profile image;
  • or say a message on channel 8 within 20 seconds to publish a post that includes both parcel info and your message. Example:
/8 This is my message

Do you need help? Feel free to contact me (Opensource Obscure) in-world, through this wiki or on FriendFeed.

Notes

FFHUD builds your posts this way:

  • LINK = SLURL of your location
  • TITLE = parcel name
  • COMMENT = parcel description (if available) OR your message
  • IMAGE = profile image of resident or group that owns the parcel
  • ROOM = according to your settings

FFHUD shows the FriendFeed logo by default. After you touch it once, it will display the parcel owner profile image, if available. It's the same picture that will be published in your post. Profile images are shown by using llSetTexture; the UUID is retrieved using the Second Life Search; the image web address (not the image itself) is sent to FriendFeed, that then retrieves and hosts a copy of the image.

If you're on FriendFeed, join the Second Life room!
http://friendfeed.com/rooms/secondlife

Feel free to use this room for testing:
http://friendfeed.com/rooms/ffhud

Script

This code works but may be horrible and flawed. Feel free to suggest me how to improve it. I am not a real developer and I lack some programming basis, so any feedback can help me. I usually make the LSL scripts I need by reading around, cutting, pasting and tweaking code from other sources. To write FFHUD I used snippets by User:Ordinal Malaprop, User:Cory Linden, MarcoDuff Palen, User:Jana Kamachi and others. Thanks to Tayra Dagostino for reporting and solving a bug.

To do:

<lsl>// FFHUD 0.7.3 // free for public use // A project started by Opensource Obscure //

// Look for your username and FriendFeed key here: https://friendfeed.com/account/api string user=""; // your FriendFeed username string ffkey=""; // your FriendFeed key

// You can send messages to a FriendFeed room: // "" -----------> default setting - you won't share messages to any room // "ffhud" ------> a test room you can freely use // "secondlife" -> an unofficial SL room - http://friendfeed.com/rooms/secondlife // Change accordingly the line below: string room="ffhud";


// after 1st click you have a few seconds to write and send // your text message before FFHUD comes back to default state. // you can change the timing below: float listentime = 20.0;


/////////////////////////////////////////////////// // you don't need to modify anything below


string desc; integer listen_handle; string baseurl="@friendfeed.com/api/share"; key request_ff; key request_texture; string ownerurl = "http://world.secondlife.com/resident/"; string groupurl = "http://world.secondlife.com/group/"; string code1 = "<img alt=\"profile image\" src=\"http://secondlife.com/app/image/"; string code2 = "\" class=\"parcelimg\" />"; key textureuuid = ""; key texturedefault = "4760a44f-06f7-622e-7429-b01570a598b0";


// let's substitute '&' character with 'and' string strReplace(string source, string pattern, string replace) {

   while (llSubStringIndex(source, pattern) > -1) {
       integer len = llStringLength(pattern);
       integer pos = llSubStringIndex(source, pattern);
       if (llStringLength(source) == len) { source = replace; }
       else if (pos == 0) { source = replace+llGetSubString(source, pos+len, -1); }
       else if (pos == llStringLength(source)-len) { source = llGetSubString(source, 0, pos-1)+replace; }
       else { source = llGetSubString(source, 0, pos-1)+replace+llGetSubString(source, pos+len, -1); }
   }
   return source;

}


// partially redundant (1) string parcelname() {

   list lstParcelName=llGetParcelDetails(llGetPos(),[PARCEL_DETAILS_NAME]);                
   string a = (string)lstParcelName;
   string name = llDumpList2String(llParseString2List(a,[" "],[]),"+"); 
   return name; 

}


// partially redundant (1) // we use this after 2nd touch if no message is provided by the user string parceldesc() {

   list lstParcelDesc=llGetParcelDetails(llGetPos(),[PARCEL_DETAILS_DESC]);                
   string a = (string)lstParcelDesc;  
   if(a != "00000000-0000-0000-0000-000000000000")
   {
       desc = llDumpList2String(llParseString2List(a,[" "],[]),"+") + "+-+";                
   } 
   else
   {
       desc = "";
   } 
   return strReplace(desc, "&", "and");   

}


// partially redundant (1) string parcelowner() {

   list lstParcelOwner=llGetParcelDetails(llGetPos(),[PARCEL_DETAILS_OWNER]);                
   string uuid = (string)lstParcelOwner;    
   return uuid;    

}


// partially redundant (1) string parcelgroup() {

   list lstParcelGroup=llGetParcelDetails(llGetPos(),[PARCEL_DETAILS_GROUP]);              
   string uuid = (string)lstParcelGroup;
   return uuid;

}


// this comes from Cory Ondrejka I think string slurl() {

   string simname = llDumpList2String(llParseString2List(llGetRegionName(),[" "],[]),"+");
   string regionname = simname;
   vector detectedPos = llGetRootPosition();        
   string sx = (string)llRound(detectedPos.x);
   string sy = (string)llRound(detectedPos.y);
   string sz = (string)llRound(detectedPos.z);
   string url = "http://slurl.com/secondlife/";  
   url += simname; 
   url += "/" + sx + "/" + sy + "/" + sz ; 
   return url;   

}


// partially redundant (1) infoparcel() {

   llOwnerSay("parcel name = " + (string)llGetParcelDetails(llGetPos(),[PARCEL_DETAILS_NAME]));
   llOwnerSay("parcel desc = " + (string)llGetParcelDetails(llGetPos(),[PARCEL_DETAILS_DESC]));
   llOwnerSay("parcel owner = " + "secondlife:///app/agent/" + parcelowner() + "/about");   
   llOwnerSay("parcel group = "  + "secondlife:///app/group/" + parcelgroup() + "/about");

}


texture() {

   if (parcelgroup() == parcelowner()) // group-owned land
   {
       request_texture = llHTTPRequest(groupurl + parcelgroup(),[HTTP_METHOD,"GET"],"");            
   }  
   else // group may be set, but land is not group-owned
       // single residents have pictures more often than group so we choose them
   { 
       request_texture = llHTTPRequest(ownerurl + parcelowner(),[HTTP_METHOD,"GET"],"");               
   }

}


string prepara(string messaggio) {

   string imageurl = "http://secondlife.com/app/image/" + (string)textureuuid + "/2";       
   messaggio = llDumpList2String(llParseString2List(messaggio,[" "],[]),"+");
   string post = 
   "http://" + 
   user + 
   ":" + 
   ffkey + 
   baseurl + 
   "?title=" + 
   parcelname() +
   "&link=" + 
   llEscapeURL(slurl()) + 
   "&comment=" +      
   messaggio +
   "&room=" +
   room +
   "&image0_url=" + 
   llEscapeURL(imageurl) +
   "&via=ffhud";
   return post;

}


default {

   on_rez(integer start_param)
   {
       llOwnerSay(": Ready. Touch once to get parcel info - Touch twice to update your FriendFeed page.");         
   }
   
   state_entry()
   {
       llSetTexture(texturedefault, ALL_SIDES);         
       llSetTimerEvent(0.0);                
   }
   
   
   touch_start(integer total_number)
   {      
       infoparcel();
       texture();
       state pronto;        
   }
   // redundant (2)
   http_response(key request_id, integer status, list metadata, string body)
   {
   if(request_id == request_ff) 
       {
        llOwnerSay(": Message sent.");
       }
   
   else if(request_id == request_texture)
       {
       textureuuid = (key)llGetSubString(body,llSubStringIndex(body, code1)+llStringLength(code1),llSubStringIndex(body,code2)-3);
       llSetTexture(textureuuid, ALL_SIDES);
       }
   }                                 

}


state pronto {

   state_entry()
   {
       llSetTimerEvent(listentime);        
       llOwnerSay(": Say your message on channel 8 within 20 seconds, or touch again to send a quick post.");        
       listen_handle = llListen(8, "", llGetOwner(), "");                
   }
   
   changed(integer change) 
   { 
   if (change & (CHANGED_TELEPORT|CHANGED_REGION))
   {
       llOwnerSay(": Location changed, restarting.");           
        state default;
   }
   }


  timer()
  {
       llOwnerSay(": Time over.");        
       state default;
  }


   touch_start(integer total_number)
   {
       request_ff = llHTTPRequest(prepara(parceldesc()), [HTTP_METHOD,"POST"], ""); 
       state default;        
   } 
   
   
   listen(integer channel, string name, key id, string message)
   {
       request_ff = llHTTPRequest(prepara(message), [HTTP_METHOD,"POST"], ""); 
       state default;        
   }
   
   // redundant (2)
   http_response(key request_id, integer status, list metadata, string body)
   {
   if(request_id == request_ff) 
       {
        llOwnerSay(": Message sent.");
       }
   
   else if(request_id == request_texture)
       {
       textureuuid = (key)llGetSubString(body,llSubStringIndex(body, code1)+llStringLength(code1),llSubStringIndex(body,code2)-3);
       llSetTexture(textureuuid, ALL_SIDES);
       }
   }                                                                     


}

</lsl>