<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>i live in science land &#187; Micheil Merlin</title>
	<atom:link href="http://iliveisl.com/author/micheil-merlin/feed/" rel="self" type="application/rss+xml" />
	<link>http://iliveisl.com</link>
	<description>avatar ramblings from the virtual world</description>
	<lastBuildDate>Fri, 24 May 2013 13:25:16 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.5.1</generator>
		<item>
		<title>Scripting Tips: Remote object update</title>
		<link>http://iliveisl.com/scripting-tips-remote-object-update/</link>
		<comments>http://iliveisl.com/scripting-tips-remote-object-update/#comments</comments>
		<pubDate>Sat, 07 May 2011 16:32:04 +0000</pubDate>
		<dc:creator>Micheil Merlin</dc:creator>
				<category><![CDATA[OpenSim]]></category>
		<category><![CDATA[second life]]></category>
		<category><![CDATA[micheil merlin]]></category>
		<category><![CDATA[scripting]]></category>

		<guid isPermaLink="false">http://iliveisl.com/?p=8854</guid>
		<description><![CDATA[A post Ener made in January regarding a desire for some method to be able to globally update a set of like objects, is the inspiration for this post. The method described in this post is not as elegant as Ener&#8217;s vision, but could be used to accomplish something similar. There are a pair of [...]]]></description>
				<content:encoded><![CDATA[<p>A post Ener made in January regarding a desire for some method to be able to <a href="http://iliveisl.com/update-one-to-update-many/">globally update a set of like objects</a>, is the inspiration for this post. The method described in this post is not as elegant as Ener&#8217;s vision, but could be used to accomplish something similar.</p>
<p>There are a pair of LSL functions, <a href="http://wiki.secondlife.com/wiki/LlSetRemoteScriptAccessPin">llSetRemoteScriptAccessPin</a> and <a href="http://wiki.secondlife.com/wiki/LlRemoteLoadScriptPin">llRemoteLoadScriptPin</a>, that allow objects belonging to the same owner and with the proper permissions, to transfer a script between them. These functions are probably normally used to update a set of scripts in a product to a newer version. Although, because of the permissions required, most people selling objects would not use this method as it may leave their product open to inspection or alteration in ways they&#8217;d like to prevent.</p>
<p>The example shown here will demonstrate making a global change to a set of objects. The global change could be anything that a script could do to an object such as changing a texture, the shape, color, sound, etc. In this example, we&#8217;ll only do something simple such as change the color of the root prim.</p>
<p>There will be a fair amount of setup and preparation to use this method so it would be most suitable for use with a set of objects that exist with some permanence in your region.  An example might be that you have placed a number of trees around your land and want to change their texture to be appropriate to the season.</p>
<p>This example will need to read a configuration notecard that contains a few parameters including the <a href="http://wiki.secondlife.com/wiki/UUID">UUIDs</a> or <a href="http://wiki.secondlife.com/wiki/Key">keys</a> of the remote objects. A post last year, <a href="http://iliveisl.com/scripting-tips-configure-by-notecard/">Scripting Tips: Configure by notecard</a>, describes what you have to do to process a notecard.</p>
<p>At the end of this post is a step by step list of how to put the demo together. So you can read through the descriptions of the scripts and LSL functions, then follow the steps at the end and copy/paste the script text when needed.  All of the following code examples work in both Second Life and OpenSim.</p>
<p>The first requirement is that the receiving objects will need a remote script access pin set. There is only one pin per prim and the pin is a prim property, so once set, remains until it is set again. Also, once set, there is no method to determine what it is. Therefore, if you forget what you set a pin to, just pick a new one. Because of the way that <a href="http://wiki.secondlife.com/wiki/LlSetRemoteScriptAccessPin">llSetRemoteScriptAccessPin</a> and <a href="http://wiki.secondlife.com/wiki/LlRemoteLoadScriptPin">llRemoteLoadScriptPin</a> function together, the pin doesn&#8217;t have to be kept quite as secret as your bank ATM card, but I still tend to protect them and treat them in the same manner that I treat anything related to object to object communication.</p>
<p>The remote script access pin is set with the <a href="http://wiki.secondlife.com/wiki/LlSetRemoteScriptAccessPin">llSetRemoteScriptAccessPin()</a> function. Supply any integer value greater than zero.</p>
<blockquote>
<pre><code>llSetRemoteScriptAccessPin(PIN);</code></pre>
</blockquote>
<p>If you need to know the UUID of a prim and can find no other way to obtain it, you can use the <a href="http://wiki.secondlife.com/wiki/LlGetKey">llGetKey()</a> function in a script to give you the UUID or key of the prim that contains the script.</p>
<blockquote>
<pre><code>llOwnerSay("Object UUID " + (string)llGetKey());</code></pre>
</blockquote>
<p>After the script executes in the remote object, it is no longer needed, since the pin never has to be set again. To conserve server resources the script can delete itself using the <a href="http://wiki.secondlife.com/wiki/LlGetScriptName">llGetScriptName()</a> and <a href="http://wiki.secondlife.com/wiki/LlRemoveInventory">llRemoveInventory()</a> functions.</p>
<blockquote>
<pre><code>llRemoveInventory(llGetScriptName());</code></pre>
</blockquote>
<p>Below is sample code that will set the pin of a prim to 54321 and then remove itself from the prim&#8217;s inventory. Place this code in each prim that you wish to remote update in order to initialize the pin that you want to use. Since the script will delete itself automatically, you may want to first create it in your inventory, then drag it to the desired object.</p>
<pre style="font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace;color: #000000;background-color: #eeeeee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px;overflow: auto;width: 100%"><code>// Set Pin and Delete // // Set the Remote Script Access Pin and self-delete this script. // // Micheil Merlin - 01/29/2011 integer PIN = 54321; // PIN. default { state_entry() { llOwnerSay("Setting PIN to " + (string)PIN); llSetRemoteScriptAccessPin(PIN); // Set PIN. llOwnerSay("Object UUID " + (string)llGetKey()); llOwnerSay("Removing script"); llRemoveInventory(llGetScriptName()); // Remove us. } } </code></pre>
<p>Later, we will need the UUIDs of all objects that you wish to remote update. If you are using <a href="http://blog.kokuaviewer.org/">Imprudence/Kokua</a>, <a href="http://www.phoenixviewer.com/">Phoenix</a> or potentially other third party viewers, obtaining the UUID of a rezzed object is easy. Use the edit tool, select the General page and then use the Copy Key button. If the viewer you are using doesn&#8217;t support this function, the pin setting script will use <a href="http://wiki.secondlife.com/wiki/LlOwnerSay">llOwnerSay()</a> to report the UUID of the prim that it operates in and you can copy/paste this from your chat log.</p>
<p>Next, we need a script to distribute to all of the desired remote objects. As noted earlier, we&#8217;re just going to do something really simple like change the prim color. So, the script below will change the prim color to red, and then delete itself. Again, after the script has done its work, it doesn&#8217;t need to remain in the object consuming server resources, any longer.</p>
<p>The remote change script has to reside in the inventory of the distribution controller. Depending on what is desired of the remote change script, this can cause problems as by default, the remote change script will also try to run inside the distribution controller. There are a couple of ways to prevent this.</p>
<p>One option is just to set the script to not-running, which can be a little confusing at times. Aside from potentially causing a little confusion, a not-running script in OpenSim doesn&#8217;t get compiled if it is edited while in the not-running state.</p>
<p>Another option is to place something else in the inventory that the script can recognize as a signal to not take any action. This allows the script to not hurt anything if it is active in the distribution controller. The approach that I&#8217;ve taken in this example is to create a piece of clothing, name it &#8220;Controller&#8221;, and place it in the distribution controller as a signal to the remote change script that it should not take any action. The <a href="http://wiki.secondlife.com/wiki/LlGetInventoryType">llGetInventoryType()</a> function is used to check if there is something in the inventory that is named &#8220;Controller&#8221; and is an inventory type of <a href="http://wiki.secondlife.com/wiki/INVENTORY_CLOTHING">INVENTORY_CLOTHING</a>.</p>
<blockquote>
<pre><code>if (llGetInventoryType("Controller") != INVENTORY_CLOTHING)</code></pre>
</blockquote>
<p>To create a clothing item, open your inventory, select the clothing folder, right click, and then select New Socks. You can actually use any type of clothing for this example. I&#8217;m just used to using socks. Rename the clothing item to &#8220;Controller&#8221;. Later, we will need to drag this to our distribution controller&#8217;s inventory.</p>
<p>As noted earlier, this example is just going to change the prim color. Other, more complicated things could be accomplished with the <a href="http://wiki.secondlife.com/wiki/LlSetPrimitiveParams">llSetPrimitiveParams()</a>, <a href="http://wiki.secondlife.com/wiki/LlSetLinkPrimitiveParams">llSetLinkPrimitiveParams()</a>, <a href="http://wiki.secondlife.com/wiki/LlSetLinkPrimitiveParamsFast">llSetLinkPrimitiveParamsFast()</a>, or several other functions.</p>
<p>We should make a point here regarding object permissions. For any circumstance where you have one object send something to another object or rez another object inworld, the object or script being transferred, needs to be copyable. If it isn&#8217;t copyable, then that particular copy is sent and will no longer be available to use again. If you are the creator, then you have permissions to copy anything you create and your objects and scripts can transfer your objects or scripts somewhere else and still retain a copy to transfer again. If you give the object to someone else to use, at the very least, you will need to let them copy the object or script to be transferred. As an example, you could create a gun and put a bullet in the gun&#8217;s inventory for the gun to shoot. If you intend to give the gun to a friend, you&#8217;ll also need to make sure you set the bullet to allow the friend to have copy permission on the bullet. Otherwise, once your friend shoots the gun once, the only bullet will be used.</p>
<p>If you intend to give a copy of your remote distribution controller away, the script to distribute will also need to be set to copyable. In this example, the Remote Change Color Demo script would have to be copyable.</p>
<pre style="font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace;color: #000000;background-color: #eeeeee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px;overflow: auto;width: 100%"><code>// Remote Change Color Demo // // Sample script to use with the Remote Object Update Demo. The demo will // use this script to distribute to the selected objects. // // This script will execute and self delete unless there is a clothing item // in the inventory named 'Controller'. If the clothing item is found, the // script does nothing. This allows an easy method for the script to reside // inside the distribution controller without taking any action until it is // distributed to a remote object. The distribution controller will have // the clothing item while the remote object will not. // // Micheil Merlin - 01/29/2011 default { state_entry() { // Only operate if there is not a piece of clothing in the inventory // called 'Controller'. This lets the script effectively stay dormant // until distributed. Alternatively, the script could be set to not // running and distributed as running, but using the inventory/clothing // method is a little simpler. if (llGetInventoryType("Controller") != INVENTORY_CLOTHING) { // Perform an action on the root prim of the object. llOwnerSay("Object UUID " + (string)llGetKey()); llSetColor(&lt;1.0, 0.0, 0.0&gt;, ALL_SIDES); // Change the prim color. llRemoveInventory(llGetScriptName()); // Remove script from inventory.. } } } </code></pre>
<p>The last script that we need is the one that will actually perform the distribution. The script needs to know the pin set for the remote objects, the script to distribute, and the UUIDs or keys of the remote objects. A notecard is used to supply all of this information. The notecard processing was described in a previous post from last year. Please refer to <a href="http://iliveisl.com/scripting-tips-configure-by-notecard/">Scripting Tips: Configure by notecard</a> for a detailed description of notecard processing. The example used in that post is largely contained in this example.</p>
<p>We need some way to save an unknown number of object UUIDs read from the notecard, to use later in the script. Actually, we could construct the script to just completely process each UUID as it is read from the notecard, but then that would require the notecard to contain all of the proper information in the correct order. That isn&#8217;t really so bad in this case. I just generally like to make the notecard processing not so dependent on the sequence of items in the notecard.</p>
<p>In other programming and scripting languages, I&#8217;d normally use a single dimension array to hold the UUIDs. The LSL designers, in their infinite wisdom, didn&#8217;t seem to think arrays were a very important data structure and didn&#8217;t include them as a data type. They did include the <a href="http://wiki.secondlife.com/wiki/Category:LSL_List">list data type</a> along with a whole set of list processing functions. An LSL list is very powerful and is easily used like a single dimensional array. It&#8217;s a little messier as a multidimensional array, but in this case we don&#8217;t need one.</p>
<p>The first thing we need to do to prepare to accumulate the UUIDs, is to declare and initialize the list. And since we need to use it across states, we declare it prior to the default state.</p>
<blockquote>
<pre><code>list gUuidList = [];</code></pre>
</blockquote>
<p>Then, each time we read a UUID, we add it to the list. We read the value from the notecard as a character string and at this point, it is still a character string, so we <a href="http://wiki.secondlife.com/wiki/LSL_Variables">cast</a> the string value to a <a href="http://wiki.secondlife.com/wiki/Category:LSL_Key">key</a>, prior to adding the entry to the list.</p>
<blockquote>
<pre><code>gUuidList += (key)keyvalue;</code></pre>
</blockquote>
<p>The += operator notation is called a <a href="http://wiki.secondlife.com/wiki/LSL_Operators">shorthand operator</a> and is the same as coding gUuidList = gUuidList + (key)keyvalue;</p>
<p>The script completely processes the notecard and then switches to a state that I called begin.</p>
<p>The begin state performs some validation to make sure we have everything we need. The items that we need to make sure that we&#8217;ve collected from the notecard at this point are&#8230;</p>
<ol>
<li>The name of the script that we want to distribute.</li>
<li>The pin to use for the distribution.</li>
<li>One or more UUIDs for the remote objects.</li>
</ol>
<p>We use the <a href="http://wiki.secondlife.com/wiki/LlGetInventoryType">llGetInventoryType()</a> function and checking against <a href="http://wiki.secondlife.com/wiki/INVENTORY_SCRIPT">INVENTORY_SCRIPT</a> to make sure the desired script is in the inventory.</p>
<blockquote>
<pre><code>if (llGetInventoryType(gScript) != INVENTORY_SCRIPT)</code></pre>
</blockquote>
<p>The pin is also checked to make sure that it isn&#8217;t zero and the length of the UUID list is checked to make sure we have at least one entry to work on Then, after all validation is complete and successful, we set a variable called gRun to TRUE for use later.</p>
<p>To have some control over when the distribution script operates, we use the <a href="http://wiki.secondlife.com/wiki/Touch_start">touch_start</a> event. Menu dialog processing could be added for more control or to perform additional functions. But to keep the example less complicated, we&#8217;ll just stick with using touch.</p>
<p>Inside the touch_start event, we first validate that the gRun flag has been set indicating that we have everything we need to run. Then we check to make sure that the touch_start event comes from the object owner, using <a href="http://wiki.secondlife.com/wiki/LlGetOwner">llGetOwner()</a> and <a href="http://wiki.secondlife.com/wiki/LlDetectedKey">llDetectedKey()</a>. The touch_start event supports multiple agents touching the object, so we loop through all touches looking for the owner. The agent touching the object will almost always be the one indexed by zero, but we construct the script to handle multiple agents.</p>
<p>The notecard may have contained UUIDs for more than one object to distribute to. We constructed a list to hold these UUIDs so we will loop through the list and work on each UUID in the list. The <a href="http://wiki.secondlife.com/wiki/LlList2Key">llList2Key()</a> function allows us to index into the list and get an item to be treated as a key. When we built the list, remember we placed each UUID into the list using (key) to cast the entry as a key.</p>
<blockquote>
<pre><code>Uuid = llList2Key(gUuidList, j);</code></pre>
</blockquote>
<p>The <a href="http://wiki.secondlife.com/wiki/LlRemoteLoadScriptPin">llRemoteLoadScriptPin()</a> function is the one that actually performs the magic. It will use the UUID we obtained from the list, the script name we supplied in the notecard and the pin also supplied in the notecard, then send the script to the remote object addressed by the UUID.  The TRUE setting means the script will be placed into the object in the running state. An integer can be passed to the script that it can obtain with the <a href="http://wiki.secondlife.com/wiki/LlGetStartParameter">llGetStartParameter()</a> function. In this case, we just pass a zero because we aren&#8217;t going to use this feature.</p>
<blockquote>
<pre><code>llRemoteLoadScriptPin(Uuid, gScript, gPin, TRUE, 0);</code></pre>
</blockquote>
<p>The distribution script uses the <a href="http://wiki.secondlife.com/wiki/Changed">changed</a> event to detect changes to the distribution controller&#8217;s inventory. So adding the notecard or changing the notecard will cause the script to reset and process the notecard again.</p>
<p>As noted previously, the rest of the distribution script is almost entirely from the <a href="../scripting-tips-configure-by-notecard/">Scripting Tips: Configure by notecard</a> example.</p>
<pre style="font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace;color: #000000;background-color: #eeeeee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px;overflow: auto;width: 100%"><code>// Remote Object Update Demo // // Sample code to demonstrate using a notecard to identify UUIDs of objects in the // same region to send an update script to. // // Micheil Merlin - 01/28/2011 string NOTECARD = "Config"; // Configuration notecard. key gQuery; // Notecard read key. integer gLine = 0; // Notecard line to read. integer gError = FALSE; // Error status. integer gDebug = FALSE; // Debug flag from notecard. list gUuidList = []; // List of object UUIDs. integer gUuidListLength = 0; // Length of UUID list. string gScript = ""; // Name of the script to distribute. integer gPin = 0; // Remote object update PIN. integer gRun = FALSE; // Ready to run state. default { state_entry() { llOwnerSay("Initializing..."); // Check to see if a notecard with the specified name is in the // object inventory. if (llGetInventoryType(NOTECARD) == INVENTORY_NOTECARD) { // If the notecard exists, get the first line. Save the key // so we can use it in the dataserver event to identify that // the event is for this notecard read. gQuery = llGetNotecardLine(NOTECARD, gLine); } else { // If no notecard exists, just switch to the begin state. // There are no configuration parameters to change. state begin; } } // When object is rezzed, reset the script. on_rez(integer num) { llResetScript(); // Reset the script. } // Use the changed event to see if the inventory has changed. We can use // this to detect that the notecard has been changed and reset the script // so the notecard can be reprocessed. There is no way to determine what // in the inventory has changed without doing some sort of processing on the // inventory. So, the script will be reset regardless of what changed in the // inventory. changed(integer change) { // If inventory has changed, assume script reset is needed. Many other // things can trigger the change event but in this case, we are only // looking for changed inventory. if (change == CHANGED_INVENTORY) { llResetScript(); // Reset the script. } } // Dataserver event to process notecard data. dataserver(key query_id, string data) { integer i; // Temp index. integer j; // Temp index. string keyword; // Configuration keyword. string keyvalue; // Configuration value. // The dataserver event is used for many things. To make sure we process // the correct data, check that the key is from the last notecard read // request. In this sample code, the dataserver event should not be // triggered for any other purpose than to present the notecard data. // But it is still a good coding practice to check to make sure // the event is what you think it is. if (query_id == gQuery) { // If 'End of File' is returned, then there is no more data. Switch // to the begin state. if (data == EOF) { state begin; } // Process the notecard data. else { // Compress out blanks and make sure the notecard line is not empty. if ( llStringTrim(data, STRING_TRIM) != "" ) { // A notecard line with a '#' in the first position is taken to be a // comment and will not be further processed. if (llGetSubString(data, 0, 0) != "#") { // If line is not a comment, get keyword and value. // The format of the data we are looking for is... // keyword=keyvalue; i = llSubStringIndex(data, "="); // Look for keyword/keyvalue separator. j = llSubStringIndex(data, ";"); // Look for end of line marker. if (i == -1 || j == -1) { // Check for 'keyword=value;' syntax. llOwnerSay("Configuration notecard contains invalid syntax at list " + (string)gLine + ". Data line follows.\n" + data + "\nCorrect the error and reset."); gError = TRUE; // Set error condition. } else { // Extract the keyword and keyvalue strings. keyword = llGetSubString(data, 0, i - 1); // Translate keyword to lower case to reduce problems from typos and // also remove leading and trailing blanks. keyword = llStringTrim(llToLower(keyword), STRING_TRIM); keyvalue = llGetSubString(data, i + 1, j - 1); // Only remove leading and trailing blanks from keyvalue. Assume // the existing case is what is intended. keyvalue = llStringTrim(keyvalue, STRING_TRIM); // Process keywords in config notecard. if (keyword == "uuid") // uuid keyword. { gUuidList += (key)keyvalue; // Save UUID. } else if (keyword == "script") // Name of script to distribute. { gScript = keyvalue; // Save the name of the script. } else if (keyword == "pin") // Remote update PIN. { gPin = (integer)keyvalue; // Save the remote update PIN. } else if (keyword == "debug") // debug keyword. { // Here is a case where we want to force a compare to lower case // as we are using keyvalue as on on/off switch. // Also, we assume that any other reply than yes means no. If you // really want to make sure someone doesn't just typo the yes and // it is taken as no, you'd want to check for yes or no and then // indicate an error if something else was encountered. if (llToLower(keyvalue) == "yes") { gDebug = TRUE; // Set debug flag. } } else { llOwnerSay( "Configuration notecard contains unknown keyword at line " + (string)gLine + ".\n Keyword found is " + keyword + "\nCorrect the error and reset."); gError = TRUE; // Set error condition. } } } } // Request the next notecard line. ++gLine; gQuery = llGetNotecardLine(NOTECARD, gLine); } } } } state begin { // Initialization completed. state_entry() { // Check to see if debug flag is set. if (gDebug) { llOwnerSay("Debug mode is on."); } // Validate that the script name was supplied in the configuration notecard // and that the script is in the inventory. if (gScript == "") { gError = TRUE; llOwnerSay("No script name to distribute, has been set."); } else { if (llGetInventoryType(gScript) != INVENTORY_SCRIPT) { gError = TRUE; llOwnerSay("The requested script, '" + gScript + "', is not " + "in the inventory"); } } // Validate that the remote script PIN is non-zero. A zero script PIN // is not valid. if (gPin == 0) { gError = TRUE; llOwnerSay("The remote script PIN must be set to a non-zero value."); } gUuidListLength = llGetListLength(gUuidList); // Validate that there are UUIDs of remote objects supplied. if (gUuidListLength == 0) { gError = TRUE; llOwnerSay("There are no remote object UUIDs"); } // Check to see if the error condition was set during configuration. // If we have an error condition, don't allow an attempt at distributing // the script. if (gError == FALSE) { llOwnerSay("Ready to run. Touch object to distribute the script."); gRun = TRUE; // We have everything we need. } else { llOwnerSay("Not ready to run."); } } // Since events are specific to a state, we need to duplicate the on_rez event in this // state also. on_rez(integer num) { llResetScript(); // Reset script. } // Since events are specific to a state, we need to duplicate the changed event in this // state also. changed(integer change) { // If inventory has changed, assume script reset is needed. if (change == CHANGED_INVENTORY) { llResetScript(); // Reset script. } } // Use the touch event to start the distribution. touch_start(integer num) { // Verify that all conditions are ok to run the distribution. if (gRun) { // Check to see if any toucher is the object owner. The integer // supplied by the touch_start event is the number of agents that // have touched the object during this cycle. It will always be // at least 1 for 1 agent. However, the detect functions all // address their list of agents relative to 0. integer i = 0; // Set loop index. while (i &lt; num) { // If this toucher is the object owner, perform the distribution. if (llGetOwner() == llDetectedKey(i)) { // The length of a list is the actual integer length. But the // index of the first item in the list is 0. So, we'll loop // beginning with an index of 0 and continue as long as the index // is less than the integer length of the list. integer j = 0; // Set loop index. key Uuid; // UUID to process. while (j &lt; gUuidListLength) { Uuid = llList2Key(gUuidList, j); // Get a UUID from the list. llOwnerSay("Sending script to UUID " + (string)Uuid); if (gDebug) { llOwnerSay("Script " + gScript + " PIN " + (string)gPin); } llRemoteLoadScriptPin(Uuid, gScript, gPin, TRUE, 0); j++; // Index next list item. } llOwnerSay("Done."); return; // Exit the event. } i++; // Index next agent. } } else { llOwnerSay("Not ready to run."); // Run flag isn't set. } } } </code></pre>
<p>The last item that we need to take care of is the notecard used by the distribution controller. There are only three required items. The pin, the name of the script to distribute, and one or more UUIDs for the objects to which to send the script to.</p>
<p>As noted earlier, the UUID or key of an object can be easily obtained with some third party viewers by using the edit tool, selecting the General tab and using the Copy Key button. I am unaware of any way to obtain the UUID using the SL Viewer 2.</p>
<p>The supplied script that sets the pin will also report the UUID. So, you can use that script to obtain the UUID, if required.</p>
<p>If you place the remote object out in the virtual world and just leave it, the UUID will never change. If you make a copy, the UUID of the original still doesn&#8217;t change. But, the thing that people don&#8217;t generally notice, is that when you make a copy, it is the copy that is left in the original location and the original is what moves to where you place it. So, the object that you&#8217;d normally think is the original, is actually a copy with a new UUID.</p>
<p>Also, if you delete the object and pull another out of inventory, it will get a new UUID.</p>
<p>There is also a debug flag in the configuration file. This was in the original notecard configuration example and I left it in this example, although it doesn&#8217;t currently do much.</p>
<pre style="font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace;color: #000000;background-color: #eeeeee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px;overflow: auto;width: 100%"><code># Config # # Configuration notecard for Remote Object Update Demo. # Debug flag for diagnostics messages. yes or no. debug = no; # The remote script access pin. PIN = 54321; # The name of the script to distribute. Script = Remote Change Color Demo; # List of UUIDs for objects to distribute to. The UUID may be obtained from the Edit tool, # the General tab and the Copy Key button. UUID = 069a1bdf-3acf-4a4d-9add-c0cbf242df10; UUID = 504f2479-f4b1-4da4-94e6-c7b7b1156792; UUID = 6bdf4e6a-500c-4b65-b5d8-dcb04106b759; UUID = 9c75fd62-ff96-4020-a107-e744438130e8; </code></pre>
<p><strong>Putting It All Together</strong></p>
<ol>
<li>We need to create some remote objects to test with. So, use the edit/build/create tool to create a few objects. It isn&#8217;t necessary to name them, but I&#8217;d give them unique names anyway. Something simple like &#8216;Remote Object 1&#8242;, &#8216;Remote Object 2&#8242;, etc.</li>
<li>Each of the remote objects will need the pin set. Copy the text of the &#8216;Set Pin and Delete&#8217; script. You need to place a copy in your inventory, because as the script is written, it will do its work and self delete. So, if you first put it in an object, you won&#8217;t have a copy after it executes. If you want to change the pin, just remember to change the pin in the notecard when we get to that point. Assuming you created the script in your inventory, drag a copy to each remote object.</li>
<li>We&#8217;re not ready for the notecard yet, but remember if you are using Viewer 2, you may need to copy the reported UUIDs out of chat before you lose them from chat.</li>
<li>Create another object to be the distribution controller. Name it appropriately.</li>
<li>Before we copy the &#8216;Remote Change Color Demo&#8217; script to the controller, remember we need to create a clothing item and name it &#8216;Controller&#8217;. This is what will keep the &#8216;Remote Change Color Demo&#8217; script from operating inside the controller.</li>
<li>Open your inventory and go to the &#8216;Clothing&#8217; folder. Right click and select an item of clothing to create. It can be any item. I generally use socks but it doesn&#8217;t matter. Name the item &#8216;Controller&#8217;. Be sure that the case is correct on each letter or the script will not recognize the item is in the inventory.  Now drag the newly created and named clothing item to the inventory of your distribution controller.</li>
<li>In the inventory of your distribution controller, create a new script, rename it to &#8216;Remote Change Color Demo&#8217;, and copy the text of the &#8216;Remote Change Color Demo&#8217; script over the default script. If your object changes color and the script disappears, then you probably messed up the name of your clothing item. If the object did change color and the script self-deleted, delete the object, check that the name of the clothing item you created is &#8216;Controller&#8217;, with an uppercase &#8216;C&#8217;, and do this step again.</li>
<li>As noted earlier in the post, you may need to set the permission on the &#8216;Remote Change Color Demo&#8217; to copy. As long as you don&#8217;t give the object to anyone else to use, this wouldn&#8217;t be required. But if you give it to someone else, they will need permission to copy the script. If they don&#8217;t have that permission, the first time it is sent to a remote object, it will disappear completely. Double check the name spelling of the script including which letters are lower and upper case, because the controller script looks for this name in the inventory based on the settings in the notecard.</li>
<li>Again, in the inventory of your distribution controller, create another new script, rename it to &#8216;Remote Object Update Demo&#8217;, and copy the text of  &#8216;Remote Object Update Demo&#8217; over the default script. The script will chat some errors about there not being any script to distribute, no pin and no UUIDs.  That&#8217;s ok. We haven&#8217;t created the notecard with that information yet.</li>
<li>Open your inventory and create a notecard named &#8216;Config&#8217;.  Once again, make sure that the case is correct on the name of the notecard as the controller script looks for this specific name. Copy the &#8216;Config&#8217; notecard text to your new notecard. Here is an important point. Those UUIDs aren&#8217;t going to work for you. You&#8217;ll need to replace them with yours. You&#8217;ll see that there are four of them in my notecard because I had four objects. Edit yours as appropriate.  If you are using Phoenix or Imprudence, use the edit tool on each of your objects and copy the keys to your clipboard using the &#8216;Copy Key&#8217; function. Otherwise, you can copy them out of chat at the point you placed the &#8216;Set Pin and Delete&#8217; scripts in the remote objects. If you&#8217;ve lost the chat already and need it, you can drag &#8216;Set Pin and Delete&#8217; script to each object again. Since you are modifying the text in the notecard to update the UUIDs, watch the syntax of those lines closely. They begin with &#8216;UUID =&#8217; and end with &#8216;;&#8217;. In particular, be careful that you don&#8217;t paste over the trailing semicolon.</li>
<li>If the syntax is ok, the distribution controller should report that it is &#8216;Ready to Run&#8217;.</li>
<li>Touch the distribution controller. It will report what it is doing and if everything works, all of the remote objects should turn red.</li>
</ol>
<p>And, that&#8217;s it!  These sample scripts don&#8217;t do anything particularly useful.  But their purpose is to generate ideas for your own work, use as a starting point for something you want to do, and to demonstrate some LSL functionality.</p>
<div id="attachment_9875" class="wp-caption aligncenter" style="width: 575px"><a href="http://iliveisl.com/scripting-tips-remote-object-update/snapshot-remote-object-update-demo-1_006/" rel="attachment wp-att-9875"><img class="size-medium wp-image-9875" src="http://iliveisl.com/wp-content/uploads/2011/05/Snapshot-Remote-Object-Update-Demo-1_006-565x300.jpg" alt="Commanding the Prims" width="565" height="300" /></a><p class="wp-caption-text">Commanding the Prims</p></div>
]]></content:encoded>
			<wfw:commentRss>http://iliveisl.com/scripting-tips-remote-object-update/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>Imprudence and Qarl&#8217;s Prim Alignment Tool</title>
		<link>http://iliveisl.com/imprudence-and-qarls-prim-alignment-tool/</link>
		<comments>http://iliveisl.com/imprudence-and-qarls-prim-alignment-tool/#comments</comments>
		<pubDate>Wed, 27 Oct 2010 01:57:08 +0000</pubDate>
		<dc:creator>Micheil Merlin</dc:creator>
				<category><![CDATA[OpenSim]]></category>
		<category><![CDATA[second life]]></category>
		<category><![CDATA[imprudence viewer]]></category>

		<guid isPermaLink="false">http://iliveisl.com/?p=7614</guid>
		<description><![CDATA[Remember Qarl? He&#8217;s the graphics guru that LL fired. While there are certainly things that we outsiders will never know about the inner workings of LL, this termination would appear to be one of those things that could be appropriately classified as an epic fail. However, that isn&#8217;t the point of this post. Qarl has [...]]]></description>
				<content:encoded><![CDATA[<p>Remember <a href="http://www.qarl.com/qLab/?p=64">Qarl</a>? He&#8217;s the graphics guru that LL fired.</p>
<p>While there are certainly things that we outsiders will never know about the inner workings of LL, this termination would appear to be one of those things that could be appropriately classified as an</p>
<blockquote><p><a href="http://www.urbandictionary.com/define.php?term=epic%20fail">epic fail</a>.</p></blockquote>
<p>However, that isn&#8217;t the point of this post.</p>
<p>Qarl has created a patch to add an alignment option to the build tool. Previous to this, you didn&#8217;t get a lot of help from the viewer with aligning prims.  I believe there are some in-world scripts that will help. But wait until you see this.</p>
<p><object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" width="640" height="385" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0"><param name="allowFullScreen" value="true" /><param name="allowscriptaccess" value="always" /><param name="src" value="http://www.youtube.com/v/7UCeU8ItZGA?fs=1&amp;hl=en_US" /><param name="allowfullscreen" value="true" /><embed type="application/x-shockwave-flash" width="640" height="385" src="http://www.youtube.com/v/7UCeU8ItZGA?fs=1&amp;hl=en_US" allowscriptaccess="always" allowfullscreen="true"></embed></object></p>
<p>Qarl posted <a href="http://www.qarl.com/qLab/?p=66">this patch to the viewer</a> on October 20, 2010.</p>
<p><a href="http://imprudenceviewer.org/">Imprudence</a> picked it up and distributed it in <a href="http://imprudenceviewer.org/2010/10/25/imprudence-experimental-release-2010-10-23/">Experimental Release 2010.10.23</a>. I use the Imprudence experimental release pretty exclusively in OpenSim and also when I need to move things between OpenSim and Second Life. The experimental release is assumed to be less stable but I generally have a very good experience with it.</p>
<p>The video that Qarl posted is pretty clear. But after the patch is implemented in a viewer, you’ll see a new selection on the build tool, just above “Edit linked parts”. So, with the build tool open, select a group of prims, then select the &#8220;Align&#8221; option just above &#8220;Edit linked parts&#8221; and have fun with your prims. Watch the short video for instructions and options.</p>
]]></content:encoded>
			<wfw:commentRss>http://iliveisl.com/imprudence-and-qarls-prim-alignment-tool/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Adventures in OpenSim: llRotBetween</title>
		<link>http://iliveisl.com/adventures-in-opensim-llrotbetween/</link>
		<comments>http://iliveisl.com/adventures-in-opensim-llrotbetween/#comments</comments>
		<pubDate>Sun, 04 Jul 2010 04:14:11 +0000</pubDate>
		<dc:creator>Micheil Merlin</dc:creator>
				<category><![CDATA[reaction grid]]></category>
		<category><![CDATA[opensim]]></category>
		<category><![CDATA[scripts]]></category>

		<guid isPermaLink="false">http://blog.iliveisl.com/?p=4800</guid>
		<description><![CDATA[A few months ago, I began work on a LSL script to assist in building a path that a scripted object could follow. I already had a script that could move a physical object around a path but didn&#8217;t have a way to assist in generating the actual path for OpenSim. I quickly determined that [...]]]></description>
				<content:encoded><![CDATA[<p>A few months ago, I began work on a LSL script to assist in building a path that a scripted object could follow. I already had a script that could move a physical object around a path but didn&#8217;t have a way to assist in generating the actual path for <a href="http://opensimulator.org/wiki/Main_Page">OpenSim</a>. I quickly determined that physical movement was going to be a problem, so adapted my path follower script to do non-physical movement. Go see <a href="http://iliveisl.com/adventures-in-opensim-the-submarine/">Adventures in OpenSim: The Submarine</a> for a recap of the little physical adventure.</p>
<p>Both scripts progressed fairly easily, but as I continued to test, I encountered occasions where the rotations generated by <a href="http://lslwiki.net/lslwiki/wakka.php?wakka=llRotBetween">llRotBetween</a>, just weren&#8217;t right. They&#8217;d be 180 degrees off. The object would end up facing the wrong direction. I had other occasions where objects rotated upside down or turned 90 degrees in the wrong direction. These last two cases turned out to be slight positioning errors due to some rounding anomalies in the movement calculations. I encountered all of these issues together and it took a bit to untangle them.</p>
<div id="attachment_4898" class="wp-caption aligncenter" style="width: 522px"><a href="http://blog.iliveisl.com/wp-content/uploads/2010/07/Submarine-6-30-2010_001.jpg"><img src="http://iliveisl.com/wp-content/uploads/2010/07/Submarine-6-30-2010_001-1024x572.jpg" alt="" width="512" height="286" class="size-large wp-image-4898" /></a><p class="wp-caption-text">That's just wrong</p></div>
<p>Things were further complicated in that I&#8217;d take the movement script to <a href="http://secondlife.com/">Second Life</a> and it would work just fine. At least it did after I took care of a divide by zero error that I wasn&#8217;t aware was happening in OpenSim. I&#8217;d still been assuming that the problem was in my script up to that point.</p>
<p>So, back to OpenSim.</p>
<p>Having decided that the OpenSim code wasn&#8217;t doing something correctly, I began to look around at algorithms for calculating the angle between two vectors, thinking that I would just make my own adaptation of llRotBetween. All of the algorithms were basically derivations of each other. They just went about the calculations in different ways.  Using a dot product, cross product, arccosine, sine, cosine or some of all of these. In some I found information regarding degenerate cases when the angle approached 0 or 180 degrees.</p>
<blockquote><p>hmmm</p></blockquote>
<p>I believe the degenerate cases applied to all of the algorithms, but surprisingly few of them mentioned these issues directly.</p>
<p>The degenerate cases occur when the dot product of the two normalized vectors is -1 (meaning an angle of 180 degrees) or when the dot product is 1 (meaning an angle of 0 degrees). What this means in simpler terms is that when the angle approaches 0 or 180 degrees, the simple algorithm does not produce correct results and some additional steps have to be added that check for these conditions.</p>
<p>Since OpenSim is open source, you can go look at the code. Figuring out where to look is a different story. I <a href="http://opensimulator.org/wiki/Download">downloaded</a> the entire source code distribution and searched for llRotBetween. By this time I&#8217;m thinking that it might be possible to submit a patch to OpenSim for this issue.</p>
<p>The OpenSim website contains <a href="http://opensimulator.org/wiki/Development">links</a> to information to assist in compiling the code and standards to follow for submitting patches.</p>
<p>Did you know that Windows 7 search is mostly broken? At least it seems to be mostly broken for me and <a href="http://www.google.com/">Google</a> finds many other people that think it&#8217;s broken. I had often used the search function in Windows XP to find files that contained certain text strings. Slow, but it worked. Windows 7 tries to speed that up by building search indexes. They just don&#8217;t see to be reliable. But that&#8217;s another story.</p>
<p>Anyway, luckily, the code that supports llRotBetween is actually called llRotBetween. And on one of those rare occasions that Windows 7 search worked for me, I found it in one of the modules that contains many of the implemented LSL functions. Windows 7 search couldn&#8217;t find it the next day after I forgot which directory it was in, so I went poking around for the module manually.</p>
<p>I found that there was no special handling of these 180 and 0 degree rotations in the code. This is likely because the original author first found those algorithms that did not make note of these special cases, so the original author didn&#8217;t know about these special cases.</p>
<p>Satisfied that I wasn&#8217;t way off in left field, I next decided to create the subroutine using LSL. This would allow me to work out the code easier and also produce a work around that I could use in the meantime.</p>
<p>I also encountered a problem with <a href="http://lslwiki.net/lslwiki/wakka.php?wakka=llVecNorm">llVecNorm</a>. The existing OpenSim implementation will return <a href="http://en.wikipedia.org/wiki/NaN">NaN</a> values (Not A Number) while LSL in Second Life returns a <a href="http://lslwiki.net/lslwiki/wakka.php?wakka=ZERO_VECTOR">ZERO_VECTOR</a>. The NaN values occur because of division by zero. The calculation in the code is actually correct, but sort of messy to deal with if you want to know the NaN values were returned. And you will only get the NaN values if the vector is a ZERO_VECTOR to begin with. So, if you try to normalize a ZERO_VECTOR, it seems to me like you should just get a ZERO_VECTOR back, just like you get with LSL in Second Life.</p>
<p>So, I submitted that simple llVecNorm patch (<a href="http://opensimulator.org/mantis/view.php?id=4752">OpenSim Mantis 4752</a>) first just to learn the process. But, I guess it wasn&#8217;t interesting enough to anyone to pick up and apply as no-one has touched it yet.</p>
<p>Moving on to llRotBetween.  The llRotBetween patch (<a href="http://opensimulator.org/mantis/view.php?id=4784">OpenSim Mantis 4784</a>) has also been submitted and was just recently picked up by a core developer, so hopefully is on the way to making it into your local OpenSim. Don&#8217;t get too excited though (as I&#8217;m sure you are&#8230;lol) as being in the development version of OpenSim, it may take a long time before it shows up in your local OpenSim.</p>
<p>The current release of OpenSim is 0.6.9 and I assume this patch will be in 0.7.x.</p>
<p>To find the OpenSim release for your region, go to the &#8220;Help&#8221; drop down menu on your viewer, then select the &#8220;About&#8221; option. The information box that opens, should give you the release information for the viewer you are using followed by the release information for the server version of your region, then some information about your own PC.</p>
<blockquote><p>So, What you gonna do?</p></blockquote>
<p>Well, you can use the RotBetween function I wrote in LSL.</p>
<p>If you&#8217;re worried about performance of an LSL script compared to a fucntion provided by LSL, you don&#8217;t really have to. I tested the script version against several OpenSim levels (including one I patched) and Second Life itself. The script function does run 1.5 to 2 times the elapsed time of the built-in function. But it takes thousands of executions in any environment to accumulate a second of elapsed time. So, the impact on efficiency can likely be ignored.</p>
<p>I&#8217;m providing the RotBetween function along with some example code that can be inserted into your script. In short, this example code will test for the bug and set a flag that will cause RotBetween function to be called if the bug exists, instead of the built-in llRotBetween function.</p>
<p>All of the example script should be copied into your code with the exception of the default state. The only section of code in the default state that you really need is the contents of state_entry.</p>
<p>Also as noted in the comments, change all occurrences of llRotBetween to XXRotBetween, in your original code. Of course you don&#8217;t want to inadvertently change the llRotBetween in the supplied XXRotBetween function or you could cause a loop if the bug is not detected.  XXRotBetween would endlessly call itself and what good would that do?</p>
<p>The example code will check for the llRotBetween bug once when it is reset and then use either the built-in llRotBetween function or the substitute RotBetween function as necessary.  The supplied XXRotBetween function is where this decision is made based on the flag set by the test that is conducted in state_entry.</p>
<p>Since the test for the bug only occurs when the script is reset, you could be using the substitute code even after the bug was gone. But you can reset the script at any time and it will check for the bug again. I didn&#8217;t want to perform this bug check every time because it just seems so redundant, but that&#8217;s up to you and what you want your code to do.</p>
<p>The example works in both Second Life or OpenSim. The bug does not exist in Second Life so the example script will not use the substitute RotBetween function in Second Life (unless you force it to). This structure allows you to use the same script between Second Life and OpenSim without change, even though the substitute function should not actually get called in Second Life.</p>
<p>And now, here is the code&#8230;</p>
<pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace;color: #800000;background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px;overflow: auto;width: 100%"><code>// llRotBetween Override Example
//
// Example of how to override the llRotBetween code to bypass an OpenSim bug.
//
// The bug has been opened under OpenSim Mantis 4784.
//
// Change all occurances of llRotBetween in your original script to XXRotBetween, so the
// llRotBetween call can be intercepted if necessary.
//
// Copy the appropriate portions of this code into your script. Basically, you need the global
// definition for the gRotBetweenBug flag, the XXRotBetween subroutine, the RotBetween subroutine
// and the bug detection code in state_entry.  The touch event is just for testing so may not be
/// appropriate.
//
// The one llRotBetween call you don't want to change is the one inside the XXRotBetween
// subroutine.  That llRotBetween call will be used by the script if the bug is not detected. so
// this code can be left inside your original script and will use the llRotBetween call or the
// internal subroutine, whichever is appropriate.
//
// This example only detects the bug at default state_entry so the script would need to be reset
// to check for the bug again.
//
// Micheil Merlin - 04/29/2010
// Updated - 07/02/2010

// Copy all of this section to your script.
// Copy from here   &#124;
//                  &#124;
//                  \/
integer gRotBetweenBug = FALSE;                     // llRotBetween bug.

// Intercept to handle potential llRotBetween bug.
rotation XXRotBetween(vector a, vector b)
{
    rotation between;                               // Rotation between vectors.
    // Handle opensim llRotBetween bug.
    if (!gRotBetweenBug)
    {
        between = llRotBetween(a, b);               // Call standard lsl llRotBetween function.
    }
    else
    {
        between = RotBetween(a, b);                 // Call internal RotBetween fucntion.
    }
    return between;
}

// Replacement internal subroutine to perform the llRotBetween function.
// Micheil Merlin - 4/29/2010
rotation RotBetween(vector a, vector b)
{
    float dot;                                      // Dot product.
    vector axis;                                    // Cross product.
    vector orthogonal;                              // Orthogonal vector for degenerate case.
    float qs;                                       // Quaternion s value.
    rotation between;                               // Calculated rotation.
    float mag;                                      // Magnitude for quaternion normalization.
    // Check for zero vectors. If either is zero, vector normalization will create undefined
    // values so just set the answer to zero rotation.
    if (a == ZERO_VECTOR &#124;&#124; b == ZERO_VECTOR)
    {
        between = ZERO_ROTATION;
    }
    // Otherwise continue with rotation calculation.
    else
    {
        a = llVecNorm(a);                           // Normalize vector a.
        b = llVecNorm(b);                           // Normalize vector b.
        dot = a * b;                                // Get the dot product between vectors.
        // There are two degenerate cases possible.  These are for vectors 180 or
        // 0 degrees apart. These have to be detected and handled individually.
        //
        // Check for vectors 180 degrees apart.
        // A dot product of -1 would mean the angle between vectors is 180 degrees.
        if (dot &lt; -0.9999999)
        {
            // First assume X axis is orthogonal to the vectors.
            orthogonal = &lt;1.0, 0.0, 0.0&gt;;
            orthogonal = orthogonal - (a * (a.x / (a * a)));
            mag = llVecMag(orthogonal);             // Get orthogonal magnitude.
            // Validate vector is not near 0. Near 0 vectors can create unanticipated
            // rotations.
            if (mag &gt; 0.0001)                       // Validate vector is not near 0.
            {
                // Create normalized rotation from orthogonal.
                between = &lt;orthogonal.x/mag, orthogonal.y/mag, orthogonal.z/mag, 0.0&gt;;
            }
            // If not X, then use Z axis.
            else
            {
                between = &lt;0.0, 0.0, 1.0, 0.0&gt;;     // Set 180 z rotation.
            }
        }
        // Check for parallel vectors.
        // A dot product of 1 would mean the angle between vectors is 0 degrees.
        else if (dot &gt; 0.9999999)
        {
            between = ZERO_ROTATION;
        }
        else
        {
            axis = a % b;                           // Get the axis of rotation.
            qs = 1.0 + dot;                         // Quat S value = length unit vec + dot product.
            // Calcuate the magnitude of the rotation.
            mag = llSqrt((axis.x * axis.x) + (axis.y * axis.y) + (axis.z * axis.z) + (qs * qs));
            between = &lt;axis.x/mag, axis.y/mag, axis.z/mag, qs/mag&gt;; // Normalize rotation.
        }
    }
    return between;                                 // Return the rotation.
}
//              /\
//              &#124;
// To here _____&#124;

default
{
    // Copy the contents of this state_entry to the appropriate location in your script. This
    // is the detection of the bug and the setting of the flag that XXRotBetween will look
    // at to decide whether or not to call the RotBetween function.
    state_entry()
    {
        // Check for llRotBetween bug related to 180 and 0 degree rotations.
        if (llRotBetween(&lt;1.0, 0.0, 0.0&gt;, &lt;-1.0, 0.0, 0.0&gt;) == &lt;0.0, 0.0, 0.0, 1.0&gt;)
        {
            // This message is just an indictor to the owner regarding the dectection of
            // the bug. Modify or remove as desired.
            llOwnerSay(&quot;Detected llRotBetween bug. Compensating.&quot;);
            gRotBetweenBug = TRUE;                  // Indicate bug present.
        }
    }

    on_rez(integer num)
    {
        llResetScript();                            // Reset script on rez.
    }

    // The touch event is for testing. This event would not be copied into the script.
    touch_start(integer num)
    {
        rotation rot;
        rot = XXRotBetween(&lt;1.0, 0.0, 0.0&gt;, &lt;-6.0, 0.0, 0.0&gt;);
        llOwnerSay(&quot;Rotation =&quot; + (string)rot);
    }
}
</code></pre>
<p><strong></p>
<p>The Tools I Used to Create the Patches</strong><br />
<br />
OpenSim can be compiled on Linux or Windows.</p>
<p>Justin Clark-Casey points out that there are a couple of conditions under which you will have to use the 32-bit launcher to run OpenSim on a 64-bit system. If you are using a 64-bit OS and the supplied ODE physics engine or the SQLite database, you will need to use the OpenSim.32bitLaunch.exe executable instead of the OpenSim.exe executable.</p>
<p>If you don&#8217;t use ODE or SQLite, then OpenSim should run in 64-bit mode and you can use the OpenSim.exe executable on either a 64-bit or 32-bit OS.</p>
<p>I use Windows 7 64-bit with <a href="http://www.microsoft.com/express/Windows/">Microsoft Visual C# 2010 Express</a> and <a href="http://tortoisesvn.tigris.org/">TortoiseSVN</a>.</p>
<p>TortoiseSVN is developed under the <a href="http://en.wikipedia.org/wiki/Gpl">GPL</a> so it is completely free to download and use. TortoiseSVN is the tool that can be used with Windows to interface with the OpenSim source code repository. It will enable you to download the most recent development level of the source code and generate patches from changes you make to the code</p>
<p>The Express version of Visual C# is also free although you have to register for a key. Be sure to use C# as opposed to C++.</p>
<p>I set the solution platform to x86 in Visual C# 2010 Express. For me it was defaulting to Itanium.</p>
<blockquote><p>Yuck on Itanium</p></blockquote>
<p>And to start OpenSim, I have to use the OpenSim.32bitLaunch.exe executable as opposed to the OpenSim.exe executable, because I&#8217;m also using the ODE physics engine.</p>
<p>The <a href="http://opensimulator.org/wiki/Development">OpenSim Dev Home</a> page has a great deal of documentation to assist in building OpenSim from source with information on selecting different database options, using Windows or Linux, etc.</p>
<p>If you want a quick and easy start to just running OpenSim standalone on your own system and aren&#8217;t ready to compile from source yet, go check out the <a href="http://www.metaverseink.com/blog/?p=21">Diva Distribution</a> from Diva Castro.</p>
]]></content:encoded>
			<wfw:commentRss>http://iliveisl.com/adventures-in-opensim-llrotbetween/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>Scripting Tips: Configure by notecard</title>
		<link>http://iliveisl.com/scripting-tips-configure-by-notecard/</link>
		<comments>http://iliveisl.com/scripting-tips-configure-by-notecard/#comments</comments>
		<pubDate>Tue, 08 Jun 2010 01:33:52 +0000</pubDate>
		<dc:creator>Micheil Merlin</dc:creator>
				<category><![CDATA[reaction grid]]></category>
		<category><![CDATA[second life]]></category>
		<category><![CDATA[opensim]]></category>
		<category><![CDATA[scripts]]></category>

		<guid isPermaLink="false">http://blog.iliveisl.com/?p=3924</guid>
		<description><![CDATA[A long time ago, in a blog far, far away&#8230;well, it has been a long time but maybe not that long. Or maybe it has been a long time. This post has been sitting out in the queue for weeks now and I bet Ener is tired of seeing it :). Continuing on a theme [...]]]></description>
				<content:encoded><![CDATA[<p>A long time ago, in a blog far, far away&#8230;well, it has been a long time but maybe not that long. Or maybe it has been a long time. This post has been sitting out in the queue for weeks now and I bet Ener is tired of seeing it :).</p>
<p>Continuing on a theme beginning with <a href="http://iliveisl.com/mono-and-bytecode-sharing/">“Mono Bytecode Sharing“</a>, followed by <a href="http://iliveisl.com/scripting-tips-does-your-script-need-socks/">“Does your script need socks“</a>, and then by <a href="http://iliveisl.com/scripting-tips-put-object-description-to-good-use/#comments">&#8220;Put object description to good use&#8221;</a>, in this post, we&#8217;ll look at using notecards for configuring options for a script.</p>
<p>To summarize the theme again, being able to configure scripts for multiple purposes has at least two advantages.</p>
<li>Scripts that don&#8217;t need to be compiled to make small parameter changes support bytecode sharing. This point likely only applies to SL itself and not <a href="http://opensimulator.org/wiki/Main_Page">OpenSim</a>. In the recent months I&#8217;ve spent a good bit of time in OpenSim and scripts are handled differently there. I don&#8217;t completely understand all that is going on with script compilation and execution in OpenSim and rather than pass on inaccurate information, I won&#8217;t try to explain my understanding of it. But, I think the OpenSim approach does have advantages even if bytecode sharing isn&#8217;t likely one of them.</li>
<li>Being able to configure a single script to serve multiple purposes potentially makes a script easier to maintain. This concept has universal applicability in SL, OpenSim and even RL (what&#8217;s that???).</li>
<p></br><br />
Notecard processing in SL is really fairly easy. The event oriented nature of LSL scripting combined with the asynchronous implementation of reading notecard lines can be confusing at first. But after understanding what is happening, most people deal with it fairly well. And after you build one model, just copy it over and over again.</p>
<blockquote><p>So why are we doing this?</p></blockquote>
<p>I think using the socks or object description methods are easier but have limitations if you want to support multiple configuration options. Using notecards provides a nearly unlimited opportunity for configuration.</p>
<p>While not an absolute requirement, generally you probably want to see if your notecard exists before trying to read it. You can choose to make the notecard required or optional but still it&#8217;s good to know whether it is there or not.</p>
<blockquote><p>llGetInventoryType(NOTECARD)</p></blockquote>
<p>The <a href="http://lslwiki.net/lslwiki/wakka.php?wakka=llGetInventoryType"><em>llGetInventoryType</em></a> with a string variable naming the notecard is how you can tell if there is a notecard with the expected name in the objects inventory. The variable used to define the notecard name will likely need to be a global variable (defined at the top of the script outside of any subroutines or states). It needs to be global so its value is available inside events. More about that later. The function actually returns either the type of the item with the requested name or an <a href="http://lslwiki.net/lslwiki/wakka.php?wakka=INVENTORY_NONE"><em>INVENTORY_NONE</em></a> flag if there is no object by that name.</p>
<p>A sidenote on my variable naming conventions. I obtained this from some LSL style suggestions somewhere. For a variable that I treat as a constant, I capitalize all letters as in NOTECARD. For a variable that I&#8217;ve defined such that it is global but is not a constant, I begin the variable with a small &#8220;g&#8221; followed by a capital letter that begins the descriptive name. For a variable that is not global but only lives inside a subroutine or event, I leave as all lowercase.</p>
<blockquote><p>if (llGetInventoryType(NOTECARD) == INVENTORY_NOTECARD)</p></blockquote>
<p>Assuming the string NOTECARD contains the desired notecard name, this <em><strong>if</strong></em> statement will be true if the notecard exists.</p>
<p>The <a href="http://lslwiki.net/lslwiki/wakka.php?wakka=llGetNotecardLine"><em>llGetNotecardLine</em></a> function is the next important function.</p>
<blockquote><p>gQuery = llGetNotecardLine(NOTECARD, gLine);</p></blockquote>
<p>In this example, NOTECARD is still the string that contains the name of the notecard. The gLine variable is the actual notecard line to read and will likely need to be a global variable. This should always start as a zero and be incremented with each read. If you don&#8217;t increment it, you will continue to read the same line over and over. The gQuery variable returns a unique key that can be used to identify that data is being returned from the function. And yes, this will likely need to be a global variable.</p>
<p>This is where LSL differs from most high level languages you might know. You&#8217;d normally expect data to be available to the next sequential statement following <em><strong>llGetNotecardLine</strong></em>. Remember I mentioned event driven and asynchronous before? In LSL, data is returned via the <a href="http://lslwiki.net/lslwiki/wakka.php?wakka=dataserver"><em>dataserver</em></a> event. LSL returns lots of stuff via the <em><strong>dataserver</strong></em> event and that&#8217;s why we need to save the key from <em><strong>llGetNotecardLine</strong></em> as in the example that uses the gQuery variable to hold the returned key, above.</p>
<p>The key point here is don&#8217;t write your script expecting that the read has happened after the <em><strong>llGetNotecardLine</strong></em> function is called. For the most part, the rest of the action will take place in the <em><strong>dataserver</strong></em> event until you are completely done reading the notecard. The example supplied can serve as a model and demonstrates a technique to use to help you logically separate the processing of the notecard data from the main function of your script.</p>
<p>Now to the <em><strong>dataserver</strong></em> event. The first thing you need to do is check that the triggered event is the one that gives you the notecard line. You do this by checking that the key supplied to you in the event matches the key you saved from the last <em><strong>llGetNotecardLine</strong></em>.</p>
<blockquote><p>dataserver(key query_id, string data)</p></blockquote>
<p>At entry to <em><strong>dataserver</strong></em>, the variable passed as the first parameter is the key that goes with the event and the second variable is the data. In the case of a <em><strong>dataserver</strong></em> event for <em><strong>llGetNotecardLine</strong></em>, the data will be a string that contains the notecard line or an indication that there are no more lines.</p>
<blockquote><p>if (query_id == gQuery)</p></blockquote>
<p>Continuing with our example, this <em><strong>if</strong></em> statement will be true if this <em><strong>dataserver</strong></em> event goes with the last <em><strong>llGetNotecardLine</strong></em>.</p>
<blockquote><p>if (data == EOF)</p></blockquote>
<p>We need to have a way to know that there is no more notecard data.  If the string variable contains the <a href="http://lslwiki.net/lslwiki/wakka.php?wakka=EOF"><em>EOF</em></a> indicator (End of File), there is no more data. So in this example, the <em><strong>if</strong></em> statement is true if there is no more data. So the code that goes with this statement being true needs to do whatever you want to happen after you&#8217;ve read all of the notecard. Sometimes this can be a little tricky to think about as you are inside the <em><strong>dataserver</strong></em> event and what are you gonna do? If you just have something simple to do maybe you can just call a subroutine or even just include the code inline following the <em><strong>if</strong></em> statement. I mentioned earlier that the example would illustrate a way to logically disconnect the notecard processing from all subsequent activity. I often do this by changing states to a new state.</p>
<blockquote><p>state begin;</p></blockquote>
<p>In this example, I switch to a state I imaginatively call begin. Begin as in &#8220;now I will begin to use my data&#8221;. But we&#8217;re getting a little ahead and we haven&#8217;t parsed the data yet. So, if the check for <em><strong>EOF</strong></em> is not true, we do the <em><strong>else</strong></em> part of the <em><strong>if</strong></em> and in the <em><strong>else</strong></em> part, we parse the data.</p>
<p>If you have some complicated parsing to do, it might be cleanest to put it into a subroutine. In many cases, that would make the script easier to read and understand. In this case we are just going to do a little bit of parsing so we won&#8217;t call a subroutine to do it.</p>
<p>Parsing a set of commands can be fairly complicated. Out in the real world, there are two very old programs that originated on Unix that can be used to create parsers for complicated command input.  <a href="http://en.wikipedia.org/wiki/Lex_%28software%29">Lex</a> and <a href="http://en.wikipedia.org/wiki/Yacc">YACC</a>.  The name of Lex comes from &#8220;lexical analyzer&#8221; and YACC means &#8220;Yet Another Compiler Compiler&#8221;.  Lex and YACC are great tools and they or their derivatives are still used today.  But aside from the fact that Lex and YACC generate C code and not LSL, they would likely be way to heavy for the vast majority of parsing requirements needed for LSL.  So, we&#8217;ll approach parsing in a little bit simpler way.</p>
<p>Our grammer will be pretty simple.</p>
<blockquote><p>keyword=keyvalue;</p></blockquote>
<p>This will allow a lot of flexibility but require very simple parsing.</p>
<p>Before getting serious with the parsing, we want to do a couple of things. Check to see if the line from the notecard actually contains any data and check to see if it is a comment. In this example we are using a &#8220;#&#8221; in the first position to indicated the line is a comment. I always include the capability to have comments in the notecard as it is a good way to self-document the syntax of the options you want to support.</p>
<p>Check for an empty line.</p>
<blockquote><p>if ( llStringTrim(data, STRING_TRIM) != &#8220;&#8221; )</p></blockquote>
<p>If this statement is true, the line is not blank and we continue to process it. We used <a href="http://lslwiki.net/lslwiki/wakka.php?wakka=llStringTrim"><em>llStringTrim</em></a> to remove any leading and trailing blanks from the line in case it only has blanks, otherwise the compare with a null string wouldn&#8217;t work. Since we used the <em><strong>llStringTrim</strong></em> function inside the conditional without doing an assignment, the string will be left unchanged for further processing.</p>
<p>Check for a comment line.</p>
<blockquote><p>if (llGetSubString(data, 0, 0) != &#8220;#&#8221;)</p></blockquote>
<p>If this statement is true, then the line does not contain the selected comment character in the first position and we continue. The <a href="http://lslwiki.net/lslwiki/wakka.php?wakka=llGetSubString"><em>llGetSubString</em></a> takes three parameters. The string to work on, the starting position where to begin extracting characters and the ending position. The positions are relative to zero and a &#8220;0, 0&#8243; means take the 1st character from the string.</p>
<p>To assist in taking apart a notecard line with data on it, we&#8217;ll use <a href="http://lslwiki.net/lslwiki/wakka.php?wakka=llSubStringIndex"><em>llSubStringIndex</em></a> to look for the &#8220;=&#8221; and &#8220;;&#8221; in our grammer. <a href="http://lslwiki.net/lslwiki/wakka.php?wakka=llParseString2List"><em>llParseString2List</em></a> is another function that can be used to easily parse a line of data into a list of words or strings. But in this example, we&#8217;ll stick with <em><strong>llSubStringIndex</strong></em>.</p>
<blockquote><p>i = llSubStringIndex(data, &#8220;=&#8221;);<br />
j = llSubStringIndex(data, &#8220;;&#8221;);</p></blockquote>
<p>These two functions will look for our two separators and set their respective index variables, i and j, to the relative locations in the string. The function returns a -1 if nothing is found in the string.</p>
<blockquote><p>if (i == -1 || j == -1)</p></blockquote>
<p>This <em><strong>if</strong></em> statement will validate that we found both of our separators. If either of the variables is set to -1, then we write out an error message and proceed to get the next data card. If we found both of our separators, then we continue parsing this line.</p>
<blockquote><p>keyword = llGetSubString(data, 0, i &#8211; 1);</p></blockquote>
<p>This will set the keyword variable to the string found looking from the beginning of the line to the first &#8220;=&#8221;, not including the &#8220;=&#8221;. Remember i is the location in the string of &#8220;=&#8221;. We&#8217;re just doing simple parsing here and not directly checking for every possible mistake someone might make. For instance, these checks don&#8217;t directly check to see that the &#8220;=&#8221; comes before the &#8220;;&#8221;. We just look to see if they are both in the string and get the substrings based on their locations. This could mean that we get garbage for our variables. But if so, the following checks will fail anyway.</p>
<p>You might want to do some things to make the grammer a little less stringent. For instance, we assume there are no spaces at the beginning of the line and before the &#8220;=&#8221;. To allow for the possibility that there are some spaces and permit things to work anyway, you can include a function to drop extra spaces before and after the key word. Also, if the case isn&#8217;t important, you can translate things to lower case and then code assuming everything is in lower case.</p>
<blockquote><p>keyword = llStringTrim(llToLower(keyword), STRING_TRIM);</p></blockquote>
<p>This will drop leading and trailing spaces from keyword and translate the string to lower case.</p>
<blockquote><p>keyvalue = llGetSubString(data, i + 1, j &#8211; 1);</p></blockquote>
<p>Next we set the variable keyvalue, to the substring that starts at the first position after the &#8220;=&#8221; and ends at the position prior to the &#8220;;&#8221;.</p>
<blockquote><p>keyvalue = llStringTrim(keyvalue, STRING_TRIM);</p></blockquote>
<p>In this case, we just remove leading and trailing spaces. You could also translate to lower case but there may be times when saving values, that you want to keep the case as specified. For instance, if you are supplying the text of a message to write, you likely would want to supply a mixed case value.</p>
<p>So at this point, we&#8217;ve collected a key word in the keyword variable and a value in the keyvalue variable. So, we&#8217;re ready to start checking and setting options.</p>
<p>We have a beginning <em><strong>if</strong></em> statement followed by as many <em><strong>else if</strong></em> statements as we need to compare all of our desired keywords. For any matched key word, the required function is performed with the corresponding value.</p>
<blockquote><p>gSeconds = (float)keyvalue;</p></blockquote>
<p>We won&#8217;t go through each of these compares but I will point out one thing. The example above is where we take something read in as a string and convert it to a floating point value.</p>
<p>There is an important point to note regarding converting strings to other types. If you perform an explicit type cast such as <em><strong>(float)</strong></em> and the string isn&#8217;t really a numeric string, LSL just quietly gives you a zero. And, there are no functions to check what kind of data the string is composed of. So, if you wanted to validate that someone entered a string of digits and not a string of alpha characters, you&#8217;re likely left with constructing a messy function to check that the contents of the string is all digits or digits and a period. Since I mostly create stuff for myself or friends, I just let this one go and consider it not worth the effort. If you&#8217;re creating something to sell, you&#8217;ll have to consider just how much you think you need to protect your customers from making mistakes.</p>
<p>If we fall through the <em><strong>if</strong></em> statement and all of the <em><strong>else if</strong></em> statements to the <em><strong>else</strong></em> statement, then we&#8217;ve encountered a key word/key value pair that we don&#8217;t know how to process.</p>
<blockquote><p>llOwnerSay(&#8220;Configuration notecard contains unknown keyword at line &#8221; + (string)gLine + &#8220;.\n Keyword found is &#8221; + keyword + &#8220;\nCorrect the error and reset.&#8221;);</p></blockquote>
<p>To help someone pinpoint their error, it&#8217;s a good idea to give them as much information as possible. This example will print the keyword and value along with the relative line in the notecard. Remember that notecard lines are relative to zero. If this is going to confuse someone, you could add one to the notecard line variable to help someone out.</p>
<p>After completely processing this notecard line, we need a new one.</p>
<blockquote><p>++gLine;<br />
gQuery = llGetNotecardLine(NOTECARD, gLine);</p></blockquote>
<p>The <em><strong>llGetNotecard</strong></em> function reads the line number you tell it to. So we first need to increment the line number with <em><strong>++gLine</strong></em> and then call the <em><strong>llGetNotecardLine</strong></em> function. In our example, we&#8217;re now at the end of the <em><strong>dataserver</strong></em> event and have nothing else to do. So the script will wait for the next event to occur which will likely be another notecard line. As mentioned earlier, this process will repeat until the <em><strong>EOF</strong></em> indicator is returned and we switch to the begin state.</p>
<p>As mentioned earlier, I use this state switch at the completion of processing the notecard, as a way to cleanly divide the logic between dealing with the notecard and everything else that happens that depends on the notecard.  It is not required to use different states.</p>
<p>Three key words are processed in this example. They are seconds, debug and text. The seconds key word is only used to demonstrate the conversion of numeric data. The debug key word doesn&#8217;t do much either except print some additional messages if set to yes. The text key word is used to set the floating text for the object.</p>
<p>The example script also contains two events that I generally include in any script that processes notecards.  The first is the <a href="http://lslwiki.net/lslwiki/wakka.php?wakka=on_rez"><em>on_rez</em></a> event used to detect the object being rezzed from inventory and to reset the script when that happens. The other event is the <a href="http://lslwiki.net/lslwiki/wakka.php?wakka=changed"><em>changed</em></a> event used to detect an inventory change. The <em><strong>changed</strong></em> event is coded to cause a script reset and a reprocessing of the notecard. This is to support rereading the notecard if you&#8217;ve made changes to it.</p>
<p>And because there are two states in this example, both the <em><strong>on_rez</strong></em> and <em><strong>changed</strong></em> events are coded in each state. This is a downside of having multiple states. Event handlers are only effective in the state they are coded in. So any event that you want to handle in any state has to be coded in all states.</p>
<p>Now for the example code. As usual, this code example will work for both Second Life and <a href="http://opensimulator.org/wiki/Main_Page">OpenSim</a>. An example notecard follows the code.</p>
<pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace;color: #800000;background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px;overflow: auto;width: 100%"><code>// Config Demo - Notecard
//
// Sample code to demonstrate using a notecard to set configuration
// parameters.
//
// Micheil Merlin - 05/18/2010

string NOTECARD = &quot;Config&quot;;                             // Configuration notecard.
key gQuery;                                             // Notecard read key.
integer gLine = 0;                                      // Notecard line to read.
integer gError = FALSE;                                 // Error status.
float gSeconds = 0.0;                                   // Seconds value from notecard.
integer gDebug = FALSE;                                 // Debug flag from notecard.
string gText = &quot;&quot;;                                      // Hover text from notecard.


default
{
    state_entry()
    {
        llOwnerSay(&quot;Initializing...&quot;);
        // Check to see if a notecard with teh specified name is in the
        // object inventory.
        if (llGetInventoryType(NOTECARD) == INVENTORY_NOTECARD)
        {
            // If the notecard exists, get the first line. Save the key
            // so we can use it in the dataserver event to identify that
            // the event is for this notecard read.
            gQuery = llGetNotecardLine(NOTECARD, gLine);
        } else
        {
            // If no notecard exists, just switch to the begin state.
            // There are no configuration parameters to change.
            state begin;
        }
    }

    // When object is rezzed, reset the script.
    on_rez(integer num)
    {
        llResetScript();                                // Reset the script.
    }

    // Use the changed event to see if the inventory has changed. We can use
    // this to detect that the notecard has been changed and reset the script
    // so the notecard can be reprocessed. There is no way to determine what
    // in the inventory has changed without doing some sort of processing on the
    // inventory. So, the script will be reset regardless of what changed in the
    // inventory.
    changed(integer change)
    {
        // If inventory has changed, assume script reset is needed. Many other
        // things can trigger the change event but in this case, we are only
        // looking for changed inventory.
        if (change == CHANGED_INVENTORY)
        {
            llResetScript();                            // Reset the script.
        }
    }

    // Dataserver event to process notecard data.
    dataserver(key query_id, string data)
    {
        integer i;                                      // Temp index.
        integer j;                                      // Temp index.
        string keyword;                                 // Configuration keyword.
        string keyvalue;                                // Configuration value.
        // The dataserver event is used for many things. To make sure we process
        // the correct data, check that the key is from the last notecard read
        // request. In this sample code, the dataserver event should not be
        // triggered for any other purpose than to present the notecard data.
        // But it is still a good coding practice to check to make sure
        // the event is what you think it is.
        if (query_id == gQuery)
        {
            // If 'End of File' is returned, then there is no more data. Switch
            // to the begin state.
            if (data == EOF)
            {
                state begin;
            }
            // Process the notecard data.
            else
            {
                // Compress out blanks and make sure the notecard line is not empty.
                if ( llStringTrim(data, STRING_TRIM) != &quot;&quot; )
                {
                    // A notecard line with a '#' in the first position is taken to be a
                    // comment and will not be further processed.
                    if (llGetSubString(data, 0, 0) != &quot;#&quot;)
                    {
                        // If line is not a comment, get keyword and value.
                        // The format of the data we are looking for is...
                        // keyward=keyvalue;
                        i = llSubStringIndex(data, &quot;=&quot;);    // Look for keyword/keyvalue separator.
                        j = llSubStringIndex(data, &quot;;&quot;);    // Look for end of line marker.
                        if (i == -1 &#124;&#124; j == -1)
                        {
                            // Check for 'keyword=value;' syntax.
                            llOwnerSay(&quot;Configuration notecard contains invalid syntax at list &quot; +
                                (string)gLine + &quot;. Data line follows.\n&quot; + data +
                                &quot;\nCorrect the error and reset.&quot;);
                            gError = TRUE;                  // Set error condition.
                        } else
                        {
                            // Extract the keyword and keyvalue strings.
                            keyword = llGetSubString(data, 0, i - 1);
                            // Translate keyword to lower case to reduce problems from typos and
                            // also remove leading and trailing blanks.
                            keyword = llStringTrim(llToLower(keyword), STRING_TRIM);
                            keyvalue = llGetSubString(data, i + 1, j - 1);
                            // Only remove leading and trailing blanks from keyvalue. Assume
                            // the existing case is what is intended. There may be specific
                            // uses of keyvalue where it still may be desireable to force
                            // everything to one case.
                            keyvalue = llStringTrim(keyvalue, STRING_TRIM);
                            // Process keywords in config notecard.
                            if (keyword == &quot;seconds&quot;)       // seconds keyword.
                            {
                                // We don't really have anything to do with the seconds value.
                                // We are just demonstrating translating a string from
                                // notecard to a float.
                                gSeconds = (float)keyvalue; // Translate value to float and save.
                            } else if (keyword == &quot;debug&quot;)  // debug keyword.
                            {
                                // Here is a case where we want to force a compare to lower case
                                // as we are using keyvalue as on on/off switch.
                                // Also, we assume that any other reply than yes means no. If you
                                // really want to make sure someone doesn't just typo the yes and
                                // it is taken as no, you'd want to check for yes or no and then
                                // indicate an error if something else was encountered.
                                if (llToLower(keyvalue) == &quot;yes&quot;)
                                {
                                    gDebug = TRUE;          // Set debug flag.
                                }
                            } else if (keyword == &quot;text&quot;)   // text keyword.
                            {
                                gText = keyvalue;           // Set text value.
                            } else
                            {
                                llOwnerSay(
                                    &quot;Configuration notecard contains unknown keyword at line &quot;
                                    + (string)gLine + &quot;.\n Keyword found is &quot; + keyword +
                                    &quot;\nCorrect the error and reset.&quot;);
                                gError = TRUE;              // Set error condition.
                            }
                        }
                    }
                }
                // Request the next notecard line.
                ++gLine;
                gQuery = llGetNotecardLine(NOTECARD, gLine);
            }
        }
    }
}

state begin
{   // Initialization completed.
    state_entry()
    {
        // Make some use of the debug flag. Normally, you'd sprinkle this through your
        // script printing values where ever you wanted to check that things were as
        // expected.
        if (gDebug)
        {
            llOwnerSay(&quot;Debug mode is on.&quot;);
            llOwnerSay(&quot;Seconds=&quot; + (string)gSeconds + &quot;.&quot;);
            llOwnerSay(&quot;Value of text is &quot; + gText + &quot;.&quot;);
        }
        // Check to see if the error condidition was set during configuration. We
        // may not want to do anything else if a configuration error occurred.
        if (gError == FALSE)
        {
            llOwnerSay(&quot;Ready to run.&quot;);
            llSetText(gText, &lt;1.0, 1.0, 1.0&gt;, 1.0);         // Set text as requested.
        } else
        {
            llOwnerSay(&quot;Not ready to run.&quot;);
        }
    }

    // Since events are specfiic to a state, we need to duplicate the on_rez event in this
    // state also.
    on_rez(integer num)
    {
        llResetScript();                                    // Reset script.
    }

    // Since events are specific to a state, we need to duplicate the changed event in this
    // state also.
    changed(integer change)
    {
        // If inventory has changed, assume script reset is needed.
        if (change == CHANGED_INVENTORY)
        {
            llResetScript();                                // Reset script.
        }
    }

    // Use the touch event to report what is in the settings.
    touch_start(integer num)
    {
        string debugstr;                                    // Text string for debug flag.
        if (gDebug)                                         // Translate debug flag to yes or no.
        {
            debugstr=&quot;yes&quot;;
        } else
        {
            debugstr=&quot;no&quot;;
        }
        llOwnerSay(&quot;Debug=&quot; + debugstr + &quot;.&quot;);
        llOwnerSay(&quot;Seconds=&quot; + (string)gSeconds + &quot;.&quot;);
        llOwnerSay(&quot;Text=&quot; + gText + &quot;.&quot;);
    }
}
</code></pre>
<p></br><br />
The following is the text for a notecard to go along with this coding example. Paste this text into a notecard named Config to work with this example.</p>
<pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace;color: #800000;background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px;overflow: auto;width: 100%"><code># Config notecard for Config Demo script.
# debug may be set to yes or no.
debug=yes;
# This text will be used to set the floating text of the object.
text=Config Demo;
# Supply a numeric value for seconds.
seconds=5;
</code></pre>
]]></content:encoded>
			<wfw:commentRss>http://iliveisl.com/scripting-tips-configure-by-notecard/feed/</wfw:commentRss>
		<slash:comments>9</slash:comments>
		</item>
		<item>
		<title>Adventures in OpenSim: The Submarine</title>
		<link>http://iliveisl.com/adventures-in-opensim-the-submarine/</link>
		<comments>http://iliveisl.com/adventures-in-opensim-the-submarine/#comments</comments>
		<pubDate>Sun, 07 Mar 2010 06:16:46 +0000</pubDate>
		<dc:creator>Micheil Merlin</dc:creator>
				<category><![CDATA[reaction grid]]></category>
		<category><![CDATA[second life]]></category>
		<category><![CDATA[micheil merlin]]></category>
		<category><![CDATA[opensim]]></category>

		<guid isPermaLink="false">http://blog.iliveisl.com/?p=3374</guid>
		<description><![CDATA[So&#8230;I always wanted to build a submarine. Not really a complicated thing for sure. I just never took the time. I was standing on a dock one day on one of Ener&#8217;s Reaction Grid sims and decided that I&#8217;d finally take a few minutes and whip out a sub. There&#8217;s lots of open water there [...]]]></description>
				<content:encoded><![CDATA[<p>So&#8230;I always wanted to build a submarine. Not really a complicated thing for sure. I just never took the time.</p>
<p>I was standing on a dock one day on one of Ener&#8217;s Reaction Grid sims and decided that I&#8217;d finally take a few minutes and whip out a sub. There&#8217;s lots of open water there and I had the intention of eventually making the sub putter around the bay.</p>
<p>So, here the sub sits before trying to make it move.</p>
<blockquote><p><img src="http://lh3.ggpht.com/_xnN75HJ97Hc/S5KInWoT1wI/AAAAAAAAAFA/846wVDOmuyk/s400/Submarine%20at%20Atra%20Sea%20Peninsula%20%28136%2C%20162%2C%2018%29.jpg" alt="Submarine" /><br />
Submarine at Alta Sea Peninsula</p></blockquote>
<p>For Burning Life 09, I&#8217;d written a path following script to use to make Nickola&#8217;s clown car move and also to float her hot air balloon around the exhibit.  I&#8217;d originally intended to use Loki Ball&#8217;s Slynergy Commercial Patheditor but needed a little more control than the Patheditor provided.  I did use Patheditor to build the path but created my own path follower so I could more easily make the animated object trigger other things in the exhibit.</p>
<p>If you&#8217;re interested in Loki&#8217;s path editor, look him up in SL and check his picks for the location of his store.</p>
<p>So, now to the Reaction Grid sim. There I stood with no tools&#8230;lol. I could manually create the path for the follower script to follow but what a pain that is. Particularly if you want to change it or do more things in the future. So, I created a path builder tool to be able to feed my path follower with. The path builder still needs lots of work but is far enough along to actually record a path.</p>
<p>Next, I uploaded my path follower script from SL. And, it compiled with no errors. But at runtime I encountered errors with llRotLootAt and llStopLookAt not being implemented. So I replaced them with llSetRot just to get things going and see how the sub would look. I&#8217;ve seen some OpenSim blog notes and it looks like llRotLookAt has now been implemented in the code so I assume it will show up eventually as grid operators adopt future OpenSim versions and releases.</p>
<p>I seem to be eternally rotationally challenged and generally have to mess with things a bit to get objects to face the direction I intended when trying to move them around a path. But anyway, I created a small path and moved a small object (after finding the right rotations) successfully around the path. Moved very smooth. No apparent issues at all. I thought&#8230;</p>
<blockquote><p>this is going really well :)</p></blockquote>
<p>The next step was to try to make the sub move around the bay. I swam out into the bay and placed my little path markers out to build a simple path for the sub to follow. Recorded the path, popped it in a notecard with a few other directives, put it all in a copy of the sub, held my breath and told it to take off.</p>
<blockquote><p><img src="http://lh5.ggpht.com/_xnN75HJ97Hc/S5KInc_ZC_I/AAAAAAAAAFE/-d3aDHndZAE/s400/Submarine%20after%20first%20movement%20test.jpg" alt="Submarine after the first move test" /><br />
After the maiden voyage!</p></blockquote>
<p>I&#8217;m just glad I had copies. :)</p>
]]></content:encoded>
			<wfw:commentRss>http://iliveisl.com/adventures-in-opensim-the-submarine/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Scripting Tips: Put object description to good use</title>
		<link>http://iliveisl.com/scripting-tips-put-object-description-to-good-use/</link>
		<comments>http://iliveisl.com/scripting-tips-put-object-description-to-good-use/#comments</comments>
		<pubDate>Thu, 28 Jan 2010 01:20:30 +0000</pubDate>
		<dc:creator>Micheil Merlin</dc:creator>
				<category><![CDATA[second life]]></category>
		<category><![CDATA[scripts]]></category>

		<guid isPermaLink="false">http://blog.iliveisl.com/?p=3036</guid>
		<description><![CDATA[Continuing on a theme beginning with &#8220;Mono Bytecode Sharing&#8220;, followed by &#8220;Does your script need socks&#8220;, this is another post describing another method to pass configuration options to scripts.  I really struggled with the title of this one and just couldn’t come up with anything near as cute as &#8220;Does your script need socks&#8220;.  Oh [...]]]></description>
				<content:encoded><![CDATA[<p>Continuing on a theme beginning with &#8220;<a href="http://iliveisl.com/mono-and-bytecode-sharing/">Mono Bytecode Sharing</a>&#8220;, followed by &#8220;<a href="http://iliveisl.com/scripting-tips-does-your-script-need-socks/">Does your script need socks</a>&#8220;, this is another post describing another method to pass configuration options to scripts.  I really struggled with the title of this one and just couldn’t come up with anything near as cute as &#8220;<a href="http://iliveisl.com/scripting-tips-does-your-script-need-socks/">Does your script need socks</a>&#8220;.  Oh well…</p>
<p>To summarize the theme again, being able to configure scripts for multiple purposes has at least two advantages.</p>
<ul>
<li>Scripts that don’t need to be compiled to make small parameter changes support bytecode sharing.</li>
</ul>
<ul>
<li>Being able to configure a single script to serve multiple purposes potentially makes a script easier to maintain.</li>
</ul>
<p>In the last post I described a way to configure scripts by placing clothing items with special names inside the object.  Another way to set configuration parameters is to read them from the object description.</p>
<p>The object description is a string of up to 127 characters that can be both read and written from the script. Prior to January, 2008, the string used to be at least twice as long. But in order to address a couple of other bugs, LL changed the maximum length to 127. This in turn caused much disturbance within the community. Go take a look at <a href="https://jira.secondlife.com/browse/SVC-1394">SVC-1394</a> and related issues for more information.</p>
<p>The <a href="http://lslwiki.net/lslwiki/wakka.php?wakka=llGetObjectDesc">llGetObjectDesc</a> function is what is used to read the description of the object the script is in.  Actually, if the script is in a prim linked to other prims, it will only read the description from the prim containing the script.</p>
<blockquote><p>objdesc = llToLower(llStringTrim(llGetObjectDesc(), STRING_TRIM));</p></blockquote>
<p>In the example above, I’m saving the object description string in a variable called ‘objdesc’.  I also use the <a href="http://lslwiki.net/lslwiki/wakka.php?wakka=llToLower">llToLower</a> function to make the string lower case so I don’t have to worry about what case things are in. All compares I do will be in lower case.  And, I use the <a href="http://lslwiki.net/lslwiki/wakka.php?wakka=llStringTrim">llStringTrim</a> function to remove any leading and trailing blanks. It’s easy to put a blank somewhere you didn’t intend, so removing any leading and trailing blanks helps somewhat.</p>
<p>Following the <a href="http://lslwiki.net/lslwiki/wakka.php?wakka=llGetObjectDesc">llGetObjectDesc</a> code, the script goes through a series of if and else if statements comparing the string to my special selected settings.  In this case, ‘debug on’ and ‘debug off’.  Finding either of those, the script turns a debug flag on or off.  You can get as complex as you want here as long as you don’t go past the 127 character limit. The object description could hold several keywords to be used to set several options within your script.</p>
<p>Some peculiarities about the object description.</p>
<ul>
<li>If the description is null and if the object has been saved and taken from inventory, the function will return &#8216;(no description)&#8217; instead of null or a blank string. So, your script needs to allow for this if it is important to know if the description is null.</li>
<li>If the description is null and if the object has not been saved and taken from inventory, the function will return a null string.</li>
<li>If you’ve ever typed anything in the description and then tried to remove it, the description may now have spaces. You may need to be aware of this. If you use the <a href="http://lslwiki.net/lslwiki/wakka.php?wakka=llStringTrim">llStringTrim</a> function as I have, the string appear as null and you don’t have to worry about how many spaces might be there.</li>
<li>If you try to remove the description by deleting characters in the edit gui, it will look like it is gone but is not actually saved as a null when you get out of edit. The string will still be there when you look again. There are a few JIRAs open on this. You can set the description back to null by using the <a href="http://lslwiki.net/lslwiki/wakka.php?wakka=llSetObjectDesc">llSetObjectDesc</a>(“”) function.</li>
</ul>
<p>A few other notes about the sample script.</p>
<p>In the &#8220;<a href="http://iliveisl.com/scripting-tips-does-your-script-need-socks/">Does your script need socks</a>&#8221; sample, I used the <a href="http://lslwiki.net/lslwiki/wakka.php?wakka=changed">changed</a> event to detect the change of inventory and trigger the reprocessing of the options automatically.  There is no way to automatically detect the change of the description so you’ll have to have a way to tell the script to reread the description if you change it or just manually reset the script to make it read the description again.</p>
<p>In this sample, I put all of the option processing in the readdesc() subroutine and then used the <a href="http://lslwiki.net/lslwiki/wakka.php?wakka=touch_start">touch_start</a> event to trigger the readdesc() subroutine. Again, this is some sample code to demonstrate the approach and you may not want this to happen when the object is touched.  I also have the readdesc() in the <a href="http://lslwiki.net/lslwiki/wakka.php?wakka=state_entry">state_entry</a> and that may be the only place you want it in your script.</p>
<p>In some ways, this approach to configuration may be simpler than the socks approach. I’ve seen many examples of this object description approach in use within SL.  However, it is easy to type the wrong thing or otherwise mess up the object description so you’ll have to decide how much error checking for typos you need to have in your script.</p>
<p>And now for the sample code. This sample has been tested in both SL and <a href="http://opensimulator.org/wiki/Main_Page">OpenSim</a>.</p>
<pre style="border: 1px dashed #999999;padding: 5px;overflow: auto;font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace;color: #800000;background-color: #ffffff;font-size: 12px;line-height: 14px;width: 100%"><code>// Config Demo - Read Object Desc
//
// Script to demonstrate the use of the object description to supply
// parameters.
//
// The object description is checked to see if it says either 'debug on'
// or 'debug off'.  Set the gDebug flag accordingly.
//
// Micheil Merlin/SL - 1/1/2010

integer gDebug = 0;                 // Debug flag.

readdesc()
{
     string objdesc;             // Object description.
    // Read the description field for the object.
    // Translate to lower case and trim blanks from the end.
    objdesc = llToLower(llStringTrim(llGetObjectDesc(), STRING_TRIM));
    // Look for an object description of 'debug on' in lower case.
    if (objdesc == "debug on")
    {
        gDebug = 1;
    // Look for an object description of 'debug off' in lower case.
    } else if (objdesc == "debug off")
    {
        gDebug = 0;
    // Check for an empty object description.
    // Empty object descriptions could either be blanks or the string
    // '(no description)'.  Earlier, we trimmed blanks from the string
    // so if it was blanks, it is now a null string.
    } else if (objdesc == "" || objdesc == "(no description)")
    {
        llSay(0, "No object description exists.");
    // If the object description is not one of our choices or empty, then
    // say the string.
    } else
    {
        llSay(0, "Object Description of '" + objdesc +
            "' found. We weren't expecting this.");
    }
    llSay(0, "Debug is set to " + (string)gDebug);
    //
    // The object description processing is complete. Other code could be
    // inserted here.
    //
}

default
{
    state_entry()
    {
        readdesc();                 // Process object description.
    }

    // This event is triggered when the object is rezzed.
    on_rez(integer num)
    {
        llResetScript();            // Reset script when object rezzed.
    }

    // This event is triggered when the object is touched.
    touch_start(integer total_number)
    {
        readdesc();                 // Go check the object description.
    }
}

</code></pre>
]]></content:encoded>
			<wfw:commentRss>http://iliveisl.com/scripting-tips-put-object-description-to-good-use/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Scripting Tips: Does your script need socks?</title>
		<link>http://iliveisl.com/scripting-tips-does-your-script-need-socks/</link>
		<comments>http://iliveisl.com/scripting-tips-does-your-script-need-socks/#comments</comments>
		<pubDate>Sat, 02 Jan 2010 20:15:30 +0000</pubDate>
		<dc:creator>Micheil Merlin</dc:creator>
				<category><![CDATA[second life]]></category>
		<category><![CDATA[scripts]]></category>

		<guid isPermaLink="false">http://blog.iliveisl.com/?p=2815</guid>
		<description><![CDATA[Earlier I&#8217;d written a post on Mono and Bytecode Sharing. In that post, I mentioned that there were several ways that a script could be written to take configuration parameters. Being able to configure scripts for multiple purposes has at least two advantages. Scripts that don&#8217;t need to be compiled to make small parameter changes [...]]]></description>
				<content:encoded><![CDATA[<p>Earlier I&#8217;d written a post on <a href="http://iliveisl.com/mono-and-bytecode-sharing/">Mono and Bytecode Sharing</a>. In that post, I mentioned that there were several ways that a script could be written to take configuration parameters. Being able to configure scripts for multiple purposes has at least two advantages.</p>
<ul>
<li>Scripts that don&#8217;t need to be compiled to make small parameter changes support bytecode sharing.</li>
<li>Being able to configure a single script to serve multiple purposes potentially makes the script easier to maintain.</li>
</ul>
<p>One way to make a script configurable is to put socks in your object. Yeah, yeah, I know that sounds weird. But it is really a pretty easy way to set simple configuration parameters. And if you don&#8217;t like socks you could use any clothing object. The LSL functions that deal with clothing can&#8217;t actually tell what type of clothing it is.</p>
<p>Basically, what you do is place a clothing item with a particular name in the object. Then have the script read the object inventory looking for clothing items. If it finds an item with a name of a keyword that you&#8217;ve chosen, then set a flag, flip a switch or whatever you need to do in your script to make it behave differently.</p>
<p>First you have to create a pair of socks. Don&#8217;t worry. This is easy. You don&#8217;t have to do anything to them other than name them as their name is all we&#8217;re interested in. Open your inventory, select the &#8216;Clothing&#8217; folder and right click on it. On the menu that opens, select &#8216;New Clothing&#8217;, then &#8216;New Socks&#8217;. If you don&#8217;t rename them now, they&#8217;ll be called &#8216;New Socks&#8217;. Drag them to the inventory of your object and rename them to whatever you like.</p>
<p>The <a href="http://lslwiki.net/lslwiki/wakka.php?wakka=llGetInventoryName">llGetInventoryName</a> function is the key to socks approach. It will return the n&#8217;th item of the indicated type from the inventory. In this case I specified &#8217;0&#8242; for the item number so we get the first item.</p>
<blockquote><p>socks = llToLower(llGetInventoryName(INVENTORY_CLOTHING, 0));</p></blockquote>
<p>In the example above, I&#8217;m saving the name of the first item of type <a href="http://lslwiki.net/lslwiki/wakka.php?wakka=clothing">INVENTORY_CLOTHING</a> in the variable &#8216;socks&#8217;. I also use the <a href="http://lslwiki.net/lslwiki/wakka.php?wakka=llToLower">llToLower</a> function to make it lower case so I don&#8217;t have to worry about what case things are. I&#8217;ll do all of my compares in lower case.</p>
<p>For this demonstration, the assumption is that there is only one clothing item in the inventory. If there are others, the one you want might not be the first one and the code would have to loop through and look at all clothing items.</p>
<p>In the sample script below, the code immediately after <a href="http://lslwiki.net/lslwiki/wakka.php?wakka=llGetInventoryName">llGetInventory</a> goes through a sequence of if statements to check for various names and sets a flag as appropriate. In this example, I was setting a debug flag. Of course you could just as easily set a &#8216;left&#8217; or &#8216;right&#8217; to tell a script to open a door to the left or right. Or a &#8216;blue&#8217; or &#8216;red&#8217; to make a particle script spew blue or red particles. You get the idea.</p>
<p>A few other comments about the sample code.</p>
<p>I use the <a href="http://lslwiki.net/lslwiki/wakka.php?wakka=on_rez">on_rez</a> event in most of my scripts to cause an automatic reset when the object is rezzed.</p>
<p>Also, in this sample, I used the <a href="http://lslwiki.net/lslwiki/wakka.php?wakka=changed">changed</a> event to detect when the object inventory changes. The result is that if you rename the socks inventory item, or change any inventory item, the script automatically resets.</p>
<p>Then lastly, the <a href="http://lslwiki.net/lslwiki/wakka.php?wakka=touch_start">touch_start</a> event is just included so you can touch the object and have it report the current setting of the flag.</p>
<p>And now for the sample code. It doesn&#8217;t do anything useful. Just demonstrates the approach. And, it works in both SL and OpenSim.</p>
<pre style="border: 1px dashed #999999;padding: 5px;overflow: auto;font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace;color: #800000;background-color: #ffffff;font-size: 12px;line-height: 14px;width: 100%"><code>// Config Demo - Socks
//
// Script to demonstrate the use of socks to set config parameters.
//
// The clothing object name in inventory is checked to see if it is
// a particular keyword of 'debug on' or 'debug off'.  Set the gDebug
// flag accordingly.
//
// Additional inventory objects could be used to set other flags.
//
// Micheil Merlin/SL - 12/1/2009

integer gDebug = 0;                 // Debug flag.

default
{
    state_entry()
    {
        string socks;               // Name of inventory clothing object.
        // Get the name of the first inventory item of type clothing. Any
        // clothing type will work. The llGetInventoryName function does
        // not look for socks specfically.  The llGetInventoryName function
        // is called with a '0' to get the first item of type clothing. It
        // could be called successively to obtain additional clothing
        // items.  If it returns an empty string, there is no more
        // inventory of that type.
        socks = llToLower(llGetInventoryName(INVENTORY_CLOTHING, 0));
        // Look for clothing name of 'debug on' in lower case.
        if (socks == "debug on")
        {
            gDebug = 1;
        // Look for clothing name of 'debug off' in lower case.
        } else if (socks == "debug off")
        {
            gDebug = 0;
        // Check for the existence of the inventory item.
        } else if (socks == "")
        {
            llSay(0, "No inventory of type clothing exists.");
        // If the clothing name is neither, then just say it.
        } else
        {
            llSay(0, "Clothing name of '" + socks +
                "' found. We weren't expecting this.");
        }
        llSay(0, "Debug is set to " + (string)gDebug);
        //
        // The socks processing is complete. Other code could be inserted
        // here.
        //
    }

    // This event is triggered when the object is rezzed.
    on_rez(integer num)
    {
        llResetScript();            // Reset script when object rezzed.
    }

    // This event is triggered when the object has changed.
    changed(integer change)
    {
        // If inventory has changed, assume script reset is needed.
        // Adding socks to the inventory or renaming them will cause this
        // event to trigger.
        if (change == CHANGED_INVENTORY)
        {
            llResetScript();
        }
    }

    // This event is triggered when the object is touched.
    touch_start(integer total_number)
    {
        llSay(0, "Debug is set to " + (string)gDebug);
    }
}
</code></pre>
]]></content:encoded>
			<wfw:commentRss>http://iliveisl.com/scripting-tips-does-your-script-need-socks/feed/</wfw:commentRss>
		<slash:comments>9</slash:comments>
		</item>
		<item>
		<title>Sim Stats: December 09</title>
		<link>http://iliveisl.com/sim-stats-december-09/</link>
		<comments>http://iliveisl.com/sim-stats-december-09/#comments</comments>
		<pubDate>Thu, 31 Dec 2009 07:20:54 +0000</pubDate>
		<dc:creator>Micheil Merlin</dc:creator>
				<category><![CDATA[reaction grid]]></category>
		<category><![CDATA[second life]]></category>
		<category><![CDATA[simstats]]></category>

		<guid isPermaLink="false">http://blog.iliveisl.com/?p=2790</guid>
		<description><![CDATA[Welcome to the sim stats for December. SIM Micheil&#8217;s Rating Dilation FPS Physics Time Script Time Spare Time Script Speed Enerville 1.0 45 1.1 14.0 6.2 0.74 Ener Skerry 0.99 44 0.5 15.8 4.9 0.89 Ener Passage 0.92 42 0.4 5.1 17.9 0.71 Ener Strait 0.99 44 0.1 2.4 19.7 1.01 Enercay Midkey 0.99 44 [...]]]></description>
				<content:encoded><![CDATA[<p>Welcome to the sim stats for December.</p>
<table style="text-align: center; height: 478px;" border="0" width="465">
<tbody>
<tr>
<td>
<h5><span style="color: #008000;"><strong>SIM</strong></span></h5>
</td>
<td>
<h5><span style="color: #008000;"><strong>Micheil&#8217;s Rating</strong></span></h5>
</td>
<td>
<h5><span style="color: #008000;"><strong>Dilation<br />
</strong></span></h5>
</td>
<td>
<h5><span style="color: #008000;"><strong>FPS<br />
</strong></span></h5>
</td>
<td>
<h5><span style="color: #008000;"><strong>Physics<br />
Time</strong></span></h5>
</td>
<td>
<h5><span style="color: #008000;"><strong>Script<br />
Time</strong></span></h5>
</td>
<td>
<h5><span style="color: #008000;"><strong>Spare<br />
Time</strong></span></h5>
</td>
<td>
<h5><span style="color: #008000;"><strong>Script<br />
Speed</strong></span></h5>
</td>
</tr>
<tr>
<td>Enerville</td>
<td><img class="alignnone size-full wp-image-570" src="http://iliveisl.com/wp-content/uploads/2009/04/star_08.gif" alt="star_08" width="91" height="19" /></td>
<td>1.0</td>
<td>45</td>
<td>1.1</td>
<td>14.0</td>
<td>6.2</td>
<td>0.74</td>
</tr>
<tr>
<td>Ener Skerry</td>
<td><img class="alignnone size-full wp-image-570" src="http://iliveisl.com/wp-content/uploads/2009/04/star_09.gif" alt="star_09" width="91" height="19" /></td>
<td>0.99</td>
<td>44</td>
<td>0.5</td>
<td>15.8</td>
<td>4.9</td>
<td>0.89</td>
</tr>
<tr>
<td>Ener Passage</td>
<td><img class="alignnone size-full wp-image-570" src="http://iliveisl.com/wp-content/uploads/2009/04/star_07.gif" alt="star_07" width="91" height="19" /></td>
<td>0.92</td>
<td>42</td>
<td>0.4</td>
<td>5.1</td>
<td>17.9</td>
<td>0.71</td>
</tr>
<tr>
<td>Ener Strait</td>
<td><img class="alignnone size-full wp-image-570" src="http://iliveisl.com/wp-content/uploads/2009/04/star_10.gif" alt="star_10" width="91" height="19" /></td>
<td>0.99</td>
<td>44</td>
<td>0.1</td>
<td>2.4</td>
<td>19.7</td>
<td>1.01</td>
</tr>
<tr>
<td>Enercay Midkey</td>
<td><img class="alignnone size-full wp-image-570" src="http://iliveisl.com/wp-content/uploads/2009/04/star_10.gif" alt="star_10" width="91" height="19" /></td>
<td>0.99</td>
<td>44</td>
<td>0.2</td>
<td>6.3</td>
<td>15.5</td>
<td>1.00</td>
</tr>
<tr>
<td>Enercay Westkey</td>
<td><img class="alignnone size-full wp-image-570" src="http://iliveisl.com/wp-content/uploads/2009/04/star_10.gif" alt="star_10" width="91" height="19" /></td>
<td>1.0</td>
<td>45</td>
<td>0.5</td>
<td>7.9</td>
<td>12.9</td>
<td>0.98</td>
</tr>
<tr>
<td>Enercity Harbor</td>
<td><img class="alignnone size-full wp-image-570" src="http://iliveisl.com/wp-content/uploads/2009/04/star_06.gif" alt="star_06" width="91" height="19" /></td>
<td>0.99</td>
<td>45</td>
<td>0.8</td>
<td>19.8</td>
<td>0.0</td>
<td>0.44</td>
</tr>
<tr>
<td>Enercity Weston</td>
<td><img class="alignnone size-full wp-image-570" src="http://iliveisl.com/wp-content/uploads/2009/04/star_06.gif" alt="star_06" width="91" height="19" /></td>
<td>0.99</td>
<td>45</td>
<td>0.4</td>
<td>19.7</td>
<td>0.0</td>
<td>0.56</td>
</tr>
<tr>
<td>Enercity Easton</td>
<td><img class="alignnone size-full wp-image-568" src="http://iliveisl.com/wp-content/uploads/2009/04/star_06.gif" alt="star_06" width="91" height="19" /></td>
<td>0.98</td>
<td>44</td>
<td>6.4</td>
<td>13.9</td>
<td>0.0</td>
<td>0.43</td>
</tr>
<tr>
<td>Enercity Square</td>
<td><img class="alignnone size-full wp-image-570" src="http://iliveisl.com/wp-content/uploads/2009/04/star_09.gif" alt="star_09" width="91" height="19" /></td>
<td>1.00</td>
<td>45</td>
<td>0.1</td>
<td>12.3</td>
<td>8.4</td>
<td>0.91</td>
</tr>
<tr>
<td>Enercity Shores</td>
<td><img class="alignnone size-full wp-image-570" src="http://iliveisl.com/wp-content/uploads/2009/04/star_07.gif" alt="star_07" width="91" height="19" /></td>
<td>0.99</td>
<td>44</td>
<td>1.6</td>
<td>19.0</td>
<td>0.0</td>
<td>0.73</td>
</tr>
<tr>
<td>Enercity Park</td>
<td><img class="alignnone size-full wp-image-570" src="http://iliveisl.com/wp-content/uploads/2009/04/star_10.gif" alt="star_10" width="91" height="19" /></td>
<td>0.99</td>
<td>45</td>
<td>0.1</td>
<td>1.0</td>
<td>20.8</td>
<td>1.02</td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>Selected SL Regions</td>
<td><img class="alignnone size-full wp-image-570" src="http://iliveisl.com/wp-content/uploads/2009/04/star_06.gif" alt="star_06" width="91" height="19" /></td>
<td>0.99</td>
<td>45</td>
<td>2.1</td>
<td>17.5</td>
<td>0.0</td>
<td>0.42</td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
</tbody>
</table>
<p><img class="size-full wp-image-573 alignleft" src="http://iliveisl.com/wp-content/uploads/2009/04/micheilsthoughts.gif" alt="micheilsthoughts" width="163" height="107" /></p>
<p>Two server deploys occurred during December. The first, <a href="http://wiki.secondlife.com/wiki/Release_Notes/Second_Life_Server/1.34">server 1.34.0.140927</a>, included some fixes and support for the <a href="http://wiki.secondlife.com/wiki/Linden_Lab_Official:Linden_Home">Linden Homes</a> program.  The second, <a href="http://wiki.secondlife.com/wiki/Release_Notes/Second_Life_Server/1.34">server 1.34.1.141394</a>, included an unspecified security fix to address an exploit that could be used for content theft.</p>
<p>Almost as soon as the second deploy started, reports of <a href="http://jira.secondlife.com/browse/SVC-5150">#SVC-5150</a> began occurring. Objects with scripts that request permission to attach to an AV, began to fail. This is an approach used in many vehicle scripts. The problem seemed to be fairly prevalent early on but also seems to have cleared up to a large extent. The issue is still open.</p>
<p>A handful of other temporary problems also occurred such as TP failures, object rezzing failures and inventory issues. These seem to have settled down to normal levels.</p>
<p>Out of curiosity, I took my sim timing test scripts over to the Ener and subQuark <a href="http://reactiongrid.com/">Reaction Grid</a> venue which runs on <a href="http://opensimulator.org/wiki/Main_Page">OpenSim</a>. I don&#8217;t know that I had any real expectations, but did I get a big surprise.</p>
<blockquote><p>They ran 30 times faster!!!!</p></blockquote>
<p>They are really simple counting and looping scripts. Originally, I played with making them more comprehensive but it seemed that their simpleness worked just fine for comparing SL sims with each other. In any case, you&#8217;d need to test and compare a number of common operations to draw real script performance comparison conclusions between SL and OpenSim. And even then, OpenSim implementations occur on a range of software and hardware so comparisons would be specific to one implementation of OpenSim.</p>
<p>Maybe more comprehensive testing scripts will be a little future project :).</p>
<hr />Some key points regarding Second Life sim performance.</p>
<ul>
<li>A sim frame is 22.2 ms in length.</li>
<li>A time dilation of 1.0 means the sim is running at full speed.</li>
<li>As frame time gets larger than 22.2, time dilation drops below 1.0 and sim FPS drops below 45.</li>
<li>Spare time means there is time in the frame that the sim has nothing to do and is not running at capacity.</li>
<li>When busy, the sim will try to avoid increasing the sim frame time by spending less time running scripts.</li>
</ul>
<p>The above points apply primarily to full sims. Openspace and Homestead sim stats can be somewhat different, particularly in regard to what spare time means.</p>
]]></content:encoded>
			<wfw:commentRss>http://iliveisl.com/sim-stats-december-09/feed/</wfw:commentRss>
		<slash:comments>11</slash:comments>
		</item>
		<item>
		<title>Mono and Bytecode Sharing</title>
		<link>http://iliveisl.com/mono-and-bytecode-sharing/</link>
		<comments>http://iliveisl.com/mono-and-bytecode-sharing/#comments</comments>
		<pubDate>Thu, 03 Dec 2009 00:32:02 +0000</pubDate>
		<dc:creator>Micheil Merlin</dc:creator>
				<category><![CDATA[second life]]></category>
		<category><![CDATA[scripting]]></category>

		<guid isPermaLink="false">http://blog.iliveisl.com/?p=2591</guid>
		<description><![CDATA[Server version 1.24.3 in August of 2008, implemented Mono as an alternate way to compile and run LSL scripts. Mono is a free and open source implementation of Microsoft&#8217;s .NET and is sponsored by Novell. This is all pretty old news by now. But there is one feature in the implementation with Second Life that [...]]]></description>
				<content:encoded><![CDATA[<p><a href="http://wiki.secondlife.com/wiki/Release_Notes/Second_Life_Server/1.24">Server version 1.24.3</a> in August of 2008, implemented <a href="http://wiki.secondlife.com/wiki/Mono">Mono as an alternate</a> way to compile and run LSL scripts. <a href="http://en.wikipedia.org/wiki/Mono_(software)">Mono is a free and open source implementation of Microsoft&#8217;s .NET</a> and is sponsored by Novell. This is all pretty old news by now. But there is one feature in the implementation with Second Life that is worth talking about.  Bytecode sharing. </p>
<blockquote><p>So, what&#8217;s a bytecode?  And how do you share it?</p></blockquote>
<p>The term &#8216;bytecode&#8217; came into general usage when Sun Microsystems created <a href="http://en.wikipedia.org/wiki/Java_(Sun)">Java</a>.  But the concept is actually at least as old as 1966.  It was just called other things such as <a href="http://en.wikipedia.org/wiki/O-code_machine">o-code</a>, <a href="http://en.wikipedia.org/wiki/P-code_machine">p-code</a> and pseudo-code.  The idea behind all of these is that a compiler can translate a high level programming language into a hardware independent set of instructions that can either be translated into machine code or quickly interpreted at run time for a specific hardware platform.  This approach allowed compilers to be created that could be relatively easily ported to different hardware platforms or compiled code to be created that was independent of a specific hardware platform.  The hardware specific translator or interpreter would still have to be created for each hardware platform, but this was a far easier task than rewriting a compiler for each set of hardware to directly produce machine code for that hardware.</p>
<p>And now to the sharing part. The Second Life server will only load one copy of the compiled bytecode for a script, no matter how many times that script occurs in the sim. So, 10 instances of the script use the same amount of memory as one instance of the script, not counting the data. Only the program code portion of the script is shared. Each individual usage of the script gets its own data area. The requirement to support bytecode sharing is that the same script is not recompiled each time it is placed in a new object. For example, each time you want to reuse the same script, either copy the object with the script intact or drag the compiled script from your inventory into each object without recompiling it. If you recompile the script the sim can no longer tell that it is a duplicate copy.</p>
<p>In reality, this may be a small savings in memory. It is likely that in the 1,000s of scripts loaded in a sim, there may be a small percentage of duplication. And those that are duplicated may be small scripts like your fancy window tinting scripts. But, treating scripts carefully to support bytecode sharing is an easy thing to do and every little bit helps.</p>
<p>You may have scripts that differ only in the setting of just a few variables. Having to compile slightly different versions of the same script would prevent bytecode sharing in addition to making it a little harder to maintain changes to the script. In future blog entries, I plan to show several methods to allow scripts to obtain different configuration options so that the same script can be used to perform slightly different operations.</p>
]]></content:encoded>
			<wfw:commentRss>http://iliveisl.com/mono-and-bytecode-sharing/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>Sim Stats &#8211; November 09</title>
		<link>http://iliveisl.com/sim-stats-november-09/</link>
		<comments>http://iliveisl.com/sim-stats-november-09/#comments</comments>
		<pubDate>Mon, 09 Nov 2009 14:57:06 +0000</pubDate>
		<dc:creator>Micheil Merlin</dc:creator>
				<category><![CDATA[second life]]></category>
		<category><![CDATA[simstats]]></category>

		<guid isPermaLink="false">http://blog.iliveisl.com/?p=2441</guid>
		<description><![CDATA[Welcome to the sim stats for November. SIM Micheil&#8217;s Rating Dilation FPS Physics Time Script Time Spare Time Script Speed Enerville 1.0 45 0.1 16.7 4.2 0.87 Ener Skerry 0.99 45 0.2 14.9 6.2 0.82 Ener Passage 0.94 42 0.6 4.8 17.7 0.65 Ener Strait 0.96 44 0.1 5.7 16.3 0.72 Enercay Midkey 1.00 45 [...]]]></description>
				<content:encoded><![CDATA[<p>Welcome to the sim stats for November.</p>
<table style="height: 478px;text-align: center" border="0" width="465">
<tbody>
<tr>
<td>
<h5><span style="color: #008000"><strong>SIM</strong></span></h5>
</td>
<td>
<h5><span style="color: #008000"><strong>Micheil&#8217;s Rating</strong></span></h5>
</td>
<td>
<h5><span style="color: #008000"><strong>Dilation<br />
</strong></span></h5>
</td>
<td>
<h5><span style="color: #008000"><strong>FPS<br />
</strong></span></h5>
</td>
<td>
<h5><span style="color: #008000"><strong>Physics<br />
Time</strong></span></h5>
</td>
<td>
<h5><span style="color: #008000"><strong>Script<br />
Time</strong></span></h5>
</td>
<td>
<h5><span style="color: #008000"><strong>Spare<br />
Time</strong></span></h5>
</td>
<td>
<h5><span style="color: #008000"><strong>Script<br />
Speed</strong></span></h5>
</td>
</tr>
<tr>
<td>Enerville</td>
<td><img class="alignnone size-full wp-image-570" src="http://iliveisl.com/wp-content/uploads/2009/04/star_09.gif" alt="star_09" width="91" height="19" /></td>
<td>1.0</td>
<td>45</td>
<td>0.1</td>
<td>16.7</td>
<td>4.2</td>
<td>0.87</td>
</tr>
<tr>
<td>Ener Skerry</td>
<td><img class="alignnone size-full wp-image-570" src="http://iliveisl.com/wp-content/uploads/2009/04/star_08.gif" alt="star_08" width="91" height="19" /></td>
<td>0.99</td>
<td>45</td>
<td>0.2</td>
<td>14.9</td>
<td>6.2</td>
<td>0.82</td>
</tr>
<tr>
<td>Ener Passage</td>
<td><img class="alignnone size-full wp-image-570" src="http://iliveisl.com/wp-content/uploads/2009/04/star_07.gif" alt="star_07" width="91" height="19" /></td>
<td>0.94</td>
<td>42</td>
<td>0.6</td>
<td>4.8</td>
<td>17.7</td>
<td>0.65</td>
</tr>
<tr>
<td>Ener Strait</td>
<td><img class="alignnone size-full wp-image-570" src="http://iliveisl.com/wp-content/uploads/2009/04/star_07.gif" alt="star_07" width="91" height="19" /></td>
<td>0.96</td>
<td>44</td>
<td>0.1</td>
<td>5.7</td>
<td>16.3</td>
<td>0.72</td>
</tr>
<tr>
<td>Enercay Midkey</td>
<td><img class="alignnone size-full wp-image-570" src="http://iliveisl.com/wp-content/uploads/2009/04/star_10.gif" alt="star_10" width="91" height="19" /></td>
<td>1.00</td>
<td>45</td>
<td>0.4</td>
<td>8.0</td>
<td>13.1</td>
<td>1.02</td>
</tr>
<tr>
<td>Enercay Westkey</td>
<td><img class="alignnone size-full wp-image-570" src="http://iliveisl.com/wp-content/uploads/2009/04/star_10.gif" alt="star_10" width="91" height="19" /></td>
<td>1.0</td>
<td>45</td>
<td>0.2</td>
<td>11.2</td>
<td>10.1</td>
<td>1.01</td>
</tr>
<tr>
<td>Enercity Harbor</td>
<td><img class="alignnone size-full wp-image-570" src="http://iliveisl.com/wp-content/uploads/2009/04/star_07.gif" alt="star_07" width="91" height="19" /></td>
<td>0.99</td>
<td>44</td>
<td>0.6</td>
<td>19.8</td>
<td>0.0</td>
<td>0.68</td>
</tr>
<tr>
<td>Enercity Weston</td>
<td><img class="alignnone size-full wp-image-570" src="http://iliveisl.com/wp-content/uploads/2009/04/star_07.gif" alt="star_07" width="91" height="19" /></td>
<td>0.99</td>
<td>45</td>
<td>0.4</td>
<td>20.8</td>
<td>0.0</td>
<td>0.75</td>
</tr>
<tr>
<td>Enercity Easton</td>
<td><img class="alignnone size-full wp-image-568" src="http://iliveisl.com/wp-content/uploads/2009/04/star_06.gif" alt="star_06" width="91" height="19" /></td>
<td>0.96</td>
<td>44</td>
<td>8.9</td>
<td>11.9</td>
<td>0.0</td>
<td>0.34</td>
</tr>
<tr>
<td>Enercity Square</td>
<td><img class="alignnone size-full wp-image-570" src="http://iliveisl.com/wp-content/uploads/2009/04/star_09.gif" alt="star_09" width="91" height="19" /></td>
<td>0.99</td>
<td>45</td>
<td>0.1</td>
<td>13.1</td>
<td>8.2</td>
<td>0.86</td>
</tr>
<tr>
<td>Enercity Shores</td>
<td><img class="alignnone size-full wp-image-570" src="http://iliveisl.com/wp-content/uploads/2009/04/star_07.gif" alt="star_07" width="91" height="19" /></td>
<td>0.99</td>
<td>45</td>
<td>1.6</td>
<td>18.2</td>
<td>0.0</td>
<td>0.72</td>
</tr>
<tr>
<td>Enercity Park</td>
<td><img class="alignnone size-full wp-image-570" src="http://iliveisl.com/wp-content/uploads/2009/04/star_10.gif" alt="star_10" width="91" height="19" /></td>
<td>0.99</td>
<td>44</td>
<td>0.1</td>
<td>1.1</td>
<td>20.9</td>
<td>1.00</td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>Selected SL Regions</td>
<td><img class="alignnone size-full wp-image-570" src="http://iliveisl.com/wp-content/uploads/2009/04/star_06.gif" alt="star_06" width="91" height="19" /></td>
<td>0.99</td>
<td>44</td>
<td>0.8</td>
<td>19.3</td>
<td>0.2</td>
<td>0.51</td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
</tbody>
</table>
<p><img class="size-full wp-image-573 alignleft" src="http://iliveisl.com/wp-content/uploads/2009/04/micheilsthoughts.gif" alt="micheilsthoughts" width="163" height="107" /></p>
<p>As part of the testing that I do, I always try to find a couple of empty mainland regions to run some test scripts in and capture elapsed times. I generally first try the same ones I used during the previous testing unless those regions are no longer empty. I look for regions with no objects and no scripts so the only scripts running in the region are the ones I&#8217;m carrying. If possible, I also look for regions that don&#8217;t show any child agents. And no, these really aren&#8217;t children&#8230;lol. In sim terms, a child agent is an AV that can see into your current region. These child agents do impact sim resources to some extent as the sim has to communicate certain information back to these AVs. Information about objects that the AV can see and where they move to, etc. For an empty sim, this extra child agent communication may be so minimal as to not make any difference.</p>
<p>Anyway, I use these tests in the empty regions as a baseline to see what the best possible script performance could be. Generally, these empty regions test about the same as the best testing iLIVEisl regions. However, this time, several of the iLIVEisl regions actually tested better than these empty mainland regions. What&#8217;s up with that? Just when you think you sort of understand things, something changes. lol.</p>
<p>There have been several more server releases in the last two months.  A few more <a href="http://wiki.secondlife.com/wiki/Release_Notes/Second_Life_Server/1.30">1.30</a> releases and a <a href="http://wiki.secondlife.com/wiki/Release_Notes/Second_Life_Server/1.32">1.32</a> release. The release notes for these recent releases are still very slim on details. Either they contain very minor updates or not many of the updates are documented in the release notes. One thing of note, the 1.32 release contains this&#8230;</p>
<blockquote><p>Added back-end support for improved tracking of script memory usage</p></blockquote>
<p>Could that be in support of future script limitations referred to during the open space episode from last year?</p>
<hr />Some key points regarding sim performance.</p>
<ul>
<li>A sim frame is 22.2 ms in length.</li>
<li>A time dilation of 1.0 means the sim is running at full speed.</li>
<li>As frame time gets larger than 22.2, time dilation drops below 1.0 and sim FPS drops below 45.</li>
<li>Spare time means there is time in the frame that the sim has nothing to do and is not running at capacity.</li>
<li>When busy, the sim will try to avoid increasing the sim frame time by spending less time running scripts.</li>
</ul>
<p>The above points apply primarily to full sims. Openspace and Homestead sim stats can be somewhat different, particularly in regard to what spare time means.</p>
]]></content:encoded>
			<wfw:commentRss>http://iliveisl.com/sim-stats-november-09/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Burning Life &#039;09</title>
		<link>http://iliveisl.com/burning-life-09/</link>
		<comments>http://iliveisl.com/burning-life-09/#comments</comments>
		<pubDate>Fri, 23 Oct 2009 01:21:11 +0000</pubDate>
		<dc:creator>Micheil Merlin</dc:creator>
				<category><![CDATA[second life]]></category>

		<guid isPermaLink="false">http://blog.iliveisl.com/?p=2260</guid>
		<description><![CDATA[The Monkey Burning Life is on again. This year&#8217;s event started on October 17th (yeah I know I should get this out earlier&#8230;lol) and officially ends on October 25th. If you haven&#8217;t heard of Burning Life or don&#8217;t know what it is, you can go read up on the Burning Life History. But to sum [...]]]></description>
				<content:encoded><![CDATA[<p><img src="http://farm3.static.flickr.com/2652/4034173751_e5775c6b1b.jpg" alt="BL09 Exhibit - Image Copyright Nickola Martynov" /><a href="http://livingvirtually.wordpress.com/"><br />
<em>The Monkey</em></a></p>
<p><a href="http://burninglife.secondlife.com/">Burning Life</a> is on again.  This year&#8217;s event started on October 17th (yeah I know I should get this out earlier&#8230;lol) and officially ends on October 25th.  If you haven&#8217;t heard of Burning Life or don&#8217;t know what it is, you can go read up on the <a href="http://burninglife.secondlife.com/whatis/history">Burning Life History</a>.  But to sum it up, to me it&#8217;s lots of art and exhibits. To other people, it&#8217;s parties, causes, dancing, music, basically much of the stuff you are used to finding in SL crammed into 34 sims for one week.</p>
<p>For this Burning Life, I worked on an exhibit with Nickola Martynov entitled <a href="http://slurl.com/secondlife/Burning%20Life-Quinn/77/4/25">&#8220;How to Catch a Monkey&#8221;</a>. If you know what a Rube Goldberg machine is, just think of that in a circus theme and you&#8217;ll have a general idea of what the exhibit is. If you&#8217;d like to take a look, go check it out <a href="http://slurl.com/secondlife/Burning%20Life-Quinn/77/4/25">here</a>.  And go check out Nikki&#8217;s <a href="http://livingvirtually.wordpress.com/">blog</a> for some more information about the build.</p>
<p>As usual, there are many interesting builds to view and explore. But take your time. With so much content, rezzing is very slow. In fact, if you don&#8217;t spend some time walking around instead of flying, you&#8217;ll miss 90% of it.</p>
<p>Here are some builds that I found interesting. When you land at these SLURLs, be sure to turn around and look for the exhibit. You&#8217;ll almost never be facing the correct direction after you TP there. And, as noted earlier, take some time and let things rez. It&#8217;ll be worth it :)</p>
<p><a href="http://slurl.com/secondlife/Burning%20Life-Black%20Rock/27/18/25">The Roof is Gone</a> by Miso Susanowa and Misprint Thursday<br />
You&#8217;ll want to get a notecard at the exhibit and read the hints for the best expierence. Turn on your music and media. Climb around in the exhibit and find all the things to interact with.</p>
<p><a href="http://slurl.com/secondlife/Burning%20Life-3%20Mile/232/124/25">Gulliver&#8217;s Travel</a> by Ub Yifu and Copan Falta<br />
A big Gulliver tied up on the playa.</p>
<p><a href="http://slurl.com/secondlife/Burning%20Life-Trego/112/237/25">Irregularity</a> by Selavy Oh<br />
This one is a tall one. Make sure your sound is on and then fly around through this exhibit and watch (and listen to) the things that happen.</p>
<p><a href="http://slurl.com/secondlife/Burning%20Life-Limbo/73/66/25">!Filaments of Life</a> by Kerryth Tarantal<br />
Another tall one. And made with fractals. Fractals are so cool :). This one is most impressive when your environment is set to midnight.  Back up and take a good look at it then come close and walk around inside.</p>
<p><a href="http://slurl.com/secondlife/Burning%20Life-Quinn/203/194/25">Mars Landing</a> by zeusdinne Baroque and Fafner Hoffmann<br />
Be sure to pick up a free rover out front.</p>
<p><a href="http://slurl.com/secondlife/Burning%20Life-Elko/57/133/25">Primordial Soup</a> by Maerok Westland with assistance from Traxie Ying and Sarita Meili<br />
Be sure to take a swim in the soup :).</p>
<p><a href="http://slurl.com/secondlife/Burning%20Life-Jungo/229/31/25">Among Other Things</a> by AM Radio<br />
Make sure your media is turned on for this one.  When you touch the spray can, you&#8217;ll get a link to a website where you can go make graffiti.  When you publish your graffiti, it will show up on the side of the train (as long as your media is on).</p>
<p><a href="http://slurl.com/secondlife/Burning%20Life-Bluewing/205/14/24">Burning Fantasies</a> by Caro Fayray and Eliopod Beaumont<br />
Go to midnight for this one also. Ride a cloud.</p>
<p><a href="http://slurl.com/secondlife/Burning%20Life-Quinn/80/130/25">Candlemania</a> by Arrow Inglewood<br />
Another one that looks nice at midnight.</p>
<p>And many, many others&#8230;.</p>
<p>Oh, and if you see a Porta Potty, go check it out. Some of them are as good as the exhibits themselves :).</p>
]]></content:encoded>
			<wfw:commentRss>http://iliveisl.com/burning-life-09/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Sim Stats: September 09</title>
		<link>http://iliveisl.com/sim-stats-september-09/</link>
		<comments>http://iliveisl.com/sim-stats-september-09/#comments</comments>
		<pubDate>Sun, 20 Sep 2009 23:48:51 +0000</pubDate>
		<dc:creator>Micheil Merlin</dc:creator>
				<category><![CDATA[second life]]></category>
		<category><![CDATA[simstats]]></category>

		<guid isPermaLink="false">http://blog.iliveisl.com/?p=1909</guid>
		<description><![CDATA[Welcome to the sim stats for September. SIM Micheil&#8217;s Rating Dilation FPS Physics Time Script Time Spare Time Script Speed Enerville 0.99 45 0.5 20.0 0.0 0.63 Ener Skerry 1.0 45 0.1 11.0 10.3 0.99 Ener Passage 0.96 43 4.7 1.8 16.0 0.43 Ener Strait 0.98 44 1.2 5.2 15.8 0.85 Enercay Midkey 1.00 45 [...]]]></description>
				<content:encoded><![CDATA[<p>Welcome to the sim stats for September.</p>
<table style="text-align: center; height: 478px;" border="0" width="465">
<tbody>
<tr>
<td>
<h5><span style="color: #008000;"><strong>SIM</strong></span></h5>
</td>
<td>
<h5><span style="color: #008000;"><strong>Micheil&#8217;s Rating</strong></span></h5>
</td>
<td>
<h5><span style="color: #008000;"><strong>Dilation<br />
</strong></span></h5>
</td>
<td>
<h5><span style="color: #008000;"><strong>FPS<br />
</strong></span></h5>
</td>
<td>
<h5><span style="color: #008000;"><strong>Physics<br />
Time</strong></span></h5>
</td>
<td>
<h5><span style="color: #008000;"><strong>Script<br />
Time</strong></span></h5>
</td>
<td>
<h5><span style="color: #008000;"><strong>Spare<br />
Time</strong></span></h5>
</td>
<td>
<h5><span style="color: #008000;"><strong>Script<br />
Speed</strong></span></h5>
</td>
</tr>
<tr>
<td>Enerville</td>
<td><img class="alignnone size-full wp-image-570" src="http://iliveisl.com/wp-content/uploads/2009/04/star_07.gif" alt="star_07" width="91" height="19" /></td>
<td>0.99</td>
<td>45</td>
<td>0.5</td>
<td>20.0</td>
<td>0.0</td>
<td>0.63</td>
</tr>
<tr>
<td>Ener Skerry</td>
<td><img class="alignnone size-full wp-image-570" src="http://iliveisl.com/wp-content/uploads/2009/04/star_10.gif" alt="star_10" width="91" height="19" /></td>
<td>1.0</td>
<td>45</td>
<td>0.1</td>
<td>11.0</td>
<td>10.3</td>
<td>0.99</td>
</tr>
<tr>
<td>Ener Passage</td>
<td><img class="alignnone size-full wp-image-570" src="http://iliveisl.com/wp-content/uploads/2009/04/star_06.gif" alt="star_06" width="91" height="19" /></td>
<td>0.96</td>
<td>43</td>
<td>4.7</td>
<td>1.8</td>
<td>16.0</td>
<td>0.43</td>
</tr>
<tr>
<td>Ener Strait</td>
<td><img class="alignnone size-full wp-image-570" src="http://iliveisl.com/wp-content/uploads/2009/04/star_09.gif" alt="star_09" width="91" height="19" /></td>
<td>0.98</td>
<td>44</td>
<td>1.2</td>
<td>5.2</td>
<td>15.8</td>
<td>0.85</td>
</tr>
<tr>
<td>Enercay Midkey</td>
<td><img class="alignnone size-full wp-image-570" src="http://iliveisl.com/wp-content/uploads/2009/04/star_09.gif" alt="star_09" width="91" height="19" /></td>
<td>1.00</td>
<td>45</td>
<td>0.4</td>
<td>14.8</td>
<td>6.2</td>
<td>0.83</td>
</tr>
<tr>
<td>Enercay Westkey</td>
<td><img class="alignnone size-full wp-image-570" src="http://iliveisl.com/wp-content/uploads/2009/04/star_10.gif" alt="star_10" width="91" height="19" /></td>
<td>1.0</td>
<td>45</td>
<td>0.6</td>
<td>13.4</td>
<td>7.3</td>
<td>1.00</td>
</tr>
<tr>
<td>Enercity Harbor</td>
<td><img class="alignnone size-full wp-image-570" src="http://iliveisl.com/wp-content/uploads/2009/04/star_09.gif" alt="star_09" width="91" height="19" /></td>
<td>0.98</td>
<td>44</td>
<td>0.2</td>
<td>20.7</td>
<td>0</td>
<td>0.84</td>
</tr>
<tr>
<td>Enercity Weston</td>
<td><img class="alignnone size-full wp-image-570" src="http://iliveisl.com/wp-content/uploads/2009/04/star_07.gif" alt="star_07" width="91" height="19" /></td>
<td>0.99</td>
<td>45</td>
<td>1.1</td>
<td>19.4</td>
<td>0</td>
<td>0.62</td>
</tr>
<tr>
<td>Enercity Easton</td>
<td><img class="alignnone size-full wp-image-568" src="http://iliveisl.com/wp-content/uploads/2009/04/star_06.gif" alt="star_06" width="91" height="19" /></td>
<td>0.98</td>
<td>44</td>
<td>12.9</td>
<td>7.3</td>
<td>0</td>
<td>0.16</td>
</tr>
<tr>
<td>Enercity Square</td>
<td><img class="alignnone size-full wp-image-570" src="http://iliveisl.com/wp-content/uploads/2009/04/star_09.gif" alt="star_09" width="91" height="19" /></td>
<td>1.0</td>
<td>45</td>
<td>0.2</td>
<td>10.1</td>
<td>10.8</td>
<td>0.84</td>
</tr>
<tr>
<td>Enercity Shores</td>
<td><img class="alignnone size-full wp-image-570" src="http://iliveisl.com/wp-content/uploads/2009/04/star_10.gif" alt="star_10" width="91" height="19" /></td>
<td>1.0</td>
<td>45</td>
<td>0.4</td>
<td>18.4</td>
<td>1.9</td>
<td>0.98</td>
</tr>
<tr>
<td>Enercity Park</td>
<td><img class="alignnone size-full wp-image-570" src="http://iliveisl.com/wp-content/uploads/2009/04/star_10.gif" alt="star_10" width="91" height="19" /></td>
<td>0.99</td>
<td>45</td>
<td>0.1</td>
<td>1.1</td>
<td>20.8</td>
<td>1.02</td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>Selected SL Regions</td>
<td><img class="alignnone size-full wp-image-570" src="http://iliveisl.com/wp-content/uploads/2009/04/star_06.gif" alt="star_06" width="91" height="19" /></td>
<td>0.99</td>
<td>44</td>
<td>1.9</td>
<td>16.6</td>
<td>0.0</td>
<td>0.46</td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
</tbody>
</table>
<p><img class="size-full wp-image-573 alignleft" src="http://iliveisl.com/wp-content/uploads/2009/04/micheilsthoughts.gif" alt="micheilsthoughts" width="163" height="107" /></p>
<p>In the past week, a new server version, 1.30.0.133784, has been deployed. The <a href="http://wiki.secondlife.com/wiki/Release_Notes/Second_Life_Server/1.30">release notes</a> don&#8217;t say much about this version. You may notice that the server version numbers jumped from 1.27 to 1.30. Normally, this would imply some fairly significant changes. Instead, the version number jump just reflects a new version numbering scheme. There is a <a href="http://forums.secondlife.com/showpost.php?p=2546198&amp;postcount=10"> forum entry</a> from Dante Linden regarding the numbering convention.</p>
<blockquote><p>We&#8217;re using even-numbered minor release numbers for production releases and odd-numbered minor release numbers for internal, development versions.</p></blockquote>
<p>I have noticed just this last week, that the Pump IO statistic under Time Details is now registering some time. Previously, I only noticed Pump IO values over 0.1 for openspace or homestead sims. Open the statistics bar with Ctrl-Shift-1 or by selecting the option on the View drop down menu. Pump IO can be found by expanding Time and then Time Details. What this statistic means does not appear to be documented anywhere that I can find. Since I&#8217;ve only seen appreciable values for openspace or homestead sims, my assumption has been that this statistic was related to something that indicated the lost time and resources that a sim thought it should have but actually didn&#8217;t have because some other sim on the same processor core was using the resources. This processor core sharing has only been documented to occur for homestead and openspace sims. In any case, I&#8217;m now seeing intermittent values above 0.1 in this statistic where I normally saw only 0.0 or 0.1.</p>
<hr />Some key points regarding sim performance.</p>
<ul>
<li>A sim frame is 22.2 ms in length.</li>
<li>A time dilation of 1.0 means the sim is running at full speed.</li>
<li>As frame time gets larger than 22.2, time dilation drops below 1.0 and sim FPS drops below 45.</li>
<li>Spare time means there is time in the frame that the sim has nothing to do and is not running at capacity.</li>
<li>When busy, the sim will try to avoid increasing the sim frame time by spending less time running scripts.</li>
</ul>
<p>The above points apply primarily to full sims. Openspace and Homestead sim stats can be somewhat different, particularly in regard to what spare time means.</p>
]]></content:encoded>
			<wfw:commentRss>http://iliveisl.com/sim-stats-september-09/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Prim Twisting</title>
		<link>http://iliveisl.com/prim-twisting/</link>
		<comments>http://iliveisl.com/prim-twisting/#comments</comments>
		<pubDate>Thu, 17 Sep 2009 03:22:07 +0000</pubDate>
		<dc:creator>Micheil Merlin</dc:creator>
				<category><![CDATA[second life]]></category>

		<guid isPermaLink="false">http://blog.iliveisl.com/?p=1885</guid>
		<description><![CDATA[Now there&#8217;s a term! Depending on your level of building experience in SL you may already be familiar with that term. But even if you are an experienced builder, it&#8217;s very likely that you&#8217;ll be surprised just how far you can twist a prim. Prims put through this much torture can create shapes that you [...]]]></description>
				<content:encoded><![CDATA[<p>Now there&#8217;s a term!</p>
<p>Depending on your level of building experience in SL you may already be familiar with that term.  But even if you are an experienced builder, it&#8217;s very likely that you&#8217;ll be surprised just how far you can twist a prim.  Prims put through this much torture can create shapes that you would normally think would require several prims or a sculpty.  All of the shapes in this picture consist of only one prim!<br />
<img src="http://farm3.static.flickr.com/2412/3763746914_d62fd2295d_o.jpg" alt="Twisted Prim Display" width="637" height="459" /></p>
<p>Ayumi Cassini has a complete tutorial on how to create these prims on her <a href="http://ayumicassini.blogspot.com/2009/07/ultimate-guide-to-prim-twisting.html">blog</a>.  Many thanks to her for collecting this set and for her willingness to share these secrets.<br />
Thanks also to Torley for pointing out Ayumi&#8217;s tutorial in one of his <a href="https://blogs.secondlife.com/community/community/tnt">Tips and Tricks</a> posts.</p>
]]></content:encoded>
			<wfw:commentRss>http://iliveisl.com/prim-twisting/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Sim Stats: July 09</title>
		<link>http://iliveisl.com/sim-stats-july-09/</link>
		<comments>http://iliveisl.com/sim-stats-july-09/#comments</comments>
		<pubDate>Tue, 21 Jul 2009 23:44:54 +0000</pubDate>
		<dc:creator>Micheil Merlin</dc:creator>
				<category><![CDATA[second life]]></category>
		<category><![CDATA[simstats]]></category>

		<guid isPermaLink="false">http://blog.iliveisl.com/?p=1236</guid>
		<description><![CDATA[Welcome to the sim stats for July. SIM Micheil&#8217;s RATING DILATION FPS PHYSICS TIME SCRIPT TIME SPARE TIME SCRIPT SPEED Enerville 1.0 45 1.1 12.0 8.4 0.87 Ener Skerry 1.00 45 0.2 15.4 5.7 0.83 Ener Passage 0.98 44 0.4 5.9 15.4 0.66 Ener Strait 0.99 45 1.0 6.4 15.3 0.67 Enercay Midkey 1.00 45 [...]]]></description>
				<content:encoded><![CDATA[<p>Welcome to the sim stats for July.</p>
<table style="text-align: center; height: 478px;" border="0" width="465">
<tbody>
<tr>
<td>
<h5><span style="color: #008000;"><strong>SIM</strong></span></h5>
</td>
<td>
<h5><span style="color: #008000;"><strong>Micheil&#8217;s RATING</strong></span></h5>
</td>
<td>
<h5><span style="color: #008000;"><strong>DILATION<br />
</strong></span></h5>
</td>
<td>
<h5><span style="color: #008000;"><strong>FPS<br />
</strong></span></h5>
</td>
<td>
<h5><span style="color: #008000;"><strong>PHYSICS<br />
TIME</strong></span></h5>
</td>
<td>
<h5><span style="color: #008000;"><strong>SCRIPT<br />
TIME</strong></span></h5>
</td>
<td>
<h5><span style="color: #008000;"><strong>SPARE<br />
TIME</strong></span></h5>
</td>
<td>
<h5><span style="color: #008000;"><strong>SCRIPT<br />
SPEED</strong></span></h5>
</td>
</tr>
<tr>
<td>Enerville</td>
<td><img class="alignnone size-full wp-image-570" src="http://iliveisl.com/wp-content/uploads/2009/04/star_09.gif" alt="star_09" width="91" height="19" /></td>
<td>1.0</td>
<td>45</td>
<td>1.1</td>
<td>12.0</td>
<td>8.4</td>
<td>0.87</td>
</tr>
<tr>
<td>Ener Skerry</td>
<td><img class="alignnone size-full wp-image-570" src="http://iliveisl.com/wp-content/uploads/2009/04/star_09.gif" alt="star_09" width="91" height="19" /></td>
<td>1.00</td>
<td>45</td>
<td>0.2</td>
<td>15.4</td>
<td>5.7</td>
<td>0.83</td>
</tr>
<tr>
<td>Ener Passage</td>
<td><img class="alignnone size-full wp-image-570" src="http://iliveisl.com/wp-content/uploads/2009/04/star_07.gif" alt="star_07" width="91" height="19" /></td>
<td>0.98</td>
<td>44</td>
<td>0.4</td>
<td>5.9</td>
<td>15.4</td>
<td>0.66</td>
</tr>
<tr>
<td>Ener Strait</td>
<td><img class="alignnone size-full wp-image-570" src="http://iliveisl.com/wp-content/uploads/2009/04/star_07.gif" alt="star_07" width="91" height="19" /></td>
<td>0.99</td>
<td>45</td>
<td>1.0</td>
<td>6.4</td>
<td>15.3</td>
<td>0.67</td>
</tr>
<tr>
<td>Enercay Midkey</td>
<td><img class="alignnone size-full wp-image-570" src="http://iliveisl.com/wp-content/uploads/2009/04/star_10.gif" alt="star_10" width="91" height="19" /></td>
<td>1.00</td>
<td>45</td>
<td>0.4</td>
<td>15.8</td>
<td>5.1</td>
<td>0.96</td>
</tr>
<tr>
<td>Enercay Westkey</td>
<td><img class="alignnone size-full wp-image-570" src="http://iliveisl.com/wp-content/uploads/2009/04/star_10.gif" alt="star_10" width="91" height="19" /></td>
<td>1.0</td>
<td>45</td>
<td>0.6</td>
<td>18.2</td>
<td>2.3</td>
<td>1.01</td>
</tr>
<tr>
<td>Enercity Harbor</td>
<td><img class="alignnone size-full wp-image-570" src="http://iliveisl.com/wp-content/uploads/2009/04/star_07.gif" alt="star_07" width="91" height="19" /></td>
<td>0.99</td>
<td>44</td>
<td>0.4</td>
<td>20.1</td>
<td>0</td>
<td>0.67</td>
</tr>
<tr>
<td>Enercity Weston</td>
<td><img class="alignnone size-full wp-image-570" src="http://iliveisl.com/wp-content/uploads/2009/04/star_06.gif" alt="star_06" width="91" height="19" /></td>
<td>0.98</td>
<td>44</td>
<td>2.0</td>
<td>17.2</td>
<td>0</td>
<td>0.37</td>
</tr>
<tr>
<td>Enercity Easton</td>
<td><img class="alignnone size-full wp-image-568" src="http://iliveisl.com/wp-content/uploads/2009/04/star_06.gif" alt="star_06" width="91" height="19" /></td>
<td>0.99</td>
<td>44</td>
<td>10.9</td>
<td>9.7</td>
<td>0</td>
<td>0.38</td>
</tr>
<tr>
<td>Enercity Square</td>
<td><img class="alignnone size-full wp-image-570" src="http://iliveisl.com/wp-content/uploads/2009/04/star_08.gif" alt="star_08" width="91" height="19" /></td>
<td>1.0</td>
<td>45</td>
<td>0.5</td>
<td>14.5</td>
<td>6.1</td>
<td>0.81</td>
</tr>
<tr>
<td>Enercity Shores</td>
<td><img class="alignnone size-full wp-image-570" src="http://iliveisl.com/wp-content/uploads/2009/04/star_10.gif" alt="star_10" width="91" height="19" /></td>
<td>1.0</td>
<td>45</td>
<td>0.6</td>
<td>18.6</td>
<td>1.4</td>
<td>1.00</td>
</tr>
<tr>
<td>Enercity Park</td>
<td><img class="alignnone size-full wp-image-570" src="http://iliveisl.com/wp-content/uploads/2009/04/star_09.gif" alt="star_09" width="91" height="19" /></td>
<td>1.0</td>
<td>45</td>
<td>0.1</td>
<td>1.1</td>
<td>20.5</td>
<td>0.89</td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>Selected SL Regions</td>
<td><img class="alignnone size-full wp-image-570" src="http://iliveisl.com/wp-content/uploads/2009/04/star_06.gif" alt="star_06" width="91" height="19" /></td>
<td>0.99</td>
<td>44</td>
<td>8.5</td>
<td>12.1</td>
<td>0.0</td>
<td>0.37</td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
</tbody>
</table>
<p><img class="size-full wp-image-573 alignleft" src="http://iliveisl.com/wp-content/uploads/2009/04/micheilsthoughts.gif" alt="micheilsthoughts" width="163" height="107" /><br />
For those of you counting, you&#8217;ll know that there wasn&#8217;t a Sim Stats report for June :).  June was sort of busy&#8230;lol.</p>
<p>Anyway, over the past month, server version 1.27.0.127440 was rolled out. The major highlight of this release is the LSL HTTP-In facility that allows prims to become mini web-servers.  Review the <a href="http://wiki.secondlife.com/wiki/Release_Notes/Second_Life_Server/1.27">release notes</a> for information about this server version.  Details for LSL HTTP-In can be found in the <a href="http://wiki.secondlife.com/wiki/LSL_http_server">wiki</a>.  Before you get too exited about being able to create little web servers out of your prims, there are some drawbacks related to the persistence of the URL used to address the prim.  The major limitation is that the URL goes away when the sim is restarted.  The limitations make sense when you consider that there has to be some way to clean up unused URLs.  <a href="http://world.secondlife.com/resident/6a5aef83-93a6-42e1-9d76-bd03b4f5e8aa">Darien Caldwell</a> has published some notes in the <a href="http://forums.secondlife.com/showthread.php?t=323981">forum</a> about how to use <a href="http://code.google.com/appengine/">Google App Engine</a> to provide a dynamic naming service for use with HTTP-In, that would allow you to maintain a consistent way to contact the prim even after URL changes.</p>
<p>Even with the limitations, there is some excitement about this feature. <a href="http://world.secondlife.com/resident/5f0c45b4-e8d7-49ae-973f-4c2bb209e852">Doran Zemlja</a> of the <a href="http://ma8p.com/~opengate/">Astria Porta Open Stargate Network</a>, has been busy converting the communication between the stargates to use this new function. And those of you that know me know that I consider stargates to be just about the coolest thing in SL :) and am very fond of the Open Stargates in particular (even contributed textures and sculpties).  Previously, llEmail was used to pass information between stargates and there have been some long standing <a href="http://jira.secondlife.com/browse/SVC-23">bugs</a> related to email queues getting hung and such.  So, Doran has high hopes that the use of this function clears up some long standing issues.</p>
<p>Now back to the sim stats&#8230;</p>
<p>Things look pretty good this month.  In general, the <a href="http://www.iliveisl.com/">iliveisl</a> sims usually seem better than any average sampling of similar sims.  But this month is even better than usual.</p>
<p>To assist in taking a more objective look at sim performance, I use a simple script to measure elapsed run time.  During this month, I noticed that the run time on empty or nearly empty sims seems to be longer than I&#8217;ve seen previously.  Not by a lot.  Up to 45 to 46 seconds for a test that used to be about 40 seconds.  I use the run time on several empty sims as a baseline for comparing other sims. I don&#8217;t know if this is due to the server version change or something else in the infrastructure.  In any case, for this month, I made slight adjustments to the formula that I use to assist with the rating.</p>
<p>Some key points regarding sim performance.</p>
<ul>
<li>A sim frame is 22.2 ms in length.</li>
<li>A time dilation of 1.0 means the sim is running at full speed.</li>
<li>As frame time gets larger than 22.2, time dilation drops below 1.0 and sim FPS drops below 45.</li>
<li>Spare time means there is time in the frame that the sim has nothing to do and is not running at capacity.</li>
<li>When busy, the sim will try to avoid increasing the sim frame time by spending less time running scripts.</li>
</ul>
<p>The above points apply primarily to full sims. Openspace and Homestead sim stats can be somewhat different, particularly in regard to what spare time means.</p>
]]></content:encoded>
			<wfw:commentRss>http://iliveisl.com/sim-stats-july-09/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Second Life 6th Birthday</title>
		<link>http://iliveisl.com/second-life-6th-birthday/</link>
		<comments>http://iliveisl.com/second-life-6th-birthday/#comments</comments>
		<pubDate>Sun, 28 Jun 2009 04:07:41 +0000</pubDate>
		<dc:creator>Micheil Merlin</dc:creator>
				<category><![CDATA[second life]]></category>

		<guid isPermaLink="false">http://blog.iliveisl.com/?p=990</guid>
		<description><![CDATA[The celebration of the 6th birthday of Second Life opened on June 23, 2009.  There are 20 SL6B sims filled with the creations of your fellow Second Life residents.  The official celebration runs through June 29th with the last event scheduled for June 30th.  But you can visit the sims until July 6th. The sims [...]]]></description>
				<content:encoded><![CDATA[<div class="wp-caption alignleft" style="width: 122px"><img title="SL6B" src="http://wiki.secondlife.com/w/images/0/00/SL6BFINALLOGOcr.jpg" alt="" width="112" height="110" /><p class="wp-caption-text">SL6B</p></div>
<p>The celebration of the 6th birthday of Second Life opened on June 23, 2009.  There are 20 SL6B sims filled with the creations of your fellow Second Life residents.  The official celebration runs through June 29th with the last event scheduled for June 30th.  But you can visit the sims until July 6th.</p>
<p>The sims are set to midnight and most of the builds were created with this in mind.  Lots of glow.  So, in general, things should look more attractive letting your viewer stay in midnight.</p>
<p>I was fortunate enough this year to be able to build an exhibit at SL6B with a friend and fellow <a href="http://iliveisl.com/">iliveisl</a> resident, Nickola Martynov.  Visit our exhibit at <a href="http://slurl.com/secondlife/SL6B%20Uplink/138/44/23">Space is There&#8230; in SL6B Uplink</a>.  There is a video to watch and things to interact with. Be sure to take the space elevator up to explore the planets.</p>
<p>The sims this year follow a theme created by <a href="http://world.secondlife.com/resident/3e11b7b7-5104-08ad-4cc8-19b48d3a90a5">Phaylen Fairchild</a>.</p>
<blockquote><p>800 Light Years away we are spiraling through outer space on a Meteor discovered by Space Explorer Ghorman Dallier in 2499 while searching for new worlds to inhabit! Although we&#8217;re too far away from the sun to see it and any flora has to be kept in an AEC (Artificial Environment Chamber.) we still know how to throw a party!</p></blockquote>
<p>Further information. SL6B <a href="http://wiki.secondlife.com/wiki/SL6B">Wiki</a> and <a href="http://dalliershope.wordpress.com/">Blog</a></p>
<p>The <a href="http://slurl.com/secondlife/SL6B%20The%20Paradox/128/128/198">cloning station in SL6B Paradox</a> is a central jumping off point to the infrastructure builds.  Click the planet with the name of the infrastructure build that you&#8217;re interested in.  You can also click on one of the large signs and receive a touring hud along with some other items.</p>
<p>Catch a <a href="http://slurl.com/secondlife/SL6B%20Uplink/128/120/25">tram</a> that tours the SL6B sims.  I understand the tour takes about 35 minutes or so.  These tram stops are all over the SL6B sims at many road intersections.  Press the small button to call a tram or click the sign where it says &#8216;click&#8217;.</p>
<p>The following are all exhibits that I found interesting.  My criteria was mostly interesting things to look at, games to play or interesting things to interact with.  If you like causes, culture, etc., those things are there also.</p>
<p><a href="http://slurl.com/secondlife/SL6B%20Titan/54/105/23">The OmniPrim by Crap Mariner</a>. This one is interactive and occurs on a schedule.  Visit the site to see when the next &#8216;performance&#8217; is.  I&#8217;m getting this out so late, there may not be many left.  Sorry about that.</p>
<p><a href="http://slurl.com/secondlife/SL6B%20Dimension/144/42/23">Folding Minds by Kolor Fall</a>. Be sure to locate the obelisk looking thing and draw on it with the mouse. Then watch the blocks move around in the background.  There are some instructions at the site.</p>
<p><a href="http://slurl.com/secondlife/SL6B%20Nano/229/217/23">Atmospheric Clouds by Caro Fayray</a>.</p>
<p><a href="http://slurl.com/secondlife/SL6B%20Nano/164/232/24">Future Games and Leisure by MoutainLion Shinn</a>. Bumper cars.  You can have some fun by yourself, but these are probably best with someone else you can bump in to.  There are two levels.  Find the tunnel that takes you to the 2nd level.</p>
<p><a href="http://slurl.com/secondlife/SL6B%20Nucleus/179/137/24">Synthetic University by MosMax Hax</a>.</p>
<p><a href="http://slurl.com/secondlife/SL6B%20Nano/135/185/24">Virtual Sport nexus &#8211; Simboarding by Cyphien Heart</a>. Yes, really simboarding on a half pipe.</p>
<p><a href="http://slurl.com/secondlife/SL6B%20Polaris/65/77/24">Polaris by Sabine Stonebender</a>. Actually, the name might not be Polaris as that is the name of the sim. But it&#8217;s the only name I saw.</p>
<p><a href="http://slurl.com/secondlife/SL6B%20Polaris/149/75/23">Mechatiki Research Public Lab by magggnnus woodget</a>. Little physical robot animals that randomly walk around their enclosure.</p>
<p><a href="http://slurl.com/secondlife/SL6B%20Callisto/149/76/23">The Wall of Mirages by Robin Moore</a>.</p>
<p><a href="http://slurl.com/secondlife/SL6B%20Callisto/114/62/23">The Future is Ruth by Manx Wharton and Nestra Careless</a>.</p>
<p><a href="http://slurl.com/secondlife/SL6B%20Polaris/55/91/24">Your Future  Will Be&#8230; by Scrap Godenot</a>.</p>
<p><a href="http://slurl.com/secondlife/SL6B%20Polaris/126/162/28">Dizzy Banjo, Gestural Instrument</a>. This is on public land.  The point of interest here is the 3 round objects with Dizzy Banjo&#8217;s name on them.  Interact with them and figure out what they do.</p>
<div class="wp-caption alignnone" style="width: 510px"><a title="sl6b_030 by iliveisl, on Flickr" href="http://www.flickr.com/photos/iliveisl/3670507120/" target="_blank"><img title="Space is There" src="http://farm4.static.flickr.com/3319/3670507120_a149b05f46.jpg" alt="sl6b_030" width="500" height="298" /></a><p class="wp-caption-text">Space is There</p></div>
<p><span style="color: #888888;"><a href="http://www.flickr.com/photos/iliveisl/sets/72157620560028505/" target="_blank">Flicker set</a> by Ener Hax</span></p>
]]></content:encoded>
			<wfw:commentRss>http://iliveisl.com/second-life-6th-birthday/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Sim Stats: 05.16.09</title>
		<link>http://iliveisl.com/sim-stats-051609/</link>
		<comments>http://iliveisl.com/sim-stats-051609/#comments</comments>
		<pubDate>Sun, 17 May 2009 00:13:36 +0000</pubDate>
		<dc:creator>Micheil Merlin</dc:creator>
				<category><![CDATA[second life]]></category>
		<category><![CDATA[simstats]]></category>
		<category><![CDATA[iliveisl]]></category>
		<category><![CDATA[micheil merlin]]></category>

		<guid isPermaLink="false">http://blog.iliveisl.com/?p=679</guid>
		<description><![CDATA[Welcome to the sim stats for mid-May. SIM Micheil&#8217;s RATING DILATION FPS PHYSICS TIME SCRIPT TIME SPARE TIME SCRIPT SPEED Enerville 0.93 42 1.1 19.7 0 0.45 Ener Skerry 1.00 45 0.1 15.0 6.3 0.99 Ener Passage 0.98 44 3.4 4.5 14.1 0.35 Ener Strait 0.99 45 0.1 0.9 21.1 0.98 Enercay Midkey 1.00 45 [...]]]></description>
				<content:encoded><![CDATA[<p>Welcome to the sim stats for mid-May.</p>
<table style="text-align: center; height: 478px;" border="0" width="465">
<tbody>
<tr>
<td>
<h5><span style="color: #008000;"><strong>SIM</strong></span></h5>
</td>
<td>
<h5><span style="color: #008000;"><strong>Micheil&#8217;s RATING</strong></span></h5>
</td>
<td>
<h5><span style="color: #008000;"><strong>DILATION<br />
</strong></span></h5>
</td>
<td>
<h5><span style="color: #008000;"><strong>FPS<br />
</strong></span></h5>
</td>
<td>
<h5><span style="color: #008000;"><strong>PHYSICS<br />
TIME</strong></span></h5>
</td>
<td>
<h5><span style="color: #008000;"><strong>SCRIPT<br />
TIME</strong></span></h5>
</td>
<td>
<h5><span style="color: #008000;"><strong>SPARE<br />
TIME</strong></span></h5>
</td>
<td>
<h5><span style="color: #008000;"><strong>SCRIPT<br />
SPEED</strong></span></h5>
</td>
</tr>
<tr>
<td>Enerville</td>
<td><img class="alignnone size-full wp-image-568" src="http://iliveisl.com/wp-content/uploads/2009/04/star_06.gif" alt="star_06" width="91" height="19" /></td>
<td>0.93</td>
<td>42</td>
<td>1.1</td>
<td>19.7</td>
<td>0</td>
<td>0.45</td>
</tr>
<tr>
<td>Ener Skerry</td>
<td><img class="alignnone size-full wp-image-572" src="http://iliveisl.com/wp-content/uploads/2009/04/star_10.gif" alt="star_10" width="91" height="19" /></td>
<td>1.00</td>
<td>45</td>
<td>0.1</td>
<td>15.0</td>
<td>6.3</td>
<td>0.99</td>
</tr>
<tr>
<td>Ener Passage</td>
<td><img class="alignnone size-full wp-image-568" src="http://iliveisl.com/wp-content/uploads/2009/04/star_06.gif" alt="star_06" width="91" height="19" /></td>
<td>0.98</td>
<td>44</td>
<td>3.4</td>
<td>4.5</td>
<td>14.1</td>
<td>0.35</td>
</tr>
<tr>
<td>Ener Strait</td>
<td><img class="alignnone size-full wp-image-570" src="http://iliveisl.com/wp-content/uploads/2009/04/star_10.gif" alt="star_10" width="91" height="19" /></td>
<td>0.99</td>
<td>45</td>
<td>0.1</td>
<td>0.9</td>
<td>21.1</td>
<td>0.98</td>
</tr>
<tr>
<td>Enercay Midkey</td>
<td><img class="alignnone size-full wp-image-572" src="http://iliveisl.com/wp-content/uploads/2009/04/star_08.gif" alt="star_08" width="91" height="19" /></td>
<td>1.00</td>
<td>45</td>
<td>0.3</td>
<td>16.6</td>
<td>4.6</td>
<td>0.86</td>
</tr>
<tr>
<td>Enercay Westkey</td>
<td><img class="alignnone size-full wp-image-570" src="http://iliveisl.com/wp-content/uploads/2009/04/star_10.gif" alt="star_10" width="91" height="19" /></td>
<td>1.0</td>
<td>45</td>
<td>0.3</td>
<td>2.1</td>
<td>19.7</td>
<td>1.02</td>
</tr>
<tr>
<td>Enercity Harbor</td>
<td><img class="alignnone size-full wp-image-570" src="http://iliveisl.com/wp-content/uploads/2009/04/star_07.gif" alt="star_07" width="91" height="19" /></td>
<td>0.99</td>
<td>44</td>
<td>0.3</td>
<td>20.2</td>
<td>0</td>
<td>0.69</td>
</tr>
<tr>
<td>Enercity Weston</td>
<td><img class="alignnone size-full wp-image-568" src="http://iliveisl.com/wp-content/uploads/2009/04/star_06.gif" alt="star_06" width="91" height="19" /></td>
<td>0.99</td>
<td>45</td>
<td>1.4</td>
<td>18.8</td>
<td>0</td>
<td>0.42</td>
</tr>
<tr>
<td>Enercity Easton</td>
<td><img class="alignnone size-full wp-image-568" src="http://iliveisl.com/wp-content/uploads/2009/04/star_06.gif" alt="star_06" width="91" height="19" /></td>
<td>0.98</td>
<td>43</td>
<td>6.7</td>
<td>15.3</td>
<td>0</td>
<td>0.64</td>
</tr>
<tr>
<td>Enercity Square</td>
<td><img class="alignnone size-full wp-image-570" src="http://iliveisl.com/wp-content/uploads/2009/04/star_08.gif" alt="star_08" width="91" height="19" /></td>
<td>1.0</td>
<td>45</td>
<td>0.6</td>
<td>14.8</td>
<td>6.2</td>
<td>0.86</td>
</tr>
<tr>
<td>Enercity Shores</td>
<td><img class="alignnone size-full wp-image-571" src="http://iliveisl.com/wp-content/uploads/2009/04/star_10.gif" alt="star_10" width="91" height="19" /></td>
<td>1.0</td>
<td>45</td>
<td>0.3</td>
<td>17.4</td>
<td>2.7</td>
<td>0.96</td>
</tr>
<tr>
<td>Enercity Park</td>
<td><img class="alignnone size-full wp-image-572" src="http://iliveisl.com/wp-content/uploads/2009/04/star_08.gif" alt="star_08" width="91" height="19" /></td>
<td>1.0</td>
<td>45</td>
<td>0.2</td>
<td>1.1</td>
<td>20.4</td>
<td>0.87</td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>Selected SL Regions</td>
<td><img class="alignnone size-full wp-image-568" src="http://iliveisl.com/wp-content/uploads/2009/04/star_06.gif" alt="star_06" width="91" height="19" /></td>
<td>0.99</td>
<td>44</td>
<td>1.0</td>
<td>18.7</td>
<td>0.2</td>
<td>0.5</td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
</tbody>
</table>
<p><img class="size-full wp-image-573 alignleft" src="http://iliveisl.com/wp-content/uploads/2009/04/micheilsthoughts.gif" alt="micheilsthoughts" width="163" height="107" /><br />
Over the past month, server version 1.26.3.118673 was rolled out. The bulk of the changes seem to be geared toward the coming adult content implementation.</p>
<p>Also, since the last report, Enercay Westkey has been upgraded from a homestead to a full sim.</p>
<p>The statistics that I collect largely come from the statistics bar in the viewer. You can open this bar by selecting the View tab at the top of the screen, then selecting Statistics Bar. The <a href="http://wiki.secondlife.com/wiki/Statistics_Bar_Guide" target="_blank">Second Life Wiki</a> contains some information related to how to interpret some of this statistics. When reading the wiki, keep in mind that the current simulator version is 1.26 and the viewer version is 1.22.11. The release candidate viewer, 1.23.1 (119104), will save the state and screen location of the statistics bar if it is open when you log off and will open it again the next time you log on. Previous viewer versions did not save the state of the statistics bar.</p>
<p>The simulator divides the work it has to do into time slots generally referred to as a frame.</p>
<p>In the statistics bar, you&#8217;ll see frame referenced in a couple of different ways. The first, under the Basic heading, represents work that the viewer is doing. This is the frame per second (FPS) statistic that relates to how many times per second the viewer redraws you screen.</p>
<p>The second place you see frame referenced is under the Simulator heading. Here you&#8217;ll see Sim FPS and Physics FPS. The Sim FPS and Physics FPS numbers should be very close to the same. In practice, they usually vary from each other just a tiny bit.</p>
<p>The sim frame represents a slot of time that the sim uses to coordinate and complete its work. Things like accounting for sim weather, updating all the AV&#8217;s present with various information, running scripts, handling network traffic, etc. The physics part of the simulator also spends part of this time updating everything related to how physical objects are interacting with each other and other objects in the sim. By design, 45 FPS is the target rate for the sim. That means that each frame should ideally be 22.2 milliseconds (ms) in length. You get that number by dividing 1,000 ms (1 second) by 45.</p>
<p>So, what happens if there is too much work to do in 22.2 ms? It used to be that this was where time dilation kicked in which means that the frame times get stretched out to be longer than 22.2 ms. But now, the first thing that happens is that the sim devotes less of this time slot to running scripts. So, scripts slow down. In many cases, this can go fairly unnoticed allowing the sim to continue to appear to be running ok.</p>
<p>When slowing down scripts isn&#8217;t enough is when adjustments to the frame time happen. If you expand the Time section under Simulator, you&#8217;ll see Total Frame Time. Under load, that number will rise above 22.2 and the Time Dilation number will decrease below 1.0. If the sim is able to keep the frame rate up fairly well by slowing down scripts, you&#8217;ll generally see a time dilation of .99 with a frame rate of 44 to 45 and a total frame time of about 22.3 ms.</p>
<p>One really good indicator of whether or not the sim is busy is the Spare Time statistic. If there is any non-zero number here, then it means that this was the amount of time in the frame that the sim had nothing to do. However, it is not very normal for this number to be something other than zero which probably reflects how much we like scripted objects and physical objects.</p>
<p>An exception to the spare time &#8216;non-zero is good&#8217; rule is if the sim is not a full sim and is instead a homestead or openspace sim. In the case of a homestead or openspace, the spare time number can be greater than zero and the sim can still be overloaded. I think this is because homestead and openspace sims share processor cores, they don&#8217;t know how busy another sharing sim is and the sharing sim might be taking more than its share. There is also the fact that the whole idea of 22.2 ms frame time is based on a sim having complete access to processor resources and when there are sims sharing processors, that isn&#8217;t the case. But, that&#8217;s another subject.</p>
<p>In summary&#8230;</p>
<ul>
<li>A sim frame is 22.2 ms in length.</li>
<li>A time dilation of 1.0 means the sim is running at full speed.</li>
<li>As frame time gets larger than 22.2, time dilation drops below 1.0 and sim FPS drops below 45.</li>
<li>Spare time means there is time in the frame that the sim has nothing to do and is not running at capacity.</li>
<li>When busy, the sim will try to avoid increasing the sim frame time by spending less time running scripts.</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://iliveisl.com/sim-stats-051609/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
	</channel>
</rss>
