$30 off During Our Annual Pro Sale. View Details »

Unityによるリアルタイム通信とMagicOnionによるC#大統一理論の実現

Yoshifumi Kawai
January 25, 2020
140

 Unityによるリアルタイム通信とMagicOnionによるC#大統一理論の実現

Yoshifumi Kawai

January 25, 2020
Tweet

More Decks by Yoshifumi Kawai

Transcript

  1. View Slide

  2. 河合 宜文 / Kawai Yoshifumi / @neuecc
    Cysharp, Inc.
    Cygames
    C#大統一理論
    C#

    View Slide

  3. MagicOnion
    MasterMemory
    UniTask
    https://github.com/Cysharp
    SlnMerge
    RuntimeUnitTestToolkit
    RandomFixtureKit

    View Slide

  4. ConsoleAppFramework
    ValueTaskSupplement
    https://github.com/Cysharp
    LitJWT
    Ulid
    Difference

    View Slide

  5. UniRx
    MessagePack-CSharp
    ZeroFormatter
    Utf8Json
    https://github.com/neuecc
    LINQ to GameObject
    SerializableDictionary
    CloudStructures
    Open on GitHub

    View Slide

  6. View Slide

  7. Unified Realtime/API Engine
    https://github.com/Cysharp/MagicOnion
    特徴

    View Slide

  8. 全てのロジックをC#サーバー上で実行
    AI・演算・結果処理など全てサーバー側で処理

    View Slide

  9. Realtime Network

    View Slide

  10. Microser
    vices
    Realtime
    Server
    Unity
    Native App
    Browser
    API
    Server
    P2P

    View Slide

  11. Microser
    vices
    Realtime
    Server
    Unity
    Native App
    Browser
    API
    Server
    P2P

    View Slide

  12. P2P
    Dedicated Server

    View Slide

  13. P2P
    Dedicated Server

    View Slide

  14. Microser
    vices
    Realtime
    Server
    Unity
    Native App
    Browser
    API
    Server

    View Slide

  15. ⚫ Unity Connected Games
    ⚫ Photon Engine
    ⚫ Monobit Engine
    ⚫ DIY - WebSocket + Server App
    ⚫ DIY - WebSocket + mBaaS
    ⚫ DIY - TCP(UDP) + Server App
    ⚫ DIY - TCP(UDP) + Unity Headless

    View Slide

  16. Unity Connected Games

    View Slide

  17. Photon Engine
    Monobit Engine

    View Slide

  18. WebSocket + ServerApp
    WebSocket(TCP/UDP) + mBaaS(mobile backend as a Service)

    View Slide

  19. TCP(UDP) + ServerApp
    TCP(UDP) + Unity HeadlessApp

    View Slide

  20. TCP(UDP) + ServerApp
    TCP(UDP) + Unity HeadlessApp

    View Slide

  21. About MagicOnion

    View Slide

  22. C#の型が通信定義となる単方向/双方向RPC
    // 自然な書き味で、タイプセーフにRPC(Remote Procedure Call)を実現
    // C#のasync/await構文により、非同期通信も自然に見える
    var client = MagicOnionClient.Create(channel);
    var result = await client.Sum(100, 200);
    public class TestService : ITestService
    {
    public async UnaryResult Sum(int x, int y)
    {
    return x + y;
    }
    }

    View Slide

  23. C#の型が通信定義となる単方向/双方向RPC
    // 自然な書き味で、タイプセーフにRPC(Remote Procedure Call)を実現
    // C#のasync/await構文により、非同期通信も自然に見える
    var client = MagicOnionClient.Create(channel);
    var result = await client.Sum(100, 200);
    public class TestService : ITestService
    {
    public async UnaryResult Sum(int x, int y)
    {
    return x + y;
    }
    }
    クライアントもサーバーも自
    然に繋がっているように見え
    る(デバッガもサーバー/クラ
    イアント共有でステップ実行
    で繋がって動いていく)

    View Slide

  24. リアルタイム通信のための双方向の型付きRPC
    public interface IGamingHub : IStreamingHub{
    Task JoinAsync(string roomName, string userName, Vec
    Task LeaveAsync();
    Task MoveAsync(Vector3 position, Quaternion rotation);
    }
    public interface IGamingHubReceiver
    {
    void OnJoin(Player player);
    void OnLeave(Player player);
    void OnMove(Player player);
    }

    View Slide

  25. View Slide

  26. il.Emit(OpCodes.Ldloc_0);
    il.Emit(OpCodes.Ldloc_0);
    il.Emit(OpCodes.Call, typeof(AsyncDuplexStreamingCall).GetProperty("RequestStream").GetMethod);
    il.Emit(OpCodes.Ldarg_0);
    il.Emit(OpCodes.Ldfld, serializerOptionsField);
    il.Emit(OpCodes.Newobj, (typeof(MarshallingClientStreamWriter<>).MakeGenericType(def.RequestType).GetConstructors().Singl
    il.Emit(OpCodes.Ldloc_0);
    il.Emit(OpCodes.Call, typeof(AsyncDuplexStreamingCall).GetProperty("ResponseStream").GetMethod);
    il.Emit(OpCodes.Ldarg_0);
    il.Emit(OpCodes.Ldfld, serializerOptionsField);
    il.Emit(OpCodes.Newobj, (typeof(MarshallingAsyncStreamReader<>).MakeGenericType(def.ResponseType).GetConstructors().Singl
    il.Emit(OpCodes.Ldarg_0);
    il.Emit(OpCodes.Ldfld, serializerOptionsField);
    resultType2 = typeof(DuplexStreamingResult<,>).MakeGenericType(def.RequestType, def.ResponseType);
    il.Emit(OpCodes.Newobj, resultType2.GetConstructors()[0]);
    MethodType t;
    string requestType;
    string responseType;
    ITypeSymbol unwrappedOriginalResponseType;
    ExtractRequestResponseType(y, out t, out requestType, ou
    var id = FNV1A32.GetHashCode(y.Name);
    return new MethodDefinition
    {
    Name = y.Name,
    MethodType = t,
    RequestType = requestType,
    ResponseType = responseType,
    UnwrappedOriginalResposneTypeSymbol = unwrappedOrigi
    OriginalResponseTypeSymbol = y.ReturnType,
    IsIfDebug = y.GetAttributes().FindAttributeShortName
    HubId = id,
    Parameters = y.Parameters.Select(p =>
    {

    View Slide

  27. C#で自然にサーバーとクライアントを繋げる
    機能として提供するものはシンプルなRPCのみ
    あとはアプリケーションの作り込みで何でも作れる
    Unityにも依存しないことであらゆる使い方ができる(サーバーtoサーバーなど)
    一つのシンプルなやり方で応用が効く(土管にもなるし土管以外もOK)
    サーバープログラムを透明にしない
    どちらにも平等に配置できることを意識したフレームワーク
    サーバーもクライアントもどちらも大事
    適切な場所に適切なコードを書くことで、サーバー/クライアント全体を通し
    たアーキテクチャの最適化を支援する

    View Slide

  28. エコシステムには全部乗る
    未来で償却する

    View Slide

  29. エコシステムには全部乗る
    未来で償却する

    View Slide

  30. All in Oneではない
    RPCしかない

    View Slide

  31. API Services

    View Slide

  32. Microser
    vices
    Realtime
    Server
    Unity
    Native App
    Browser
    API
    Server

    View Slide

  33. Microser
    vices
    Realtime
    Server
    Unity
    Native App
    Browser
    API
    Server

    View Slide

  34. PROS
    CONS

    View Slide

  35. 中間言語からコード生成する
    IDL(JSON/XML/proto/etc...)
    サーバーコード
    (PHP/Ruby/Go/C#/etc...)
    クライアントコード
    (C#/Swift/JavaScript/etc...)

    View Slide

  36. PROS
    CONS

    View Slide

  37. protoはC#/* 任意の言語 */ではない

    View Slide

  38. C# as a Schema
    C#に固定することで
    通信定義そのものをC#で表現する

    View Slide

  39. 言語の違うREST
    Response型を別々
    に書く
    APIクライアント
    を手書きする
    (ザ・マイクロ
    サービスみたいな
    構成)
    中間IDLを書く
    そこからクライア
    ント・レスポンス
    型自動生成
    (←を嫌う時によ
    くある構成、一番
    メジャー)
    サービスを普通に
    書く、そこからク
    ライアントを自動
    生成、リクエス
    ト・レスポンス型
    はC#のDLLとして
    共有
    サービスを普通に
    書く、クライアン
    トはそのプロジェ
    クト参照から実行
    時動的生成

    View Slide

  40. 認証、課金、クエスト、ミッション、etc...

    View Slide

  41. https://logmi.jp/tech/articles/322333

    View Slide

  42. 適切なコードを適切なところに書く
    作り込みを現実のものにする

    View Slide

  43. 適切なコードを適切なところに書く
    作り込みを現実のものにする

    View Slide

  44. MagicOnion is
    Unified Realtime/API Engine

    View Slide

  45. Microser
    vices
    Realtime
    Server
    Unity
    Native App
    Browser
    API
    Server

    View Slide

  46. サーバーとクライアントの距離が限りなく近い

    View Slide

  47. ConsoleAppFramework
    https://github.com/Cysharp/ConsoleAppFramework
    引数の自動割当
    複数コマンドのルーティング
    コンフィグ処理
    ロギング処理
    ライフサイクル管理(Daemon)
    などCLIの面倒ごとに対応
    class Program : ConsoleAppBas
    {
    static async Task Main(string[] args)
    {
    await Host.CreateDefaultBuilder()
    .RunConsoleAppFrameworkAsync(args);
    }
    public void Run(string name, int repeat = 3)
    {
    for (int i = 0; i < repeat; i++)
    {
    Console.WriteLine($"Hello from {name}");
    }
    }
    }

    View Slide

  48. Realtime
    Unity
    API
    Service

    View Slide

  49. Realtime
    Unity
    API
    Service

    View Slide

  50. Conclusion

    View Slide

  51. 時代の変わり目を超える
    リアルタイム通信がほぼ必須だったり、5Gが迫っていたり
    旧来のフレームワークから変わっていくタイミング
    一歩先の理想形へ
    クライアントとサーバーを、APIとリアルタイムを
    全てをC#で統合するという夢想を具現化するのがMagicOnion
    ただの旧来のXXの置き換えなどではなく、
    誰も見たことのない究極的な理想の形に近づけていく
    銀の弾丸はないので、相応の困難は発生するかもしれないけれど
    ぜひ一緒に乗り越えていきましょう!
    →お、コンタクトフォームが https://cysharp.co.jp/contact/

    View Slide

  52. View Slide