Adam Frisby

Archive for November, 2008

And now, for some shameless self promotion.

with 3 comments

Cyanic Content - Part 1

As many of you know – we’ve been doing a little bit more content development than usual lately. If you have attended one of the Sine Wave Pub Quizzes on OSGrid, you will probably recognise some of the items above. It’s part of our DeepThink content collection – something we’re licensing to people who need to get some nice looking content onto OpenSim grids quickly.

It’s all very low prim (most of the items are either 1 or 3 prims – the majority just a single prim), it’s all professionally rendered and sculpted by our artists, and up until this week, it hasnt really been availible in Second Life itself (with the exception of the halloween content pictured below).

It is now. You can find our content individually packaged and for sale now on OnRez and XStreetSL. We’re still lagging a little bit behind on our OnRez deployment, but we’ll get there eventually (we do seem to find the OnRez interface significantly more thought out). We’ve so far released only a portion of the total content we have developed, and we’re adding more regularly – so expect some new releases fairly often.

Cyanic Preview 3

We’ve also started to add a little bit of holiday content to our mix – we did a little bit of Halloween content in October which is availible, that content also has some general purpose bits and bobs which would be useful for any gothic or vampiric castle. (Coffins, Tombstones, etc.)

Finally, a small preview of some of the content we’re adding to the mix for Christmas this year, this is still a very early preview (there’s a lot more coming) – but we’re hoping to have it all ready and availible by December 1st.

Cyanic Preview 2

Where to get it

Pricing

Most items range between L$100 and L$300. Most permissions are copyable / no-trans (although a couple of items are no-copy/trans – check before buying).

Running an OpenSim Grid?

We’ve also got this all availible in a convenient OAR format for OpenSim operators. We provide the content to you under a few restrictions (mostly relating to distribution) as a flat yearly subscription fee for access to our entire library. We also have a bunch of content suitable for realXtend and Multiverse (and probably other virtual worlds). Contact us for licensing details.

Written by Adam Frisby

November 27th, 2008 at 4:24 pm

Posted in DeepThink

Microthreading .NET

with 2 comments

An issue becoming increasingly apparent with the OpenSim platform is that user scripting is a hammer – it works fine if you only need a couple of them, but lots of them running in conjunction and the operating system begins to start running poorly. The common key to fixing this is to use something such as Fibres – small lightweight threads that perform better in mass numbers to full blown Operating System threads.

The problem is – there’s no cross platform way to access Fibres, and we have the additional problem that scripts under OpenSim should be transportable from one server to another – meaning the ability to pack up an execution context, move it to another machine, then resume is a feature we want to support.

Linden Lab’s Jim Purbrick wrote in 2006 about their work to use a modified version of Mono to achieve this – unfortunately with OpenSim we do not have the luxury of using modified runtimes, nor do we plan on dropping support for the official .NET runtime either. This means solutions such as Mono Continuations dont work for us very well.

(Update 26/11/08: I had a chat with Jim after showing him this article – apparently Linden is doing something fairly similar to this proposal already, without the aid of a modified runtime.)

The solution, is ideally something we can run on both .NET and Mono, runs reasonably quickly (but obviously some overhead is acceptable) – it needs the ability to save and restore the current execution state, and it needs the ability to suspend and resume. Suspension and resumation should be fairly fast to allow it to be used in a microthreading context.

These requirements unfortunately knock out a very large number of options – the options we considered ranged from using IEnumerator and ‘yield’ to handle threading (no save/restore or return values), to using reflection to emulate an instruction pointer and stack (too slow and complex).

The idea I am currently developing manages to avoid most of these problems, but requires a degree of runtime code mangling – the result however is something that is generally applicable to generic .NET applications that desire save/resume functionality (or microthreading).

The result centers around Mono.Cecil – the runtime analysis library written by one of the Mono developers. It has a very nifty feature however in that it is capable of changing a CIL stream, then writing back out the resulting assembly – meaning we can at the CIL level, begin to manipulate the results and hook in accessory functions to handle our save/restore worries.

Shadowing Variables

The first thing we need to consider trying to save the state of an in-execution script is that unlike Java, C# doesnt have a MethodInfo.LocalVariables.Get() method – to the C# programmer, the current Method’s stack is completely inaccessible. It does however, have the ability to list the local variables within this method.

And that’s where we enter the shadow variables – the goal of the shadow variables, is to dynamically build a Struct that contains a corresponding entry for each local variable within the method, at runtime we use Cecil to swap references to the local variables, to references to the Shadow equivilent – then saving and restoring becomes as simple as serialising and deserialising the shadow container.

