Files
LSL-Scripts/XS Pet Robot/XS Robot/Server/texture_server.lsl
2015-08-09 16:54:31 -05:00

481 lines
15 KiB
Plaintext

// :CATEGORY:XS Pet
// :NAME:XS Pet Robot
// :AUTHOR:Ferd Frederix
// :KEYWORDS: Pet,XS,breed,breedable,companion,Ozimal,Meeroo,Amaretto,critter,Fennux,Pets
// :CREATED:2013-09-06
// :EDITED:2014-07-29
// :ID:988
// :NUM:1453
// :REV:0.54
// :WORLD:Second Life, OpenSim, Opensim
// :DESCRIPTION:
// XS Pet textures server
// :CODE:
// Revisions 0.51 changed llCeil to llFloor to not skip texture 0 and changed an index to not run off the end for texture 1.0
// revision 0.54 07-28-2014 fixed server to actually work.
// Xs_Pets textures
/////////////////////////////////////////////////////////////////////
// This code is licensed as Creative Commons Attribution/NonCommercial/Share Alike
// See http://creativecommons.org/licenses/by-nc-sa/3.0/
// Noncommercial -- You may not use this work for commercial purposes
// If you alter, transform, or build upon this work, you may distribute the resulting work only under the same or similar license to this one.
// This means that you cannot sell this code but you may share this code.
// You must attribute authorship to me and leave this notice intact.
//
// Exception: I am allowing this script to be sold inside an original build.
// You are not selling the script, you are selling the build.
// Ferd Frederix
////////////////////////////////////////////////////////////////////y
// You must put any textures you want to send to your pets in the same prim as this server.
// You MUST have a notecard named "Breed"
// Each line of the notecard must be the name of the pet Breed type. The first line matches the first texture, and so on.
// example notecard for a two texture chicken:
// Fat Yellow Chicken
// Scrawny Red Chicken
// The first one will be the name of the breed for Body 0, Head 0
// The Scrawny red chicken wiol be the breed name for Body 1, Head 1
// Colors such as color1 and color2 are stored in the Description of the pet prims. Use the prim Name for the texture name
//
// The names must match the following pattern:
// PrimName N
// Where PrimName is the name you put in the prim to be textured, and N is a number from 0 to however many sets of skins you have.
//
// 2-prime xample: Body 0
// Head 0
// Body 1
// Head 1
//
// In this case, there should be at least two prims in the pet whoes prim name is Body/Head
// So you will end up with two possible breeds for your pets, either the 0th or the 1st textures.
//
// If the breedable param Color1.x value (Red coloration) is < 0.5, you get Body 0 and Head 0, and the name will be Fat Yellow Chicken
// If the breedable param Color1.x value (Red coloration) is > 0.5, you get Body 1 and Head 1 and the name will be Scrawny Red Chicken
// The pets breed by mixing colors. If a 1.0 (all Red) breeds with a 0.0 (No Red), you get a code near the average, or 0.5.
// Root prim:
// There is a special name 'root' for the root prim since your pet could be renamed, whioch would change the name of the root prim..
// root 0 would be the name to use for the first root prim texture, root 1 for the second, and so on.
// If your root prim is an invisible prim or is not to be textured, you can ignore this 'root' name.
// Deeper example:
// You have a pet robot with 3 sets of breedable skins, and 4 prims, called 'head'. 'body', 'leg' and 'tail'.
// You will need 3X4, or 12 textures in all.
// edit the pet, and change the name of the head to 'head', change the body name to 'body', the left leg to 'leg', and the right leg to 'leg'.
// each texture must also a single digit after it to represent the breed type:
// head 0, head 1 and head 2
// body 0, body 1, and body 2
// leg 0, leg 1, and leg 2
// tail 0 , tail 1, and tail 2
// you may have up to 254 total textures in the server. In the above example, there are
// 4 textures per skin set, so you can have 254/4, or 63 skins for your pet.
// What about the root prim?
// The last prim you link to is the root prim. It holds the xs_pet scripts.
// This prim gets renamed in various objects, so you cannot add a name to the prim that matches a
// texture. A special texture name 'root 0', 'root 1' etc. is set aside for this prim.
// Most xs_pets will not need to use the root prim texture, because the root prim is the base of the pet
// and it usually is made invisible. If your root prim needs to be visible and textured,
// just add a root 0, root1 and so on texture for each texture set.
//////////////////////////////////////////////////////////
// CONFIGURATION //
//////////////////////////////////////////////////////////
// you must put in a UUID from this web site here and in the brain script
//http://gridurl.appspot.com/random
string UUID = "48246356-a7c5-474b-a6fe-f2cec98926b2";
integer debug = TRUE; // set to 1 or TRUE for debuging information to the owner
integer LSLEDIT = FALSE; // set to TRUE if debugging in LSLEditor as it does not support the HTTP headers we need.
// Type "POST" in the [method] field and click [http_response]
// You should get a response based on "teststring" below
float testBreed = 0.01;
// 1/13/2, 1/2 the number of textures.
//for testing to fake out HTTP traffic for a breed value of whatever this string is.
// 0.0 is the first, 1.0 is the last
float testIncrement = 0.076923077;
// 1/13 , the number of test textures
integer testCounter = 0; // just for testing in LSLEditor.
//////////////////////////////////////////////////////////
// INTERNALS //
//////////////////////////////////////////////////////////
key notecardQueryId;
string notecardName = "Breeds"; // the notecard
integer notecardLine; // script-wise, the first notecard line is line 0, the second line is line 1, etc.
list textureDB; // texture storage
integer nTextures; // how many we find
integer nServed; // how many we served
integer nPrims ; // how many prims there must be
integer nBreeds; // how man breeds
list lNames; // a list of names
list lBreedNames; // a list of breed names read from the notecard
key gtextureUUID; // The UUID of the detected texture
string gtextureName; // the name of the detected texture
key URLReq = NULL_KEY;
string url; // sop we can release HTTP-In keys
key urlRequestId;
getNoteCard()
{
notecardLine = 0;
notecardQueryId = llGetNotecardLine(notecardName, notecardLine);
}
request_url()
{
DEBUG("get URL");
llReleaseURL(url);
url = "";
urlRequestId = llRequestURL();
}
getImage(integer breedNum, string Name)
{
DEBUG("Seeking Number " + (string) breedNum );
integer i;
integer j = llGetListLength(textureDB);
for (i = 0; i < j; i += 3)
{
integer myBreedParam = llList2Integer(textureDB,i);
string humanName = llList2String(textureDB,i+1);
key UUID = llList2Key(textureDB,i+2);
gtextureName = humanName;
gtextureUUID = UUID;
if (myBreedParam >= breedNum && Name == humanName)
{
DEBUG("saving " + humanName + " " + (string) myBreedParam);
return;
}
}
return;
}
list ListUnique( list lAll ) {
integer i;
list lFiltered = llList2List(lAll, 0, 0);
integer iAll = llGetListLength( lAll );
for (i = 1; i < iAll; ++i) {
if ( llListFindList(lFiltered, llList2List(lAll, i, i) ) == -1 ) {
lFiltered += llList2List(lAll, i, i);
}
}
return lFiltered;
}
list parsePostData(string message)
{
list postData = [];
list parsedMessage = llParseString2List(message,["&"],[]);
integer len = ~llGetListLength(parsedMessage);
while(++len) {
string currentField = llList2String(parsedMessage, len);
integer split = llSubStringIndex(currentField,"=");
if(split == -1) {
postData += [llUnescapeURL(currentField),""];
} else {
postData += [llUnescapeURL(llDeleteSubString(currentField,split,-1)), llUnescapeURL(llDeleteSubString(currentField,0,split))];
}
}
return postData ;
}
getTextures()
{
textureDB = [];
lNames = [];
integer j = llGetInventoryNumber(INVENTORY_TEXTURE);
integer i;
for (i = 0; i < j ; i++)
{
string textureName = llGetInventoryName(INVENTORY_TEXTURE,i);
list splits = llParseString2List(textureName,[" "],[]);
string humanName = llList2String(splits,0);
integer breedParam = (integer) llList2String(splits,1);
key UUID = llGetInventoryKey(textureName);
DEBUG("Name:" + humanName);
DEBUG("breedParam:" + (string) breedParam);
textureDB += breedParam;
textureDB += humanName;
textureDB += UUID;
lNames += humanName;
}
nTextures = llGetListLength(textureDB)/3;
lNames = ListUnique(lNames);
nPrims = llGetListLength(lNames);
if (nPrims == 0) {
llOwnerSay("No Textures!");
nPrims = 1; // prevent divide by zero errors.
}
DEBUG("Number of colorable prims = " + (string) nPrims);
nBreeds = nTextures / nPrims;
textureDB = llListSort(textureDB,3,1);
DEBUG(llDumpList2String(textureDB,"-"));
DEBUG("Number of textures = " + (string) nTextures);
DEBUG("Number of breeds = " + (string) nBreeds);
llSetText("Textures Loaded",<0,1,0>,1.0);
request_url();
}
string getTexture(string body)
{
DEBUG("Parsing " + body);
list incomingMessage = parsePostData(body);
// fake out a http header
if (LSLEDIT)
incomingMessage = llParseString2List(body,["="],[]);
DEBUG("Params: " + llDumpList2String(incomingMessage,"\n"));
if (llList2String(incomingMessage,0) == "breed")
{
float myBreed = (float) llList2String(incomingMessage,1);
DEBUG("myBreed = " + (string) myBreed);
if (myBreed > 1)
myBreed = 1;
integer myBreedNum = llFloor((myBreed * (nBreeds)));
DEBUG("myBreedNum = " + (string) myBreedNum);
string Name = llList2String(lBreedNames,myBreedNum);
string response = Name + "|"; // frst param is the notecard line
DEBUG("Scanning for Breed named: " + Name + " for value = " + (string) myBreed);
llSetText("Served:" + (string) nServed + "\nLast Breed:"+ (string) Name ,<1,1,1>,1.0);
integer i;
for (i = 0; i < nPrims; i++)
{
string breedName = llList2String(lNames,i);
DEBUG("Fetching prim number: " + (string) i);
getImage(myBreedNum,breedName);
response += gtextureName + "|";
response += (string) gtextureUUID + "|";
}
// LSLEDIT DIAGNOSTOCS
if (LSLEDIT)
{
DEBUG("test # "+(string) testCounter);
DEBUG("Name "+ Name);
DEBUG("S.b. "+ llList2String(lBreedNames,testCounter));
if ( Name == llList2String(lBreedNames,testCounter))
{
DEBUG("test Passed************");
} else {
DEBUG("test Failed************");
}
}
return "texture|" + response;
}
return "texture|blank|blank|" + (string) TEXTURE_BLANK; // no name, no prim type, no texture
}
key Request(string URL)
{
llSetText("Registering",<1,1,1>,1.0);
string url = "http://gridurl.appspot.com/reg?service=" + UUID + "&url=" + llEscapeURL(URL) + "/";
return llHTTPRequest( url, [HTTP_METHOD, "GET"], "");
}
throw_exception(string inputString)
{
key owner = llGetOwner();
llInstantMessage(owner, inputString);
llSleep(60); // so we do not flood owner with IM's
llResetScript();
}
DEBUG(string msg)
{
if (debug)
llSay(0,llGetScriptName() + " : " + msg);
}
default
{
state_entry()
{
getNoteCard();
llSetText("Initializing",<1,1,1>,1.0);
}
on_rez(integer param)
{
llResetScript();
}
http_request(key id, string method, string body)
{
DEBUG("Response:" + body);
if (method == URL_REQUEST_GRANTED)
{
DEBUG(body);
url = body; // save body response so we can release it.
URLReq = Request(body);
}
else if(method == URL_REQUEST_DENIED)
{
llOwnerSay("ERROR: URL REQUEST was DENIED "+body);
llSetText("ERROR: URL REQUEST was DENIED",<1,0,0>,1.0);
llSleep(5);
llResetScript();
}
else if(id == URLReq)
{
if (body == "OK")
{
llSetText("OK",<1,0,0>,1.0);
}
else
{
llSetText("Unable to register",<0,0,1>,1.0);
}
}
else if(method == "POST")
{
nServed++;
string resp;
if (LSLEDIT) {
resp = getTexture("breed=" + (string) testBreed);
testBreed += testIncrement; // 1/13
testCounter++;
}
else
resp = getTexture(llGetHTTPHeader(id, "x-query-string"));
DEBUG("Response:" + resp);
llHTTPResponse(id, 200, resp);
}
else
{
llSetText("Not Implemented",<1,0,0>,1.0);
llHTTPResponse(id, 501, "Not Implemented "+method);
}
}
http_response(key request_id, integer status, list metadata, string body)
{
if(URLReq == request_id)
{
URLReq = NULL_KEY;
if(status == 200)
{
llSetText("Ok",<1,1,1>,1.0);
}
else
{
llSetText("Request failed",<1,0,0>,1.0);
llOwnerSay("Request failed status="+(string)status+" "+body);
llSleep(10);
request_url();
}
}
}
dataserver(key query_id, string data)
{
if (query_id == notecardQueryId)
{
if (data == EOF) {
llSetText("Done reading notecard.\n" + (string) llGetListLength(lBreedNames) + " breeds saved.",<1,1,1>,1.0);
DEBUG("Notecard contained: " + llDumpList2String(lBreedNames,","));
getTextures();
}
else
{
list stuff = llParseString2List(data,[" "],[]);
string comment = llList2String(stuff,0);
if (comment != "//") {
lBreedNames += data;
DEBUG( "Reading Breed name =" + data );
}
// bump line number for reporting purposes and in preparation for reading next line
++notecardLine;
notecardQueryId = llGetNotecardLine(notecardName, notecardLine);
}
}
}
changed (integer what)
{
if (what & CHANGED_INVENTORY)
{
getNoteCard();
}
if (what & (CHANGED_REGION_START ))
{
llReleaseURL(url);
llResetScript();
}
}
}