UnityとMagicOnionの環境構築(IL2CPP)
はじめに
Unityを始めたばっかり! や、サーバー分らん! という方でも、
順番にやっていけば、動作を確認できるように記載しています
スクロールが小さくて長いように見えますが、説明画像がほとんどなのでご安心を!!
MagicOnionのREADMEをベースに、ローカル動作確認の環境構築をしていきます!!
今回のゴールは、
Unityのクライアントから、サーバー側の関数の結果を受け取れるところまで!!
サーバーへ数値を2つ渡し、足した結果をクライアントに戻してもらうシンプルなものです!
MagicOnionのREADMEは英語なので、日本語の備忘録的に・・・(ToT)
英語できる人すごいですよね~(>ω<)
環境
- Windows 10
 - VisualStudio 2019
 - Unity 2020.3.13f1
 - MagicOnion 4.3.1
 - MessagePack-CSharp 2.1.194
 - gRPC 2.40.0
 
前提条件
下記がインストール済みである事
- VisualStudio 2019
 - Unity 2020.3.13f1
 
手順
- 作業用フォルダの作成
 - Unityのクライアントプロジェクト作成・設定
 - サーバー関数の呼び出し実装
 - gRPC用のサーバープロジェクト作成・設定
 - 通信用インターフェース共有プロジェクトの作成
 - サーバー側の関数の実装
 - 動作確認
 
■作業用フォルダの作成
クライアントとサーバーのプロジェクトを、格納するフォルダを任意の場所に作成
クライアントとサーバーで、通信用インターフェースを相対パスで共有するので、
プロジェクトは作成したフォルダ配下に格納していきます
最終的な構成は、こんな感じ
例:D:/work/KumattaApp
KumattaApp ← このルートフォルダを任意の場所に作成
  ├─ KumattaApp-Client
  ├─ KumattaApp-Server
  └─ KumattaApp-Shared
■Unityのクライアントプロジェクト作成・設定
プロジェクトの作成

プロジェクトの設定
「Edit -> Project Settings...」を押下

「Player -> Other Settings -> Configuration」の設定を変更
| 項目 | 設定値 | 
|---|---|
| Scripting Backend | IL2CPP | 
| App Compatibility Level* | .Net 4.x | 


MessagePackをインポート
MessagePackのunitypackageをダウンロードし、作成したプロジェクトへインポート
MessagePack 2.2.85


MessagePackのコード補完用の拡張をインストール
MessagePackのunitypackageをダウンロードし、ダブルクリックでインストール




gRPCを配置
gRPCのUnity向けzipをダウンロードし、解凍した「Plugins」の配下にある、
下記のフォルダを、Unityプロジェクトの「Plugins」配下にコピー
gRPC 2.40.0
- Google.Protobuf
 - Grpc.Core
 - Grpc.Core.Api
 


MagicOnionをインポート
MagicOnionのunitypackageをダウンロードし、作成したプロジェクトへインポート
MagicOnion 4.3.1


クライアントスクリプト用のフォルダを作成
少し階層が多いですが、スクリプトの区別の為に分けています
| パス(KumattaApp/Scriptsの配下) | 用途 | 
|---|---|
| MagicOnion/Client/Generated | 後述のサーバービルドで、生成されるスクリプトを格納 | 
| MagicOnion/Server/Services/Interface | サーバー通信用インターフェースを格納 | 
| MyApp | 動作確認用のスクリプトを格納 | 

KumattaApp
  └─Scripts
      ├─MagicOnion
      │  ├─Client
      │  │  └─Generated
      │  └─Server
      │      └─Services
      │          └─Interface
      └─MyApp
サーバー通信用のインターフェース作成
- サーバー通信用インターフェースのフォルダを選択
 - 右クリックして、「Create -> C# Script」を押下し、「IMyFirstService」を作成
 

