这篇文章讲述了如何使用UE tools 和runtime开发自己的插件。
许多UE子系统都是可扩展的,允许你添加新的功能,修改内置的功能而不需要修改引擎代码。你可以添加新的文件类型,添加新的菜单项和工具栏命令到编辑器中,甚至添加新功能和编辑器子模式。
如果你现在就想试着使用插件,可以直接观看Plugin Examples部分
- Plugins Editor UI
- Anatomy of a Plugin插件剖析
- Plugin Folders
- Code in Plugins
- Content in Plugins
- Plugins in your Game Project
- Engine Plugins
- Distributing a Plugin
- Plugin Descriptor files
- Descriptor File Example
- Descriptor File Format描述符文件格式
- Module Descriptors
- Icon Files
- Plugin Examples
Plugins Editor UI
你可以在Plugins编辑界面中看到已经安装的插件。
插件编辑器可以从主窗口菜单中访问。此界面显示当前安装的所有插件,并允许您单独启用或禁用插件。
你可以使用左边的界面浏览插件的目录。选择一个目录将在右边显示该目录下所有的插件以及所有子目录下的插件。
主列表显示插件的名称图标,当前版本,描述及作者(和可选的网页超链接),以及该插件是否已启用。
你可以在你的项目中启用或禁用插件的使用。
Anatomy of a Plugin(插件剖析)
带有代码的插件有一个源文件夹。该文件夹将包含一个或多个源代码模块源代码。注:插件通常都会包含代码,但不是必须的。查看插件中的代码可获得更多信息。
对于有着代码模块的插件来说,这类插件有着自己的二进制文件夹,其中包含该插件的编译代码。此外,临时构建的项目文件将被存储到插件目录下的一个中间文件夹中。
插件可以拥有自己的内容文件夹,其中包含该插件特定的资源文件。查看插件部分的Content以了解更多信息。
注:插件不支持配置文件。这是我们正在考虑在今后添加的东西。并且插件还不支持自己派生数据缓存分配。这是我们预计在稍后添加的一些东西。
Plugin Folders
插件始终位于插件目录下。在虚幻引擎中如果要找到这些插件的话,它们必须位于一个有效的搜索路径中。
Plugin type | Search path |
Engine plugin | /UE4 root/Engine/Plugins/My Engine Plugin/ |
Game plugin | /My project/Plugins/My Game Plugin/ |
你也可以讲插件放入Plugins文件夹下的子目录中。引擎将会自动扫描并加载Plugins下的所有子文件夹中的插件,但当一个目录中找到存在插件后便不会继续扫描该目录的子目录。
虚幻引擎通过搜索 磁盘上的.uplugin文件而找到插件。可称这些文件为插件描述符。它们是文本文件,提供关于插件的基本信息。程序运行时,插件描述符将被虚幻引擎发现后将被自动加载。查看Plugin descriptor部分以了解创建和自定义这些文件。
Code in Plugins
生成Visual Studio或XCode文件项目文件时,任何有着源文件夹的插件(*.Build.cs文件)都将被添加到项目文件中以使得更容易找到它们的源代码。当编译游戏项目时,Unreal Build Tool将自动编译这些插件。
插件可以有任意数量的模块代码目录。大多数插件只有一个模块,但是可以创建多个模块,例如,如果有一些功能是为编辑器设计的,其他部分代码是运行游戏时必须的。
大多数情况下,插件的源文件格式和其他C++模块在虚幻引擎中是一样的。
插件允许在模块文件代码申明新的UObject类型(UCLASS,USTRUCT等),插件可以在模块代码文件夹的子目录中的头文件里声明新的UObject类型。虚拟引擎构建系统会检测这些文件并生成支持这些UObjects的代码。你需要遵循在C++模块中使用UObjects的通用规则,例如包含生成的头文件以及在模块源文件中模块的generated.ini文件。
“Public” 源文件的头文件是一个与插件模块有点不同的东西。在Public源文件夹中大多数插件模块都没有在头文件中都没有公共的业务接口,因为它们永远不会和引擎或游戏代码有直接依赖关系(静态链接)。所以通常你的Public源文件夹都是空的。但是这条规则也有几个例外:
- 如果你的插件包含多个C++模块,并且在Public文件夹中的代码能在插件的各模块中共享。
- 如果你正在创建一个游戏插件(不是引擎插件),并且你想让游戏与你的一个插件模块静态链接。这打破了一个插件点的概念,但是申明一个新的游戏类可以继承或直接使用的UObject类型对于插件来说通常是很有用的。引擎本身不依赖于这个插件,但游戏项目代码和内容很有可能有直接的依赖关系。
- 如果你想使用插件发布公共接口头(public interface headers),以允许游戏代码或其他插件访问插件模块中实现的类型。这是非常少见的,一般不推荐只用这种方法,因为我们目前不打算支持一个插件直接依赖于另一个插件。
Content in Plugins
虚幻引擎支持包含Content及二进制代码的插件。这项功能仍在完善中。
为了在插件中使用Content,插件描述符的CanContainContent设置必须为true。插件的Content是一个仍在完善中的特性,目前还不建议使用。更多关于这点的信息将在日后提供。
我们打算支持允许内容被包括在分布式的插件中。此功能尚未完全实现,因此不建议使用它。
Plugins in your Game Project
在游戏项目目录下,插件存在于名为“Plugins”的子目录下,并在启动的时候被游戏引擎和编辑器检测和加载。
如果插件中存在包含源文件夹(以及*.Build.cs文件)的模块,插件代码将被自动添加到生成的C++项目文件中,这样的话就可以很容易的在开发游戏项目的同时开发插件。当编译游戏项目时,所有存在Source的插件都讲被编译成一种游戏的合成依赖(synthetic dependency)。
没有Source子文件夹的插件将被项目生成器忽略,并且不会出现在C++项目文件中,但只要二进制文件存在便会在游戏启动时被加载。
Engine Plugins
UE4有一些内置的插件包含在引擎目录下。引擎插件就像你在游戏中所拥有的插件, 并且可以用于所有的游戏项目中。通常情况下,这些插件是有引擎和工具程序员提供一个类似插件的基准功能。使得用户可以删除或重写整个引擎功能而不修改任何引擎代码。
默认情况下,引擎插件的加载在所有游戏模块或游戏项目加载之前。
引擎插件有一个特别的要求:引擎代码模块不能够静态链接引擎插件模块库。即,引擎插件必须与引擎本身独立开,插件模块是引擎模块的“依赖模块”。这是一种明智的选择,当插件不可用时引擎仍可继续工作。
Distributing a Plugin
以下是发布插件所需的步骤。
- 编辑插件描述符(.uplugin文件)并确保插件名称、模块。版本和配置所需的其他设置。
- 删除插件的二进制文件和中间文件夹。确保从一个干净的slate开始。
- 如果插件包含Source文件夹,编译Win64 Development配置版本的插件二进制文件。这个配置是PC平台加载插件总是需要的。
- 对于插件的Source,如果你希望支持额外的配置,例如Mac系统,所以应该建立这些。
- 将插件复制到工程目录外的一个新的临时文件夹中。这不是必须的,但会在这个临时文件夹中对插件进行修改。
- 在插件的临时目录中,删除中间目录。这些都是临时性的目录,不应该被分发。
- 如果插件包含源文件代码,但不想发布它,在插件的临时文件夹中删除Source文件夹即可。
- 在插件的临时目录中,可以删除所以不想发布的文件。
- 最后,插件就可以准备发布了!
重要笔记:
- 暂不支持发布的插件中仅包含Public头文件。所以你必须包含整个Source目录或者没有任何Source目录。我们打算在今后添加发布Public源文件(以及*.build.cs文件)的支持。
- 我们正在调查这个过程的自动化工具。更多细节将在稍后发布。
- 对于插件的Content,你可能希望生成派生数据包含于插件中,以避免终端用户需要它生产新的需求。但此功能尚未提供,但将在稍后添加。敬请关注。
Plugin Descriptor files
插件描述符是以.uplugin扩展名结尾的文件。文件名的第一部分是插件的名字。插件描述文件总是位于插件目录下,引擎会在启动时发现它们。
插件描述符在JSON(JavaScript Object Notation)文件格式
Descriptor File Example
此实例插件描述符是从UObjectPlugin下载的例子。
{
"FileVersion" : 3,
"FriendlyName" : "UObject Example Plugin",
"Version" : 1,
"FriendlyVersion" : "1.0",
"EngineVersion" : 1579795,
"Description" : "An example of a plugin which declares its own UObject type. This can be used as a starting point when creating your own plugin.",
"Category" : "Programming Examples.Plugins",
"Modules" : [ { "Name" : "UObjectPlugin", "Type" : "Developer" } ]
}
Descriptor File Format(描述符文件格式)
Field name | Info | Description |
FileVersion | Required | Version of this plugin descriptor file itself. It is used for backwards compatibility as new features are added to the plugin system. You should usually set this to the latest version that is allowed by the version of the engine you are using. The latest version is currently 3, and is the version of format that is documented here. We do not expect this version to change very frequently. In source code, you can look at**EProjectFileVersion** to see the actual value. If you require maximum compatibility with older versions of the engine, then you can use an older version of the format, but it is not recommended. |
Version | Optional | Current version number of this build of your plugin. This value should always increase with future versions. This version number is not usually displayed to end-users. |
VersionName | Optional | Version of the plugin displayed in the editor UI. This is never used for any versioning checks and can be in whatever format you would like, however we suggest a simple Major.Minor format. You should always update the VersionName whenever the Version number has increased. |
EngineVersion | Optional | Minimum engine version necessary to be able to load this plugin. The plugin will fail to load when installed to projects using an engine version less than the value specified here. |
PackageFileUE4Version | Optional | Minimum package file version necessary to load content in this plugin. The plugin will fail to load when installed to projects using a package file version less than the value specified here. |
PackageFileLicenseeUE4Version | Optional | A secondary minimum package file version necessary to load content in this plugin. The plugin will fail to load when installed to projects using a licensee package file version less than the value specified here. |
FriendlyName | Optional | Name of the plugin displayed in the editor UI. If not specified, the name will default to the .uplugin file name. |
Description | Optional | A paragraph of text that describes what this plugin is used for. This will be displayed in the editor’s plugin window. |
Category | Optional | This is a special dot-separated path string that allows you to assign your plugin to a category in the editor UI. It is purely for organizational purposes. An example of a category path is “Editor Features.Level Editing.Mesh Painting”. Each category is separated by a period character and represents a deeper level in the tree. |
CreatedBy | Optional | The individual or company name that created this plugin. This may be displayed in the plugin UI or in other locations. |
CreatedByURL | Optional | A web link to the individual or company that created this plugin. If specified, the editor UI may display a hyperlink that allows the user to browse to this web page. |
CanContainContent | Optional | When specified and set to true, enables Content support for this plugin. The default setting is false. See the section on Content in Plugins for more info. |
Modules | Optional | For plugins that contain source code (and binaries), this is the list of modules that should be loaded at startup. See below for more info. |
这种.uplugin的文件格式仍在完善并存在改变的可能。例如,我们预计版本控制的方式将在后续的Release版中修改。
插件名称和描述字符串定位尚未支持,并且GUI中的实现文字显示位置的定位是不支持的。
Module Descriptors
对于包含代码的插件,描述符文件将包含至少一个模块描述符。
{
"Name" : "UObjectPlugin",
"Type" : "Developer"
}
Field | Info | Description |
Name | Required | Unique name of this plugin module that will be loaded with the plugin. At runtime, the engine will expect appropriate plugin binaries to exist in the plugin’s Binaries folder with the module name as specified here. For modules that have a Source directory, a matching *.Build.cs file is expected to exist within the module’s subfolder tree. |
Type | Required | Sets the type of module. Valid options are Runtime, RuntimeNoCommandlet, Developer, Editor,EditorNoCommandlet, and Program. This type determines which types of applications this plugin’s module is suitable for loading in. For example, some plugins may include modules that are only designed to be loaded when the editor is running. Runtime modules will be loaded in all cases, even in shipped games. Developer modules will only be loaded in development runtime or editor builds, but never in shipping builds. Editor modules will only be loaded when the editor is starting up. Your plugin can use a combination of modules of different types. |
LoadingPhase | Optional | If specified, controls when the plugin is loaded at startup. This is an advanced option that should not normally be required. The valid options are Default (which is used when no LoadingPhase is specified),PreDefault, and PostConfigInit. PostConfigInit allows the module to be loaded before the engine has finished starting up key subsystems. PreDefault loads just before the normal phase. Typically, this is only needed if you expect game modules to depend directly on content within your plugin, or types declared within your plugin’s code. |
Icon Files
随着描述符文件,插件通常有一个图标文件,用于在编辑器UI中显示插件。
File Name | Info | Format | Description |
/Resources/Icon128.png | Required | 128x128 PNG file | This icon represents this plugin in the editor UI. It will be displayed in the ‘Plugins’ user interface accessible from the main Window menu. |
Plugin Examples
我们已经创建了一些没有任何功能的实例插件。可以在创建插件时作为空壳使用。这些都包含在引擎源代码中。
Example Name | Info |
BlankPlugin | This plugin is an empty shell that shows the bare minimal files needed to setup a new code plugin module. |
UObjectPlugin | A simple empty plugin that demonstrates how to declare your own UObject class. |
- 复制一个实例插件到一个新的文件夹中,重命名目录、文件和代码内容以匹配新的插件名称。不然的话会与内置的插件包括引擎发生冲突。
- 在游戏项目目录创建一个“Plugins”文件夹,然后复制插件的所有子目录到“Plugins”目录下。
- Rebuild你的C++项目文件。插件模块和源代码将出现在工程目录下的一个目录中。
- 通常编译游戏项目,UBT将检测到插件,并将它们编译为游戏项目的依赖关系!
- 启动编辑器(或游戏),你的插件将被禁用,但你可以在编辑界面中打开它。
- 打开插件编辑器(Windows –> Plugins),搜索你的插件,Enable它
- 重新启动编辑器。你的插件将在启动时自动加载。
在Window -> Developer工具菜单下你可以看到被加载的插件。另一个方式是使用代码调试器在插件启动代码中设置断点,例如在FBlankPlugin::StartupModule()中设置断点.