Adam Frisby

Archive for the ‘mrm’ tag

OS Under the Surface: May 2009

with 2 comments

With May coming to a close, I would like to start the first of a monthly feature – some explanations of what’s going on under the surface of OpenSim. But wait, you may ask; doesn’t Justin already provide excellent weekly reports on what’s been committed? Of course – 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 – not only what has been committed, but also where it is going.

There has been a lot of progress this month – starting at revision 9358 there have been several major areas of focus.

Networking: LLUDP Improvements

We now support the Multiple Object Update packet format for Linden UDP clients (most notably Second Life & 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 – 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 tests done by Intel for ScienceSim. Object aggregation produces similar results (although hasn’t been measured precisely.)

Packet Pooling – the next major improvement is in ‘packet pooling’ – 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) – 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.

Packet Pooling solves this problem by recycling classes – 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) – however more profiling done by intel managed to locate the problem as being due to a finite sized pool – 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).

Overall, the OpenSim networking code has been improved very significantly (especially with April’s texture resend fixes), and I would appreciate seeing more testing with large userbases – 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.

Some early bugs did present themselves with this networking code – 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.

I introduced, then disabled support for NAT Loopback – 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) – 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.

Groups Support

mcortez has been working on adding a fully functional implementation of groups into OpenSim this month – 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 – 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).

New Region Modules Framework

I’m not entirely sure if this was introduced this month – 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 – however if you are feeling adventurous you can investigate the new format and look at porting modules across.

New Services Framework

As part of a general improvement of OpenSim code quality, Diva and Melanie improved the services framework this month, deleting the old OGS1 ‘UGAIM’ in favor of a new ‘OpenSim.Services’ binary – this also means that the Grid mode and Standalone mode now share all the major infrastructure internally (Standalone runs the grid services in ‘private’ now) – this reduces code complexity and makes it easier for us to add and adjust the services framework.

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 – 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 – after it was discovered the previous asset cache did not infact, cache anything, early testing indicates this one works.

Finally, Arthur implemented some improvements to the User Service framework which prevents people from seeing the ‘You are already logged in’ message’ in grid mode.

Remote Control, Administration and Web Integration

BlueWall introduced and improved his JSON Stats plugin system for OpenSim which allows remote monitoring via AJAX applications of a region. Melanie introduced a ‘remote console’ 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.

Inventory Archives

Justin continued work on Inventory Archives – 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.

Justin also added the ability to store creator IDs as a URL rather than a UUID – this allows you to reference foreign grid avatars as a creator.

Prim Meshing

Dahlia continued work on the internal ‘Prim Mesher’ 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.

XML Serialisation Formats and Region Archives

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.

Scripting

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 MRM Loader project (located on the forge) allows you to write (and debug!) MRM scripts from within Visual Studio (very cool.), 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).

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.

IRC Clientstack

As mentioned earlier, 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 – this may be an advantage over the previous IRC Bridge module where IRC users were not represented inworld with an avatar.

Final Words

If I missed anything – let me know, Justin’s notes are likely to be slightly more comprehensive on smaller non-architectural changes.

Written by Adam Frisby

May 30th, 2009 at 11:35 am

MRM Article on MaxPing

without comments

Ziah Zhangsun has written an interesting article on using MRMs in OpenSim, go take a look.

Written by Adam Frisby

April 29th, 2009 at 11:11 am

Posted in OpenSim

Tagged with , ,

MRM: Language Contributions

without comments

If you are a coder and like the work I have been doing on MRM so far – I’m keen to accept any contributions you may have to the langage – patches on mantis are welcome (here’s how to submit). 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;

Coding Standards – The Rules for API Changes

The MRM API is designed to ‘feel’ like the official .NET API in as many ways as possible – 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.

1. Class Library Design and Naming

For core API (those items distributed with OpenSim), you must follow the Microsoft .NET Coding Standards for naming and class design.

2. Subclassing and Inheritance

Subclass (or subinterface) where possible to make a useful inheritence chain. The following is the current proposed structure for MRM entity inheritance.

Fig 1. IEntity Inheritance

Fig 1. IEntity Inheritance

Note that the above proposal is not set in stone – the alternative I am considering is inheriting IPlant from IObject, and making a new IPrimitiveObject – where we move prim related properties (such as Shape) into the subinterface.

3. “Superglobals”

You should insert items into the “Superglobals” appropriately. Superglobals are the [presently three] properties which are inherited from MRMBase. In the user-accessible language these are items such as “Host” or “World”.

3.1 Host Superglobal

