エンジニアっぽくなりたい

UnityやUnrealEngine 4などでなにか役に立ちそうなことを発信していく。

UE4 LevelSequenceDirectorを使いまわす~with ちょっとエンジン改造~

最近ヒロアカにハマっています。PlusUltraって言葉がとても好きです。
さらに向こうへ!!って感じの意味らしい。
私もエンジン改造から逃げずにさらに向こうへ行きたいところです。


前回の記事
naoxgames.hatenablog.jp

「LevelSequenceDirectorを使いまわす」の内容で、ちょっと改造するとちょっと面倒が減らせるなぁ、というところがあったので対応してみようと思います。


目標


「LevelSequenceDirector」が生成される瞬間から「BP_MyLevelSequenceDirector」に置き換える。
都度親クラスの変更を行う必要をなくしたい!!


環境

・UE 4.27.0 (Gitのコミット:99b6e203a15d04fc7bbbf554c421a985c1ccb8f1 をビルド)
・VisualStudio 2019 16.11.2


やってみる

作戦としてはC++でのクラス「ULevelSequenceDirector」を検索し、生成される瞬間の対象クラスを入れ替える。
入れ替える方法はiniファイルを使用する。

置き換え準備

プロジェクトのConfigフォルダにある「DefaultEditor.ini」に以下を追記します。

[EngineOverride]
LevelSequenceDirector="BlueprintGeneratedClass'/Game/LevelSequenceTest/LevelSequenceDirectorTest/BP_MyLevelSequenceDirector.BP_MyLevelSequenceDirector_C'"

※[EngineOverride]や「LevelSequenceDirector」の文字列はなんでも問題ありません。
クラスパスは前回の記事で作成した「BP_MyLevelSequenceDirector」のパス+「_C」です。

ここに記述した情報を使い、エンジン内で自作プロジェクト側のクラス(BPクラス?)を呼びます。


ULevelSequenceDirector生成場所を探す

「ULevelSequenceDirector」でエンジンを検索してみると MovieSceneSequenceEditor_LevelSequence.h
CreateBlueprintForSequence 関数内で

Blueprint = FKismetEditorUtilities::CreateBlueprint(ULevelSequenceDirector::StaticClass(), InSequence, BlueprintName, BPTYPE_Normal, UBlueprint::StaticClass(), UBlueprintGeneratedClass::StaticClass());

このような処理が行われており、ここで生成されているようです。
この「ULevelSequenceDirector::StaticClass()」を置き換えたいです。


エンジン改造

該当箇所のクラスを置き換える処理を行います。
以下、MovieSceneSequenceEditor_LevelSequence.hのCreateBlueprintForSequence改造後の内容になります。
コメントで挟まれている箇所が追加、変更箇所です。

  virtual UBlueprint* CreateBlueprintForSequence(UMovieSceneSequence* InSequence) const override
    {
        UBlueprint* Blueprint = GetBlueprintForSequence(InSequence);
        if (!ensureMsgf(!Blueprint, TEXT("Should not call CreateBlueprintForSequence when one already exists")))
        {
            return Blueprint;
        }

        ULevelSequence* LevelSequence = CastChecked<ULevelSequence>(InSequence);
        //***********************************************
        //改造:LevelSequenceDirectorのClassを置き換える追加
        FString OverrideClassName;
        GConfig->GetString(TEXT("EngineOverride"), TEXT("LevelSequenceDirector"), OverrideClassName, GEditorIni);
        TSubclassOf<class UObject> LevelSequenceDirectorClass = LoadClass<ULevelSequenceDirector>(NULL, *OverrideClassName, NULL, LOAD_NoWarn, NULL);

        if (LevelSequenceDirectorClass == nullptr)
        {
            LevelSequenceDirectorClass = ULevelSequenceDirector::StaticClass();
        }
        //ここまで
        //***********************************************
        
        FName BlueprintName = "SequenceDirector";
        
        //***********************************************
        //改造:LevelSequenceDirectorClassを指定するよう変更
        Blueprint = FKismetEditorUtilities::CreateBlueprint(LevelSequenceDirectorClass, InSequence, BlueprintName, BPTYPE_Normal, UBlueprint::StaticClass(), UBlueprintGeneratedClass::StaticClass());
        //Blueprint = FKismetEditorUtilities::CreateBlueprint(ULevelSequenceDirector::StaticClass(), InSequence, BlueprintName, BPTYPE_Normal, UBlueprint::StaticClass(), UBlueprintGeneratedClass::StaticClass());
        //ここまで
        //***********************************************
        
        Blueprint->ClearFlags(RF_Standalone);

        LevelSequence->SetDirectorBlueprint(Blueprint);
        return Blueprint;
    }



Plus ultra !!!!

見える形で示すのが少し難しいですが、以下のような感じです。

このように、作成したばかりのシーケンサーの「LevelSequenceDirector」の初期の親クラスがすでに置き換わっている状態にできました。
こうすることでいくらか楽できるようになったのかなと思います。
一応これでも問題はあり、すでに作成済みの「LevelSequenceDirector」は置き換わらないです。


思ったこと

ちょっとしたエンジン改造でワークフローの改善につながるものは多いと思います。
データ作成をする人のミスが減る環境を作れたら結果エンジニアが楽な未来にたどり着くこともありますよね。
エンジン改造がすべてではありませんが、適切な対応をできるようになっていきたいものです。




正しい対応方法やより良い方法があればご指摘お願いいたします!!!