Internally, the shadow container should be created before the method call is begun and passed in as an argument – for something that isnt resuming, it would simply be containing null values.

Resuming Execution

The next consideration is the ability to save and resume from an execution point within the code – this is handled through gratuitous use of the CIL equivilent of a ‘GOTO Label’. After each statement, we place a new label – and at the beggining of the method call, we also add a new argument (”InstructionPointerStartPoint”) and a switch statement that will ‘goto’ the appropriate label.

Since we’re passing the shadow container in via the arguments – we do not need to do anything special in terms of copying data back, as all the code references the shadow container directly ‘as is’. This basically emulates the instruction pointer within a standard x86 processor.

Handling Return Values and the Stack

The final consideration we need to make is recursive calls. Suspendable user methods are allowed to call other suspendable user methods – so we need to implement our own call stack manager to make sure we can save the context of a previous call leading to the current one. (Otherwise resumption would effectively fail).

The solution to this is thankfully fairly simple – we create a new ‘StackItem’ class which contains: A reference to the virtual instruction pointer (where we are currently in the execution), a reference to the function call for this method, and a reference to the current shadow container, as well as an optional reference to a decendant stack item for nested calls.

Before proceeding into a nested call, we need to create a new stackitem for it, and launch it within that execution context, but otherwise it falls together fairly simply.

By folding the stackitems together from the initial execution context, we’re able to then package up a copy of the running execution at any single point in time, transport it, then bring it back later. The whole thing ends up looking something like this.

How it all looks

Optimising

Under this situation, we do have some fairly expensive penalties when it comes to calling into a recursive function, but at the same point there are a number of relatively easy fixes. Functions for example can be inlined – only a very tiny number of functions (such as self-recursive functions) need to be handled fully. The vast majority can be inlined, thereby reducing the need to setup nested function calls in a large number of cases.

Written by Adam Frisby

November 26th, 2008 at 6:40 am

Posted in OpenSim

Tagged with , , , , ,

OpenSim 0.6 Goals – IClientAPI Overhaul

without comments

One of the goals of the 0.6.0 release is to replace the current IClientAPI interface with something that will improve compatibility down the road with alternative clients. Instead of our current model where we dictate the features that clients must support, the new model will allow clients to pick and choose features we handle, and then implement them.

The basic way this is handled, is through the new ‘IClientCore’ interface. We introduced the IClientCore interface within a few hours of version 0.6.0 being tagged – however switching to the interface internally will take some time – probably a month or two, so any projects using IClientAPI are still safe.

As many of you who have played with writing region modules will know, IClientAPI represents everything you can do to every possible client – as one may guess, this doesnt scale when you begin adding multiple different clients into the mix. It also makes things difficult when two clients have the same feature in radically different ways.

A diagram of IClientAPI

As you can see in the diagram above – all the particulars of IClientAPI are bundled up together as one common interface. It is convenient – but it’s also problematic when it comes to implementing a new client, as you need to stub out every single function – and modules cannot tell whether a particular event or function was simply ignored by the client as unsupported.

Enter IClientCore

IClientCore is presently a very narrow interface – we’re defining it as everything a client must support, whether it likes it or not. As a consequence – we’re sticking to things that every single client has and implements in a common manner.

In practice – this means IClientCore dictates only the Name, ID and other very common internal parameters. It also needs to support two new ’special’ interfaces – Get<IFace>() and TryGet<IFace>(IFace out). These last two are the keys to how the new system works.

IClientCore

Under the new system – we implement interfaces for Chat, Primitives, and each seperate functionality group. It’s then possible to use, ‘IClientCore.TryGet<IClientChat>(…)’ which returns an interface to this clients IChat interface. If the client doesnt support chatting – then TryGet returns false.

The first most obvious question to arise here is related to how this looks more complicated than it used to be, and that’s definetely true – where we differ is that the new model means you need to check a client supports something before attempting to use it.

Previously we had no way from modules to indicate whether a feature was supported on clients – and we also had no way of handling extensions. This also means that if you choose to implement a new Client adapter for OpenSim, you dont need to implement the previous 350 functions and ignore any custom ones. You can write new interfaces for your custom features, and only implement interfaces from the Linden Viewer where you think you share enough functionality to make it useful.

In most cases – the changes arent fairly significant, you can see a comparison of two functions under the old and the new in the porting guide I wrote.

If anyone has any comments or questions relating to this, please let me know.

Written by Adam Frisby

November 19th, 2008 at 6:39 am

Logging into an OpenSim via realXtend accounts