Host means “Scripting Host”, items in Host should be directly related to the runtime environment the script is running in, such as performance characteristics, security permissions, etc. – it could almost be seen as analoguous to “System.Environment”.

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 ‘Host’ since it is unrelated to the world itself and is something that is dependent on the runtime environment.

3.2 World Superglobal

World refers to the SceneGraph – and should contain elements which are reflected inside the visual environment. For instance Avatars, Objects and other items which exist in the ‘World’. This also includes properties of the world itself, such as lighting conditions, sun angle, etc.

4. No Assumed Parameters

MRM API entries should not be designed with an assumed ‘target’ – 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.

BAD: llSetPos(vector3 pos); // Sets the position of the host object.
GOOD: llSetPos(IObject target, vector3 pos); // Sets the position of ‘target’

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).

5. Do not use OpenSim Types.

This means do not expose OpenSim internals to the MRM programmer – 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’s implementors (SOPObject, SPAvatar, LOParcel, …)

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 “IAbcd” interface but instead a proxy should be written (see SOPObject for an example).

There is two reasons for this – the first is that passing internals means that any internal change will break MRM scripts. The second reason is security – security can be implemented inside the proxy whereas it cannot be implemented in the internal class.

6. Use OpenMetaverse.Types

libOpenmetaverse provides a number of useful types such as UUID, Vector3, etc. Use these whereever possible – for instance when representing U/V coordinates use “Vector2″.

7. Use the most appropriate Type for the job.

Do not use Vector3 to store only two values – use Vector2. There is a lot of types availible to use – make sure to pick the right one for the right job.

8. Do not copy LSL needlessly.

This is a big one – do not assume the LSL function set is an ideal to be upheld. Ask yourself when implementing a MRM replacement, “What is the using developer trying to do?”. Take the llSay, llShout, llWhisper, llRegionSay group – each implements the same underlying task, however the differing methods have a varying ‘range’ depending on which one is called.

For instance, llShout will ’say’ 100m. llSay will ’say’ 20m. A using developer is going to pick between them based on which range they need — 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 – but you have given the user more power.

9. Name Consistently

