{"id":3077,"date":"2021-01-02T13:53:01","date_gmt":"2021-01-02T05:53:01","guid":{"rendered":"http:\/\/blog.coolcoding.cn\/?p=3077"},"modified":"2021-01-02T19:44:09","modified_gmt":"2021-01-02T11:44:09","slug":"creating-a-new-editor-module","status":"publish","type":"post","link":"https:\/\/blog.coolcoding.cn\/?p=3077","title":{"rendered":"Creating a new editor module"},"content":{"rendered":"\n<p> The following recipes all interact with editor mode-specific code and engine modules. As a result, it is considered good practice to create a new module that will only be loaded when\u00a0the engine is running in editor mode, so that we can place all our editor-only code inside it. <\/p>\n\n\n\n<p><\/p>\n\n\n\n<h1 class=\"wp-block-heading\">How to do it&#8230;<\/h1>\n\n\n\n<ol><li>Open your project&#8217;s&nbsp;.uproject&nbsp;file in a text editor such as Notepad or Notepad++. You can find the file inside your project folder, and it should look similar to what&#8217;s shown in the following screenshot:<\/li><\/ol>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"http:\/\/blog.coolcoding.cn\/wp-content\/uploads\/2021\/01\/b4051c5c-b769-4866-98f4-39af0c8018de.png\" alt=\"\"\/><\/figure>\n\n\n\n<ol><li>Add the bold section of text in the following snippet to the file:<\/li><\/ol>\n\n\n\n<pre class=\"wp-block-preformatted\">{<br>  \"FileVersion\": 3,<br>  \"EngineAssociation\": \"4.21\",<br>  \"Category\": \"\",<br>  \"Description\": \"\",<br>  \"Modules\": [<br>    {<br>      \"Name\": \"Chapter_10\",<br>      \"Type\": \"Runtime\",<br>      \"LoadingPhase\": \"Default\"<br>    }<strong>, <\/strong><br><strong>      { <\/strong><br><strong>          \"Name\": \"Chapter_10Editor\", <\/strong><br><strong>          \"Type\": \"Editor\", <\/strong><br><strong>          \"LoadingPhase\": \"PostEngineInit\", <\/strong><br><strong>          \"AdditionalDependencies\": [ <\/strong><br><strong>            \"Engine\", <\/strong><br><strong>            \"CoreUObject\" <\/strong><br><strong>          ] <\/strong><br><strong>      }<\/strong> <br>  ]<br>}<br><br><\/pre>\n\n\n\n<p>Note the comma after the first module before the second set of curly braces.<\/p>\n\n\n\n<ol><li>In your&nbsp;Source&nbsp;folder, create a new folder using the same name as you specified in your&nbsp;uproject&nbsp;file (in this instance,&nbsp;&#8220;Chapter_10Editor&#8221;):<\/li><\/ol>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"http:\/\/blog.coolcoding.cn\/wp-content\/uploads\/2021\/01\/fc3ee6b5-e94d-4330-a120-4b2f707d6edc.png\" alt=\"\"\/><\/figure>\n\n\n\n<ol><li>Open up the&nbsp;Chapter_10Editor.Target.cs&nbsp;file and update it to the following:<\/li><\/ol>\n\n\n\n<pre class=\"wp-block-preformatted\">using UnrealBuildTool;<br>using System.Collections.Generic;<br><br>public class Chapter_10EditorTarget : TargetRules<br>{<br>  public Chapter_10EditorTarget(TargetInfo Target) : base(Target)<br>  {<br>    Type = TargetType.Editor;<br><br>    ExtraModuleNames.AddRange( new string[] { \"Chapter_10<strong>Editor<\/strong>\" } );<br>  }<br>}<\/pre>\n\n\n\n<ol><li>Inside this new folder, create a blank&nbsp;.txt&nbsp;file and rename it to&nbsp;Chapter_10Editor.Build.cs:<\/li><\/ol>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"http:\/\/blog.coolcoding.cn\/wp-content\/uploads\/2021\/01\/1f0a6cba-aeb7-420e-9d08-cec2aed2029e.png\" alt=\"\"\/><\/figure>\n\n\n\n<ol><li>Insert the following into the file:<\/li><\/ol>\n\n\n\n<pre class=\"wp-block-preformatted\">using UnrealBuildTool;<br><br>public class Chapter_10Editor : ModuleRules<br>{<br>    public Chapter_10Editor(ReadOnlyTargetRules Target) : <br>    base(Target)<br>    {<br>        PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs;<br><br>        PublicDependencyModuleNames.AddRange(new string[] { \"Core\", <br>        \"CoreUObject\", \"Engine\", \"InputCore\", \"RHI\", \"RenderCore\", <br>        \"ShaderCore\", \"MainFrame\", \"AssetTools\", \"AppFramework\", <br>        \"PropertyEditor\"});<br>    <br>       PublicDependencyModuleNames.Add(\"Chapter_10\");<br><br>        PrivateDependencyModuleNames.AddRange(new string[] { <br>        \"UnrealEd\", \"Slate\", \"SlateCore\", \"EditorStyle\", <br>        \"GraphEditor\", \"BlueprintGraph\" });<br><br>    }<br>}<\/pre>\n\n\n\n<ol><li>Still inside of the&nbsp;Chapter10_Editor&nbsp;folder, create a new file called&nbsp;Chapter_10Editor.h&nbsp;and add the following:<\/li><\/ol>\n\n\n\n<pre class=\"wp-block-preformatted\">#pragma once<br><br>#include \"Engine.h\"<br>#include \"Modules\/ModuleInterface.h\"<br>#include \"Modules\/ModuleManager.h\"<br>#include \"UnrealEd.h\"<br> <br> <br>class FChapter_10EditorModule: public IModuleInterface <br>{ <br>}; <\/pre>\n\n\n\n<ol><li>Lastly, create a new source file called&nbsp;Chapter_10Editor.cpp.<\/li><li>Add the following code:<\/li><\/ol>\n\n\n\n<pre class=\"wp-block-preformatted\">#include \"Chapter_10Editor.h\" <br>#include \"Modules\/ModuleManager.h\"<br>#include \"Modules\/ModuleInterface.h\"<br><br>IMPLEMENT_GAME_MODULE(FChapter_10EditorModule, Chapter_10Editor)<\/pre>\n\n\n\n<ol><li>Finally, close Visual Studio if you have it open. Then, right-click on the&nbsp;.uproject&nbsp;file and select&nbsp;Generate Visual Studio Project files:<\/li><\/ol>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"http:\/\/blog.coolcoding.cn\/wp-content\/uploads\/2021\/01\/71edf948-dcce-4da8-a1a3-e8069a117f83.png\" alt=\"\"\/><\/figure>\n\n\n\n<ol><li>You should see a small window launch, display a progress bar, and then close:<\/li><\/ol>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"http:\/\/blog.coolcoding.cn\/wp-content\/uploads\/2021\/01\/766c4e4b-557f-4785-8c01-ae82430cadc7.jpg\" alt=\"\"\/><\/figure>\n\n\n\n<ol><li>You can now launch Visual Studio, verify that your new module is visible in the IDE, and compile your project successfully:<\/li><\/ol>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"http:\/\/blog.coolcoding.cn\/wp-content\/uploads\/2021\/01\/770bd61f-d16a-49f2-9c81-f2f1d3be25d3.png\" alt=\"\"\/><\/figure>\n\n\n\n<ol><li>The module is now ready for the next set of recipes.<\/li><\/ol>\n\n\n\n<p>Code changes made in this editor module won&#8217;t support hot-reloading in the same way that code in runtime modules does. If you get a compilation error that mentions changes to generated header files, simply close the editor and rebuild it from within your IDE instead. <\/p>\n\n\n\n<h1 class=\"wp-block-heading\">How it works&#8230;<\/h1>\n\n\n\n<p>Unreal projects use the&nbsp;.uproject&nbsp;file format to specify a number of different pieces of information about the project.<\/p>\n\n\n\n<p>This information is used to inform the Header and Build tools about the modules that comprise this project, and is used for code generation and&nbsp;makefile&nbsp;creation.<\/p>\n\n\n\n<p>The file uses JSON-style formatting.<\/p>\n\n\n\n<p>These include the following:<\/p>\n\n\n\n<ul><li>The engine version that the project should be opened in<\/li><li>A list of modules that are used in the project<\/li><li>A list of module declarations<\/li><\/ul>\n\n\n\n<p>Each of these module declarations contain the following:<\/p>\n\n\n\n<ul><li>The name of the module.<\/li><li>The type of module\u2014is it an editor module (only runs in editor builds, has access to editor-only classes) or a runtime module (runs in both editor and Shipping builds)?<\/li><li>The loading phase of the module\u2014modules can be loaded at different points during program startup. This value specifies the point at which the module should be loaded, for example, if there are dependencies in other modules that should be loaded first.<\/li><li>A list of dependencies for the module. These are essential modules that contain exported functions or classes that the module relies on.<\/li><\/ul>\n\n\n\n<p>We added a new module to the&nbsp;uproject file. The module&#8217;s name is&nbsp;Chapter_10Editor&nbsp;(Conventionally,&nbsp;Editor&nbsp;should be appended to the main game module for an editor module).<\/p>\n\n\n\n<p>This module is marked as an editor module, and is set to load after the baseline engine so that it can use the classes that have been declared in Engine code.<\/p>\n\n\n\n<p>Our module&#8217;s dependencies are left at the default values for now.<\/p>\n\n\n\n<p>With the&nbsp;uproject&nbsp;file altered to contain our new module, we need a build script for it.<\/p>\n\n\n\n<p>Build scripts are written in C#, and take the name&nbsp;&lt;ModuleName&gt;.Build.cs.<\/p>\n\n\n\n<p>C#, unlike C++, doesn&#8217;t use a separate header file and implementation&nbsp;\u2013&nbsp;it&#8217;s all there in the one&nbsp;.cs&nbsp;file.<\/p>\n\n\n\n<p>We want to access the classes that have been declared in the&nbsp;UnrealBuildTool&nbsp;module, so we include a&nbsp;using&nbsp;statement to indicate that we want to access that namespace.<\/p>\n\n\n\n<p>We create a&nbsp;public&nbsp;class with the same name as our module, which inherits from&nbsp;ModuleRules.<\/p>\n\n\n\n<p>Inside our constructor, we add a number of modules to the dependencies of this module. There are both private dependencies and public dependencies.<\/p>\n\n\n\n<p>According to the code of the&nbsp;ModuleRules&nbsp;class, public dependencies are modules that your module&#8217;s public header files depend on. Private dependencies are modules that the private code depends on. Anything used in both public headers and private code should go into the&nbsp;PublicDependencyModuleNames&nbsp;array.<\/p>\n\n\n\n<p>You&#8217;ll note that our&nbsp;PublicDependencyModuleNames&nbsp;array contains our main game module. This is because some recipes in this chapter will extend the editor to better support the classes that are defined within our main game module.<\/p>\n\n\n\n<p>Now that we&#8217;ve told the build system that we have a new module to build through the project file, and we&#8217;ve specified how to build the module with the build script, we need to create the C++ class that is our actual module.<\/p>\n\n\n\n<p>We create a header file that includes the Engine header, the&nbsp;ModuleManager&nbsp;header, and the&nbsp;UnrealEd&nbsp;header.<\/p>\n\n\n\n<p>We include&nbsp;ModuleManager&nbsp;because it defines&nbsp;IModuleInterface, the class that our module will inherit from.<\/p>\n\n\n\n<p>We also include&nbsp;UnrealEd&nbsp;because we&#8217;re writing an editor module that will need to access the editor functionality.<\/p>\n\n\n\n<p>The class we declare inherits from&nbsp;IModuleInterface, and takes its name from the usual prefix,&nbsp;F, followed by the module name.<\/p>\n\n\n\n<p>Inside the&nbsp;.cpp&nbsp;file, we include our module&#8217;s header, and then use the&nbsp;IMPLEMENT_GAME_MODULE&nbsp;macro.<\/p>\n\n\n\n<p>IMPLEMENT_GAME_MODULE&nbsp;declares an exported C function,&nbsp;InitializeModule(), which returns an instance of our new module class.<\/p>\n\n\n\n<p>This means that Unreal can simply call&nbsp;InitializeModule()&nbsp;on any library that exports it to retrieve a reference to the actual module implementation without needing to know what class it is.<\/p>\n\n\n\n<p>Having added our new module, we now need to rebuild our Visual Studio solution, so we close Visual Studio and then regenerate the project files using the context menu.<\/p>\n\n\n\n<p>With the project rebuilt, the new module will be visible in Visual Studio, and we can add code to it as usual.<\/p>\n\n\n\n<p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>The following recipes all interact with editor mode-spe [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[27,1],"tags":[26],"_links":{"self":[{"href":"https:\/\/blog.coolcoding.cn\/index.php?rest_route=\/wp\/v2\/posts\/3077"}],"collection":[{"href":"https:\/\/blog.coolcoding.cn\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.coolcoding.cn\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.coolcoding.cn\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.coolcoding.cn\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=3077"}],"version-history":[{"count":1,"href":"https:\/\/blog.coolcoding.cn\/index.php?rest_route=\/wp\/v2\/posts\/3077\/revisions"}],"predecessor-version":[{"id":3087,"href":"https:\/\/blog.coolcoding.cn\/index.php?rest_route=\/wp\/v2\/posts\/3077\/revisions\/3087"}],"wp:attachment":[{"href":"https:\/\/blog.coolcoding.cn\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=3077"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.coolcoding.cn\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=3077"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.coolcoding.cn\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=3077"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}