Featured image of post [UE5] 『Add C++ Class』の Common Classes にクラスを追加する

[UE5] 『Add C++ Class』の Common Classes にクラスを追加する

UE 5.1.1

はじめに

前々回と前回の記事で、『Add C++ Class』ウィザードが自動生成するコードをカスタマイズする方法について解説してきました。

特に前回に関しては、特定のクラスのコード生成時に自作の Template ファイルが使用されるようにするために、エンジンコードの修正まで行いました。

そこまでやったのであれば、そのクラスを『Add C++ Class』ウィザードの Common Classes に追加してみたくないですか?

エンジンコード修正案件ではありますが、実はかなり簡単に追加できるので、サクッとやってしまいましょう。

実例

『Add C++ Class』の Common Classes に、UCheatManager を追加することにします。

変更すべきファイルは、/Engine/Source/Editor/GameProjectGeneration/Public/FeaturedClasses.inl です。

このファイルで定義されている関数 FFeaturedClasses::AllNativeClasses() の返り値が Common Classes に並ぶクラスのリストになるので、return される変数 ArrayUCheatManager の情報を追加します (下記コードの 25 行目)。なお、Array に追加された順に Common Classes に並びます。

また、これに伴い、UCheatManager のヘッダファイルを #include します (下記コードの 9 行目)。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
(省略)

/** Inline file to avoid introducing many UObject headers into the global namespace */

#include "CoreTypes.h"
(山ほどある #include を省略)
#include "Components/DirectionalLightComponent.h"

#include "GameFramework/CheatManager.h" // ← 追加

struct FFeaturedClasses;
struct FNewClassInfo;

/** Get a list of all featured native class types */
FORCEINLINE TArray<FNewClassInfo> FFeaturedClasses::AllNativeClasses()
{
    TArray<FNewClassInfo> Array;
    Array.Add(FNewClassInfo(FNewClassInfo::EClassType::EmptyCpp));

    AddCommonActorClasses(Array);
    AddCommonComponentClasses(Array);

    AddExtraActorClasses(Array);

    Array.Add(FNewClassInfo(UCheatManager::StaticClass())); // ← 追加

    Array.Add(FNewClassInfo(UBlueprintFunctionLibrary::StaticClass()));
    
    (省略)
    
    return Array;
}

エンジンビルドを行い、『Add C++ Class』を開きます。

『Cheat Manager』の項目が追加されていることが確認できました!

余談 : FeaturedClasses.inl 周りのコード設計について

今回修正を行った FeaturedClasses.inl は、拡張子が .inl (アイエヌエル) となっています。

この拡張子は “inline” を省略したものです。「インライン関数の定義を宣言から分離させたファイルである」ということを読む人に伝えるために、ファイルをこの拡張子にすることがあります。あくまで『人間に対して用途をわかりやすく示すために付けられる拡張子』であって、この拡張子にしたからといって、何か特別な処理が行われるわけではありません。コンパイラから見たらただのヘッダファイル (.h) と同じであり、ヘッダファイルと同じように #include されて使われます。

FeaturedClasses.inl は『struct FFeaturedClasses のインラインクラス関数の定義を宣言から分離させたファイル』です。FFeaturedClasses およびそのインライン関数の宣言は、FeaturedClasses.inl と同じ階層にある AddToProjectConfig.h にあります。

インライン関数の定義を宣言から分離させる理由はいくつか考えられるのですが、FeaturedClasses.inl のコメントに

/** Inline file to avoid introducing many UObject headers into the global namespace */

とあるように、「大量の UObject ヘッダファイルが #include によってグローバル名前空間に導入されることを (極力) 避けるため」に分離されているようです。

実例解説にて処理を追加した FFeaturedClasses::AllNativeClasses() は、Common Classes に並ぶすべてのクラスの情報を配列で返す関数でした。つまり、この関数を定義するにあたっては、それらすべてのクラスの宣言情報が必要になるため、多くのヘッダファイルを #include する必要があります。

よって、もしも FeaturedClasses のインライン関数の定義が AddToProjectConfig.h にまとめられていた場合、AddToProjectConfig.h#include したときに漏れなく大量のヘッダファイルが連鎖的に #include されることになります。しかし、AddToProjectConfig.h には FFeaturedClasses のインライン関数以外の宣言・定義もあり、AddToProjectConfig.h#include するファイルすべてが FFeaturedClasses のインライン関数を利用するわけではないので、そういったファイルからすると「不要なファイルが大量に #include される」ことになってしまいます。これは望ましくないため、FeaturedClasses.inl にインライン関数の定義を分離し、

  • FFeaturedClasses のインライン関数を (直接的にも間接的にも) 利用しない場合

    • AddToProjectConfig.h のみを #include する
  • FFeaturedClasses のインライン関数を (直接的もしくは間接的に) 利用する場合

    • AddToProjectConfig.hFFeaturedClasses.inl の両方を #include する

という決まりにすることで、グローバル名前空間の汚染を最小限にしようというわけです。

……と書くと「AddToProjectConfig.h から FFeaturedClasses を丸ごとパージすればいいのでは?」と思うかもしれませんが、AddToProjectConfig.h にある struct FAddToProjectConfig の一部関数が FFeaturedClasses の宣言を必要としているため、定義のみを分離する形になっているようです。

(´・∀・`)……

(´・∀・`)ヘー

(´・∀・`)<おわり