【UE5】使われているプラグインを列挙する

[IPluginManager]:https://docs.unrealengine.com/5.1/en-US/API/Runtime/Projects/Interfaces/IPluginManager/
[IPlugin]:https://docs.unrealengine.com/5.1/en-US/API/Runtime/Projects/Interfaces/IPlugin/
[GetEnabledPlugins]:https://docs.unrealengine.com/5.1/en-US/API/Runtime/Projects/Interfaces/IPluginManager/GetEnabledPlugins/
[GetDiscoveredPlugins]:https://docs.unrealengine.com/5.1/en-US/API/Runtime/Projects/Interfaces/IPluginManager/GetDiscoveredPlugins/


:::note info
確認したバージョンはUE5.1.1です。
:::

# やりたいこと

Plugin Managerはそれはそれで便利なのだが、全容をざっと確認したり、複数のプロジェクト間で比較したりするには少し使いにくい。
プラグイン一覧をざっとテキストで見られたら楽なのに…　というのが動機。

テキストだと複数のプロジェクト間の比較もしやすい。
特に、誰かからもらったサンプルプロジェクトなどで、何をONにしていて、何をOFFにしているのかなどを自分のプロジェクトと比較するときなどに使いたい。

# このクラスを使う

- [IPluginManager]：プラグインの列挙や情報の取得などのメンバが揃っている。
- [IPlugin]：個々のプラグインの情報の取得など。

:::note info
IPluginManagerなどを使うには、"Projects"モジュールが必要。
"Projects"モジュールを.Build.csに追加しておく。
:::

:::note info
おそらくゲーム本編では使うことは滅多にないだろうから、Editorモジュールに入れておくのが良いだろう。
:::

# 例１：有効(Enabled)になっているプラグインをOutput Logにざっと出力する

現在のプロジェクトで有効になっているプラグインを列挙するには[IPluginManager::GetEnabledPlugins()](GetEnabledPlugins)を利用する。

```C++
#include "PluginUtilityFunctionLibrary.h"
#include "Interfaces/IPluginManager.h" // IPluginManager ("Projects"モジュールが必要)

DEFINE_LOG_CATEGORY_STATIC(LogPluginUtil, Log, All);

// 有効なプラグインをログに出力する
void UPluginUtilityFunctionLibrary::LogEnabledPlugins()
{
	// 有効(Enabled)になっているプラグインの取得
	TArray<TSharedRef<IPlugin>> EnabledPlugins = IPluginManager::Get().GetEnabledPlugins();

	// プラグイン名でソートした方が見やすかろう
	EnabledPlugins.Sort([](TSharedRef<IPlugin> PluginA, TSharedRef<IPlugin> PluginB)
		{
			return PluginA->GetName() < PluginB->GetName();
		});

	// Output Logに出力
	UE_LOG(LogPluginUtil, Log, TEXT("==== Enabled Plugins"));

	int32 i = 0;
	for (const TSharedRef<IPlugin>& Plugin : EnabledPlugins)
	{
		UE_LOG(LogPluginUtil, Log, TEXT("[%3d] %s (%s)"), 
			i++,							// 通し番号(ループインデックス)
			*Plugin->GetName(),				// プラグイン名
			*Plugin->GetFriendlyName());	// 人間が見やすいプラグイン名
	}
}
```

Editor Utility Widgetのボタンから呼び出してみた例：
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/358170/664f61c6-cc44-1101-435e-66b004c92ae1.png)


# 例２：全プラグインのプラグインの情報をOutput Logにざっと出力する

全てのプラグインを列挙するには[IPluginManager::GetDiscoveredPlugins()](GetDiscoveredPlugins)を利用する。

```C++
// このcppファイル内のみで使う関数を括るnamespace
namespace PluginUtilities
{
	//「カテゴリ名 / プラグイン名」の文字列を作成する
	FString MakeCategoriedName(TSharedRef<IPlugin> Plugin)
	{
		const FPluginDescriptor& Descriptor = Plugin->GetDescriptor();
		FString CategoriedName = Descriptor.Category.IsEmpty() ? TEXT(".") : Descriptor.Category; // カテゴリ名がない場合がある
		CategoriedName += TEXT("/");
		CategoriedName += Plugin->GetName();
		return CategoriedName;
	}

} // namespace PluginUtilities

// すべてのプラグインをログに出力する
void UPluginUtilityFunctionLibrary::LogDiscoveredPlugins()
{
	// 全プラグインの取得
	// ※Discoveredという命名から「見つかる範囲ですべて」というニュアンスだと思われる。
	TArray<TSharedRef<IPlugin>> DiscoveredPlugins = IPluginManager::Get().GetDiscoveredPlugins();

	// 今度は「カテゴリ名/プラグイン名」でソートしてみる
	DiscoveredPlugins.Sort([](TSharedRef<IPlugin> PluginA, TSharedRef<IPlugin> PluginB)
		{
			const FString CompareStringA = PluginUtilities::MakeCategoriedName(PluginA);
			const FString CompareStringB = PluginUtilities::MakeCategoriedName(PluginB);
			return CompareStringA < CompareStringB;
		});

	// Output Logに出力
	UE_LOG(LogPluginUtil, Log, TEXT("==== Discovered (All) Plugins"));

	int32 i = 0;
	for (const TSharedRef<IPlugin>& Plugin : DiscoveredPlugins)
	{
		const FPluginDescriptor& Descriptor = Plugin->GetDescriptor(); // プラグイン情報(Descriptor)の取得

		UE_LOG(LogPluginUtil, Log, TEXT("[%3d%c] %s (%s): %s"),
			i++,							// 通し番号(ループインデックス)
			Plugin->IsEnabled() ? TEXT('*') : TEXT(' '),	// Enabledなプラグインは番号の後ろに"*"を付ける
			*PluginUtilities::MakeCategoriedName(Plugin),		// カテゴリ名/プラグイン名
			*Plugin->GetFriendlyName(),		// 人間が見やすいプラグイン名
			*Descriptor.Description);		// プラグインの説明
	}
}
```

Editor Utility Widgetのボタンから呼び出してみた例：
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/358170/8dd1035d-0fbc-b389-bc01-d94b49ea19f9.png)

これで、無駄なプラグインが含まれていることを知りつつ、無効にする作業が面倒だから放置していたりする事態が解消されるといいな。