Language:
Page Info
Engine Version:
Share
此中文页面内容对应的英文页面有后续更新,如需浏览最新文档可切换至英文页面浏览。

插件

本页面描述了如何开发插件,使它和虚幻引擎工具集以及运行库协同工作。

很多虚幻引擎中的子系统都被设计为具有可扩展的能力,能够在不直接修改引擎代码的前提下,为引擎添加完整独立的新功能, 或者修改引擎中内建的功能。可以为引擎创建新的文件类型,为编辑器添加新的菜单项或者工具栏按钮, 甚至增加一个完整的全新功能模块或者编辑器的子模块!

如果希望马上尝试一下插件,请直接阅读 插件范例 章节。

插件编辑器界面

可以从 Edit 菜单打开 Plugins 编辑界面,这里可以看到当前引擎已经安装了哪些插件。

PluginsEditor.png

插件编辑器可以通过主菜单中的 “Window” 项打开。这个界面中显示了当前已安装的所有插件,并且能够选择性的对每个插件进行启用/禁用的操作。

可以在这个界面的左侧看到有一些插件的分类目录。选择一个目录就会显示该分类下的所有插件,以及子分类的插件。 在浏览这些目录时,在界面上方会显示“寻迹路径”来方便快速跳转回上一级分类。在分类右侧的数字则显示该分类下可用插件的数量。

PluginCategories.png

在列表主界面上显示的插件,有插件名称和图表,以及当前的插件版本,还有个提供说明信息的描述, 插件的作者(并且可能还有网站的超链地址),以及当前该插件是否启用。

顶部的搜索框可以通过搜索插件的名字来找相应的插件。

SearchingPlugins.png

可以对当前项目是否要启用插件来选择 Enable 勾选框,这部分有改动的话可能需要重启编辑器才会生效。

解析插件

带有代码的插件会有一个 Source 的目录,该目录中包含一个或者多个子目录,以及模块化的插件源代码。 这里要留意,通常来说,插件都包含源代码,但并不意味着必须包含源代码。查阅 插件中的代码 以获得更多信息。

对于有代码模块的插件而言,该插件会有它自有的 Binaries 目录,其中包含了该插件代码编译后的文件, 临时的中间文件将会保存在插件目录里的 Intermediate 文件夹内。

插件也可以有自己的 Content 目录,附带和插件相关的资源文件。查阅 插件中的内容 以获得更多信息。

插件目前并不支持配置文件。我们也正在考虑将来增加这个支持。

另外,插件暂时并不支持自有 Derived Data Cache。同样我们也会考虑将来增加该功能。

插件目录

插件总是保存在本地的插件目录中。为了让插件能够被正确的找到,它们必须存在于一下某个有效的虚幻引擎搜索路径中。

插件类型

搜索路径

引擎插件

/UE4 root/Engine/Plugins/My Engine Plugin/

游戏插件

/My project/Plugins/My Game Plugin/

也可以将插件放在 Plugins 目录的子目录中。引擎会扫描 Plugins 目录中的所有子目录中的插件并加载, 但引擎如果在当前目录中已经找到一个可以加载的插件时并不会对该目录的子目录进一步扫描。

虚幻引擎通过查找 .uplugin 文件来定位插件。我们把这些文件称为插件描述器,这些文件是文本文件,提供了插件的基础信息。 虚幻引擎、编辑器以及编译工具(UBT)在运行时,会自动发现并加载插件描述器。 查阅 插件描述器 来了解更多关于创建这些文件或者自定义这些文件的方法。

插件中的代码

在为 Visual Studio 或者 XCode 生成项目文件的时候,任何带有 Source 目录的插件(有 *.Build.cs 文件)都会添加项目文件, 以便更容易的浏览插件的代码。这些插件在 UBT 编译游戏项目时,也会被自动编译。

制作插件时可以有任意数量的 Source 目录模块。大部分插件都只有一个模块,但实际上是可以创建多个模块的。 举个例子来说,有种情况是插件中一部分功能只是用来给编辑器使用的,而其他代码是给引擎运行时使用的。

