Adam Frisby

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.
2 Vote

Feedback

If you found this post useful and want me to write more on this topic, please use the vote button to the left or leave me a comment below.

Written by Adam Frisby

April 25th, 2009 at 5:48 am

Posted in OpenSim

Tagged with , ,

Leave a Reply

 

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