UE4のネットワークハンズオン (Replicate、RPC)

## 記事の目的
最近、UE4のネットワーク機能を触っているのですが、仕組みをざっくり理解して
まずは手を動かしてみようといったところで、記事をまとめます。

## 前提
#### 対象
初心者向けですがBPをある程度自分で組んだことのある方向けになります。
C++は本記事では利用せず、全てをBP想定で記載しています。

#### UE4の利用バージョン
4.26.2

## 目次
・マルチプレイを動かしてみよう
・Dedicated ServerとListen Server
・アニメーションを同期させる Part1
・Replicate
・RPC
・アニメーションを同期させる Part2

## マルチプレイを動かしてみよう
UE4はパッとマルチプレイで動かすことが出来るので
まずは、マルチプレイが出来る状態で動かしてみましょう。

「ThirdPerson」のテンプレートを利用して新規プロジェクトを作成します。
https://docs.unrealengine.com/ja/Resources/Templates/index.html

その後、Playの▼のところから、以下のように数値を設定して、実行してみてください。
![0.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12340/cf8184fd-2dad-b995-bd49-0c4007633a61.png)

どうでしょう？実行すると2つの画面が開くと思います。

片方の画面のキャラクターを操作すると、キャラクターが動き、別画面でもキャラクターが動くと思います。
画面ごとにプレイヤーが生成されているということですね。
（なぜか3体いると思いますが、これはデフォルトで置かれている「ThirdPersonCharacter」アクタです）

もちろんこれで終わりではなく、実際に開発を進めていくにあたって
UE4でのネットワークのクセ、仕様を把握していないといけない場面が多々あります。
その触りだけになりますが、早速見ていきましょう。
## Dedicated ServerとListen Server
まず、UE4のマルチプレイには、2つの通信方式があります。

Dedicated Server
独立(Dedicated)されたサーバーがいて、サーバーの動作にクライアントは不要です。
クライアントは個別に動作します。

Listen-Server
特定のクライアントがサーバーを兼ねることになります。

Listen-Serverは触ったことがないので
今回は、Dedicated Serverの利用を想定として、記事を書いています。

## アニメーションを同期させる Part1
先程使った「ThirdPerson」のプロジェクトをそのまま利用して、アニメーションを同期させてみます。

まず、特定のキーを押したら、プレイヤーにアニメーションをさせるようにしてみます。

詳細手順は、本筋ではないのでさっくりとなるので、わからなければ、プロジェクトのサンプルを以下に置いておきますので、見てみてください。
https://github.com/CreaterShiba/NetworkSample1

・「ThirdPersonCharacter」のBPにBoolの変数を追加します。
・特定のキーボードの入力でそのフラグのON/OFFを切り替えるようにします。
サンプルでは、「C」のPressedとReleasedで切り替えています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12340/1e4e0775-6a52-2486-45b3-9f227b0645bc.png)

・「ThirdPerson_AnimBP」のBPで、特定のモーションをフラグに応じて再生させるようにします。
「ThirdPerson_AnimBP」のBPにBoolの変数を追加
EventGraphで「ThirdPersonCharacter」のフラグを取得するように
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12340/ad941b6f-8c6d-6e39-fb30-e402da482650.png)
AnimGraphで、フラグに応じてアニメーションを再生させる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12340/a49f706c-2d4c-a83a-7c03-f12e3dc33f96.png)
上記手順を行うことで、自分のキャラクターに、アニメーションをさせる事ができると思います。

ここで、最初の「マルチプレイを動かしてみよう」手順を元に動かして、アニメーションをさせてみます。
どうでしょうか？

残念ながら、上記手順では、アニメーションが再生されたとしても
片方のクライアントでは、そのアニメーションの状態は反映されていないと思います。

ここで起きていることとしては、上記で追加した、アニメーションフラグが関連しています。

アニメーション命令を出し、クライアントの内部のフラグが変わると、そのクライアントでアニメーションは再生されますが
もう一つのクライアントではそのフラグが有効になっていないため、アニメーションが行われずに、画面上に反映されていないわけです。

