UE4 モジュール追加手順のメモ書き

# 概要
UnrealEngine のモジュール追加についてのメモ書きです。
エディタ用モジュールの追加手順を記録しています。

## 更新履歴
| 日付 | 内容 |
|:----|:-----|
|2020/09/14| プラグインについて追記。 |
|2020/10/13| モジュールの外部参照についての備考追記。 |

## 環境
Windows10
Visual Studio 2017
UnrealEngine 4.22


## 参考
以下を参考にさせて頂きました、ありがとうございます。

[モジュールについて](http://historia.co.jp/archives/3097/)
[【UE4】モジュール追加](https://www.romsuke.com/entry/2019/01/10/212704)
https://qiita.com/kanurapoison/items/e4b551a1f22b85162c70
https://qiita.com/go_astrayer/items/5d001a9cde182488f9f3


# モジュール追加手順
ファイル追加と設定ファイルの書き換えが必要です。

## モジュールソースの作成
モジュール名を決めてフォルダを作成、それをプロジェクトの[Source]フォルダ以下へ配置する。フォルダには[***.Build.cs][***.h][***.cpp]のファイルを置く。

以下[TestModuleEd]というモジュールを作成する場合は以下のようになります。

![TestModuleFiles.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/303806/9c4fb9b8-72ea-1522-ca27-62d384a00bae.jpeg)


```cs:TestModuleEd.Build.cs
namespace UnrealBuildTool.Rules 
{ 
	public class TestModuleEd : ModuleRules 
	{ 
		public TestModuleEd(ReadOnlyTargetRules Target) : base(Target) 
		{ 
			PublicIncludePaths.AddRange( 
				new string[] { 
                    "TestModuleEd", 
					// ... add public include paths required here ... 
				} 
				); 
			PrivateIncludePaths.AddRange( 
				new string[] { 
					"TestModuleEd", 
					// ... add other private include paths required here ... 
				} 
				); 
			PublicDependencyModuleNames.AddRange( 
				new string[] 
				{ 
					"Core", 
                    "CoreUObject", 
                    "Engine", 
					// ... add other public dependencies that you statically link with here ... 
				} 
				); 
			PrivateDependencyModuleNames.AddRange( 
				new string[] 
				{ 
					// ... add private dependencies that you statically link with here ... 
				} 
				); 
			DynamicallyLoadedModuleNames.AddRange( 
				new string[] 
				{ 
					// ... add any modules that your module loads dynamically here ... 
				} 
				); 
		} 
	} 
} 

```

```cpp:TestModule.h
#pragma once 
#include "CoreMinimal.h" 
#include "Modules/ModuleInterface.h" 
#include "Modules/ModuleManager.h" 
/** 
 * The public interface to this module 
 */ 
class ITestModuleEd : public IModuleInterface 
{ 
public: 
	/** 
	 * Singleton-like access to this module's interface.  This is just for convenience 
	 * Beware of calling this during the shutdown phase, though.  Your module might have been unloaded already. 
	 * 
	 * @return Returns singleton instance, loading the module on demand if needed 
	 */ 
	static inline ITestModuleEd& Get() 
	{ 
		return FModuleManager::LoadModuleChecked< ITestModuleEd >( "TestModuleEd" ); 
	} 
	/** 
	 * Checks to see if this module is loaded and ready.  It is only valid to call Get() if IsAvailable() returns true. 
	 * 
	 * @return True if the module is loaded and ready to use 
	 */ 
	static inline bool IsAvailable() 
	{ 
		return FModuleManager::Get().IsModuleLoaded( "TestModuleEd" ); 
	} 
}; 

```

```cpp:TestModule.cpp
#include "TestModuleEd/TestModuleEd.h" 
class FTestModuleEd : public ITestModuleEd 
{ 
	/** IModuleInterface implementation */ 
	virtual void StartupModule() override; 
	virtual void ShutdownModule() override; 
}; 
IMPLEMENT_MODULE( FTestModuleEd, TestModuleEd ) 
void FTestModuleEd::StartupModule() 
{ 
	// This code will execute after your module is loaded into memory (but after global variables are initialized, of course.) 
} 
void FTestModuleEd::ShutdownModule() 
{ 
	// This function may be called during shutdown to clean up your module.  For modules that support dynamic reloading, 
	// we call this function before unloading the module. 
} 

```

## ファイル内容の修正
追加したモジュールの情報を反映させるために設定ファイルに追記します。
修正するファイルはエディタ用モジュールを想定し、[MyProject.uproject][MyProject.Build.cs][MyProjectEditor.Target.cs]の3ファイルです。


Modulesに追加します。

```xml:MyProject.uproject
{
	"FileVersion": 3,
	"EngineAssociation": "4.22",
	"Category": "",
	"Description": "",
	"Modules": [
		{
			"Name": "MyProject",
			"Type": "Runtime",
			"LoadingPhase": "Default",
			"AdditionalDependencies": [
				"Engine"
			]
		}
## ここから追加↓、（カンマに注意）
		,{
			"Name": "TestModuleEd",
			"Type": "Editor",
			"LoadingPhase": "PostEngineInit"
		}
## ここまで↑
	],
	"Plugins": [
		{
			"Name": "EditorTests",
			"Enabled": true
		},
	]
}

```

PublicDependencyModuleNamesに追加します。

```cs:MyProject/MyProject.Build.cs

using UnrealBuildTool;

public class MyProject : ModuleRules
{
	public MyProject(ReadOnlyTargetRules Target) : base(Target)
	{
		PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs;
	
		PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore" });
		PublicDependencyModuleNames.AddRange(new string[] { "TestModuleEd"});   // ←ここを追加
		
		PrivateDependencyModuleNames.AddRange(
			new string[]
			{
				"Slate",
				"SlateCore",
			}
		);
	}
}

```

ExtraModuleNameに追加します。

```cs:MyProjectEditor.Target.cs

using UnrealBuildTool;
using System.Collections.Generic;

public class MyProjectEditorTarget : TargetRules
{
	public MyProjectEditorTarget(TargetInfo Target) : base(Target)
	{
		Type = TargetType.Editor;

		ExtraModuleNames.AddRange( new string[] { "MyProject" } );
		ExtraModuleNames.AddRange( new string[] { "TestModuleEd" } );    // ←ここを追加
	}
}


```

## モジュールファイルのソリューションへの追加
[MyProject.uproject]の右クリックメニューから[Generate VisualStudio project files]を実行し、ソリューションを確認し、ビルドする。

![ContextManu.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/303806/48633797-78fd-3eb9-554c-e1a424fbce91.jpeg)

エラーが出る場合は、設定を確認する。

UEエディタにて
[ウィンドウ] -> [デベロッパーツール] -> [モジュール] に追加したモジュールが表示されます。

![ModuleWindow.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/303806/4b48eb83-d2e0-0710-fc65-956e0a12721a.jpeg)


# 備考
## プラグインでのサポート
モジュール追加をサポートするプラグインもあるようです。
[New C++ Module tool
](https://www.unrealengine.com/marketplace/ja/product/new-c-module-tool/)

インストールをしてプラグインを有効に。
![ModuleGeneration_Plugin.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/303806/ee963c25-41be-c66e-3c55-da5b3f52bd0a.jpeg)

メニューに追加されます。
![ModuleGeneration_Menu.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/303806/c1d2fc2c-f824-1e1f-87ce-87a52ea9281d.jpeg)



## 外部公開について
外部モジュールへの参照は `.Build.cs` ファイルの `PublicDependencyModuleNames` に追記することによって可能となりますが、外部公開のためにはそのクラスやストラクトに `MYPROJECT_API` (MyProjectはモジュール名)というマクロをつける必要があります。
これがない場合ヘッダのみに書かれた`getter`のようなメソッドはアクセスできますが、それ以外は参照エラーとなります。


# まとめ
機能別にモジュール分割をするように推奨されているようですが、依存関係は設計段階で考慮しないと大変なことになります。
EditorUtilityWidget などエディタ専用の機能をC++から使う場合はエディタ専用モジュールを作成は必須になります。