If you use a function name ‘SetFoobar’, the ‘GetFoobar’ should be called exactly that. Do not have ‘SetFoo/FooGet’, or ‘SetFoo/Foo’. (Note in practice, Set/Gets should always be implemented as C# properties.) To use LSL as another example – we should never end up with a pair like ‘llGetTextureOffset’ and ‘llOffsetTexture’.

10. Do not implement abitrary limits.

Copying from earlier, “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.”

If you are implementing limits on particular MRM functions, make sure you have a damn good reason for it – you should assume MRM authors are region operators. If you implement specific limits, make sure you load them from OpenSim.ini.

“Safe” Areas to Contribute to

If the above has made you uncertain about contributing – there are a number of areas you can contribute safely towards, and they are pretty easy to find in the codebase.

  • Look for “throw new NotImplementedException()” inside the code base – in classes such as SOPObject you can safely implement these functions and properties and nearly guaruntee your patch will get accepted.
  • Suggestions – 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.
  • Documentation – I’m using XMLDOC to build the final API documentation, so inserting ///<summary> 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 “I”).
  • Tests and Examples – 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.

Written by Adam Frisby

April 25th, 2009 at 5:48 am

Posted in OpenSim

Tagged with , ,

MRM: Microthreading Functions

without comments

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 ‘lag’. For instance – 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 is each will run for a fairly long period of time until broken up by a processing expensive “thread switch” at which point the next gets a long run before going to the next and the next and the next, or alternatively – none will finish and only one will be running.

The following diagram explains this in action – 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 “llSleep(0)” statement in LSL, however the cost of switching threads is still present.

Fig 1. Normal Threaded Scripting

Fig 1. Normal Threaded Scripting

Microthreading allows you to say “You can pause and give time to another script” – 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 ‘tasklets’, 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 – broken up at the tasklet borders.

The following diagram shows the same as above, in a microthreading environment.

Fig 2. Microthreaded Runtime

Fig 2. Microthreaded Runtime

C# supports a limited form of microthreading via something called the “yield” keyword – and a lot of people have recognised you can use it to build a state machine — the basis of microthreading. Where we apply this to MRM is with some additional keywords.

The basic C# microthreading can be implemented in MRM without any additional work – 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.

The first is “microthreaded” – this keyword is inserted between the public/private/protected/internal keywords at the beggining of the function, and the variable type.For example, “private microthreaded void MyFunction(…) {”. Microthreaded functions can only work on functions with a no return type (void) – and internally it works by replacing “microthreaded void” with “IEnumerable”.

The second important keyword is “relax” – this keyword is defined as a breakpoint – 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.

The relax keyword can only be placed inside of functions marked microthreaded – and you cannot call microthreaded functions directly (as in “Function(params)”). You must place microthreaded functions into the host scheduler marked as ‘Host.Microthreads.Run(myfunc(params));’

Another important note is that microthreaded functions will run asynchronously to your code, so do not expect “Microthreads.Run(…)” to block, consider it more a ‘Microthreads.ScheduleToRun(…)’. 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.

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.

The following is an example script that uses MRM microthreads.

Enjoy.

Written by Adam Frisby

April 24th, 2009 at 6:14 am

Posted in OpenSim

Tagged with , , , , ,

MRM: Language Extensions and Libraries

with 2 comments

As of r9240, MRM now has proper support for language extensions – these come in two key flavours – 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 – so when CAS is implemented in MRM for security, you will need to be aware that they will be affected too.

The syntax for importing a library is fairly simple – just place within your code, below the //MRM:C# line, a line which reads like this:

//@DEPENDS:MyLibrary.dll

Dependencies are requirements – if the dependent DLL cannot be found, it will throw a compile error, even if no code utilizes this extension.

Accessing Region Modules

The second form of language extension – 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 – one module will define an interface it can be accessed by (eg, IMRMModule)

Communicating with an MRM is done in a very similar fashion – 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 “Hello World” module, it’s structure is pretty simple.

The Module Code

A sample MRM using the above

This code represents a fairly simple example – 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.

Good practices when writing a module interface

These are based loosely on the rules I am employing in designing the default API.

  • Use MRM types where possible – 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).
  • Do not pass in internal OpenSim classes. This means do not ever return something like SceneObjectPart – 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.
  • Do not require IHost for anything. If you want the user to pass in the host object, ask them to do it – 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.
  • If you need a unique ID for the script instance, require a UUID to passed, then request the user uses the global variable “ID”. This is a UUID that corresponds with the internal Inventory Item UUID of the MRM script.
  • Do not place abitrary limits on scripts. 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.
  • Follow MSDN C# Coding Guidelines. We use the MSDN Class Library coding standard in OpenSim, MRM by extension uses the same guidelines.

Happy Extending!

Written by Adam Frisby

April 21st, 2009 at 5:51 am

Posted in OpenSim

Tagged with , ,

MRM Micropost: Keyword Rename

without comments

//MiniMod:C# no longer is the MRM keyword, the new keyword is //MRM:C#

That is all.

Written by Adam Frisby

April 11th, 2009 at 7:24 am

Posted in Uncategorized

Tagged with , ,

MRM Micropost: “Type” via ‘is’

without comments

Determining the type of object returned via a sensor or other detection event (eg collision, etc) in LSL is done via llDetectedType() – this returns a bitflags containing whether the object is an avatar, prim, etc.

Under MRM, the same is achieved by using the C# keyword “is”. In C# this returns true if the object is a specific type, or implements the interface ‘type’; because of this it means that we can determine what an IEntity is by looking for the inherited classes.

For example:

In this example, e.Sender is defined to be an IEntity – 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 “is IObject” or “is IAvatar”, and if it returns true, you can typecast to those interfaces safely.

Written by Adam Frisby

April 10th, 2009 at 6:48 am

Posted in OpenSim

Tagged with , ,

MRM: The API, Continued.

with 7 comments

MRM is now functional to the point where you can begin to implement simple scripts in it (r9060), the following is the ‘default LSL script’ written as a MRM:

The API is slowly being documented too – it is being documented with .NET XMLDOC comments, so that our docs project site will also provide up to date information on how to write MRM scripts. For example, take a look at the documentation for IObject or IHeightmap.

As you can see, it is slowly taking shape – the areas in most need of attention are Avatar properties, defining “social entities” (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.)

The following table is my ‘in progress’ list of what will be replacing what in LSL nomenclature – functions which have no corresponding MRM properties are not listed here yet.

Read the rest of this entry »

Written by Adam Frisby

April 9th, 2009 at 8:05 am

Posted in OpenSim

Tagged with , ,

MRM: Making Scripting Simpler and Faster

with 2 comments

I mentioned previously the introduction of MRM Scripting into OpenSim. You can go read my early introduction into it – since then, I have committed the code into the OpenSim trunk and been improving it a bit, it’s enablable today. As a quick recap – it’s C# (or any .NET language) with a World API that is both simpler, more logical and more powerful than LSL/OSSL.

The first, most obvious, question is why not LSL? The shortest answer is, it’s bad. Linden Lab made a lot of mistakes in LSL – 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 – 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 – 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.

That’s the first big complaint – the API is designed for something its not used for. To a programmer, writing in LSL can be a serious chore.

The second big complaint is that it is designed (not on purpose) to waste serious amounts of programming cycles on simple tasks.

Consider the following task: You want a list of every avatar within the region.

Under LSL your script looks something like the following:

Let’s go through this an examine how that gets processed by the simulator.

Entrypoint.

  • Examine every entity in the SceneGraph of type AGENT
  • Put every agent into a seperate list containing the agent and it’s position.
  • 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)
  • Sort the list. (note: Sorting is also somewhat expensive)
  • Save the top 16 items in the sorted list.
  • Trigger the VM to schedule a SENSOR event, with the above list

