Dynamic Plugin Quickstart

From OpenSimulator

Jump to: navigation, search

NOTE: This tutorial now refers to a very old OpenSimulator and so is only partially useful. See IRegionModule for something more up to date.


A quick guide to writing plugins. Please refer to How to create a dynamic plugin for more in-depth information.

Defining Extension Points

Extension points describe the location in the program where external modules can be plugged-in at runtime. Extension points can be defined in one of two ways:

  • decorating interfaces, classes or methods with attributes in the source code
  • embedding an XML file, called a manifest, as a resource in an assembly

In OpenSim, the preferred method is to embed an XML manifest in the assembly. Below is an example manifest defining one extension point in the AssetInventoryServer:

<Addin id="OpenSim.Grid.AssetInventoryServer" isroot="true" version="0.1">
    <Runtime>
        <Import assembly="OpenSim.Grid.AssetInventoryServer.exe" />
        <Import assembly="OpenSim.Framework.dll" />
    </Runtime>
    <ExtensionPoint path="/OpenSim/AssetInventoryServer/AssetStorageProvider">
        <ExtensionNode name="Plugin"
                       type="OpenSim.Framework.PluginExtensionNode"
                       objectType="OpenSim.Grid.AssetInventoryServer.IAssetStorageProvider" />
    </ExtensionPoint>
</Addin>

This manifest contains the following elements:

  • Addin
    • id: an identifier describing this addin, used for dependencies in other addins.
    • isroot: set to true if this manifest does not define any extension nodes, otherwise can be left out completely.
    • version: a version number, also used for dependencies in other addins.
  • Runtime: a list of assemblies that need to be imported by Mono.Addins as it builds the plugin repository. In the example, the OpenSim.Grid.AssetInventoryServer.exe assembly contains the definition for OpenSim.Grid.AssetInventoryServer.IAssetStorageProvider interface, while OpenSim.Framework.dll contains a definition for OpenSim.Framework.PluginExtensionNode.
  • ExtensionPoint
    • path: the location of the extension point in the extension point tree (see Extension Paths).
  • ExtensionNode
    • name: a name describing this extension node.
    • type: a class that handles plugin loading, this should probably be OpenSim.Framework.PluginExtensionNode unless you know what you're doing.
    • objectType: an instance of this object will be loaded into this extension point at runtime. This is probably what your plugin will instantiate/subclass/implement.

At this stage, all that is needed is OpenSim.Grid.AssetInventoryServer.IAssetStorageProvider defined and present in OpenSim.Grid.AssetInventoryServer.exe.

PLEASE NOTE: embedding XML manifests in .exe assemblies doesn't work. The .addin.xml file must reside in a directory that Mono.Addins will scan for plugins. Currently in OpenSimulator this is the current working directory (bin/). Ideally all applications would consist of an .exe assembly and a .dll assembly which contains the embedded XML manifest.

Defining Extensions

Extensions that implement extension points are defined in a similar way. Below is an example corresponding XML file describing a plugin for the above extension point:

<Addin id="OpenSim.Grid.AssetInventoryServer.Plugins.OpenSim" version="0.1">
    <Runtime>
        <Import assembly="OpenSim.Grid.AssetInventoryServer.Plugins.OpenSim.dll" />
        <Import assembly="OpenSim.Data.dll" />
    </Runtime>
 
    <Dependencies>
        <Addin id="OpenSim.Grid.AssetInventoryServer" version="0.1" />
    </Dependencies>
 
    <ExtensionPoint path = "/OpenSim/AssetData">
        <ExtensionNode name="Plugin"
                       type="OpenSim.Framework.PluginExtensionNode"
                       objectType="OpenSim.Data.IAssetDataPlugin" />
    </ExtensionPoint>
 
    <Extension path="/OpenSim/AssetInventoryServer/AssetStorageProvider">
        <Plugin id="OpenSimAssetStorage"
                provider="OpenSim.Grid.AssetInventoryServer.Plugins.OpenSim.dll"
                type="OpenSim.Grid.AssetInventoryServer.Plugins.OpenSim.OpenSimAssetStoragePlugin" />
    </Extension>
</Addin>

The elements (not in the same order as in the file) are:

  • Addin
    • id: a string identifying this plugin, can be used for dependencies in other plugins.
    • version: a version of this plugin, also used for dependencies in other plugins.
  • Runtime: a list of assemblies to import at runtime while Mono.Addins builds up the plugin registry. In this case, OpenSim.Grid.AssetInventoryServer.Plugins.OpenSim.dll contains the definition for OpenSim.Grid.AssetInventoryServer.Plugins.OpenSim.OpenSimAssetStoragePlugin, and OpenSim.Framework.dll contains a definition for OpenSim.Framework.PluginExtensionNode.
  • Dependencies: describes other addin(s) required to be loaded before this addin can be loaded. The id and version is used.
  • Extension
    • path: the path along the extension point tree to the extension point which this extension implements.
    • Plugin
      • id: a string identifying this particular extension. Pretty much an arbitrary string.
      • provider: another property of the extension, which can be an arbitrary string. In OpenSim, the convention seems to be to place the assembly name here which contains this plugin.
      • type: the fully qualified class name to be instantiated which implements the extension. In the code, this class will inherit from/implement the class/interface specified in objectType attribute of the ExtensionPath.
  • NOTE: this XML file also defines another extension point, meaning that this plugin also takes another plugin. Note the isroot attribute in the topmost Addin element is omitted.

Source Code

The relevant code which ends up in OpenSim.Grid.AssetInventoryServer.exe and loads the AssetStorage plugin looks something like this:

private IAssetStorageProvider LoadAssetStorageProvider(string addinPath)
{
    PluginLoader<IAssetStorageProvider> loader = new PluginLoader<IAssetStorageProvider>();
    loader.Add(addinPath);
 
    try
    {
        loader.Load();
    }
    catch (PluginNotInitialisedException e)
    {
        // log the error, clean up, exit if needed, etc
    }
 
    return loader.Plugin;
}
 
// Then, from elsewhere in the code:
IAssetStorageProvider StorageProvider = LoadAssetStorageProvider("/OpenSim/AssetInventoryServer/AssetStorageProvider");

The PluginLoader class lives in OpenSim.Framework; have a look through the code for more plugin loading options.

Personal tools
General
About This Wiki