UE4 Plugins

Following on from the previous post on UE4 modules, I wanted to briefly cover plugins as another form of encapsulation available in UE4.

Plugins vs modules

In UE4, plugins are simply a higher level unit of encapsulation than modules, rather than an alternative approach. Like projects, plugins can contain any number of code modules within them. They can also optionally contain content.

UE4 plugins are not strictly plugins

UE4's concept of a plugin deviates a little from the norm. A true plugin conforms to and implements a pre-existing interface, thereby extending an application in a predefined way. While UE4 plugins can take this approach, they can also export new types and be used as libraries, with project code having a direct dependency on the plugin. See this excellent AnswerHub post for an overview of this distinction.

Another way in which the UE4 approach differs is that, by default at least, its plugins are linked and their content processed when packaging a release build of a project. The underlying architecture may support delaying this process and loading them dynamically as true plugins (I'd be interested to know if anyone has tried), however it certainly doesn't seem to be the intended usage.

Engine level vs project level plugins

Plugins can exist at either the engine level ([UE4 Installation]/Engine/Plugins), or the project level ([Project Folder]/Plugins). In a launcher installation, plugins at the engine level must be prebuilt. Project level plugins containing source code will always be compiled as part of the project build process, regardless of engine installation type.

Creating a plugin

While the editor has a plugin wizard to automate the process, I'm going to go over the manual approach to detail all the elements of a UE4 plugin. In the following example, the plugin is named 'MyPlugin'.

Here is the basic structure of a plugin. The following would be placed in either /Engine/Plugins or [Project Folder]/Plugins.

- MyPlugin
    - MyPlugin.uplugin
    - Source [Optional]
        [C++ modules here]
    - Content [Optional]
    - Config [Optional]
        - FilterPlugin.ini

The plugin descriptor

The plugin descriptor file lives in the root folder of the plugin, and is named [PluginName].uplugin. In this example, 'MyPlugin.uplugin'. Here is a basic example.

{
    "FileVersion": 3,
    "Version": 1,
    "VersionName": "1.0",
    "FriendlyName": "My Plugin",
    "Description": "An example plugin.",
    "Category": "Kantan Dev",
    "Modules": [
        {
            "Name": "MyPluginMainModule",
            "Type": "Runtime",
            "WhitelistPlatforms": [ "Win64", "Win32", "Android", "Mac", "IOS", "Linux" ]
        },
        {
            "Name": "MyPluginEditorModule",
            "Type": "Editor",
            "WhitelistPlatforms": [ "Win64", "Mac", "Linux" ]
        }
    ],
    "EnabledByDefault": false,
    "CanContainContent": true
}

See the official documentation for more details.

Plugin source

The Source folder contains C++ module code, in exactly the same structure as for a project's Source folder. See my earlier post for a rundown of modules.

In the above example, there would be subfolders for two modules, MyPluginMainModule and MyPluginEditorModule.

Plugin content

If you want to include content in your plugin, the easiest way is to create it in the editor in the context of a project. Make sure you have "CanContainContent" in the plugin descriptor set to true. I generally create a dedicated development project for each plugin I make and do all coding and development in the context of that project. In the editor, ensure you have Show Plugin Content enabled in the content browser view options, and you should see a content folder visible for your plugin. You can then create whatever assets you need there.

Note that the editor's content migration does not support moving assets into plugin content folders, and that copying assets between plugin and project content folders in the content browser is also unreliable when it comes to asset references.

Building a plugin

As noted above, at project level, plugin code will be compiled along with project code. However if you intend to distribute a plugin, the recommended way to do so is with the engine's automation tool. On Windows, run the RunUAT batch file located at [UE4 Installation]/Engine/Build/BatchFiles as follows:

RunUAT.bat BuildPlugin -plugin=[path/to/pluginname.uplugin] -package=[path/to/output/directory]

This will compile the plugin code for its whitelisted platforms (for Development, DevelopmentEditor and Shipping configurations), and output the full plugin ready for distribution, including source, intermediate, binaries and content, along with anything specified by the plugin filter (see below).

FilterPlugin.ini

This optional config file specifies any additional files that should be included when building a plugin for distribution using the automation tool as described above. Note that this is not the same as packaging a project which uses a plugin - that is a later step, and any additional files that should also be copied at that stage must be specified separately via the RuntimeDependencies array inside the Build.cs file of one of your plugin's modules.

For example syntax of the FilterPlugin.ini, just run the BuildPlugin command above. An example FilterPlugin.ini file will be generated in /Config directory of the source plugin.

Conclusion

The vast majority of my UE4 programming is done in plugin form. Just like with modules, the encapsulation encourages good design and less dependencies. Plugins can have content bundled with them when necessary, and can be easily shared and reused. They also offer a way of reducing project recompilation time, by putting infrequently changing code into a binary-only or engine level plugin.