UnityでgRPCを動かす #2 Unity

ゴール：Unity(iOS/Android)でgRPCを動かす

* [UnityでgRPCを動かす #1 コンソールアプリ](https://qiita.com/nakaken0629/items/faf355db576542c2712c)
* UnityでgRPCを動かす #2 Unity
* [UnityでgRPCを動かす #3 iOS](https://qiita.com/nakaken0629/items/0e2d6cdb7eb5283a7d34)
* [UnityでgRPCを動かす #4 Android](https://qiita.com/nakaken0629/items/bd86a62e762f7fd073ae)

~~開発環境：macOS Sierra + Unity 2017.3.0f3~~
開発環境：macOS Mojave + Unity 2019.1.5f1

今回はその２です。

# （前準備）UnityとVisual Studioの連携

その１でVisual Studio for Macをインストールしていると思いますので、Unityと連携しておいてください。"Unity + Visual Studio for Mac"で検索すると、色々出てくると思います。以下、簡単に手順を記載しておきます。

1. メニューから"Unity"を選択して、Unity Preferenceダイアログを開く
2. ダイアログから"External Tools"を選択する
3. "External Script Editor"から"Visual Studio"を選択する

# プロジェクトの.NET Frameworkのバージョンを4.xにする

メニューから"File - Build Settings"を選択する。"Player Settings ..."ボタンをクリックして、Inspectorを表示する。"Configuration - Scripting Runtime Version*"から".NET 4.x Equivalent"を選択する。Unity再起動の確認が出た時には、はいと答えてUnityを再起動する。

# UnityでgRPCのサンプルを動かす

Unity用のサンプルプロジェクトが用意されています。

/grpc/examples/csharp/HelloworldUnity

さらにこのディレクトリの中にあるREADME.mdに動かし方が書いてあります。基本はこのドキュメントに書かれている通りにすれば動作します。

```:readme.md
- Follow instructions in https://github.com/grpc/grpc/tree/master/src/csharp/experimental#unity to obtain the grpc_csharp_unity.zip
  that contains gRPC C# for Unity. Unzip it under `Assets/Plugins` directory.  
- Open the `HelloworldUnity.sln` in Unity Editor.  
- Build using Unity Editor.
```

`HelloworldUnity.sln`をUnityエディターで開くには、Unity Hubで`HelloworldUnity`ディレクトリをリストに追加してください。

<img width="1072" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/75307/99531056-6255-b3c7-68c8-28e611b63a56.png">

## 実行する

Unityで実行すると、画面上に緑色のボタンが表示されます。ボタンを押すたびに通信が発生してボタン上の文字列が更新されます。

<img width="1141" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/75307/9bd880df-ca11-534d-df44-4d685e4998e2.png">

ボタンが表示されない場合は、シーンが選ばれていない可能性があります。`Assets/Scenes/SampleScene`をダブルクリックして、Hierarchy上のルートがSampleSceneになっていることを確認してください。

## プログラムの解説

このサンプルプロジェクトでは、Unityプロジェクトの中にサーバーとクライアントが両方用意されています。

```cs:HelloWorldTest.cs
(略)
class HelloWorldTest
{
(略)
  public static HelloReply Greet(string greeting)
  {
    // サーバーを起動する処理、ここから
    const int Port = 50051;

    Server server = new Server
    {
      Services = { Greeter.BindService(new GreeterImpl()) },
      Ports = { new ServerPort("localhost", Port, ServerCredentials.Insecure) }
    };
    server.Start();
    // サーバーを起動する処理、ここまで

    Channel channel = new Channel("127.0.0.1:50051", ChannelCredentials.Insecure);

    var client = new Greeter.GreeterClient(channel);

    var reply = client.SayHello(new HelloRequest { Name = greeting });

    channel.ShutdownAsync().Wait();

    // 起動したサーバーをシャットダウンする処理、ここから
    server.ShutdownAsync().Wait();
    // 起動したサーバーをシャットダウンする処理、ここまで

    return reply;
  }

  // サーバーサイドの処理、ここから
  class GreeterImpl : Greeter.GreeterBase
  {
    // Server side handler of the SayHello RPC
    public override Task<HelloReply> SayHello(HelloRequest request, ServerCallContext context)
    {
      return Task.FromResult(new HelloReply { Message = "Hello " + request.Name });
    }
  }
  // サーバーサイドの処理、ここまで
}
```

# 別プロセスのサーバーを呼び出すように修正する

まずは、オリジナルのソースから、サーバーサイドの処理を削除します。上記のソースコードの「ここから〜ここまで」のコメント内のコードをすべて削除します。

```cs:HelloWorldTest.cs(サーバーサイド処理を削除したもの)
(略)
class HelloWorldTest
{
(略)
  public static HelloReply Greet(string greeting)
  {
    Channel channel = new Channel("127.0.0.1:50051", ChannelCredentials.Insecure);

    var client = new Greeter.GreeterClient(channel);

    var reply = client.SayHello(new HelloRequest { Name = greeting });

    channel.ShutdownAsync().Wait();

    return reply;
  }
}
```

次に[UnityでgRPCを動かす #1 コンソールアプリ](https://qiita.com/nakaken0629/items/faf355db576542c2712c)で説明したGreeting Serverを起動します。Visual Studioは複数のソリューションを開けないので、HelloworldUnityソリューションは閉じられてしまいますが、大丈夫です。

サーバーの処理が使われていることを確認するために、GreeterImpl.SayHelloメソッドを少し書き換えておきましょう。

```cs:GreeterImpl.cs(SayHelloメソッドのみ)
// "Hello "から"Hello Server "に文字列を修正
return Task.FromResult(new HelloReply { Message = "Hello Server " + request.Name });
```

もう一度Unityを起動します。ボタンの文字列が今編集した内容で更新されることを確認します。

<img width="1141" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/75307/a7949386-43a9-59a4-759e-203f29b1199c.png">


# 次回予告

次は、iOSで動かしてみます。