using MagicOnion;
namespace MyApp.Shared
{
    public interface IMyFirstService : IService<IMyFirstService>
    {
        // The return type must be `UnaryResult<T>`.
        UnaryResult<int> SumAsync(int x, int y);
    }
}
■サーバー関数の呼び出し実装
クライアント処理を作成
前述と同様の手順で、下記のフォルダにサーバー処理呼出しのスクリプトを作成
using UnityEngine;
using Grpc.Core;
using MagicOnion.Client;
using MyApp.Shared;
public class KumattaAppCall : MonoBehaviour
{
    void Start()
    {
        CallTest();
    }
    public async void CallTest() 
    {
        string host = "localhost";
        int port = 5001;
        // http用に変更
        var channel = new Channel(host, port, ChannelCredentials.Insecure);
        var client = MagicOnionClient.Create<IMyFirstService>(channel);
        var result = await client.SumAsync(100, 23);
        Debug.Log($"Result: {result}");
    }
}
スクリプトを動作させる為に、GameObjectへアタッチ
「Hierarchy」で右クリックして、「Create Empty」を押下

- 作成した「GameObject」を選択
 - 「Inspector -> Add Component」押下
 - 上記で作成したスクリプト「KumattaAppCall」を検索して押下
 - アタッチを確認出来たら「Ctrl + s」で、シーンの変更を保存
 


■gRPC用のサーバープロジェクト作成・設定
プロジェクトの作成
VisualStudio 2019を起動して、「新しいプロジェクトの作成(N)」を押下

検索条件に下記を設定して、検索結果に表示される
「ASP.NET Core gRPC サービス」を選択し、「次へ」を押下
| 項目 | 値 | 
|---|---|
| テンプレートの検索 | gRPC | 
| 言語 | C# | 
| プラットフォーム | すべてのプラットフォーム | 
| プロジェクトの種類 | コンソール | 

プロジェクト名と、前述で作成した作業用フォルダを指定して、「次へ」を押下

ターゲットフレームワークに「.Net Core 3.1 (長期的なサポート)」を選択し、「次へ」を押下

MagicOnion.Serverの追加
- 作成したサーバープロジェクトを選択
 - 右クリックして「NuGetパッケージ管理」を押下
 

NuGet画面の「参照」を押下

- 検索に「MagicOnion.Server」を入力
 - 検索結果の「MagicOnion.Server」を選択
 - バージョンは「4.3.1」選択
 - 「インストール」を押下
 
「OK」を押下

プロジェクトの不要ファイルを削除
MagicOnionでは、「Protos」、「Services」は利用しない為、フォルダを削除

「Startup.cs」を変更
MagicOnionをロードする為に、スクリプトを変更

using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
namespace KumattaApp_Server
{
    public class Startup
    {
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddGrpc();
            services.AddMagicOnion();  // ← MagicOnionを追加
        }
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            app.UseRouting();
            app.UseEndpoints(endpoints =>
            {
                endpoints.MapMagicOnionService();  // ← MagicOnionにアクセスする為、変更
                endpoints.MapGet("/", async context =>
                {
                    await context.Response.WriteAsync("Communication with gRPC endpoints must be made through a gRPC client. To learn how to create a client, visit: https://go.microsoft.com/fwlink/?linkid=2086909");
                });
            });
        }
    }
}
通信を「http」に変更
「applicationUrl」が「https」になっているので、「http」に変更

{
  "profiles": {
    "KumattaApp-Server": {
      "commandName": "Project",
      "launchBrowser": false,
      "applicationUrl": "http://localhost:5001",
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development"
      }
    }
  }
}
■通信用インターフェース共有プロジェクトの作成
共有プロジェクトの作成
ソリューションを右クリックして、「追加 -> 新しいプロジェクト」を押下

検索条件に下記を設定して、検索結果に表示される
「クラス ライブラリ」を選択し、「次へ」を押下
| 項目 | 値 | 
|---|---|
| テンプレートの検索 | クラス | 
| 言語 | C# | 
| プラットフォーム | すべてのプラットフォーム | 
| プロジェクトの種類 | すべてのプロジェクトの種類 | 

