【UE4】Web Remote Controlを試してみる【★★】

※この記事で使用しているUnrealのVersionは04.23.0です。

※今回はプロジェクトのテンプレート「Third Person」を使用しています。

※この記事のサンプルプロジェクトは以下URLにアップされています。
サンプルプロジェクト

今回は4.23でベータ版を使えるようになった「Remote Control API」プラグインを使ってみたいと思います。

Webリモートコントロールで書かれている内容をみてやっただけな感じです。。

HTTP経由でUnrealEditorとのやり取りをする レベル【★★】

※今回の説明はローカルPCでのやり方の説明です。
ローカル エリアネットワーク(LAN)内や仮想プライベートネットワーク(VPN)などのネットワークを使った説明は、その辺の知識がもう少しついたら紹介するかもしれません。。

まずは下準備をします。

ThirdPersonTemplateのプロジェクトを作ったら、プラグインを有効にします。

エディター左上の「Edit」→「Plugins」でPlugin設定ウィンドウを開き、「Remote Control API」にチェックを入れます。

出来ましたらエディターを一度再起動します。

その後エディターの再起動が完了しましたら、エディター左上にある「Window」→「DeveloperTools」→「OutputLog」を選択して、OutputLogウィンドウを出します。

そして「OutputLog」下にある「Cmd」部分に「WebControl.StartServer」と入力してエンターキーを押します。

OutputLogウィンドウに
LogHttpServerModule: Starting all listeners…
LogHttpListener: Created new HttpListener on port 8080
LogHttpServerModule: All listeners started
と報じされましたらOKです。

次に、HTTP経由で情報を送信するためのソフトをダウンロードします。

公式ではInsomniaPostmanを紹介していましたが、今回はInsomniaの方を使ってみました。

ダウンロードして開くと以下のような画面が出てくるかと思います。

これで準備は完了です。

では早速RemoteControllAPIを使って情報をやり取りしてみたいと思います。最初に「プロパティの操作」をやってみたいと思います。

操作できるプロパティは、C++定義で「UPROPERTY」がつけられているものに限られ、その中でも「EditEnywhere」(非プレイイン時)や 「BlueprintVisible 」(プレイイン時)を与えられていないと書き込みはできません。
→ネイティブを見ずに簡単に見極めるには、そのプロパティがエディター上やプループリント上で読んだり書いたりできるかどうかを確認してみてください。

編集可能なものは基本的にRemote Controlでも編集が可能です。

基本的に送信する命令は「JSON (JavaScript Object Notation) 」というフォーマットを使って書きます。

プロパティを操作する場合は以下の4つの項目を記述します。

ObjecPath:

/Path/PackageName.ObjectName(:SubObjectName.SubObject)で指定します。Pathは/Gameから始まるアセットのパス。 PackageNameはアセットの名前。ObjectNameはインスタンス化されているアセットの名前(大抵PackageNameと同じです)
例:
“objectPath” : “/Game/ThirdPersonBP/Maps/M_Test.M_Test”

※コンテンツブラウザでアセットをクリックした状態でCtrl+Cを押し、それをテキストでペーストしたものから、先頭のクラス名表記をなくしたものになります。

↓コピーしたテキスト
Material’/Game/ThirdPersonBP/Maps/M_Test.M_Test’

※レベル内のアクターなどにアクセスする場合は後程やり方を書きます。

②Access:

アクセスのタイプです(ENUM)以下の4種類が記述できます。
「NO_ACCESS」→これは使わない。
「READ_ACCESS」→プロパティの値を読むためのもの。
「WRITE_ACCESS」→プロパティの値を書き込むためのもの。
「WRITE_TRANSACTION_ACCESS」→プロパティの値を書き込むためのもの。UndoHistoryに乗るのでCtrl+Zなどで行った編集を取り消すことができる。
例:

"access":"READ_ACCESS"

③PropertyName:

対象のプロパティの名前です。
例:
Materialの「BlendMode」を読み取る場合。

"propertyName":"BlendMode"

④PropertyValue:

「 WRITE_ACCESS」と「WRITE_TRANSACTION_ACCESS 」専用。
プロパティを更新する際の値を記述します。
例:

"PropertyValue" : {
"BlendMode" : "BLEND_MASKED"
}

上記を踏まえてInsomniaを使って簡単にテストしてみます。

/Game/ThirdPersonBP/Maps/ 以下に、「M_Test」というマテリアルを作ります。
(特に設定をいじる必要はありません)

