Getting Started
Migrating to UNIGINE 2.0
C++ API Migration
UnigineScript
The Language
Core Library
Engine Library
Node-Related Classes
GUI-Related Classes
Plugins Library
High-Level Systems
Samples
Usage Examples
C++ API
API Reference
Integration Samples
Usage Examples
C++ Plugins

Making Custom Editor Plugins

With a plugin system, UnigineEditor can be easily customized for project-specific needs. While implementing custom functionality, you can easily add new tabs into the default windows or new editor modules, as well as change a set of editor features for different projects.

A custom plugin is implemented by means of UnigineScript and then can be loaded the same way as any other UnigineEditor plugin.

Notice
It is also possible to implement a C++ plugin as a dynamic-link library and then export required functions and classes into custom editor plugin implemented in UnigineScript. See also implementation of the Collada Import plugin and OpenFlight Import plugin available in the Unigine SDK.

See Also

  • A sample plugin implementation located in the <UnigineSDK>/data/editor/plugins/samples directory.

Preparing Plugin Files

A custom editor plugin is a script implemented in UnigineScript and stored in a *.cpp file. Every plugin has a *.plugin file with meta data. This file should be located in the data/editor/plugins directory of your project: in this case, the plugin will automatically appear in the list of available plugins on UnigineEditor loading.

Notice
If a .plugin file is located outside the data/editor/plugins directory, the plugin won't appear in the list of available plugins automatically. See details below.

The recommended file structure is the following:

  • data
    • editor
      • plugins
        • *.cpp - plugin source code.
        • *.plugin - plugin meta data.
    • my_project

Implementing a Plugin

A custom plugin logic stored in a *.cpp file should contain implementation of the following functions:

  • getName() function that returns an arbitrary namespace name for the plugin. You should use this namespace for all created GUI elements and callbacks, or if you need to call plugin functions from outside a plugin namespace.
  • An init() function that receives plugin meta data as an instance of the PluginMeta class and will be called on editor initialization.
  • A shutdown() function that will be called on editor shutdown.
  • An update() function that receives an integer argument. This function will be called each frame while the editor is loaded.
    Notice
    This function is optional. You should implement it only if you have a code to be executed each frame.
    The engine will pass to this function a need_reload flag: if this flag is equal to 1 you may need to reload your custom resources. This flag is equal to 1 when:
    • A world is loaded.
    • A world state is restored.
    • A new node is added to the editor.
    • A node is removed from the editor.
    • The editor releases its ownership of a node (for it to be handled from scripts).
    • Positions of 2 nodes are swapped in the list of editor nodes.
  • A show() function that shows a plugin window on plugin enabling.
  • A save() function that will be called on world saving. Here you can save custom plugin data into the world.

If a custom plugin interface is implemented as an external window, you should also add the following function calls to your code (implementations can be found in <UnigineSDK>/data/editor/editor_plugins.h):

  • pluginsAddWindow() into the plugin init() function to add a plugin name to the quick access list of currently enabled plugins.
  • pluginsShowWindow() into the plugin show() function to show a plugin window.
  • pluginsRemoveWindow() into the plugin shutdown() function to remove a plugin name from the quick access list of currently enabled plugins.
    Notice
    This function should be called before you delete an instance of the Unigine::Widgets::Window widget.
As a result, your plugin will be added to the quick access list of currently enabled plugins and its window will be shown on plugin enabling, for example:

Source code (UnigineScript)
#include <core/unigine.h>

// this function should return your plugin namespace name
string getName() {
	return "TestPlugin";
}

void init(PluginMeta meta) {
	TestPlugin::init(meta);
}

void shutdown() {
	TestPlugin::shutdown();
}

void update(int need_reload) {
	TestPlugin::update(need_reload);
}

void save() {
	TestPlugin::save();
}

void show() {
	TestPlugin::show();
}

/******************************************************************************\
*
* TestPlugin
*
\******************************************************************************/

namespace TestPlugin {
	
using Unigine::Widgets;

Window window;

PluginMeta meta;