with 4 comments

Modular realXtend Login

Previously…

For those who havent been reading up on the OpenSim IRC channels or mailing list, your probably not aware of the work we’re doing at DeepThink for the realXtend team.

For the last month and a half, we’ve been working with the realXtend team to convert their version of OpenSimulator, to something that closer resembles a suite of OpenSim plugins rather than a fork. Part of this work has been some sponsored contributions to improving the modularity of OpenSim itself with alternate clients (like the IClientAPI changes that are currently in progress), the other part has been conversion of the current realXtend server into a single plugin DLL called ‘ModularRex.dll’ which encompasses all the previous internal changes.

The single biggest bit of news however is, once this is done – realXtend is no longer a fork of OpenSim. It’s not opensim stock, but it’s not a seperate codebase either. Patches from realXtend can be applied fairly smoothly towards OpenSim-trunk and vice-versa, because the core files are unchanged.

Now we’re not done yet, but we’re making some pretty steady progress to getting there by the end of the year – today marks the date at which the core architectural bits and pieces are mostly done and the realXtend server developers can get onboard and help finish the rest.

The code for the modular rex DLL’s is located on the forge project for it. It may not always represent the latest testing versions (since we’re working offline a lot), but we’re doing checkins every now and then – if you’re interested in following progress, that’s the best spot to go. Future development will be going on on the forge exclusively however.

Multiple Concurrent Clients

One of the largest feature’s we’ve now got with the latest version is the ability to insert clients into the scene while bypassing the normal login routines. This may not sound like much – but the technology needed to support this, is the same technology that will allow you to login with two completely different virtual world clients and have a conversation between them, while viewing potentially the same content.

The new ModularRex code skips all the current login methods and actually has a new subclassed and derived version which it enables entirely through a shared region module. In future – we may be able to take this same methodology and convert the current login and protocol handling routines into their own modules which allows them to be replaced without effort.

ModRex Support Table

Features

  • Rex Avatars - We support all the packeting for the avatars now, however we do not automatically send this on login yet. If you know your rexav address, you can just type “/rexav http://somewhere.com/myav” in chat to set the parameter manually – or you can wait a few days now that we have login implemented and we can get to setting it automatically.
  • Rex Logins – You can now login with a traditional rex username, that is you can login with “username@hostname.com”, and your authentication server will authorise you instead of a direct login.

Infrastructure

  • Rex Packet Handling via RexClientView – We implement a IClientNetworkServer compatible interface which deals specifically with the modified realXtend protocol. This is subclassed from LLClientView / LLUDPServer / LLPacketServer but contains overrides and new methods to represent realXtend features.
  • Rex Methods and Events on ClientView – We now process a number of the realXtend events and packets and fire new ‘OnRexXYZ’ events that you can use to send specific things to users. This does not effect IClientAPI, rather these are members of RexClientView which means you need to check the client supports features before using them. Currently, we’re sitting at about 13 of 36 handlers – however we’re 13/13[?] if you exclude methods related to RexPython (as of 0.31, there are likely going to be new things to support with the upcoming Rex release).

The TODO List

  • Conversion to IClientCore – We started a lot of the conversion work before 0.6.0 was tagged, this means that the realXtend modules use a older method for checking client capabilities. We need to convert it to the new IClientCore interface to allow us standardised access to extension capabilities in modules.
  • Finish SceneObjectGroup/SceneObjectPart Overloads – We’re inheriting and extending from the SOG/SOP interfaces to add additional rex-only properties to objects. There’s a degree of difficulty involved here which may nessecitate additional metadata fields in SOG/SOP. A post to OpenSim-dev will be coming shortly no doubt with some suggestions there. This is needed to be able to get rex meshes and other special object features working.
  • Provide RexCommsManager – One of the limitations right now with the modular rex code is that Rex Logins (see above) dont provide a valid UserProfile class, because the Rex protocol there is different to OGS1. We need to provide an additional comms manager to allow Rex avatars to be handled correctly, or abstract OpenSim to allow ClientView to indicate the type of CommsManager it needs. This will also allow the global inventory features to be re-enabled (however moving them to the client may be a smarter long term move).
  • Write generic LibRexAuth – A problem with the current dealings with the authentication server are that they are fairly hard coded for specific features. It would be nice to add a library or static class which can provide simple functions such as ‘GetProfileByAccountName’ or ‘IsUserAuthorised’ – this allows us to communicate better with the authentication server, saving hassle and headache and centralising things so that problems are more easily fixable. A similar class may be useful for the avatar server – however the simulator’s dealings with that server are very limited.
  • Python – This needs to be converted a module, but shouldnt be too difficult as most of the code is presently abstracted and modular. With a little bit of work it may be possible to make realXtend python scripts editable in a similar manner to the LSL/C#/etc scripts, which would be very cool.
  • Voice – As with the above, the Rex Voice Daemon is fairly seperate from the main codebase, so porting this should be a fairly quick and painless job.
  • Update protocols to 0.35 – We’re currently sitting at the 0.31 release of realXtend which means there might be issues when the 0.35 realXtend viewer goes mainstream.
  • Minor bits and bobs – Getting things such as the ODE Mesh Collisions working with realXtend collision meshes may nessecitate some additional work (and probably a subclassed version of our current ODE DLLs with additional functionality). There are probably a number of minor features and fixes that will need to be ported over once the main items on the TODO are done.