では、作成した「M_Test」マテリアルアセットの「BlendMode」を読み取ってみます。
Insomnia側のウィンドウを開きましょう。

左側にある+ボタンから「New Request」を選択します。

作成時に右側にある「GET」となっているMethodを「PUT」にしてください。

さらに、PUTにすると新たなプルダウンが出てくるので、その中から「JSON」を選択しましょう。

出来ましたら、「Create」ボタンを押します。

すると、以下のような画面になります。

この上にあるURLを入力する場所に、「http://localhost:8080/remote/object/property」と入力します。
また、その下のJSONを記述する場所には以下を記述します。

{
    "ObjectPath" : "/Game/ThirdPersonBP/Maps/M_Test.M_Test",
    "Access":"READ_ACCESS",
    "PropertyName":"BlendMode"
}

これを「Send」ボタンでUnreal側に送信すると、Insomnia内の右側のPreviewウィンドウ内に結果が見れます。

また、Unreal側では「OutputLog」に通信ログが表示されます。

正しく通信されれば
LogHttpConnection: BeginProcessRequest [8080][14]-1 : /remote/object/property
LogHttpConnection: EndProcessRequest [8080][14]-1 : 200

という記述が出るかと思います。

うまくいかない場合は、「EndProcessRequest」の番号とエラーログを見てみましょう。

ここの数字が「404」になっている場合は、HTTPメソッドが「PUT」になっているかを確認してみましょう。
Insomnia 側のエラーログとして
“ErrorCode”: “errors.com.epicgames.httpserver.route_handler_not_found”
と出てしまいます。

問題ない場合はObjectPathなどがまちがっていないか確認しましょう。

OutputLogで「400」と数字が出た場合は、送信するURLの指定を確かめてみましょう。

行いたい動作にあった指定になっていないかもしれません。

それでもエラーが起こる場合は一度該当アセットを開いてから閉じると実行されたりします(1回開かないとアセットがないって怒られることがあります)

ちなみに書き込む場合の例:

JSON記述

{
"objectPath" : "/Game/ThirdPersonBP/Maps/M_Test.M_Test",
"access":"WRITE_ACCESS",
"PropertyName" :"BlendMode",
"PropertyValue" : {
    "BlendMode" : "BLEND_MASKED"
    }
}

明示的な内容の結果はログには出ませんが、編集されたアセットがDirty(編集状態)のマークがついていると思います。

↓「BlendMode」が「Masked」になっている。

次に関数の呼び出しを行ってみます。

プロパティの操作と同じで、こちらも呼び出せるのはUFUNCTIONの「BlueprintCallable」がついているものか、プループリント側で定義された関数に限ります。

①ObjectPath

プロパティと同じ。

②FunctionName

呼び出したい関数の名前。
例:

"functionName" : "PrintLog"

③Parameters

関数に渡す引数。
例:

"parameters" : {
"Text" : "Sucsess!"
}

では、こちらもテストをしてみましょう。

まずは/Game/ThirdPersonBP/Maps/以下に「Actor」クラスを継承したBluePrintを作成します。

中を開き、「MyBluePrint」ウィンドウの「Function」にある+ボタンを押して新しい関数を作ります。

関数の名前・中身を以下のような感じに書きます。

出来ましたら、ウィンドウを閉じてアクターをレベル上配置しましょう。

公式のチュートリアルではさらっとレベル内のアクターを参照してやっていますが、名前の指定方法が若干ややこしいです。

アクターを配置した際に「WorldOutliner」上を見てみます。

この名前をそのまま指定して実行すると、エラーになってしまいます。
「WorldOutliner」上の名前は「DisplayName」といって、エディター内での管理用の名前です。
これはこのオブジェクトの名前ではありません。

オブジェクトの名前を取得するには、「WorldOutliner」上でそのオブジェクトにカーソルを合わせてみてください。

「ID Name:BP_Test_2」というのが出てきました。
これがこのオブジェクトの名前になります。ややこしいですね。
※DisplayNameは重複可能ですが、ObjectNameは重複しない管理IDのようなものです。

指定をする際は「BP_Test_2 」を指定します。

では実際にやってみます。

JSON記述↓

{
"objectPath" : "/Game/ThirdPersonBP/Maps/ThirdPersonExampleMap.ThirdPersonExampleMap:PersistentLevel.BP_Test_2",
"functionName" : "PrintLog",
"parameters" : {
    "Text" : "Sucsess!"
    }
}

実行結果

しっかり呼び出すことができました。

以上

※この記事のサンプルプロジェクトは以下URLにアップされています。
サンプルプロジェクト