プロジェクト名と、前述で作成した作業用フォルダを指定して、「次へ」を押下

ターゲットフレームワークに「.Net Standard 2.1」を選択し、「次へ」を押下

自動で作成される「Class1.cs」は、不要なので削除

NuGetからパッケージの追加
前述の「MagicOnion.Serverの追加」の手順と同様に、下記のパッケージを追加
| パッケージ名 | バージョン | 
|---|---|
| MagicOnion.Shared | 4.3.1 | 
| MagicOnion.MSBuild.Tasks | 4.3.1 | 
| MessagePack.UnityShims | 2.1.194 | 
| MessagePack.MSBuild.Tasks | 2.1.194 | 
- 作成した共有プロジェクトを選択
 - 右クリックして「NuGetパッケージ管理」を押下
 
NuGet画面の「参照」を押下

- 検索に「パッケージ名」を入力
 - 検索結果の「パッケージ名」を選択
 - 「指定バージョン」選択
 - 「インストール」を押下
 
「OK」を押下

Unityクライアントのサーバー通信用インターフェースの参照追加
- 共有プロジェクトを選択
 - 右クリックして「プロジェクトファイルの編集」を押下
 

下記の3つの要素を追加
★1つ目は、サーバー通信用のインターフェース
前述の「クライアントスクリプト用のフォルダを作成」で作成したフォルダを設定
KumattaApp
  └─Scripts
      ├─MagicOnion
      │  ├─Client
      │  │  └─Generated
      │  └─Server  ← このフォルダの相対パスを設定!!!
      │      └─Services
      │          └─Interface
      └─MyApp
<ItemGroup>
  <Compile Include="..\Unityプロジェクト名から「Server」までのパス\**\*.cs" Link="Server/%(RecursiveDir)/%(FileName)%(Extension)" />
</ItemGroup>
★次は、IL2CPP用のスクリプト自動生成を2つ追加
KumattaApp
  └─Scripts
      ├─MagicOnion
      │  ├─Client
      │  │  └─Generated  ← このフォルダに出力する用に設定!!!
      │  └─Server
      │      └─Services
      │          └─Interface
      └─MyApp
<Target Name="GenerateMessagePack" AfterTargets="Compile">
  <MessagePackGenerator Input="$(ProjectPath)" Output="..\Unityプロジェクト名から「Generated」までのパス\MessagePack.Generated.cs" />
</Target>
<Target Name="GenerateMagicOnion" AfterTargets="Compile">
  <MagicOnionGenerator Input="$(ProjectPath)" Output="..\Unityプロジェクト名から「Generated」までのパス\MagicOnion.Generated.cs" />
</Target>
修正後
<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>netstandard2.1</TargetFramework>
    <RootNamespace>KumattaApp_Shared</RootNamespace>
  </PropertyGroup>
  <ItemGroup>
    <PackageReference Include="MagicOnion.MSBuild.Tasks" Version="4.3.1" />
    <PackageReference Include="MagicOnion.Shared" Version="4.3.1" />
    <PackageReference Include="MessagePack.MSBuild.Tasks" Version="2.2.85">
      <PrivateAssets>all</PrivateAssets>
      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
    </PackageReference>
    <PackageReference Include="MessagePack.UnityShims" Version="2.2.85" />
  </ItemGroup>
  <!-- =========================== 以下を追加 =========================== -->
  <ItemGroup>
    <Compile Include="..\KumattaApp-Client\Assets\KumattaApp\Scripts\MagicOnion\Server\**\*.cs" Link="Server/%(RecursiveDir)/%(FileName)%(Extension)" />
  </ItemGroup>
  <Target Name="GenerateMessagePack" AfterTargets="Compile">
    <MessagePackGenerator input="$(ProjectPath)" output="..\KumattaApp-Client\Assets\KumattaApp\Scripts\MagicOnion\Client\Generated\MessagePack.Generated.cs" />
  </Target>
  <Target Name="GenerateMagicOnion" AfterTargets="Compile">
    <MagicOnionGenerator Input="$(ProjectPath)" Output="..\KumattaApp-Client\Assets\KumattaApp\Scripts\MagicOnion\Client\Generated\MagicOnion.Generated.cs" />
  </Target>
  <!-- ================================================================== -->