So overall, we’ve still got a lot of work to do – but the great news is all the architectural bits are just about done, and we’ve proven that such advanced functionality can infact be done entirely with the current OpenSim region modules.

Written by Adam Frisby

November 19th, 2008 at 4:21 am

OpenSim Internals: Rebuilding SceneObjectGroup & co.

with one comment

Since we are on the verge of tagging the 0.6 OpenSim release, there’s a number of fundemental architectural changes we are investigating internally towards a path of more vendor neutrality. One of the changes I am proposing we make is to restructure SceneObjectGroup into part of the ClientStack heirachy rather than make assumptions about client representation models.

This is a proposal – it is not beyond reproach or comment.

The Current Model: SceneObjectGroup

Let’s begin by describing the current model – the largest limitation enforced on the current model is it dictates a method of heirachy which is fairly constrained. You have a parent who contains all the properties of the children, plus a few extra, then zero or more child primitives who are linked directly to the parent. The combined whole forms the ‘object’.

When you wish to modify a group property from a child, you need to check if you have a parent, if you do, modify the parent – but beware, certain things like the Position property mean different things as a child or root (why we also have AbsolutePosition and OffsetPosition properties to avoid confusion).

Current SceneObjectGroup

The obvious downsides of this approach are – we’ve made decisions that indicate that heirachical linking will never happen (something clients such as VastPark support via their nesting methods), neither is it possible to not have linking at all (ie say a standard Torque game). We’ve also got a mess of message routing which results in a very large number of if-null checks that perform different tasks depending on the outcome.

What should a revision also contain?

As part of the opportunity to fix this set of classes, we’ve got a chance to fix up some problems with SceneObjectGroup and SceneObjectPart – among them are, Vendor Neutrality (SOG/SOP is highly vendor specific), Multiple Linking models (ie not just Root->Children)

Strengthen IEntity – Derive More.

My personal favoured solution to this problem is to go back to IEntity and strengthen it up a bit. Right now, IEntity is a very minimalist interface dictating almost nothing about entities within the Scene, but it doesnt nessecarily need to be.

There are a number of properties which we can dictate as being universal about every entity regardless of the virtual world platform – these properties can be deemed as appropriate for a core interface, off the top of my head we can say the following are true of every type of ‘Entity’ we want to implement.

  • ID – The internal number used to indicate the object ID.
  • Position – The position of the entity inworld.
  • Serialised Version – A version of the object which can be imported/exported easily (XML?)
  • Physics Shell – The bounding box or triangle collection of this collection.
  • Name?
  • Scale?
  • Rotation?
  • BoundingBox?
  • etc…

In the case of the Linden model specified above (SceneObjectGroup), the container becomes harder – we access our information about the object collection via the container. Physics shells are given for the container rather than every object inside, etc.

It also becomes possible to have multiple seperate models sharing the same scene simultaneously, each shares and communicates via the properties on IEntity. As a result, the scenegraph then resembles something like this.

New SceneObjectGroup

A part overview

IEntity - Basic building block of objects contained in virtual worlds, it contains only properties which can be considered common to every virtual world platform.

LLEntity – This forms a replaceemnt for the current SceneObjectGroup, it contains properties which are applicable to the entire object, such as Owner, Permissions, Position and others. It contains a list of Children in the form of LLPrimitive. Unlike the current SceneObjectGroup, we do not utilise the .Root property from children to store group parameters. For instance, LLEntity.Root.OffsetPosition does not dictate where the entire object is located – as the root object, it will always be [0,0,0].

