Developing extendable editor extensions for Unity

Many of the editor extensions that are available from the asset store are closed source. For those who do not understand, this simply means that the source code is compiled into one or more class libraries (DLL).

There are a number of very good reasons why some extension developers choose to do this:

  • Avoid script naming conflicts with user code and indeed other extensions

    Unity requires that each script file that contains a MonoBehaviour is named to match the class name. At the time of writing Unity does not allow two user scripts to coexist with the same name; neither directories or namespaces will help here!

    However, these limitations do not apply to classes that are exposed by a class library. When developing a class library it is also possible to put namespaces to good use! This helps to avoid clashing with other extensions!

  • Reduce chance of breaking things upon updating

    When source code is available developers will often find it tempting to tweak functionality to meet their needs. Obviously there are many scenarios where this is genuinely useful, however this should always be a last resort. Where possible developers should be encouraged to override and extend functionality using an API exposed by the extension.

    As a developer you may be thinking “Sure I’ll be careful not to break anything”. Except, the problem usually occurs the opposite way around. Custom changes will often be lost when the extension is updated in the future!

    So, a note for those who do need to modify extension scripts; always keep track of your changes so that you can reapply them again in future releases!

What can an editor extension developer do to make their library more extensible?

The first step is to expose an API that can be used to:

  • Register new types of functionality (interfaces and abstract classes very useful here)

  • Unregister unwanted functionality

  • Expose events so that users can tap into various extension processes

  • Provide options that can be tweaked programmatically

The second step is to fully document the API to help developers understand how to do this. Often it is useful to provide both automatically generated API documentation (from XML comments) and to provide one or more tutorials.

For example, Rotorz Tile System allows developers to define custom painting tools. This can be achieved by implementing the ITool interface or by extending one of the standard tool classes. The custom implementation can then be registered via the ToolManager class.

How to create an extension though?

Custom extensions can be created by creating an editor script in a directory called “Editor” somewhere in your project. The implementation of the script does not need to be a MonoBehaviour, so the default code template can be replaced with custom namespaces, classes, structs, interfaces, etc. Try to keep classes, etc. in separate files because this will make your project more manageable.

Your custom extension script will need to execute an initialization function so that it can interact with the API as needed. This can be achieved using the editor attribute InitializeOnLoad. This attribute has been available for a while but appears to have only become documented more recently.

For example, if you were to create a custom tool for Rotorz Tile System then you might write something like the following:

using Rotorz.TileSystem.Editor;
 
namespace MyNamespace
{
   [InitializeOnLoad]
   public class MagicTool : ITool
   {
      // Executed each time editor scripts are recompiled
      static MagicTool() {
         // Register custom tool with tool manager
         ToolManager.RegisterTool<MagicTool>();
      }
 
      // Remainder of custom tool implementation...
   }
}