Notice this isnt exactly efficient – 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.

This is an event fired by the VM, the results from the previous query are returned here – 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 – you need to wait for the first to return results before firing the second.

Iterate through each potential value, nothing particularly inefficient here, however foreach syntax is nicer.

This forms another badly designed section of LSL – we have two calls here, llSay and llDetectedName – say is fine, it’s not perfect, but there’s nothing wrong with it. llDetected*() however on the other hand is badly designed. First it’s not consistent or type checked – not every llDetected function is availible in every event. There is no error handling – if an object has a empty blank name, it returns the same result as if you passed an invalid parameter as i. The other major issue is it requires making a function call to fish out the member of the list – the data is not stored ready to go in an array or object. (LSL lacks both arrays and objects)

If we count all the lines ‘doing something’ with the sensor, we have 7 lines of code to achieve the above simple task. We also have the VM doing walks of it’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?

Well the similar code in an MRM looks like this:

We have three lines ‘doing something’, to examine them in the same methodology as above:

This collects the list of World.Avatars from the SceneGraph – 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 – not just the select few exposed to a llDetected*() function.

This prints the result out onto the OpenSim console – 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’ll see about moving that into a specialised console for script outputs.

For those interested in experimenting with MRM, it is still early days – 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 – and it is a degree more logical. If you compare the full LSL example to the MRM one – 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 – such as libraries and extensibility, arrays, objects and more.

Written by Adam Frisby

April 4th, 2009 at 5:20 am

Posted in OpenSim

Tagged with , ,

MRM Scripting – Coming to OpenSim soon!

with 6 comments

Scripting OpenSim right now is a chore for the seasoned developer – there’s very few options sitting between ‘write a plugin’, and the LSL/OSSL implementation currently in place. For reasons I wont go into too much detail here, LSL is badly designed – the API in particular places too much emphasis on restricting the programmer rather than empowering them.

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 – MRM is short for ‘Mini Region Module’, 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.

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’s probably best illustrated with a couple of examples – below is the obligatory ‘Hello World’ as a MRM module.

Hello World in MRM

As you can see, the entrypoints to an application are the Start() and Stop() events. Unlike LSL/OSSL, you wont recieve an ‘event’ 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

The result is fairly clean – 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 – MRM has a much wider scope than LSL/OSSL.

Where on the Toolchain?

MRM’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 ‘World Builders’ who want reasonable amounts of power, and know the repercussions for abusing it (ie, lag, etc). They fit somewhere between OSSL and Region Modules – sharing many of the advantages of both.

To summarise this in a somewhat incomplete table of features, the scope of a MRM can be seen below

The Scope of the Script

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 ‘World’, and consequently contains a much wider ‘Scope’. This means, if you want to listen to the touch event on any object in the world, it is quite possible to do.

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.

Hosted Scripts

The final point worth noting is that MRM can act as a complete replacement for LSL – 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 ‘Object’, 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.

Final Notes, Enabling, Security, etc.

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’ve implemented all the members correctly. It’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 – infact it should be possible to write a LSL2MRM cross-compiler (Part of this comes from my discussions with Jim Purbrick about distilling LSL to a simple set of interfaces).

MRM can be enabled via the [MRM] section of the OpenSim.ini, however it is strongly recommended that you be wary with this on a public environment. 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.

Written by Adam Frisby

March 13th, 2009 at 8:57 am

Posted in OpenSim

Tagged with , ,

 

You need to log in to vote

The blog owner requires users to be logged in to be able to vote for this post.

Alternatively, if you do not have an account yet you can create one here.

Powered by Vote It Up