LoginSignup
2
0

More than 1 year has passed since last update.

コンソールコマンドの引数の入力候補を出す

Posted at

はじめに

この記事を見ているということは、自分で追加したコンソールコマンドを使っていて引数に文字列やEnumを指定する場合、毎回自分で入力しないといけないのが面倒くさいと思ったことがあるのではないでしょうか?

UENUM(BlueprintType)
enum class ETestCommandArg : uint8
{
    Unreal,
    Engine,
    Epic,
};

UCLASS()
class CONSOLECOMMANDTEST_API UConsoleCommandTestObject : public UObject
{
    GENERATED_BODY()

public:
    UFUNCTION(Exec)
    static void AutoCompleteTest(ETestCommandArg Type);
};

例えばこちらのAutoCompleteTestというコンソールコマンドを使おうとすると、引数のTypeを毎回入力する羽目になります。
1.PNG

今回は下の画像のように引数の入力候補が表示されるようする方法をご紹介します。
2.PNG

やり方(C++を使わない場合)

3.PNG
プロジェクト設定にあるManualAutoCompleteListにデータを追加します。
4.PNG
このようにCommandにコマンド名と入力候補を、Descにコマンドの横に表示される説明文を設定します。
5.PNG
設定すると上の画像の様に入力候補が表示されわざわざ文字列を入力する必要がなくなりました。
しかし、今回の様に引数が1つで候補があまり多くない場合は良いですが、候補が数十個あったり引数が複数あった場合はその分Manual Auto Complete Listに追加しなければならないデータが多くなるため、あまり現実的ではありません。

やり方(C++を使う場合)

そこで、C++の出番です!!入力候補が多くても、引数が複数個あってもC++を使えば楽勝です。

まずは、UConsoleにある入力補間のデータを登録するデリゲートに自前の関数をバインドします。
ConsoleCommandTest.h
ConsoleCommandTest.cpp

ConsoleCommandTest.h
class FConsoleCommandTest : public IModuleInterface
{
public:
    // IModuleInterface interface.
    virtual void StartupModule() override;
    virtual void ShutdownModule() override;
    virtual bool IsGameModule() const override;
    // End of IModuleInterface interface.

private:
    // Register the predictive conversion of console commands.
    void HandleRegisterConsoleAutoCompleteEntries(TArray<FAutoCompleteCommand>& AutoCompleteList) const;

private:
    // Delegate handle for registering hot-reloaded classes that have been added.
    FDelegateHandle BuildConsoleEntriesHandle;
};
ConsoleCommandTest.cpp
void FConsoleCommandTest::StartupModule()
{
    BuildConsoleEntriesHandle = UConsole::RegisterConsoleAutoCompleteEntries.AddRaw(this, &FConsoleCommandTest::HandleRegisterConsoleAutoCompleteEntries);
}

void FConsoleCommandTest::ShutdownModule()
{
    UConsole::RegisterConsoleAutoCompleteEntries.Remove(BuildConsoleEntriesHandle);
}

バインドするタイミングはどこでも良いのですが、今回はモジュールクラス内でバインドすることにします。
一応お行儀よくデリゲートハンドルを取っておいて終了時にアンバインドしています。

ここまでやるとHandleRegisterConsoleAutoCompleteEntriesがプレイを開始して最初にコンソールコマンドを入力し始めた時に呼ばれるようになります。

引数のAutoCompleteListは先程のプロジェクト設定のManualAutoCompleteListが渡されるので、そこにデータを追加していきます。
ConsoleCommandTest.cpp

ConsoleCommandTest.cpp
void FConsoleCommandTest::HandleRegisterConsoleAutoCompleteEntries(TArray<FAutoCompleteCommand>& AutoCompleteList) const
{
    auto AddAutoCompleteEntries = [&AutoCompleteList](const TArray<FString>& CommandElements) -> int32
    {
        const FString Command = FString::Join(CommandElements, TEXT(" "));
        int32 Index = 0;
        for (; Index < AutoCompleteList.Num(); Index++)
        {
            if (AutoCompleteList.IsValidIndex(Index))
            {
                if (AutoCompleteList[Index].Command == Command)
                {
                    break;
                }
            }
        }

        FColor AutoCompleteCommandColor = FColor::Green;
        if (const auto* ConsoleSettings = GetDefault<UConsoleSettings>())
        {
            AutoCompleteCommandColor = ConsoleSettings->AutoCompleteCommandColor;
        }

        const int32 NewIndex = ((Index < AutoCompleteList.Num()) ? Index : AutoCompleteList.AddDefaulted());
        AutoCompleteList[NewIndex].Command = Command;
        AutoCompleteList[NewIndex].Color = AutoCompleteCommandColor;
        return NewIndex;
    };

    // AutoCompleteTest
    {
        const FString FunctionName = GET_FUNCTION_NAME_STRING_CHECKED(UConsoleCommandTestObject, AutoCompleteTest);
        const FString Description = TEXT("A test to try predictive conversion of console commands");

        {
            const int32 NewIndex = AddAutoCompleteEntries({ FunctionName });
            AutoCompleteList[NewIndex].Desc = Description;
        }

        if (const UEnum* Enum = StaticEnum<ETestCommandArg>())
        {
            for (int32 Index = 0; Index < Enum->NumEnums() - 1; Index++)
            {
                const FString EnumString = Enum->GetDisplayNameTextByIndex(Index).ToString();
                const int32 NewIndex = AddAutoCompleteEntries({ FunctionName, EnumString });
                AutoCompleteList[NewIndex].Desc = Description;
            }
        }
    }
}

まず、AddAutoCompleteEntriesというラムダ関数を定義していますが、こちらはManualAutoCompleteListに既にデータがある場合はそのデータの、ない場合は新しく追加したデータのインデックスを返します。
返ってきたインデックスのFAutoCompleteCommandDescに説明文を設定しています。

C++を使うと入力候補の文字の色を変えられますが、今回は全てエンジンと同じ色にするため、プロジェクト設定の値を使用しています。
こちらの色はプロジェクト設定のAutoCompleteCommandColorから変更できます。
6.PNG

ConsoleCommandTest.Build.cs

ConsoleCommandTest.Build.cs
PrivateDependencyModuleNames.AddRange(new string[]
{
    "EngineSettings",
});

最後に、UConsoleSettingsを使用するために、EngineSettingsモジュールを使うのでbuild.csで追加しておきます。
ここまでやるとプロジェクト設定でデータを追加した時と同様に入力候補が表示されるようになります。

おわりに

少し手間がかかることではありますが、一度作っておくとその後の開発効率を上げられるので積極的に取り入れていきたいところです。
コンソールコマンドで文字列を何度も打つことに疲れた方の役に立てれば嬉しいです。

この記事で紹介したプロジェクトは以下でダウンロードできます。
https://github.com/Naotsun19B/ConsoleCommandTest

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0