大部分时候,插件的源文件的布局方式和虚幻引擎中其他的 C++ 模块的布局方式是一样的。

在插件模块化代码目录的 Classes 子目录的头文件中,也能够声明新的 UObject 类型(UCLASS,USTRUCT 等)。 虚幻引擎的编译系统会检测到这些文件,并生成所需要的代码来支持这些 UObject 实现。用户需要遵循通用的规则在 C++ 模块中使用这些 UObject, 比如要在模块的源文件中 include 相应的 generated 头文件以及模块的 generated.inl 文件。

Plugin 模块有一个地方有点特别,那就是 Public 的源码头文件。大部分插件模块并不需要在 Public 的源码目录中的 API 存在对外的 public 接口, 因为通常它们都不会被引擎或者游戏代码有直接的依赖关系(被静态链接)。因此通常 Public 的源码目录是空的。 不过基于下面这几条规则,也有例外情况:

  • 如果插件具有多个 C++ 模块,在插件的 Public 目录中的代码可以在这写模块之间共享。

  • 在制作游戏插件(非引擎插件)时,如果希望游戏能够静态链接一个插件模块的时候。这里稍微有点打破插件的概念,但在有时候会有实际用处, 比如希望插件中定义的新的 UObject 类型能够在游戏中直接被继承并且使用。引擎本身并不会依赖这个插件, 但游戏项目的代码和资源可以对这样的插件中定义的 UObject 类型直接使用。

  • 如果想要在在插件中分发出一部分功能让游戏代码或者其他插件能够进行访问。这种做法并不常见,通常也不鼓励这么做, 如同我们目前也不打算支持需要依赖其他插件功能的插件一样。

插件中的内容

虚幻引擎支持在插件中包含 Content 的数据,也支持二进制代码格式。该功能还处于开发过程中。

是在插件中包含 Content 的话,需要在插件的描述器中将 'CanContainContent' 设置为 'true'。 插件中的 Content 内容目前属于 work-in-progress 的功能,尚不推荐使用。以后会提供更多这方面的信息。

我们计划支持在发行的插件中允许包含 Content。目前该功能尚未完全实现,因此也不推荐现在用它。

游戏项目中的插件

在游戏项目的目录中,插件应该存在于 Plugins 的目录下,并且在游戏引擎或者编辑器启动时被侦测加载。

如果插件具有 Source 目录的模块(以及 *.Build.cs 文件),插件的代码会自动添加到生成的 C++ 项目中,这样便能更容易的一边开发游戏一边开发插件。 每当编译游戏项目是,任何带有源码的插件也会根据游戏的依赖关系一并被编译。

对于没有源代码目录的插件,并不会被生成,也不会出现在 C++ 项目文件中,但只要二进制文件存在,它们都会在游戏启动时被加载。

引擎插件

虚幻引擎 4 已经内建了一些插件,在 Engine 的目录下面。引擎的插件和游戏项目目录里的插件十分相似,区别在于它们对所有游戏项目都是可用的。 一般来说,这些插件是由引擎和工具程序员提供的一些基础功能,只是做成了插件的形式。 这么做能够让用户移除或者改写某个部分的引擎功能,而无需修改任何引擎代码。

默认情况下,引擎插件的加载早于任何游戏模块或者游戏项目插件的加载。

引擎插件有一个特殊的要求:引擎的代码模块必须不能够有任何静态链接依赖到引擎插件的模块库上。 也就是说,引擎的插件必须要保持不被引擎依赖的独立性——插件模块必须不能够成为“被引擎依赖的模块”。这是一个设计哲学上的选择, 这样能够让引擎在这些插件不可用的时候仍然能够工作正常。

发布插件