</Project>
■サーバー側の関数の実装
サーバープロジェクトに、共有プロジェクトの参照を追加
- サーバープロジェクトを選択
 - 右クリックして「追加 -> プロジェクト参照」を押下
 
共有プロジェクトにチェックをつけて、「OK」を押下

サーバー側の関数を作成
- サーバープロジェクトを選択
 - 右クリックして「追加 -> 新しいフォルダ」を押下
 - 「Services」のフォルダを作成
 


- 作成した「Services」を選択
 - 右クリックして「追加 -> クラス」を押下
 
- 「クラス」を選択
 - 名前に「MyFirstService.cs」を入力
 - 「追加」を押下
 
using MagicOnion;
using MagicOnion.Server;
using MyApp.Shared;
using System;
namespace KumattaAppServer.Services
{
    public class MyFirstService : ServiceBase<IMyFirstService>, IMyFirstService
    {
        public async UnaryResult<int> SumAsync(int x, int y)
        {
            Console.WriteLine($"Received:{x}, {y}");
            return x + y;
        }
    }
}
Unityクライアントプロジェクトに、自動生成されるスクリプトを適用
メニューの「ビルド -> ソリューションのビルド」を押下して、ソリューションをビルド

出力画面でビルドが成功している事を確認

Unityクライアントプロジェクトに、スクリプトが生成されている事を確認
出力先は前述の「クライアントスクリプト用のフォルダを作成」で作成したフォルダ
KumattaApp
  └─Scripts
      ├─MagicOnion
      │  ├─Client
      │  │  └─Generated ← このフォルダに生成されている!!!
      │  └─Server
      │      └─Services
      │          └─Interface
      └─MyApp

生成されたスクリプトをロードするスクリプトを作成
- 上記のフォルダで、右クリックして「Create -> C# Script」を押下
 - 「MagicOnionLoad」を作成
 


using MessagePack;
using MessagePack.Resolvers;
using UnityEngine;
public class MagicOnionLoad 
{
    [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
    static void RegisterResolvers()
    {
        StaticCompositeResolver.Instance.Register(
            MagicOnion.Resolvers.MagicOnionResolver.Instance,
            MessagePack.Resolvers.GeneratedResolver.Instance,
            StandardResolver.Instance
        );
        MessagePackSerializer.DefaultOptions = MessagePackSerializer.DefaultOptions
            .WithResolver(StaticCompositeResolver.Instance);
    }
}
■動作確認
サーバーの起動
メニューの「KumattaApp-Serrver」を押下

コマンドプロンプトが起動し、URLが前述の「通信を「http」に変更」で設定した
「applicationUrl」の値になっている事を確認

Unityクライアントの実行
Unityのメニューの再生ボタンを押下

Unityの「Console」に計算結果が、表示されていれば成功!!!

サーバーのコマンドプロンプト側

クライアント、サーバーの停止
Unityクライアントは、メニューの再生ボタン押下で停止

サーバーの停止は、コマンドプロンプトを選択している状態で、「Ctrl+C」を押下

お疲れさまでした!!!
以上で、動作確認の環境構築は完了です!!!!!!
あとがき
ここまで読んでいただきありがとうございます!!!
参考になりましたか?
次回は、この環境を元に、Android、iOSの動作確認をしようと思います!!
記事を書くモチベーションにしたいので、よろしければサポートをお願いします!!
Discussion