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.
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.
The recommended file structure is the following:
-
data
-
editor
-
plugins
- *.cpp - plugin source code.
- *.plugin - plugin meta data.
-
plugins
- my_project
-
editor
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.
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:This function is optional. You should implement it only if you have a code to be executed each frame.
- 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.
This function should be called before you delete an instance of the Unigine::Widgets::Window widget.
#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.
Plugin Meta Data
Plugin meta data is stored in a *.plugin file in the XML format and includes the following:
<?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:
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:
// 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.
main_x64 -editor_plugin "/path/to/custom_plugin.plugin"
To load the created editor plugin, perform the following:
- Choose Plugins -> Manage... on the Menu bar. The Plugins window will open:
- 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:
- Open the Plugins window by choosing Plugins -> Manage... on the Menu bar.
- Disable and then enable the changed plugin.