<?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>Adam Frisby &#187; mrm</title>
	<atom:link href="http://www.adamfrisby.com/blog/tag/mrm/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.adamfrisby.com/blog</link>
	<description>ZOMGWTFHAI</description>
	<lastBuildDate>Sat, 26 Dec 2009 07:02:09 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8.4</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>OS Under the Surface: May 2009</title>
		<link>http://www.adamfrisby.com/blog/2009/05/os-under-the-surface-may-2009/</link>
		<comments>http://www.adamfrisby.com/blog/2009/05/os-under-the-surface-may-2009/#comments</comments>
		<pubDate>Sat, 30 May 2009 11:35:15 +0000</pubDate>
		<dc:creator>Adam Frisby</dc:creator>
				<category><![CDATA[OpenSim]]></category>
		<category><![CDATA[Under the Surface]]></category>
		<category><![CDATA[assets]]></category>
		<category><![CDATA[groups]]></category>
		<category><![CDATA[IRC]]></category>
		<category><![CDATA[lludp]]></category>
		<category><![CDATA[mrm]]></category>
		<category><![CDATA[oar]]></category>
		<category><![CDATA[region modules]]></category>
		<category><![CDATA[remote control]]></category>
		<category><![CDATA[rest]]></category>
		<category><![CDATA[scripting]]></category>
		<category><![CDATA[services]]></category>
		<category><![CDATA[uts]]></category>
		<category><![CDATA[xmlrpc]]></category>

		<guid isPermaLink="false">http://www.adamfrisby.com/blog/?p=323</guid>
		<description><![CDATA[With May coming to a close, I would like to start the first of a monthly feature &#8211; some explanations of what&#8217;s going on under the surface of OpenSim. But wait, you may ask; doesn&#8217;t Justin already provide excellent weekly reports on what&#8217;s been committed? Of course &#8211; where this differs is in the level [...]]]></description>
			<content:encoded><![CDATA[<p>With May coming to a close, I would like to start the first of a monthly feature &#8211; some explanations of what&#8217;s going on under the surface of OpenSim. But wait, you may ask; doesn&#8217;t <a href="http://justincc.wordpress.com">Justin</a> already provide excellent weekly reports on what&#8217;s been committed? Of course &#8211; where this differs is in the level of detail, particularly on infrastructure projects. Justin does a weekly feature which means he only has time and space to report on features in bullet form. Where I plan to differentiate with these posts is in the details &#8211; not only what has been committed, but also where it is going.</p>
<p>There has been a lot of progress this month &#8211; starting at revision 9358 there have been several major areas of focus.</p>
<h3>Networking: LLUDP Improvements</h3>
<p>We now support the Multiple Object Update packet format for Linden UDP clients (most notably Second Life &amp; realXtend), this builds on work that Mikko of realXtend provided late in April that did the same for Avatar Updates. The work done by Melanie reduces the total number of packets that need to be tracked by packing multiple updates into each packet &#8211; resulting in a significantly lower workload for our packeting code. The Avatar packet aggregation with 100 Avatars in the region results in a massive 71% reduction in the number of packets transmitted, and a 29% drop in CPU requirements, according to <a href="http://www.sciencesim.com/wiki/doku.php/opensim/performance_profiling">tests done by Intel</a> for ScienceSim. Object aggregation produces similar results (although hasn&#8217;t been measured precisely.)</p>
<p>Packet Pooling &#8211; the next major improvement is in &#8216;packet pooling&#8217; &#8211; one of the drawbacks to managed languages is very little control over optimising garbage collection. OpenSim handles potentially thousands of packets each second, in our previous packet system for each of these packets, we created several classes representing the internal data structures. (eg, Byte[] Packet becomes MyPacketObject) &#8211; while the processing is fairly quick, creating these packets results in the Garbage Collector handling tens of thousands of tiny unused classes at each collection. On .NET this runs so-so, but on Mono it runs atrociously.</p>
<p>Packet Pooling solves this problem by recycling classes &#8211; rather than leaving a dead class to be garbage collected, we stuff new data into it and re-use the class instance. We previously did this work back in 2007 with the help of 3Di developers, however it was at the time proven unworkable due to problems with old data persisting into new data blocks. Melanie managed to solve this issue, and nearly two years later we have it re-enabled. Early pooling code did not show much promise past 40 avatars (although up to that point was fairly dramatically better) &#8211; however more <a href="http://www.sciencesim.com/wiki/doku.php/opensim/performance_profiling#r9395_with_some_optimizations">profiling done by intel</a> managed to locate the problem as being due to a finite sized pool &#8211; a patch fixed this problem and the overall improvement was a further 40% reduction in CPU requirements for 100 avatars (total reduction for this and aggregation is a whopping 57% reduction in CPU requirements for a busy sim).</p>
<p>Overall, the OpenSim networking code has been improved very significantly (especially with April&#8217;s texture resend fixes), and I would appreciate seeing more testing with large userbases &#8211; the Wright Plaza weekly meetings have been running better than they have for a long time, but only represent a peak of 35 concurrent users.</p>
<p>Some early bugs did present themselves with this networking code &#8211; most notably running into several MTU limits for international users (apparently most international trunk lines will simply drop rather than fragment big UDP packets), myself, Nebadon and Melanie managed to identify and fix this problem.</p>
<p>I introduced, then disabled support for NAT Loopback &#8211; this allows you to emulate a loop-back compatible router for those hosting from home and unable to get a public internet IP. This is currently commented out due to issues with compatibility in Grid Mode (however Standalone mode can be made to work effectively) &#8211; further improvements will be in the realm of adding UPnP support allowing you to host a region from home reliably. Finally I also introduced the capability to use IP and DNS based bans (including wildcards), Dr Scofield improved this with some stability checks.</p>
<h3>Groups Support</h3>
<p>mcortez has been working on adding a fully functional implementation of groups into OpenSim this month &#8211; previously located as part of the flotsam project, the groups implementation has hit core. Early revisions ran into a problem with a permissions exploit and group deeding (allowing anonymous users to group deed a parcel), however these have been fixed and it is ready for further testing. My initial feedback is that it looks good &#8211; things such as group chat are behaving well and responsively, although it is not yet fully functionally complete yet (particularly around the area of group permissions).</p>
<h3>New Region Modules Framework</h3>
<p>I&#8217;m not entirely sure if this was introduced this month &#8211; however a large amount of work was done porting from IRegionModule to the new ISharedRegionModule interface[s]. This new version is syntactically nearly identical, however has better support for removing regions at runtime, and also utilizes the Mono.Addins framework, which will be essential as we begin to add PECL/CPAN-style module repositories to OpenSim (although exactly when this happens is an unknown). The older region module format is going to remain working for quite some time yet &#8211; however if you are feeling adventurous you can investigate the new format and look at porting modules across.</p>
<h3>New Services Framework</h3>
<p>As part of a general improvement of OpenSim code quality, Diva and Melanie improved the services framework this month, deleting the old OGS1 &#8216;UGAIM&#8217; in favor of a new &#8216;OpenSim.Services&#8217; binary &#8211; this also means that the Grid mode and Standalone mode now share all the major infrastructure internally (Standalone runs the grid services in &#8216;private&#8217; now) &#8211; this reduces code complexity and makes it easier for us to add and adjust the services framework.</p>
<p>This framework has also made it easier to edit and adjust module points for Grid Services, meaning it is now possible to write Grid Service plugins &#8211; such as asset caches, external login systems, etc. Diva has been utilizing these to improve the functionality and quality of the Hypergrid technology. A new cache was implemented using GlynnTucker cache &#8211; after it was discovered the previous asset cache did not infact, cache anything, early testing indicates this one works.</p>
<p>Finally, Arthur implemented some improvements to the User Service framework which prevents people from seeing the &#8216;You are already logged in&#8217; message&#8217; in grid mode.</p>
<h3>Remote Control, Administration and Web Integration</h3>
<p>BlueWall introduced and improved his JSON Stats plugin system for OpenSim which allows remote monitoring via AJAX applications of a region. Melanie introduced a &#8216;remote console&#8217; system that utilizes REST, and I introduced some basic capacity for Grid Owners to be able to send grid-wide announcements for maintainence purposes. Dr Scofield improved the XMLRPC-based Remote Admin module to handle additional formats. All of these will no doubt go towards improving administrator remote tools and web interfaces.</p>
<h3>Inventory Archives</h3>
<p>Justin continued work on Inventory Archives &#8211; these allow you to save a copy of your entire OpenSim inventory to a file on disk, which you can then restore on any other compatible OpenSimulator instance. For those who work on multiple seperate OpenSim instances (such as a personal grid, public grid, etc) being able to synchronise your inventory between the two is a big help. IAR archives are still highly experimental and should not be relied on yet for any production purposes.</p>
<p>Justin also added the ability to store creator IDs as a URL rather than a UUID &#8211; this allows you to reference foreign grid avatars as a creator.</p>
<h3>Prim Meshing</h3>
<p>Dahlia continued work on the internal &#8216;Prim Mesher&#8217; used for physics. Improving sculpty physics shells to be more accurate and support properties such as Mirror, improving the overall meshing performance and adding the capability to disk-cache converted meshes for faster startups.</p>
<h3>XML Serialisation Formats and Region Archives</h3>
<p>Sean and Justin made several improvements to our XML Serialisation support including adding unit tests to the serialisers. This will improve overall reliability and support for OAR files as we move forward (preventing OARs from becoming version-incompatible with each other.), OARs were also improved with support for a wider variety of .tar formats courtesy of Dr Scofield. Finally, OARs were renamed from .tar.gz to .oar as the default filename.</p>
<h3>Scripting</h3>
<p>I improved MRM scripting, both the Engine and the API. The engine has been improved to support real-time loading of external binaries, including debugger support. This when compiled with the <a href="http://forge.opensimulator.org/gf/project/mrmloader/">MRM Loader project</a> (located on the forge) allows you to write (<em>and debug!</em>) MRM scripts from within Visual Studio (<em>very cool</em>.), MRMs were also improved with additional security checks, fixing of certain properties (such as Avatar.Position), events (World.OnNewUser) and introduction of an Audio API (World.Audio and IObject.Sound).</p>
<p>LSL was improved with support for the LSL Webserver API going into production on the Second Life(tm) Beta Grid. Also implemented was llAttachToAvatar, llDetachFromAvatar and a host of other improvements.</p>
<h3>IRC Clientstack</h3>
<p><a href="http://www.adamfrisby.com/blog/2009/05/adventures-in-text-only-opensim/">As mentioned earlier</a>, OpenSim now has a ClientView which supports a primitive text-only IRC protocol support. This allows you to connect to a region for chat facilities using only an IRC client &#8211; this may be an advantage over the previous IRC Bridge module where IRC users were not represented inworld with an avatar.</p>
<h3>Final Words</h3>
<p>If I missed anything &#8211; let me know, Justin&#8217;s notes are likely to be slightly more comprehensive on smaller non-architectural changes.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.adamfrisby.com/blog/2009/05/os-under-the-surface-may-2009/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>MRM Article on MaxPing</title>
		<link>http://www.adamfrisby.com/blog/2009/04/mrm-article-on-maxping/</link>
		<comments>http://www.adamfrisby.com/blog/2009/04/mrm-article-on-maxping/#comments</comments>
		<pubDate>Wed, 29 Apr 2009 11:11:13 +0000</pubDate>
		<dc:creator>Adam Frisby</dc:creator>
				<category><![CDATA[OpenSim]]></category>
		<category><![CDATA[maxping]]></category>
		<category><![CDATA[mrm]]></category>

		<guid isPermaLink="false">http://www.adamfrisby.com/blog/?p=226</guid>
		<description><![CDATA[Ziah Zhangsun has written an interesting article on using MRMs in OpenSim, go take a look.
]]></description>
			<content:encoded><![CDATA[<p>Ziah Zhangsun has written an <a href="http://www.maxping.org/technology/platforms/open-simulator/experimenting-with-mrm.aspx">interesting article on using MRMs</a> in OpenSim, go take a look.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.adamfrisby.com/blog/2009/04/mrm-article-on-maxping/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>MRM: Language Contributions</title>
		<link>http://www.adamfrisby.com/blog/2009/04/mrm-language-contributions/</link>
		<comments>http://www.adamfrisby.com/blog/2009/04/mrm-language-contributions/#comments</comments>
		<pubDate>Sat, 25 Apr 2009 05:48:11 +0000</pubDate>
		<dc:creator>Adam Frisby</dc:creator>
				<category><![CDATA[OpenSim]]></category>
		<category><![CDATA[mrm]]></category>
		<category><![CDATA[scripting]]></category>

		<guid isPermaLink="false">http://www.adamfrisby.com/blog/?p=213</guid>
		<description><![CDATA[If you are a coder and like the work I have been doing on MRM so far &#8211; I&#8217;m keen to accept any contributions you may have to the langage &#8211; patches on mantis are welcome (here&#8217;s how to submit). That being said, I am being somewhat restrictive with API-changing patches to ensure we have [...]]]></description>
			<content:encoded><![CDATA[<p>If you are a coder and like the work I have been doing on MRM so far &#8211; I&#8217;m keen to accept any contributions you may have to the langage &#8211; patches on mantis are welcome (<a href="http://opensimulator.org/wiki/Submitting_code_to_OpenSim">here&#8217;s how to submit</a>). That being said, I am being somewhat restrictive with API-changing patches to ensure we have a consistent easy to understand language rather than a patchwork quilt of random features. The following is the list of rules I am using for language inclusions;</p>
<h3>Coding Standards &#8211; The Rules for API Changes</h3>
<p>The MRM API is designed to &#8216;feel&#8217; like the official .NET API in as many ways as possible &#8211; this means it should be consistent and easy to understand. The same types and interfaces should be re-used in as many places as possible, duplication is to be strongly shunned.</p>
<h4>1. Class Library Design and Naming</h4>
<p>For core API (those items distributed with OpenSim), you must follow the <a href="http://msdn.microsoft.com/en-us/library/czefa0ke.aspx">Microsoft .NET Coding Standards</a> for naming and class design.</p>
<h4>2. Subclassing and Inheritance</h4>
<p>Subclass (or subinterface) where possible to make a useful inheritence chain. The following is the current proposed structure for MRM entity inheritance.</p>
<div id="attachment_214" class="wp-caption aligncenter" style="width: 494px"><img class="size-full wp-image-214" title="MRM IEntity Inheritance" src="http://www.adamfrisby.com/blog/wp-content/uploads/mrm_inheritance.png" alt="Fig 1. IEntity Inheritance" width="484" height="249" /><p class="wp-caption-text">Fig 1. IEntity Inheritance</p></div>
<p>Note that the above proposal is not set in stone &#8211; the alternative I am considering is inheriting IPlant from IObject, and making a new IPrimitiveObject &#8211; where we move prim related properties (such as Shape) into the subinterface.</p>
<h4>3. &#8220;Superglobals&#8221;</h4>
<p>You should insert items into the &#8220;Superglobals&#8221; appropriately. Superglobals are the [presently three] properties which are inherited from MRMBase. In the user-accessible language these are items such as &#8220;Host&#8221; or &#8220;World&#8221;.</p>
<h4>3.1 Host Superglobal</h4>
<p>Host means &#8220;Scripting Host&#8221;, items in Host should be directly related to the runtime environment the script is running in, such as performance characteristics, security permissions, etc. &#8211; it could almost be seen as analoguous to &#8220;System.Environment&#8221;.</p>
<p>Items placed into Host should be related to the runtime environment that is hosting the world itself. For instance, a database interface would be appropriate for &#8216;Host&#8217; since it is unrelated to the world itself and is something that is dependent on the runtime environment.</p>
<h4>3.2 World Superglobal</h4>
<p>World refers to the SceneGraph &#8211; and should contain elements which are reflected inside the visual environment. For instance Avatars, Objects and other items which exist in the &#8216;World&#8217;. This also includes properties of the world itself, such as lighting conditions, sun angle, etc.</p>
<h4>4. No Assumed Parameters</h4>
<p>MRM API entries should not be designed with an assumed &#8216;target&#8217; &#8211; that means that you should never ever assume you know the data the user will be processing unless it is directly connected to the object the user is calling the method on. Using an LSL function as an example, you should be able to quickly understand this rule.</p>
<p><strong><span style="color: #ff0000;">BAD</span></strong>: llSetPos(vector3 pos); <span style="color: #008000;">// Sets the position of the host object.</span><br />
<strong>GOOD</strong>: llSetPos(IObject target, vector3 pos); <span style="color: #008000;">// Sets the position of &#8216;target&#8217;</span></p>
<p>It should be noted that methods inside an object are free to act on themselves (eg IObject.Position is free to operate on the IObject instance), this only applies when referencing an outside object (such as say IAvatar.SitOn should have an IObject parameter and not assume which object to sit the avatar on).</p>
<h4>5. Do not use OpenSim Types.</h4>
<p>This means do not expose OpenSim internals to the MRM programmer &#8211; that means never return SceneObjectGroup, ScenePresence or any other internal representation to a MRM programmer. MRM provides replacements which take these as constructors in the form of IObject/IAvatar/etc&#8217;s implementors (SOPObject, SPAvatar, LOParcel, &#8230;)</p>
<p>If MRM does not implement your specific internal in an interface already, you must write an interface that can be passed to MRM programmers. The internal data should not implement the MRM &#8220;IAbcd&#8221; interface but instead a proxy should be written (see SOPObject for an example).</p>
<p>There is two reasons for this &#8211; the first is that passing internals means that any internal change will break MRM scripts. The second reason is security &#8211; security can be implemented inside the proxy whereas it cannot be implemented in the internal class.</p>
<h4>6. Use OpenMetaverse.Types</h4>
<p>libOpenmetaverse provides a number of useful types such as UUID, Vector3, etc. Use these whereever possible &#8211; for instance when representing U/V coordinates use &#8220;Vector2&#8243;.</p>
<h4>7. Use the most appropriate Type for the job.</h4>
<p>Do not use Vector3 to store only two values &#8211; use Vector2. There is a lot of types availible to use &#8211; make sure to pick the right one for the right job.</p>
<h4>8. Do not copy LSL needlessly.</h4>
<p>This is a big one &#8211; do not assume the LSL function set is an ideal to be upheld. Ask yourself when implementing a MRM replacement, &#8220;What is the using developer trying to do?&#8221;. Take the llSay, llShout, llWhisper, llRegionSay group &#8211; each implements the same underlying task, however the differing methods have a varying &#8216;range&#8217; depending on which one is called.</p>
<p>For instance, llShout will &#8217;say&#8217; 100m. llSay will &#8217;say&#8217; 20m. A using developer is going to pick between them based on which range they need &#8212; but what if they need another range? Wouldnt it be smarter to have Object.Say(string message, int range)? Not only have you reduced the number of functions &#8211; but you have given the user more power.</p>
<h4>9. Name Consistently</h4>
<p>If you use a function name &#8216;SetFoobar&#8217;, the &#8216;GetFoobar&#8217; should be called exactly that. Do not have &#8216;SetFoo/FooGet&#8217;, or &#8216;SetFoo/Foo&#8217;. (Note in practice, Set/Gets should always be implemented as C# properties.) To use LSL as another example &#8211; we should never end up with a pair like &#8216;llGetTextureOffset&#8217; and &#8216;llOffsetTexture&#8217;.</p>
<h4>10. Do not implement abitrary limits.</h4>
<p>Copying from <a href="http://www.adamfrisby.com/blog/2009/04/mrm-language-extensions-and-libraries/">earlier</a>, &#8220;If you have to, make them configurable. An example of this is the mandatory sleeps in LSL on functions like llEmail. Assume instead that people writing scripts in MRM know what they are doing.&#8221;</p>
<p>If you are implementing limits on particular MRM functions, make sure you have a damn good reason for it &#8211; you should assume MRM authors are region operators. If you implement specific limits, make sure you load them from OpenSim.ini.</p>
<h3>&#8220;Safe&#8221; Areas to Contribute to</h3>
<p>If the above has made you uncertain about contributing &#8211; there are a number of areas you can contribute safely towards, and they are pretty easy to find in the codebase.</p>
<ul>
<li>Look for &#8220;throw new NotImplementedException()&#8221; inside the code base &#8211; in classes such as SOPObject you can safely implement these functions and properties and nearly guaruntee your patch will get accepted.</li>
<li>Suggestions &#8211; if you dont feel capable of writing a specific function, leave me a comment with something you want to see. Either myself or someone else may take it up and implement it.</li>
<li>Documentation &#8211; I&#8217;m using XMLDOC to build the final API documentation, so inserting ///&lt;summary&gt; and other XMLDOC tags into the codebase is always appreciated. Make sure to do the commenting on the interfaces themselves and not their implementations (eg files starting with &#8220;I&#8221;).</li>
<li>Tests and Examples &#8211; Post MRM scripts and write test scripts, these will eventually be rigged up to our internal testing framework, so the more functionality tests the better.</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://www.adamfrisby.com/blog/2009/04/mrm-language-contributions/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>MRM: Microthreading Functions</title>
		<link>http://www.adamfrisby.com/blog/2009/04/mrm-microthreading-functions/</link>
		<comments>http://www.adamfrisby.com/blog/2009/04/mrm-microthreading-functions/#comments</comments>
		<pubDate>Fri, 24 Apr 2009 06:14:19 +0000</pubDate>
		<dc:creator>Adam Frisby</dc:creator>
				<category><![CDATA[OpenSim]]></category>
		<category><![CDATA[.net]]></category>
		<category><![CDATA[c#]]></category>
		<category><![CDATA[microthreads]]></category>
		<category><![CDATA[mrm]]></category>
		<category><![CDATA[scripting]]></category>

		<guid isPermaLink="false">http://www.adamfrisby.com/blog/?p=209</guid>
		<description><![CDATA[When running an infinite loop or other computationally expensive function, you will often want to release processing time back to the region to avoid causing undue &#8216;lag&#8217;. For instance &#8211; in a sim with 4,000 colour changing scripts, each will be trying to pummel the CPU simultaneously to get their updates onccuring.
What ends up happening [...]]]></description>
			<content:encoded><![CDATA[<p>When running an infinite loop or other computationally expensive function, you will often want to release processing time back to the region to avoid causing undue &#8216;lag&#8217;. For instance &#8211; in a sim with 4,000 colour changing scripts, each will be trying to pummel the CPU simultaneously to get their updates onccuring.</p>
<p>What ends up happening is each will run for a fairly long period of time until broken up by a processing expensive &#8220;thread switch&#8221; at which point the next gets a long run before going to the next and the next and the next, or alternatively &#8211; none will finish and only one will be running.</p>
<p>The following diagram explains this in action &#8211; script A runs until there is an expensive thread switch, at which point script B will commence operation. You can manually force a thread switch through the use of the &#8220;llSleep(0)&#8221; statement in LSL, however the cost of switching threads is still present.</p>
<div id="attachment_210" class="wp-caption aligncenter" style="width: 520px"><img class="size-full wp-image-210" title="Script Normal Threading" src="http://www.adamfrisby.com/blog/wp-content/uploads/mt_thread.png" alt="Fig 1. Normal Threaded Scripting" width="510" height="400" /><p class="wp-caption-text">Fig 1. Normal Threaded Scripting</p></div>
<p>Microthreading allows you to say &#8220;You can pause and give time to another script&#8221; &#8211; in a way that is very lightweight and easy for the runtime VM. You manually insert breakpoints into the script which define points between the &#8216;tasklets&#8217;, at these points the VM can switch between runtime contexts without any penalty. As a result you can have thousands of them without problem; when running time is divided between all the running threads evenly &#8211; broken up at the tasklet borders.</p>
<p>The following diagram shows the same as above, in a microthreading environment.</p>
<div id="attachment_211" class="wp-caption aligncenter" style="width: 520px"><img class="size-full wp-image-211" title="Microthreaded Environment" src="http://www.adamfrisby.com/blog/wp-content/uploads/mt_micro.png" alt="Fig 2. Microthreaded Runtime" width="510" height="400" /><p class="wp-caption-text">Fig 2. Microthreaded Runtime</p></div>
<p>C# supports a limited form of microthreading via something called the &#8220;<a href="http://msdn.microsoft.com/en-us/library/9k7k7cf0(VS.80).aspx">yield</a>&#8221; keyword &#8211; and a lot of people have recognised you can use it to <a href="http://blogs.msdn.com/matt_pietrek/archive/2004/07/26/197242.aspx">build a state machine</a> &#8212; the basis of microthreading. Where we apply this to MRM is with some additional keywords.</p>
<p>The basic C# microthreading can be implemented in MRM without any additional work &#8211; however there is a significant manual cost in typing the construction of a microthreaded function. I have added two new keywords to MRM scripts today, which map to the C# yield statements.</p>
<p>The first is &#8220;microthreaded&#8221; &#8211; this keyword is inserted between the public/private/protected/internal keywords at the beggining of the function, and the variable type.For example, &#8220;private microthreaded void MyFunction(&#8230;) {&#8221;. Microthreaded functions can only work on functions with a no return type (void) &#8211; and internally it works by replacing &#8220;microthreaded void&#8221; with &#8220;IEnumerable&#8221;.</p>
<p>The second important keyword is &#8220;relax&#8221; &#8211; this keyword is defined as a breakpoint &#8211; an area where the VM can switch into another microthread without a penalty. There is a very small cost in placing these statements into your code, so consider placing them liberally. Place them inside of any loops or other routines which have a total processing time in excess of 2 milliseconds.</p>
<p>The relax keyword can only be placed inside of functions marked microthreaded &#8211; and you cannot call microthreaded functions directly (as in &#8220;Function(params)&#8221;). You must place microthreaded functions into the host scheduler marked as &#8216;Host.Microthreads.Run(myfunc(params));&#8217;</p>
<p>Another important note is that microthreaded functions will run asynchronously to your code, so do not expect &#8220;Microthreads.Run(&#8230;)&#8221; to block, consider it more a &#8216;Microthreads.ScheduleToRun(&#8230;)&#8217;. If you take these penalties into consideration however, these Microthreads can provide an excellent way to optimize your scripting and write coroutines relatively easily and quickly.</p>
<p>By default, the MRM VM will run 1,000 microthread tasklets per frame (or optimally 45,000 per second), this can be tweaked from inside of MRMModule.cs, however will eventually move into the OpenSim.ini [MRM] section.</p>
<p>The following is an example script that uses MRM microthreads.</p>
<textarea name="code" class="c#:nocontrols" cols="60" rows="10">
//MRM:C#
using System.Collections;
using System.Collections.Generic;
using OpenSim.Region.OptionalModules.Scripting.Minimodule;

namespace OpenSim
{
    class MiniModule : MRMBase
    {
		public microthreaded void MicroThreadFunction(string testparam) 
		{
			Host.Object.Say("Hello " + testparam);
			
			relax; // the 'relax' keyword gives up processing time.
				   // and should be inserted before, after or in
				   // any computationally "heavy" zones.
			
			int c = 500;
			while(c-- < 0) {
				Host.Object.Say("C=" + c);
				relax; // Putting 'relax' in microthreaded loops
					   // is an easy way to lower the CPU tax
					   // on your script.
			}
			
		}

        public override void Start()
        {
            Host.Microthreads.Run(
					MicroThreadFunction("World!")
				);
        }
        
        public override void Stop()
        {
            
        }
    }
}
</textarea>
<p>Enjoy.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.adamfrisby.com/blog/2009/04/mrm-microthreading-functions/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>MRM: Language Extensions and Libraries</title>
		<link>http://www.adamfrisby.com/blog/2009/04/mrm-language-extensions-and-libraries/</link>
		<comments>http://www.adamfrisby.com/blog/2009/04/mrm-language-extensions-and-libraries/#comments</comments>
		<pubDate>Tue, 21 Apr 2009 05:51:07 +0000</pubDate>
		<dc:creator>Adam Frisby</dc:creator>
				<category><![CDATA[OpenSim]]></category>
		<category><![CDATA[mrm]]></category>
		<category><![CDATA[scripting]]></category>

		<guid isPermaLink="false">http://www.adamfrisby.com/blog/?p=191</guid>
		<description><![CDATA[As of r9240, MRM now has proper support for language extensions &#8211; these come in two key flavours &#8211; the first is the ability to import outside .NET DLLs which allow you to load foreign libraries into your code, this could take the form of more advanced math libraries or other useful tools. Those libraries [...]]]></description>
			<content:encoded><![CDATA[<p>As of r9240, MRM now has proper support for language extensions &#8211; these come in two key flavours &#8211; the first is the ability to import outside .NET DLLs which allow you to load foreign libraries into your code, this could take the form of more advanced math libraries or other useful tools. Those libraries will be loaded with the same security context as your MRM &#8211; so when CAS is implemented in MRM for security, you will need to be aware that they will be affected too.</p>
<p>The syntax for importing a library is fairly simple &#8211; just place within your code, below the //MRM:C# line, a line which reads like this:</p>
<p>//@DEPENDS:MyLibrary.dll</p>
<p>Dependencies are requirements &#8211; if the dependent DLL cannot be found, it will throw a compile error, even if no code utilizes this extension.</p>
<h3>Accessing Region Modules</h3>
<p>The second form of language extension &#8211; the preferable one is to connect with other OpenSim region modules. Internally in OpenSim when a region module wishes to communicate with another module, it is done via a shared interface &#8211; one module will define an interface it can be accessed by (eg, IMRMModule)</p>
<p>Communicating with an MRM is done in a very similar fashion &#8211; you must create an interface that the script can utilize to connect to your module. This is best illustrated with an example, so printed below is a &#8220;Hello World&#8221; module, it&#8217;s structure is pretty simple.</p>
<h4>The Module Code</h4>
<textarea name="code" class="c#:nocontrols" cols="60" rows="10">
using Nini.Config;
using OpenSim.Region.Framework.Interfaces;
using OpenSim.Region.Framework.Scenes;

namespace OpenSim.Region.OptionalModules.Scripting.Minimodule.Test.Extensions
{
    internal interface IMRMExtensionTestModule
    {
        string ReturnHelloWorld();
    }

    class MRMExtensionTestModule : IRegionModule, IMRMExtensionTestModule
    {
        #region IMRMExtensionTestModule Members
        // This is the implementation for the above
        // interface and will be availible to the script
        public string ReturnHelloWorld()
        {
            return "Hello World!";
        }
        #endregion

        #region IRegionModule Members
        
        public void Initialise(Scene scene, IConfigSource source)
        {
            // Request IMRMModule to access the MRM Host...
            scene.RequestModuleInterface<IMRMModule>().
                // and register our custom extension.
                RegisterExtension<IMRMExtensionTestModule>(this);
        }

        public void PostInitialise()
        {
            
        }

        public void Close()
        {
            
        }

        public string Name
        {
            get { return "MRM Test Extension Module"; }
        }

        public bool IsSharedModule
        {
            get { return true; }
        }
        #endregion
    }
}
</textarea>
<h4>A sample MRM using the above</h4>
<textarea name="code" class="c#:nocontrols" cols="60" rows="10">
//MRM:C#
//@DEPENDS:MyModule.dll
using OpenSim.Region.OptionalModules.Scripting.Minimodule;

// Change this to your MyModule.dll namespace:
using OpenSim.Region.OptionalModules.Scripting.Minimodule.Test.Extensions;

namespace OpenSim
{
    class MiniModule2 : MRMBase
    {
        public override void Start()
        {
            // Get our extension
            IMRMExtensionTestModule testExtension = Host.Extensions.Get<IMRMExtensionTestModule>();

            // Say Hello
            Host.Object.Say(
                testExtension.ReturnHelloWorld()
                );

            // or the same thing in one line:

            Host.Object.Say(
                Host.Extensions.Get<IMRMExtensionTestModule>().ReturnHelloWorld()
                );
        }

        public override void Stop()
        {

        }
    }
}
</textarea>
<p>This code represents a fairly simple example &#8211; there are a few considerations to make however when writing MRM interfaces, especially if you desire to get those interfaces into the core OpenSim distribution.</p>
<h3>Good practices when writing a module interface</h3>
<p>These are based loosely on the rules I am employing in designing the default API.</p>
<ul>
<li><strong>Use MRM types where possible</strong> &#8211; if you need to get an object as a parameter, utilize IObject rather than pass a UUID or localID. You can convert between them pretty easily (SOPObject takes LocalID as a singular constructor, and you can fetch it off via IObject.LocalID).</li>
<li><strong>Do not pass in internal OpenSim classes.</strong> This means do not ever return something like SceneObjectPart &#8211; this is because OpenSim internal classes change, and when they change your MRM will break. If you need to use one of these classes and MRM doesnt have a matching interface already, make a new interface and contact me for possible inclusion in the standard distribution.</li>
<li><strong>Do not require IHost for anything.</strong> If you want the user to pass in the host object, ask them to do it &#8211; but do not require it. This is because someone may find it useful to utilize your function on a remote object. By using IObject you make your module more useful to programmers.</li>
<li><strong>If you need a unique ID for the script instance, require a UUID to passed</strong>, then request the user uses the global variable &#8220;ID&#8221;. This is a UUID that corresponds with the internal Inventory Item UUID of the MRM script.</li>
<li><strong>Do not place abitrary limits on scripts.</strong> If you have to, make them configurable. An example of this is the mandatory sleeps in LSL on functions like llEmail. Assume instead that people writing scripts in MRM know what they are doing.</li>
<li><strong>Follow <a href="http://msdn.microsoft.com/en-us/library/czefa0ke.aspx">MSDN C# Coding Guidelines</a></strong>. We use the MSDN Class Library coding standard in OpenSim, MRM by extension uses the same guidelines.</li>
</ul>
<p>Happy Extending!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.adamfrisby.com/blog/2009/04/mrm-language-extensions-and-libraries/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>MRM Micropost: Keyword Rename</title>
		<link>http://www.adamfrisby.com/blog/2009/04/mrm-micropost-keyword-rename/</link>
		<comments>http://www.adamfrisby.com/blog/2009/04/mrm-micropost-keyword-rename/#comments</comments>
		<pubDate>Sat, 11 Apr 2009 07:24:47 +0000</pubDate>
		<dc:creator>Adam Frisby</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[mrm]]></category>
		<category><![CDATA[OpenSim]]></category>
		<category><![CDATA[scripting]]></category>

		<guid isPermaLink="false">http://www.adamfrisby.com/blog/2009/04/mrm-micropost-keyword-rename/</guid>
		<description><![CDATA[//MiniMod:C# no longer is the MRM keyword, the new keyword is //MRM:C#
That is all.
]]></description>
			<content:encoded><![CDATA[<p>//MiniMod:C# no longer is the MRM keyword, the new keyword is //MRM:C#</p>
<p>That is all.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.adamfrisby.com/blog/2009/04/mrm-micropost-keyword-rename/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>MRM Micropost: &#8220;Type&#8221; via &#8216;is&#8217;</title>
		<link>http://www.adamfrisby.com/blog/2009/04/mrm-micropost-type-via-is/</link>
		<comments>http://www.adamfrisby.com/blog/2009/04/mrm-micropost-type-via-is/#comments</comments>
		<pubDate>Fri, 10 Apr 2009 06:48:21 +0000</pubDate>
		<dc:creator>Adam Frisby</dc:creator>
				<category><![CDATA[OpenSim]]></category>
		<category><![CDATA[mrm]]></category>
		<category><![CDATA[scripting]]></category>

		<guid isPermaLink="false">http://www.adamfrisby.com/blog/?p=164</guid>
		<description><![CDATA[Determining the type of object returned via a sensor or other detection event (eg collision, etc) in LSL is done via llDetectedType() &#8211; this returns a bitflags containing whether the object is an avatar, prim, etc.
Under MRM, the same is achieved by using the C# keyword &#8220;is&#8221;. In C# this returns true if the object [...]]]></description>
			<content:encoded><![CDATA[<p>Determining the type of object returned via a sensor or other detection event (eg collision, etc) in LSL is done via llDetectedType() &#8211; this returns a bitflags containing whether the object is an avatar, prim, etc.</p>
<p>Under MRM, the same is achieved by using the C# keyword &#8220;is&#8221;. In C# this returns true if the object is a specific type, or implements the interface &#8216;type&#8217;; because of this it means that we can determine what an IEntity is by looking for the inherited classes.</p>
<p>For example:</p>
<textarea name="code" class="c#:nocontrols" cols="60" rows="10">
//MiniMod:C#
using OpenSim.Region.OptionalModules.Scripting.Minimodule;

namespace OpenSim
{
    class MiniModule : MRMBase
    {
        public override void Start()
        {
            World.OnChat += World_OnChat;
        }

        void World_OnChat(IWorld sender, ChatEventArgs e)
        {
            if (e.Sender is IAvatar)
            {
                if (!e.Text.Contains("hic!"))
                {
                    e.Text = e.Text.Replace("s", "sh");
                    e.Text = e.Text.Replace("S", "Sh");
                    e.Text += " ...hic!";

                    Host.Object.Say(e.Text);
                }
            }

            if(e.Sender is IObject)
            {
                // Ignore
            }
        }

        public override void Stop()
        {

        }
    }
}
</textarea>
<p>In this example, e.Sender is defined to be an IEntity &#8211; which can mean an Object or an Avatar presently (there may be other types of entity potentially later on). You can determine exactly what type of entity using &#8220;is IObject&#8221; or &#8220;is IAvatar&#8221;, and if it returns true, you can typecast to those interfaces safely.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.adamfrisby.com/blog/2009/04/mrm-micropost-type-via-is/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>MRM: The API, Continued.</title>
		<link>http://www.adamfrisby.com/blog/2009/04/mrm-the-api-continued/</link>
		<comments>http://www.adamfrisby.com/blog/2009/04/mrm-the-api-continued/#comments</comments>
		<pubDate>Thu, 09 Apr 2009 08:05:16 +0000</pubDate>
		<dc:creator>Adam Frisby</dc:creator>
				<category><![CDATA[OpenSim]]></category>
		<category><![CDATA[mrm]]></category>
		<category><![CDATA[scripting]]></category>

		<guid isPermaLink="false">http://www.adamfrisby.com/blog/?p=154</guid>
		<description><![CDATA[MRM is now functional to the point where you can begin to implement simple scripts in it (r9060), the following is the &#8216;default LSL script&#8217; written as a MRM:

using OpenSim.Region.OptionalModules.Scripting.Minimodule;

namespace OpenSim
{
    class MiniModule : MRMBase
    {
        public override void Start()
   [...]]]></description>
			<content:encoded><![CDATA[<p>MRM is now functional to the point where you can begin to implement simple scripts in it (r9060), the following is the &#8216;default LSL script&#8217; written as a MRM:</p>
<textarea name="code" class="c#:nocontrols" cols="60" rows="10">
using OpenSim.Region.OptionalModules.Scripting.Minimodule;

namespace OpenSim
{
    class MiniModule : MRMBase
    {
        public override void Start()
        {
            // Say Hello
            Host.Object.Say("Hello, Avatar!");

            // Register ourselves to listen
            // for touch events.
            Host.Object.OnTouch += OnTouched;
        }

        // This is our touch event handler
        void OnTouched(IObject sender, TouchEventArgs e)
        {
            Host.Object.Say("Touched.");
        }

        public override void Stop()
        {
            
        }
    }
}
</textarea>
<p>The API is slowly being documented too &#8211; it is being documented with .NET XMLDOC comments, so that our <a href="http://docs.opensimulator.org">docs project site</a> will also provide up to date information on how to write MRM scripts. For example, take a look at the documentation for <a href="http://docs.opensimulator.org/interfaceOpenSim_1_1Region_1_1OptionalModules_1_1Scripting_1_1Minimodule_1_1IObject.html">IObject</a> or <a href="http://docs.opensimulator.org/interfaceOpenSim_1_1Region_1_1OptionalModules_1_1Scripting_1_1Minimodule_1_1IHeightmap.html">IHeightmap</a>.</p>
<p>As you can see, it is slowly taking shape &#8211; the areas in most need of attention are Avatar properties, defining &#8220;social entities&#8221; (eg Users, Groups, with a common interface to both for common properties) and also adding event handlers for the multitude of events we are capable of supporting. (In theory we could support the much wider array of Scene.EventManager than just what LSL exposes to you.)</p>
<p>The following table is my &#8216;in progress&#8217; list of what will be replacing what in LSL nomenclature &#8211; functions which have no corresponding MRM properties are not listed here yet.</p>
<p><span id="more-154"></span></p>
<h3>Appendix i. Compatibility table (as of r9060)</h3>
<p>As you can see in the codebase, some of these functions below do not have full implementations yet (eg llSensor is only partially matched up &#8211; it would be fully matched up when we have a function to allow you to determine if something falls within a cone or sphere, and request only those from Scene). </p>
<p>This will be corrected over time &#8211; as will the functionality differences. An ultimate goal with MRM will be to have a feature set which overlaps completely enough that it would be possible to write an LSL to MRM translator with reasonable accuracy. It should also be possible to write an interface or translation layer which provides LSL structures similar to our LSLBase structure &#8211; but that maps underneath over to an IObject/MRM API.</p>
<table style="border-collapse: collapse; width: 308pt;" border="0" cellspacing="0" cellpadding="0" width="410">
<col style="width: 147pt;" width="196"></col>
<col style="width: 161pt;" width="214"></col>
<tbody>
<tr style="height: 15pt;" height="20">
<td class="xl65" style="height: 15pt; width: 147pt;" width="196" height="20"><strong>Function</strong></td>
<td class="xl65" style="width: 161pt;" width="214"><strong>MRM Equivilent</strong></td>
</tr>
<tr style="height: 15pt;" height="20">
<td style="height: 15pt;" height="20">llGetDate</td>
<td class="xl64">DateTime.Now.*</td>
</tr>
<tr style="height: 15pt;" height="20">
<td style="height: 15pt;" height="20">llGetTime</td>
<td class="xl64">DateTime.Now.*</td>
</tr>
<tr style="height: 15pt;" height="20">
<td style="height: 15pt;" height="20">llGetTimeOfDay</td>
<td class="xl64">DateTime.Now.*</td>
</tr>
<tr style="height: 15pt;" height="20">
<td style="height: 15pt;" height="20">llGetTimestamp</td>
<td class="xl64">DateTime.Now.*</td>
</tr>
<tr style="height: 15pt;" height="20">
<td style="height: 15pt;" height="20">llGetAndResetTime</td>
<td class="xl64">Debug.Stopwatch</td>
</tr>
<tr style="height: 15pt;" height="20">
<td style="height: 15pt;" height="20">llGetAgentInfo</td>
<td>IAvatar.*</td>
</tr>
<tr style="height: 15pt;" height="20">
<td style="height: 15pt;" height="20">llGetAgentSize</td>
<td>IAvatar.*</td>
</tr>
<tr style="height: 15pt;" height="20">
<td style="height: 15pt;" height="20">llGetListEntryType</td>
<td class="xl64">ICollection</td>
</tr>
<tr style="height: 15pt;" height="20">
<td style="height: 15pt;" height="20">llGetListLength</td>
<td class="xl64">ICollection</td>
</tr>
<tr style="height: 15pt;" height="20">
<td style="height: 15pt;" height="20">llList2CSV</td>
<td class="xl64">ICollection</td>
</tr>
<tr style="height: 15pt;" height="20">
<td style="height: 15pt;" height="20">llList2Float</td>
<td class="xl64">ICollection</td>
</tr>
<tr style="height: 15pt;" height="20">
<td style="height: 15pt;" height="20">llList2Integer</td>
<td class="xl64">ICollection</td>
</tr>
<tr style="height: 15pt;" height="20">
<td style="height: 15pt;" height="20">llList2Key</td>
<td class="xl64">ICollection</td>
</tr>
<tr style="height: 15pt;" height="20">
<td style="height: 15pt;" height="20">llList2List</td>
<td class="xl64">ICollection</td>
</tr>
<tr style="height: 15pt;" height="20">
<td style="height: 15pt;" height="20">llList2ListStrided</td>
<td class="xl64">ICollection</td>
</tr>
<tr style="height: 15pt;" height="20">
<td style="height: 15pt;" height="20">llList2Rot</td>
<td class="xl64">ICollection</td>
</tr>
<tr style="height: 15pt;" height="20">
<td style="height: 15pt;" height="20">llList2String</td>
<td class="xl64">ICollection</td>
</tr>
<tr style="height: 15pt;" height="20">
<td style="height: 15pt;" height="20">llList2Vector</td>
<td class="xl64">ICollection</td>
</tr>
<tr style="height: 15pt;" height="20">
<td style="height: 15pt;" height="20">llListen</td>
<td class="xl64">ICollection</td>
</tr>
<tr style="height: 15pt;" height="20">
<td style="height: 15pt;" height="20">llListenControl</td>
<td class="xl64">ICollection</td>
</tr>
<tr style="height: 15pt;" height="20">
<td style="height: 15pt;" height="20">llListenRemove</td>
<td class="xl64">ICollection</td>
</tr>
<tr style="height: 15pt;" height="20">
<td style="height: 15pt;" height="20">llListFindList</td>
<td class="xl64">ICollection</td>
</tr>
<tr style="height: 15pt;" height="20">
<td style="height: 15pt;" height="20">llListInsertList</td>
<td class="xl64">ICollection</td>
</tr>
<tr style="height: 15pt;" height="20">
<td style="height: 15pt;" height="20">llListRandomize</td>
<td class="xl64">ICollection</td>
</tr>
<tr style="height: 15pt;" height="20">
<td style="height: 15pt;" height="20">llListReplaceList</td>
<td class="xl64">ICollection</td>
</tr>
<tr style="height: 15pt;" height="20">
<td style="height: 15pt;" height="20">llListSort</td>
<td class="xl64">ICollection</td>
</tr>
<tr style="height: 15pt;" height="20">
<td style="height: 15pt;" height="20">llListStatistics</td>
<td class="xl64">ICollection</td>
</tr>
<tr style="height: 15pt;" height="20">
<td style="height: 15pt;" height="20">llDetectedGrab</td>
<td class="xl63">IObject.* / On*Args</td>
</tr>
<tr style="height: 15pt;" height="20">
<td style="height: 15pt;" height="20">llDetectedGroup</td>
<td class="xl63">IObject.*</td>
</tr>
<tr style="height: 15pt;" height="20">
<td style="height: 15pt;" height="20">llDetectedKey</td>
<td class="xl63">IObject.*</td>
</tr>
<tr style="height: 15pt;" height="20">
<td style="height: 15pt;" height="20">llDetectedLinkNumber</td>
<td class="xl63">IObject.*</td>
</tr>
<tr style="height: 15pt;" height="20">
<td style="height: 15pt;" height="20">llDetectedName</td>
<td class="xl63">IObject.* / On*Args</td>
</tr>
<tr style="height: 15pt;" height="20">
<td style="height: 15pt;" height="20">llDetectedOwner</td>
<td class="xl63">IObject.* / On*Args</td>
</tr>
<tr style="height: 15pt;" height="20">
<td style="height: 15pt;" height="20">llDetectedPos</td>
<td class="xl63">IObject.* / On*Args</td>
</tr>
<tr style="height: 15pt;" height="20">
<td style="height: 15pt;" height="20">llDetectedRot</td>
<td class="xl63">IObject.* / On*Args</td>
</tr>
<tr style="height: 15pt;" height="20">
<td style="height: 15pt;" height="20">llDetectedTouchBinormal</td>
<td class="xl63">OnTouchArgs</td>
</tr>
<tr style="height: 15pt;" height="20">
<td style="height: 15pt;" height="20">llDetectedTouchFace</td>
<td class="xl63">OnTouchArgs</td>
</tr>
<tr style="height: 15pt;" height="20">
<td style="height: 15pt;" height="20">llDetectedTouchNormal</td>
<td class="xl63">OnTouchArgs</td>
</tr>
<tr style="height: 15pt;" height="20">
<td style="height: 15pt;" height="20">llDetectedTouchPos</td>
<td class="xl63">OnTouchArgs</td>
</tr>
<tr style="height: 15pt;" height="20">
<td style="height: 15pt;" height="20">llDetectedTouchST</td>
<td class="xl63">OnTouchArgs</td>
</tr>
<tr style="height: 15pt;" height="20">
<td style="height: 15pt;" height="20">llDetectedTouchUV</td>
<td class="xl63">OnTouchArgs</td>
</tr>
<tr style="height: 15pt;" height="20">
<td style="height: 15pt;" height="20">llDetectedType</td>
<td class="xl63">On*Args</td>
</tr>
<tr style="height: 15pt;" height="20">
<td style="height: 15pt;" height="20">llDetectedVel</td>
<td>IObject.*</td>
</tr>
<tr style="height: 15pt;" height="20">
<td style="height: 15pt;" height="20">llGetAccel</td>
<td>IObject.*</td>
</tr>
<tr style="height: 15pt;" height="20">
<td style="height: 15pt;" height="20">llGetCreator</td>
<td>IObject.*</td>
</tr>
<tr style="height: 15pt;" height="20">
<td style="height: 15pt;" height="20">llGetKey</td>
<td>IObject.*</td>
</tr>
<tr style="height: 15pt;" height="20">
<td style="height: 15pt;" height="20">llGetLocalPos</td>
<td>IObject.*</td>
</tr>
<tr style="height: 15pt;" height="20">
<td style="height: 15pt;" height="20">llGetLocalRot</td>
<td>IObject.*</td>
</tr>
<tr style="height: 15pt;" height="20">
<td style="height: 15pt;" height="20">llGetObjectDetails</td>
<td>IObject.*</td>
</tr>
<tr style="height: 15pt;" height="20">
<td style="height: 15pt;" height="20">llGetObjectName</td>
<td>IObject.*</td>
</tr>
<tr style="height: 15pt;" height="20">
<td style="height: 15pt;" height="20">llGetOwner</td>
<td>IObject.*</td>
</tr>
<tr style="height: 15pt;" height="20">
<td style="height: 15pt;" height="20">llGetOwnerKey</td>
<td>IObject.*</td>
</tr>
<tr style="height: 15pt;" height="20">
<td style="height: 15pt;" height="20">llGetPos</td>
<td>IObject.*</td>
</tr>
<tr style="height: 15pt;" height="20">
<td style="height: 15pt;" height="20">llGetPrimitiveParams</td>
<td>IObject.*</td>
</tr>
<tr style="height: 15pt;" height="20">
<td style="height: 15pt;" height="20">llGetRot</td>
<td>IObject.*</td>
</tr>
<tr style="height: 15pt;" height="20">
<td style="height: 15pt;" height="20">llGetScale</td>
<td>IObject.*</td>
</tr>
<tr style="height: 15pt;" height="20">
<td style="height: 15pt;" height="20">llSetPos</td>
<td>IObject.*</td>
</tr>
<tr style="height: 15pt;" height="20">
<td style="height: 15pt;" height="20">llSetPrimitiveParams</td>
<td>IObject.*</td>
</tr>
<tr style="height: 15pt;" height="20">
<td style="height: 15pt;" height="20">llSetRot</td>
<td>IObject.*</td>
</tr>
<tr style="height: 15pt;" height="20">
<td style="height: 15pt;" height="20">llSetScale</td>
<td>IObject.*</td>
</tr>
<tr style="height: 15pt;" height="20">
<td style="height: 15pt;" height="20">llSetTouchText</td>
<td>IObject.*</td>
</tr>
<tr style="height: 15pt;" height="20">
<td style="height: 15pt;" height="20">llSitTarget</td>
<td>IObject.*</td>
</tr>
<tr style="height: 15pt;" height="20">
<td style="height: 15pt;" height="20">llGetLinkKey</td>
<td>IObject.Children.*</td>
</tr>
<tr style="height: 15pt;" height="20">
<td style="height: 15pt;" height="20">llGetLinkName</td>
<td>IObject.Children.*</td>
</tr>
<tr style="height: 15pt;" height="20">
<td style="height: 15pt;" height="20">llGetLinkNumber</td>
<td>IObject.Children.*</td>
</tr>
<tr style="height: 15pt;" height="20">
<td style="height: 15pt;" height="20">llGetObjectDesc</td>
<td>IObject.Description</td>
</tr>
<tr style="height: 15pt;" height="20">
<td style="height: 15pt;" height="20">llGetStatus</td>
<td>IObject.Is*</td>
</tr>
<tr style="height: 15pt;" height="20">
<td style="height: 15pt;" height="20">llSetAlpha</td>
<td>IObject.Is*</td>
</tr>
<tr style="height: 15pt;" height="20">
<td style="height: 15pt;" height="20">llSetColor</td>
<td>IObject.Materials.*</td>
</tr>
<tr style="height: 15pt;" height="20">
<td style="height: 15pt;" height="20">llSetLinkAlpha</td>
<td>IObject.Materials.*</td>
</tr>
<tr style="height: 15pt;" height="20">
<td style="height: 15pt;" height="20">llSetLinkColor</td>
<td>IObject.Materials.*</td>
</tr>
<tr style="height: 15pt;" height="20">
<td style="height: 15pt;" height="20">llSetLinkPrimitiveParams</td>
<td>IObject.Materials.*</td>
</tr>
<tr style="height: 15pt;" height="20">
<td style="height: 15pt;" height="20">llSetLinkTexture</td>
<td>IObject.Materials.*</td>
</tr>
<tr style="height: 15pt;" height="20">
<td style="height: 15pt;" height="20">llGetAlpha</td>
<td>IObject.Materials.*</td>
</tr>
<tr style="height: 15pt;" height="20">
<td style="height: 15pt;" height="20">llGetColor</td>
<td>IObject.Materials.*</td>
</tr>
<tr style="height: 15pt;" height="20">
<td style="height: 15pt;" height="20">llSetTexture</td>
<td>IObject.Materials.*</td>
</tr>
<tr style="height: 15pt;" height="20">
<td style="height: 15pt;" height="20">llSetTextureAnim</td>
<td>IObject.Materials.*</td>
</tr>
<tr style="height: 15pt;" height="20">
<td style="height: 15pt;" height="20">llGetNumberOfSides</td>
<td>IObject.Materials.Count</td>
</tr>
<tr style="height: 15pt;" height="20">
<td style="height: 15pt;" height="20">llGetRootPosition</td>
<td>IObject.Parent.*</td>
</tr>
<tr style="height: 15pt;" height="20">
<td style="height: 15pt;" height="20">llGetRootRotation</td>
<td>IObject.Parent.*</td>
</tr>
<tr style="height: 15pt;" height="20">
<td style="height: 15pt;" height="20">llGetNumberOfPrims</td>
<td>IObject.Parent.children.count + 1</td>
</tr>
<tr style="height: 15pt;" height="20">
<td style="height: 15pt;" height="20">llGetObjectPrimCount</td>
<td>IObject.Parent.children.count + 1</td>
</tr>
<tr style="height: 15pt;" height="20">
<td style="height: 15pt;" height="20">llSetLocalRot</td>
<td>IObject.Rotation</td>
</tr>
<tr style="height: 15pt;" height="20">
<td style="height: 15pt;" height="20">llSay</td>
<td>IObject.Say</td>
</tr>
<tr style="height: 15pt;" height="20">
<td style="height: 15pt;" height="20">llSetText</td>
<td>IObject.Text</td>
</tr>
<tr style="height: 15pt;" height="20">
<td style="height: 15pt;" height="20">llAbs</td>
<td class="xl64">Math.Abs</td>
</tr>
<tr style="height: 15pt;" height="20">
<td style="height: 15pt;" height="20">llFabs</td>
<td class="xl64">Math.Abs</td>
</tr>
<tr style="height: 15pt;" height="20">
<td style="height: 15pt;" height="20">llAcos</td>
<td class="xl64">Math.Acos</td>
</tr>
<tr style="height: 15pt;" height="20">
<td style="height: 15pt;" height="20">llAsin</td>
<td class="xl64">Math.Asin</td>
</tr>
<tr style="height: 15pt;" height="20">
<td style="height: 15pt;" height="20">llAtan2</td>
<td class="xl64">Math.Atan2</td>
</tr>
<tr style="height: 15pt;" height="20">
<td style="height: 15pt;" height="20">llCeil</td>
<td class="xl64">Math.Ceil</td>
</tr>
<tr style="height: 15pt;" height="20">
<td style="height: 15pt;" height="20">llCos</td>
<td class="xl64">Math.Cos</td>
</tr>
<tr style="height: 15pt;" height="20">
<td style="height: 15pt;" height="20">llFloor</td>
<td class="xl64">Math.Floor</td>
</tr>
<tr style="height: 15pt;" height="20">
<td style="height: 15pt;" height="20">llLog</td>
<td class="xl64">Math.Log</td>
</tr>
<tr style="height: 15pt;" height="20">
<td style="height: 15pt;" height="20">llLog10</td>
<td class="xl64">Math.Log10</td>
</tr>
<tr style="height: 15pt;" height="20">
<td style="height: 15pt;" height="20">llPow</td>
<td class="xl64">Math.Pow</td>
</tr>
<tr style="height: 15pt;" height="20">
<td style="height: 15pt;" height="20">llModPow</td>
<td class="xl64">Math.Pow + %</td>
</tr>
<tr style="height: 15pt;" height="20">
<td style="height: 15pt;" height="20">llSin</td>
<td class="xl64">Math.Sin</td>
</tr>
<tr style="height: 15pt;" height="20">
<td style="height: 15pt;" height="20">llSqrt</td>
<td class="xl64">Math.Sqrt</td>
</tr>
<tr style="height: 15pt;" height="20">
<td style="height: 15pt;" height="20">llTan</td>
<td class="xl64">Math.Tan</td>
</tr>
<tr style="height: 15pt;" height="20">
<td style="height: 15pt;" height="20">llEmail</td>
<td class="xl64">Net.MailMessage</td>
</tr>
<tr style="height: 15pt;" height="20">
<td style="height: 15pt;" height="20">llEscapeURL</td>
<td class="xl64">Net.URI.*</td>
</tr>
<tr style="height: 15pt;" height="20">
<td style="height: 15pt;" height="20">llEuler2Rot</td>
<td>new Quaternion(Vector3)</td>
</tr>
<tr style="height: 15pt;" height="20">
<td style="height: 15pt;" height="20">llDumpList2String</td>
<td class="xl64">String.Concat</td>
</tr>
<tr style="height: 15pt;" height="20">
<td style="height: 15pt;" height="20">llToLower</td>
<td class="xl64">String.ToLower</td>
</tr>
<tr style="height: 15pt;" height="20">
<td style="height: 15pt;" height="20">llToUpper</td>
<td class="xl64">String.ToUpper</td>
</tr>
<tr style="height: 15pt;" height="20">
<td style="height: 15pt;" height="20">llSensorRepeat</td>
<td>Timer + World.Objects</td>
</tr>
<tr style="height: 15pt;" height="20">
<td style="height: 15pt;" height="20">llGetUnixTime</td>
<td>Util.*</td>
</tr>
<tr style="height: 15pt;" height="20">
<td style="height: 15pt;" height="20">llFrand</td>
<td>Util.Random</td>
</tr>
<tr style="height: 15pt;" height="20">
<td style="height: 15pt;" height="20">llSHA1String</td>
<td>Util.SHA1Hash</td>
</tr>
<tr style="height: 15pt;" height="20">
<td style="height: 15pt;" height="20">llVecDist</td>
<td>Vector3.*</td>
</tr>
<tr style="height: 15pt;" height="20">
<td style="height: 15pt;" height="20">llVecMag</td>
<td>Vector3.*</td>
</tr>
<tr style="height: 15pt;" height="20">
<td style="height: 15pt;" height="20">llVecNorm</td>
<td>Vector3.*</td>
</tr>
<tr style="height: 15pt;" height="20">
<td style="height: 15pt;" height="20">llGround</td>
<td>World.Heightmap[x,y]</td>
</tr>
<tr style="height: 15pt;" height="20">
<td style="height: 15pt;" height="20">llModifyLand</td>
<td>World.Heightmap[x,y]</td>
</tr>
<tr style="height: 15pt;" height="20">
<td style="height: 15pt;" height="20">llSensor</td>
<td>World.Objects</td>
</tr>
<tr style="height: 15pt;" height="20">
<td style="height: 15pt;" height="20">llSensorRemove</td>
<td>World.Objects</td>
</tr>
<tr style="height: 15pt;" height="20">
<td style="height: 15pt;" height="20">llDie</td>
<td>World.Objects.Remove(&#8230;)</td>
</tr>
</tbody>
</table>
]]></content:encoded>
			<wfw:commentRss>http://www.adamfrisby.com/blog/2009/04/mrm-the-api-continued/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>MRM: Making Scripting Simpler and Faster</title>
		<link>http://www.adamfrisby.com/blog/2009/04/mrm-making-scripting-simpler-and-faster/</link>
		<comments>http://www.adamfrisby.com/blog/2009/04/mrm-making-scripting-simpler-and-faster/#comments</comments>
		<pubDate>Sat, 04 Apr 2009 05:20:37 +0000</pubDate>
		<dc:creator>Adam Frisby</dc:creator>
				<category><![CDATA[OpenSim]]></category>
		<category><![CDATA[mrm]]></category>
		<category><![CDATA[scripting]]></category>

		<guid isPermaLink="false">http://www.adamfrisby.com/blog/?p=140</guid>
		<description><![CDATA[I mentioned previously the introduction of MRM Scripting into OpenSim. You can go read my early introduction into it &#8211; since then, I have committed the code into the OpenSim trunk and been improving it a bit, it&#8217;s enablable today. As a quick recap &#8211; it&#8217;s C# (or any .NET language) with a World API [...]]]></description>
			<content:encoded><![CDATA[<p>I mentioned previously the introduction of MRM Scripting into OpenSim. <a href="http://www.adamfrisby.com/blog/2009/03/mrm-scripting-coming-to-opensim-soon/">You can go read my early introduction into it</a> &#8211; since then, I have committed the code into the OpenSim trunk and been improving it a bit, it&#8217;s enablable today. As a quick recap &#8211; it&#8217;s C# (or any .NET language) with a World API that is both simpler, more logical and more powerful than LSL/OSSL.</p>
<p>The first, most obvious, question is why not LSL? The shortest answer is, it&#8217;s bad. Linden Lab made a lot of mistakes in LSL &#8211; particularly around the destination intended audience. LSL was designed for very simple functionality, and this is evidenced in a number of places; such as lack of library support, minimal memory limits, an API which is internally inconsistent, lack of communication between script instances, etc. One of the reasons for this was Linden Lab envisiged LSL as being tiny little bits of functionality that you added together &#8211; so one object would have lots of scripts each doing tiny little things. How it turned out however is just like any other scripting language &#8211; people wanted a single script doing all the functionality, and were forced into doing things badly in order to get them working with the concieved limits.</p>
<p>That&#8217;s the first big complaint &#8211; the API is designed for something its not used for. To a programmer, writing in LSL can be a serious chore.</p>
<p>The second big complaint is that it is designed (not on purpose) to waste serious amounts of programming cycles on simple tasks.</p>
<p>Consider the following task: You want a list of every avatar within the region.</p>
<p>Under LSL your script looks something like the following:</p>
<textarea name="code" class="c#:nocontrols" cols="60" rows="10">
default {
	state_entry() {
		llSensor("","",AGENT,96.0,PI);
	}

	sensor(integer count) {
		integer i;
		for(i=0;i<count;i++) {
			llSay(llDetectedName(i));
		}
	}
}
</textarea>
<p>Let&#8217;s go through this an examine how that gets processed by the simulator.</p>
<textarea name="code" class="c#:nocontrols" cols="60" rows="10">
default {
	state_entry() {
</textarea>
<p>Entrypoint. </p>
<textarea name="code" class="c#:nocontrols" cols="60" rows="10">
		llSensor("","",AGENT,96.0,PI);
</textarea>
<ul>
<li>Examine every entity in the SceneGraph of type AGENT</li>
<li>Put every agent into a seperate list containing the agent and it&#8217;s position.</li>
<li>Calculate the distance between the host object position and every agent in the simulator. If less than 96m, remove from list. (note: distance calculations are expensive computationally as they involve running a Square Root, this needs to be done for every agent in the region)</li>
<li>Sort the list. (note: Sorting is also somewhat expensive)</li>
<li>Save the top 16 items in the sorted list.</li>
<li>Trigger the VM to schedule a SENSOR event, with the above list</li>
</ul>
<p>Notice this isnt exactly efficient &#8211; it also has the downside that it wont show any agents outside of the 96m range, even if they are in the region. If you wanted to scan the entire region confidently you would need several hundred copies of the script.</p>
<textarea name="code" class="c#:nocontrols" cols="60" rows="10">
	sensor(integer count) {
</textarea>
<p>This is an event fired by the VM, the results from the previous query are returned here &#8211; notice how difficult this makes programming. You cannot request data within a function, you need to break the function up into several components, at the very least one to gather the data, one to process it. If you have multiple requests going on, the assembly process is even more difficult, since you cannot request two sensors at once &#8211; you need to wait for the first to return results before firing the second.</p>
<textarea name="code" class="c#:nocontrols" cols="60" rows="10">
		integer i;
		for(i=0;i<count;i++) {
</textarea>
<p>Iterate through each potential value, nothing particularly inefficient here, however foreach syntax is nicer.</p>
<textarea name="code" class="c#:nocontrols" cols="60" rows="10">
			llSay(llDetectedName(i));
</textarea>
<p>This forms another badly designed section of LSL &#8211; we have two calls here, llSay and llDetectedName &#8211; say is fine, it&#8217;s not perfect, but there&#8217;s nothing wrong with it. llDetected*() however on the other hand is badly designed. First it&#8217;s not consistent or type checked &#8211; not every llDetected function is availible in every event. There is no error handling &#8211; if an object has a empty blank name, it returns the same result as if you passed an invalid parameter as <i>i</i>. The other major issue is it requires making a function call to fish out the member of the list &#8211; the data is not stored ready to go in an array or object. (LSL lacks both arrays and objects)</p>
<p>If we count all the lines &#8216;doing something&#8217; with the sensor, we have 7 lines of code to achieve the above simple task. We also have the VM doing walks of it&#8217;s entire scenegraph, calculating distances, generating lists then sorting them, etc. The act of calculating the sensor is going to be more complicated than processing the results. How can we do better?</p>
<p>Well the similar code in an MRM looks like this:</p>
<textarea name="code" class="c#:nocontrols" cols="60" rows="10">
using OpenSim.Region.OptionalModules.Scripting.Minimodule;

namespace OpenSim
{
    class MiniModule : MRMBase
    {
        public override void Start()
        {
            foreach(IAvatar av in World.Avatars) {
		Host.Console.Info(av.Name);
            }
        }
    }
}
</textarea>
<p>We have three lines &#8216;doing something&#8217;, to examine them in the same methodology as above:</p>
<textarea name="code" class="c#:nocontrols" cols="60" rows="10">
            foreach(IAvatar av in World.Avatars) {
</textarea>
<p>This collects the list of World.Avatars from the SceneGraph &#8211; the most complex interaction here is just examining objects on the SceneGraph to see if they are agents, however we do not need to calculate their distance unnessecarily, we have no limits on only being able to return 16 at a time, the object that is returned contains all the availible properties of the avatar &#8211; not just the select few exposed to a llDetected*() function.</p>
<textarea name="code" class="c#:nocontrols" cols="60" rows="10">
		Host.Console.Info(av.Name);
</textarea>
<p>This prints the result out onto the OpenSim console &#8211; eventually that will look like Host.Object.Say(av.Name), however right now the API still needs work in terms of method calls from Objects. Right now we use the same ILog provider as OpenSim, however eventually we&#8217;ll see about moving that into a specialised console for script outputs.</p>
<p>For those interested in experimenting with MRM, it is still early days &#8211; however hopefully as the above points out, it could potentially be a very significant step forward from where we are today with LSL/OSSL. The language design is cleaner and simpler &#8211; and it is a degree more logical. If you compare the full LSL example to the MRM one &#8211; the MRM one has all the logic in a single place, both simpler and shorter. The LSL one jumps logic between events and does lots of limiting things unnessecarily. With MRM we also have a lot more potential that the C# language brings us &#8211; such as libraries and extensibility, arrays, objects and more.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.adamfrisby.com/blog/2009/04/mrm-making-scripting-simpler-and-faster/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>MRM Scripting &#8211; Coming to OpenSim soon!</title>
		<link>http://www.adamfrisby.com/blog/2009/03/mrm-scripting-coming-to-opensim-soon/</link>
		<comments>http://www.adamfrisby.com/blog/2009/03/mrm-scripting-coming-to-opensim-soon/#comments</comments>
		<pubDate>Fri, 13 Mar 2009 08:57:46 +0000</pubDate>
		<dc:creator>Adam Frisby</dc:creator>
				<category><![CDATA[OpenSim]]></category>
		<category><![CDATA[mrm]]></category>
		<category><![CDATA[scripting]]></category>

		<guid isPermaLink="false">http://www.adamfrisby.com/blog/?p=122</guid>
		<description><![CDATA[Scripting OpenSim right now is a chore for the seasoned developer &#8211; there&#8217;s very few options sitting between &#8216;write a plugin&#8217;, and the LSL/OSSL implementation currently in place. For reasons I wont go into too much detail here, LSL is badly designed &#8211; the API in particular places too much emphasis on restricting the programmer [...]]]></description>
			<content:encoded><![CDATA[<p>Scripting OpenSim right now is a chore for the seasoned developer &#8211; there&#8217;s very few options sitting between &#8216;write a plugin&#8217;, and the LSL/OSSL implementation currently in place. For reasons I wont go into too much detail here, LSL is badly designed &#8211; the API in particular places too much emphasis on restricting the programmer rather than empowering them.</p>
<p>While Region Modules are exceptionally powerful, and quite capable of doing all that LSL can (and lots more), they require the programmer shut down the sim and restart it between tests of the module, resulting in a significant loss of productivity. MRM Scripting aims to fix this &#8211; MRM is short for &#8216;Mini Region Module&#8217;, and is something I have been adding silently to the OpenSim SVN for the last month. The goal is a very clean documented API similar to a full region module, but includes the ability to add in security features and also compile and edit the modules without shutting down the sim.</p>
<p>MRM Modules are written in C# (like OpenSim itself), but unlike the currently implemented C# engine, contain a vastly different more object-oriented API. It&#8217;s probably best illustrated with a couple of examples &#8211; below is the obligatory &#8216;Hello World&#8217; as a MRM module.</p>
<h3>Hello World in MRM</h3>
<textarea name="code" class="C#:nocontrols" cols="60" rows="10">
//MiniMod:C#
using OpenSim.Region.OptionalModules.Scripting.Minimodule;

namespace OpenSim
{
    class MiniModule : MRMBase
    {
        public override void Start()
        {
            Host.Console.Info("Hello World!");
        }

        public override void Stop()
        {
            
        }
    }
}
</textarea>
<p>As you can see, the entrypoints to an application are the Start() and Stop() events. Unlike LSL/OSSL, you wont recieve an &#8216;event&#8217; automatically just by declaring the function. Like conventional OpenSimulator region modules, you need to explicitly declare which events you want to listen to via standard C# event syntax</p>
<textarea name="code" class="C#:nocontrols" cols="60" rows="10">
...
public override void Start() 
{
	World.OnFrame += MyOnFrame;
}

public void MyOnFrame() 
{
	// Do something here which occurs each frame
}
...
</textarea>
<p>The result is fairly clean &#8211; the script engine only needs to give you information that you request, rather than send the event at runtime, only to have it ignored. It also gives you the ability to selectively listen only when you want (by binding and unbinding on demand.). The largest reason for this however, is because of scope &#8211; MRM has a much wider scope than LSL/OSSL. </p>
<h3>Where on the Toolchain?</h3>
<p>MRM&#8217;s fill a niche in the tool chain between end-user scripting and region modules, while we can secure MRMs (and plan on doing so), they are designed for &#8216;World Builders&#8217; who want reasonable amounts of power, and know the repercussions for abusing it (ie, lag, etc). They fit somewhere between OSSL and Region Modules &#8211; sharing many of the advantages of both.<br />
<img alt="" src="http://www.adamfrisby.com/mrm_chart.png" title="Scripting Power Chart" class="alignnone" width="690" height="500" /><br />
To summarise this in a somewhat incomplete table of features, the scope of a MRM can be seen below<br />
<img alt="" src="http://www.adamfrisby.com/mrm_table.png" title="Scripting Feature Table" class="alignnone" width="690" height="283" /></p>
<h3>The Scope of the Script</h3>
<p>Under LSL, your scope is limited to the Primitive the script is hosted in, with some very limited exceptions to say objects in the same link set. There is absolutely no ability whatsoever to listen for events affecting another object, unless that object also contains a script which can communicate with yours. MRM by comparison lives somewhere in the &#8216;World&#8217;, and consequently contains a much wider &#8216;Scope&#8217;. This means, if you want to listen to the touch event on any object in the world, it is quite possible to do.</p>
<textarea name="code" class="C#:nocontrols" cols="60" rows="10">
...
public override void Start() 
{
	foreach(IObject obj in World.Objects) {
		obj.OnTouch += MyOnTouch;
	}
}

public void MyOnTouch(IObject sender, TouchEventArgs e) 
{
	// Do something here
}
...
</textarea>
<p>The above example demonstrates some of the power of the MRM API, the LSL equivilent would require a script in every single one of the objects in the region.</p>
<h3>Hosted Scripts</h3>
<p>The final point worth noting is that MRM can act as a complete replacement for LSL &#8211; a script which for example changes the color of the object it is located in, can be implemented via the Host. Host contains a member called &#8216;Object&#8217;, which dictates the object that the MRM Script resides in. Host.Object conforms to the same IObject interface as World.Objects[], so any function can be done on both the host and remote objects.</p>
<h3>Final Notes, Enabling, Security, etc.</h3>
<p>The MRM API is presently incomplete, the largest sections currently undesigned relate to events and callbacks. The currently implemented versions (SOPObject.cs, World.cs, etc) are missing functionality, but you can still do some reasonably nifty things with it. Just dont expect this to be a fully ready replacement until we&#8217;ve implemented all the members correctly. It&#8217;s also worth noting that any MRM compile errors will disconnect your client from the sim, this is a bug and will be fixed. The API however should be 100% capable of wrapping LSL/OSSL functionality &#8211; infact it should be possible to write a LSL2MRM cross-compiler (Part of this comes from my <a href="http://jimpurbrick.com/2008/10/23/second-life/">discussions with Jim Purbrick</a> about distilling LSL to a simple set of interfaces).</p>
<p>MRM can be enabled via the [MRM] section of the OpenSim.ini, however it is <strong>strongly recommended that you be wary with this on a public environment</strong>. Presently any MRM script has access to the complete .NET API, this means it would be possible to compile a script calling for your server disk to be formatted. I recommend using this in offline standalone regions only for the moment. Proper security is part of the design, however is currently unimplemented. There is also a few functions which are implemented badly and may cause lag if used repeatably, all on the agenda for being fixed before we hit a beta version.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.adamfrisby.com/blog/2009/03/mrm-scripting-coming-to-opensim-soon/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
	</channel>
</rss>