LLPrimitive – This contains a replacement for SceneObjectPart, unlike the current SOP it contains properties and methods only availible unique to the individual part. Properties which are shared among the group should be members of LLEntity instead. If you wish to access a group property it is always and only availible via LLEntity, and there are never members of LLPrimitive which simply act as ‘pass-thru’s to LLEntity. If you wish to access LLPrimitive – you must always access it via the parent group, it cannot be accessed via Entities directly.

XYZEntity – This is another entity from another world platform, it may have a heirachical linking situation where multiple entities in scene are chained together and share properties between each other internally. To the OpenSim perspective however we only see multiple seperate objects.

Potential Other IEntity Derivatives

In line with the above stated goal of supporting greater vendor neutrality I would like to propose some examples of other representations used today, and how we would be able to implement them under the new scheme mentioned above.

AWEntity (ActiveWorlds™) – While I’m not proposing to actually implement a AW Clientview, it’s representation of objects in scenegraph is fairly common and very similar to how game engines handle them. In ActiveWorlds, the world is a semi-finite plane divided into ‘cells’, each cell contains a number of objects however objects cannot link and have no notion of heirachy.

To implement AWEntity – we would implement all the common IEntity interfaces such as Position, Rotation, ID, etc. Then we would in addition implement some properties for the AW object parameters (Mesh Name, Object Name, Description, Client Script, etc).

We do not need to implement anything complex in terms of parents or children and the classes are without such properties. They contain a fairly ‘bare minimum’ scenegraph representation. (Just to repeat above, I have no plans to implement any such AW entity – this is just a hypothetical example using real world object representations)

Heirachical Entity (VastPark, Melanies Proposal, etc) – In this proposal, the same object consists of multiple independent parts. Each part has a collection of parents and children – however to Scene they are all independent seperate objects.

Each presents a seperate physics shell, each presents seperate property name and ID descriptions – however in special cases such as position or rotation, updating one reflects an update on the entire set simultaneously (or at least any descendants).

Handling the new objects internally

One of the largest problems of doing this (or any change) is that SceneObjectGroup is currently referenced in a very large number of places, making changes to it is likely going to result in a large number of structural changes needing to be done.

As an example of one of those changes – the following is a proposal on how to handle a single event in IClientAPI – OnNewEntity. The following represents the path that two independent IClientAPI implementations would follow in processing the same path.

Client API Overview

The goal of this structure is to allow each client the opportunity to attempt to parse foreign object formats – if LLClientView understands XYZEntity enough to write a converter, then it can do so and send the converted result onto the Linden Viewer end user.

Likewise, if XYZClient understands Linden entities, then it can in turn write a converter to it’s internal packet representation and send the same object to it’s viewer.

In practice such converters will not be particularly easy to write – most Virtual Worlds use meshes in a variety of formats, so such converters may need to convert texture formats, mesh formats, etc. For LLClientView converters, it may simply be impossible to convert certain outside representations to something the viewer is capable of displaying and simply choose to display a lower detail representation, such as a bounding box of where the object should be.

To follow this process in detail, we’ll examine the LLClientView’s core processes.

Linden Clientview

In the first step (1), the Scene fires the OnNewEntity event which each client is listening for – as part of the event payload, the new entity is attached. This gets transmitted as a IEntity interface directly into the clientview.

Here the clientview needs to work out what kind of entity it is dealing with, it may do something like “if(IEntity is LLEntity) { … }” and handle appropriately (2).

As the LLClientStack is innately familiar with the structure of LLEntity, it can pretty much directly package it up to packets and prepare to send it to the end user (3).

However when it sees XYZEntity – XYZEntity is known to the ClientView, so it is capable of understanding it and potentially writing a converter (4) to the own internal packet formats. If we assume for a moment that XYZEntity is a AWEntity described above, then it may choose to create a temporary LLEntity which forms just a single box primitive and then package that up to the viewer.

Finally we’ve got something either in packets or close to it that we can quickly and easily send to the viewer (5). They are capable of seeing ’something’ for each Object in the scene, but naturally you need to be on a suitable client to see ever feature that platform supports.

Things unmentioned

One of the things I have left unmentioned is how to handle certain common tasks such as saving and restoring from the database. For the most part the infrastructure remains fairly similar – we can do a check ‘Is LLEntity’ in the DB adapters and follow the current path, or if we dont have one, we can use the IEntity.Serialise() method to get a text string for each entity which can be saved in the DB fairly easily.

In the case of restoring from the database however we need to in addition implement a IEntityFactory which can take a set of data (such as a serialised version) and restore it to an object, these EntityFactories could be installed via a Application or Region module.

Written by Adam Frisby

November 8th, 2008 at 10:07 am

 

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