	void init(PluginMeta m) {

		meta = m;
	
		window = new Window("Title");
		window.setFlags(ALIGN_OVERLAP);
		
		// add a plugin to the quick access list of currently enabled plugins
		// and initialize a plugin window
		pluginsAddWindow(window,meta.title,meta.name);
	
	}
	
	// implement plugin shutdown logic
	void shutdown() {
		
		// remove a plugin from the quick access list of currently enabled plugins
		pluginsRemoveWindow(window,meta.name);
		
		removeChild(window);
	
		delete window;
		log.message("shutdown\n");
		
	}
	
	// implement plugin update logic
	void update(int need_reload) {
	
		// the flag of 1 indicates that the editor resources should be updated
		if(need_reload) {
			// update custom resources, if necessary
		}		
	}
	
	void show() {
		
		// show a plugin window
		pluginsShowWindow(window,meta.name);
		
	}
	
	void save() {
		// implement a world save callback here
	}

}
			

If a custom plugin interacts or somehow affects nodes, you should also implement the following node callbacks:

  • nodeInit() that will be called on node initialization (for example, when creating a new node, selecting the existing node and so on).
  • nodeUpdate() that will be called on node update.
  • nodeShutdown() that will be called when shutdown logic is executed for a node (for example, when deleting or deselecting a node and so on).
  • nodesUpdate() that will be called when changing nodes hierarchy.

Notice
For more details, see also a sample located in the <UnigineSDK>/data/editor/plugins/samples directory.

Plugin Meta Data

Plugin meta data is stored in a *.plugin file in the XML format and includes the following:

Source code (XML)
<?xml version="1.0" encoding="utf-8"?>
<plugin name="editor_plugin" version="1.0">
	<text>Test Plugin</text>
	<description>Custom editor plugin</description>
	<dependencies>HAS_INTERFACE</dependencies>
	<source>editor_plugin.cpp</source>
</plugin>
				

A <plugin/> element contains 2 attributes:

  • name - internal plugin name.
  • version - plugin version.

In addition, a <plugin/> element defines the following:

  • <text/> - plugin title that will be displayed in the list of plugins in the Plugins window.
  • <description/> - text description of a plugin.
  • <dependencies/> - external dependencies of a plugin. It can be any external #define required for plugin functioning. For example, the TestPlugin described above won't be loaded without the Interface plugin.
  • <source/> - path to a file with a plugin source code relative to the folder where the .plugin file is located.

Meta data stored in the .plugin file is available in the script via the PluginMeta class that is defined as follows:

Source code (UnigineScript)
class PluginMeta {
	string name; // corresponds to the "name" attribute of the <plugin/> element
    string version; // corresponds to the "version" attribute of the <plugin/> element
    string title; // corresponds to the <text/> element
    string description; // corresponds to the <description/> element
    string source; // corresponds to the <source/> element
}
				

An instance of this class is passed as an argument to the init() function and then can be used anywhere in the code. For example:

Source code (UnigineScript)
// declare an instance of the PluginMeta class as a global variable
PluginMeta meta;

void init(PluginMeta m) {
	// assign meta data received from the .plugin file to the global variable
	// and then use it anywhere in the code
	meta = m;
}
				

Loading a Plugin

If your .plugin file is located in the data/editor/plugins directory, it will be automatically added to the list of available UnigineEditor plugins. Otherwise, you will need to specify the editor_plugin command line option with a path to the meta data file as an argument on the engine start-up. The path to the meta data should be relative to the data directory.

Shell commands
main_x64 -editor_plugin "/path/to/custom_plugin.plugin"
			

To load the created editor plugin, perform the following:

  1. Choose Plugins -> Manage... on the Menu bar. The Plugins window will open:

  2. Enable the custom plugin.

You can choose multiple plugins to be loaded in UnigineEditor runtime. Once loaded, a plugin can be accessed via drop down menu that opens when clicking Plugins on the Menu bar.

Modifying a Plugin

After the editor plugin is modified, you can quickly see changes in action:

  1. Open the Plugins window by choosing Plugins -> Manage... on the Menu bar.
  2. Disable and then enable the changed plugin.
Last update: 2017-07-03