つまり、クライアント側が持つフラグを変えるだけではだめなわけです。
各画面で同じ動作をさせるため、各クライアントではなく、サーバーが持つフラグを変更して
そのサーバーが持つフラグを利用して、各クライアントが挙動を変更する、といった状態にする必要があります。

この対応を行うためには
「Replicate」
「サーバーへの命令(RPC)」
という仕組みを利用する必要があります。

## Replicate
Replicateとは、日本語で「複製」です。
つまり、サーバーからクライアントへデータを「複製」します。

このReplicateの設定は、変数や、特定のActor、Componentに対して有効とすることができます。
この設定が有効になっていると、サーバーからクライアントへの複製(Replicate)が行われます。
ActorクラスがReplicateの起点で、Actorクラスを継承しているクラスは、Replicateの機能を備えています。

https://docs.unrealengine.com/ja/InteractiveExperiences/Networking/Actors/index.html

https://docs.unrealengine.com/ja/InteractiveExperiences/Networking/Actors/ReplicatingVariables/index.html

## RPC
「Remote Procedure Calls」略してRPCです。

クライアント⇔サーバーをまたぐ命令として利用できます。
BPでの実装方法から。もちろんC++で実装することも出来ます。

・Add Custom CustomEventでカスタムイベントを追加
このカスタムイベントを呼び出すことで、RPCを呼び出すことができます。

・カスタムイベントのDetailsウィンドウのReplicatesの項目を変更する。
パラメータとしては3種類あります。
Run on Server...サーバーで実行
Run on owning Client...アクターの所有者上で実行。
Net Multicast...サーバー＆クライアントすべてで実行。

さて、このRPCの上記3つのイベントですが
「所有権」というものがあり
アクターはサーバーかクライアントでの所有権に応じて、機能に制限がかかり、呼び出したとしても意味がないことがあります。
こちらは、参考になる色々と記事があるので、以下のサイト様など参考にしてください。

https://historia.co.jp/archives/12823/


## アニメーションを同期させる Part2
さて、上記の概念がなんとなくでも良いので
理解できたら、上手くアニメーションが同期出来るように、手を動かしてみましょう。

以下は全て「ThirdPersonCharacter」BP上で作業を行います。
・アニメーションフラグのReplicationをReplicateにする。
BPに追加したアニメーションフラグのDetailsを開き、「Replication」の項目を「Replicated」とします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12340/15371fbd-4107-5e5b-5051-f1608543f924.png)
これで変数がReplicateの対象になりました。

・RPCを用意して、フラグを変更させる。
ここで前述のRPCを作成します
BP上で右クリックを押下して、「Add Custom Event」を行い
追加したカスタムイベントからフラグを変更する処理を作成します。
On/Off両方作っておきましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12340/55219634-d259-37c7-196b-60de199ec26f.png)

RPCの「Replicates」はRun on Serverとしておきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12340/5d955d25-3775-b5c2-bd75-a28e3a1c67aa.png)

・カスタムイベントをキー入力から呼び出すようにします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12340/b578d074-0539-c89f-c0ac-4a0426cc61a5.png)

さて、どうでしょうか？
実行して見ると、キャラクターのアニメーションが自分以外の画面でも反映される様になっていると思います。

挙動としては
・RPCがサーバー上で実行
・サーバーのアニメーションフラグが変更され、それがReplicateされてクライアントへフラグ変更が伝わる
・クライアントのフラグが変わり、挙動も変更される
わけです。

プロジェクトサンプルをこちらに置いておきます。
https://github.com/CreaterShiba/NetworkSample2

----

以上、ネットワークのとっかかりとしてまとめてみました

UE4のネットワークの資料は色々あるのですが
考え方に慣れないと、読んだだけではいまいちわからないと思うので
手を動かしながら覚えていくと良いのかなと思います。

## 参考
英語になりますが、Ue4のNetworkに関することが分かりやすくまとめられています
http://cedric-neukirchen.net/Downloads/Compendium/UE4_Network_Compendium_by_Cedric_eXi_Neukirchen.pdf

UE4の「ネットワーク機能の機能別サンプル」もネットワークの挙動が動いている状態で色々と確認できるので、おすすめです。
https://docs.unrealengine.com/ja/Resources/ContentExamples/Networking/index.html