以下是发布插件所需要的步骤。

  1. 编辑插件的描述器文件(.uplugin 文件)并确保插件的名称、模块、版本以及其他设置都正确的配置。

  2. 删除 插件中的 BinariesIntermediate 目录,这么做确保从一个干净的初始状态开始。

  3. 如果插件包含 Source 目录,用 Win64 Development 来编译插件的二进制文件。对于 PC 平台上的编辑器来说,这个设置一直都需要用于加载。

  4. 对于包含 源码 的插件,如果要支持额外的配置,比如 Mac 的话,那么这些配置的目标文件也应该被编译生成。

  5. 将插件目录拷贝到项目目录以外的一个“阶段性”目录中。无所谓具体是什么地方,但之后需要在那里对插件进行一些修改。

  6. 在上面那个阶段性目录中,删除其中的 Intermediate 目录,这个目录里是一些不需要发布的临时中间文件。

  7. 如果插件包含源码,并且这些源码不想被发布的话,在这个阶段性目录中再删除插件的所有 Source 目录

  8. 在这个阶段性目录中,删除所有不希望被发布的文件。

  9. 现在这个插件已经可以发布了!

一些要点:

  • 仅在发布插件时代上 Public 的头文件目前尚不支持。要么发布时包含整个 Source 目录,要么删掉所有的 Source 目录。 我们计划在将来会支持只发布 Public 的源码的方式(同样也针对 *.Build.cs 文件)。

  • 我们正在开发工具来自动化这一流程。更多细节将来会进一步说明。

  • 对于附带 Content 的插件,可能需要在插件中附带上生成的 Derived Data,避免终端用户重新生成这些文件。 这个功能目前还不支持,但以后会添加,敬请期待。

  • 在插件发布时自带最终用户协议或者文档的形式目前也尚不支持。我们以后会支持这一点。

插件描述器文件

插件描述器那些以 .uplugin 为扩展名的文件。文件名的第一部分始终是插件的名称。 插件描述器文件必须都保存在插件的目录中,引擎在启动时会读取这些目录来检查插件是否存在。

插件描述器采用 Json(JavaScript Object Notation) 的文件格式。

描述器文件示例

这个示例插件描述器来自下面这个 UObjectPlugin 的 示例

{
    "FileVersion" : 3,

    "FriendlyName" : "UObject Example Plugin",
    "Version" : 1,
    "FriendlyVersion" : "1.0",
    "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"
        }
    ]
}

描述器文件格式

字段名

信息

说明

FileVersion

必填

插件描述器文件本身的版本号。这个编号用来对将来插件系统添加新功能后能够向后兼容。这个编号应该设置为当前使用的引擎版本的最新的编号。当前的最新编号在这篇文档编写的时候是 3,并且我们预期这个编号并不会经常更新。在源代码中,可以查找 EProjectDescriptorVersion 查看实际数值。如果希望插件能最大程度的兼容较老的引擎版本,那么可以使用老的版本编号,但并不推荐这么做。

Version

选填

该插件的当前版本号。其数值通常会在将来的版本中不断增加,并且该数值通常并不会显示给最终用户查看。

VersionName

选填

显示在编辑器界面中的插件版本。该参数不会用于任何版本检查的逻辑,可以采用任何插件作者喜欢的格式。我们仍然建议使用 Major.Minor 的编号格式。在每次版本更新时最好都应该更新这个信息。

PackageFileUE4Version

选填

加载该插件所需要的最小的打包文件版本号。对于打包文件版本号小于该数值的项目,将无法加载此插件。

PackageFileLicenseeUE4Version

选填

另一组加载该插件所需要的最小打包文件版本号,对于小于该值的授权打包文件版本号的项目,将无法加载此插件。

FriendlyName

选填

显示在编辑器界面中的插件的名称。如果不定义此值,则使用 .uplugin 文件的文件名。

Description

选填

一小段用来描述插件功能的文本,该信息也会显示在编辑器的插件界面中。

Category

选填

这是一段特殊定义的用 . 来分割的字符串路径,能够将插件设置在特定分类下。这仅仅是为了更好组织的目的。分类的示例如 "Editor Features.Level Editing.Mesh Painting"。每个分类都由一组字符串构成,并且每串字符表示树状结构中更深的一层。

CreatedBy

选填

制作该插件的个人或者公司的名称,这个信息可能会显示在插件的界面或者其他地方。

CreatedByURL

选填

制作该插件的个人或者公司的网站地址。如果定义这个信息的话编辑器的界面上会显示一个超链,用户可以方便的跳转到浏览器中浏览。

CanContainContent

选填

在定义了这个字段并且设置为 true 的时候,为该插件启用 Content 的支持。默认设置为 false。查阅 插件中的内容 部分以获取更多信息。

Modules

选填

对于附带了源码(以及二进制文件)的插件来说,这里定义了启动时需要加载的模块列表。查阅下文以了解更多。

.uplugin 文件格式目前仍处于开发阶段,并且很有可能会进一步修改。比如,我们预期目前关于版本的处理方式将来就可能会调整。

目前尚不支持插件名称和描述的本地化文本,也不支持插件中实现在界面上显示文本的本地化。

模块描述器

对于有源码的插件而言,描述器文件至少包含一个模块描述器。

{
    "Name" : "UObjectPlugin",
    "Type" : "Developer"
}

字段名

信息

说明

Name

必填

该插件模块的唯一名称,随着插件加载会加载该模块。在引擎运行时,插件的 Binaries 目录中应该有正确的插件二进制文件,以及对应的模块文件。对于带有 Source 目录的模块,一个相应的 *.Build.cs 文件也应该存在以模块的子目录中。

Type

必填

设置模块的类型。有效的几项是:RuntimeRuntimeNoCommandletDeveloperEditorEditorNoCommandlet,和 Program。这里的类型设置决定了该插件适合于那种类型的应用程序加载。比如插件中包含的某些模块,可能只是给 Editor 运行是使用的。 Runtime 的模块在无论何时都会被加载,哪怕是在最终发行的游戏版本中也会。Developer 的模块只会在 Development 运行时或者编辑器版本中才会被加载,并不在在最终发行版本中加载。Editor 模块只会随着 Editor 的启动被加载。插件也可以使用几种不同类型的组合来达到所需要的目的。

LoadingPhase

选填

定义该项时,用来控制插件在引擎启动的何时被加载。这是一个高级选项,通常并不需要做任何设置。有效的几个选择是 Default (在不定义 LoadingPhase 的时候),PreDefault,和 PostConfigInitPostConfigInit 在引擎在开始加载核心的子系统前就加载该模块。PreDefault 在正常阶段前来加载模块。通常,需要定义这项是因为游戏模块需要依赖于该插件的 Content 内容,或者 Content 中定义的类型。

图标文件

除了描述器文件外,插件通常还有一个图标文件,能够在编辑器界面中显示该插件。

文件名

信息

格式

说明

/Resources/Icon128.png

必选

128x128 PNG 文件

这个图标在编辑器界面中代表该插件。它会显示在 “Plugins” 用户界面内。

插件范例

我们已经创建了一些示例插件,它们没有任何作用,只是作为一个空壳可以给大家作为创建自己的插件的起始手段。这些插件在引擎的源码中已经包含了。

示例名称

信息

BlankPlugin

这是一个空壳插件,展示了设置一个新的插件代码模块最少需要的文件集合。

UObjectPlugin

一个简单的空插件,展示了如何申明自定义 UObject 类。

要使用这两个范例作为制作插件的起点的话:

  1. 将示例插件拷贝到一个新目录中,并重命名目录、文件以及代码里的内容来匹配自定义的插件名称。请不要保留原来的名字,因为会和引擎中内建的插件冲突。

  2. 在游戏项目目录中 创建一个 "Plugins" 目录,然后将插件拷贝到 “Plugins” 目录内的任何子目录下。

    ExamplePlugins.png

  3. 重新生成 c++ 项目文件。插件模块和代码应该在项目文件中被体现出来。

  4. 正常的 编译游戏项目。Unreal Build Tool 会检测到插件的存在,并将它们作为游戏的依赖项进行编译。

  5. 启动编辑器(或者游戏)。插件一开始是处于禁用的状态,但可以在编辑器界面中启用它。

  6. 打开插件编辑器(Window->Plugins),找到该插件并选中勾选框。

  7. 重启编辑器。插件就会自动在启动时被加载。

可以在 Window -> Developer Tool 中打开 Modules 查看插件是否被加载。 另一个方法是调试的状态在插件的起始代码中放置一个断点,比如 FBlankPlugin::StartupModule()