Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Building the Game Server both API and Realtime via c#

5,196 views

Published on

Report:
https://dev.classmethod.jp/articles/game-server-development-seminar-by-cysharp/

Published in: Technology
  • Be the first to comment

Building the Game Server both API and Realtime via c#

  1. 1. 河合 宜文 / Kawai Yoshifumi / @neuecc Cysharp, Inc. Cygames C#大統一理論 C#
  2. 2. C#の可能性を切り開いていく https://github.com/Cysharp
  3. 3. OutGame API Server
  4. 4. アウトゲーム(API Server) インゲーム(Realtime Server)
  5. 5. Backend Services API Server Game Client Realtime Server
  6. 6. Backend Services API Server Game Client Realtime Server RDBMS Redis
  7. 7. ただのHTTPサーバー よって言語はなんでもいい 非同期処理に専用構文 型付き
  8. 8. RDBMS + Cache(Redis)が好まれる 垂直分割 vs 水平分割
  9. 9. RDBMS + Cache(Redis)が好まれる 垂直分割 vs 水平分割
  10. 10. 無限スケール
  11. 11. DB管理はGUIツールを使いたい 水平分割はツールと相性最悪
  12. 12. 永久に保存する領域 – データベース 期間保存 –RedisにExpire付きで保存 リクエスト単位 - HttpContext.Items アプリケーション単位 – Static変数
  13. 13. インメモリKey-Valueストア RDSの不得意な部分を補える
  14. 14. C#最速のシリアライザ https://github.com/neuecc/MessagePack-CSharp
  15. 15. 究極の埋込み型インメモリDB https://github.com/Cysharp/MasterMemory/
  16. 16. JSON(MessagePack/Protobuf)を返す クライアント/サーバーのスキーマ共有が鍵
  17. 17. 中間言語からコード生成する IDL(JSON/XML/proto/etc...) サーバーコード (PHP/Ruby/Go/C#/etc...) クライアントコード (C#/Swift/JavaScript/etc...)
  18. 18. PROS CONS
  19. 19. protoはC#/* 任意の言語 */ではない
  20. 20. C# as a Schema C#に固定することで 通信定義そのものをC#で表現する
  21. 21. 言語の違うREST Response型を別々 に書く APIクライアント を手書きする (ザ・マイクロ サービスみたいな 構成) 中間IDLを書く そこからクライア ント・レスポンス 型自動生成 (←を嫌う時によ くある構成、一番 メジャー) サービスを普通に 書く、そこからク ライアントを自動 生成、リクエス ト・レスポンス型 はC#のDLLとして 共有
  22. 22. 言語の違うREST Response型を別々 に書く APIクライアント を手書きする (ザ・マイクロ サービスみたいな 構成) 中間IDLを書く そこからクライア ント・レスポンス 型自動生成 (←を嫌う時によ くある構成、一番 メジャー) サービスを普通に 書く、そこからク ライアントを自動 生成、リクエス ト・レスポンス型 はC#のDLLとして 共有 サービスを普通に 書く、クライアン トはそのプロジェ クト参照から実行 時動的生成
  23. 23. Unified Realtime/API Engine https://github.com/Cysharp/MagicOnion 特徴
  24. 24. public class TestService : ITestService { // パブリックメソッドがそのままgRPC定義 public async UnaryResult<int> Sum(int x, int y) { // async/awaitにも自然に対応 // マジカル技術によりasync Task<T>じゃなくてもawait可能 await Task.Yield(); return x + y; } } // 普通のgRPCの接続を作る(MagicOnion用の特別なことはない) var channel = new Channel("127.0.0.1:12345"); // 自然な書き味で、タイプセーフにRPC通信を実現 // C#のasync/await構文により、非同期通信も自然に見える var client = MagicOnionClient.Create<ITestService>(channel); var result = await client.Sum(100, 200); クライアントもサーバーも自 然に繋がっているように見え る(デバッガもサーバー/クラ イアント共有でステップ実行 で繋がって動いていく)
  25. 25. 認証、課金、クエスト、ミッション、etc...
  26. 26. https://logmi.jp/tech/articles/322333
  27. 27. 適切なコードを適切なところに書く 作り込みを現実のものにする
  28. 28. 適切なコードを適切なところに書く 作り込みを現実のものにする mBaaSで対応しきれるかどうか ハイパーカジュアルなら気にする必要はないけど、 ヒットを狙うモバイルゲームなら難しいでしょう mBaaSを部分的に使うというのはある 認証だけ、課金だけ、Push通知だけ、etc... なにをコアに思って注力するか、ですね しかし、だからクライアントだけに注力すると、痛 い目にあう確率の方が高いと思っています
  29. 29. 言語はなんでもいい、が、理由はいる クライアント(Unity)がC# CysharpのOSS郡
  30. 30. Unityとサーバーのcsprojを結合する https://github.com/Cysharp/SlnMerge
  31. 31. C#でシナリオを書く負荷テスト(分散バッチ)ツール https://github.com/Cysharp/DFrame/
  32. 32. C#でシナリオを書く負荷テスト(分散バッチ)ツール https://github.com/Cysharp/DFrame/
  33. 33. C#は近年パフォーマンス向上に注力 https://www.techempower.com/benchmarks/#section=data-r19&hw=ph&test=plaintext
  34. 34. gRPCと一口で言っても性能は言語で千差万別
  35. 35. ZLogger Zero Allocation Text/Structured Logger for .NET Core and Unity https://github.com/Cysharp/ZLogger
  36. 36. InGame Realtime Server
  37. 37. 対戦などのインゲーム用サーバー
  38. 38. Backend Services API Server Game Client Realtime Server P2P
  39. 39. P2P Dedicated Server
  40. 40. P2P Dedicated Server
  41. 41. Backend Services API Server Game Client Realtime Server
  42. 42. ⚫ Mirror ⚫ Photon Engine ⚫ Monobit Engine ⚫ DIY - WebSocket + Server App ⚫ DIY - WebSocket + mBaaS ⚫ DIY - TCP(UDP) + Server App ⚫ Unity Headless
  43. 43. Mirror
  44. 44. Photon Engine Monobit Engine
  45. 45. WebSocket + ServerApp WebSocket(TCP/UDP) + mBaaS(mobile backend as a Service)
  46. 46. TCP(UDP) + ServerApp TCP(UDP) + Unity HeadlessApp
  47. 47. TCP(UDP) + ServerApp TCP(UDP) + Unity HeadlessApp
  48. 48. リアルタイム通信のための双方向の型付きRPC public interface IGamingHub : IStreamingHub<IGamingHub, IGamingHub { Task<Player[]> 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); }
  49. 49. il.Emit(OpCodes.Ldloc_0); il.Emit(OpCodes.Ldloc_0); il.Emit(OpCodes.Call, typeof(AsyncDuplexStreamingCall<byte[], byte[]>).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<byte[], byte[]>).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 => {
  50. 50. C#で自然にサーバーとクライアントを繋げる 機能として提供するものはシンプルなRPCのみ あとはアプリケーションの作り込みで何でも作れる Unityにも依存しないことであらゆる使い方ができる(サーバーtoサーバーなど) 一つのシンプルなやり方で応用が効く(土管にもなるし土管以外もOK) サーバープログラムを透明にしない どちらにも平等に配置できることを意識したフレームワーク サーバーもクライアントもどちらも大事 適切な場所に適切なコードを書くことで、サーバー/クライアント全体を通し たアーキテクチャの最適化を支援する
  51. 51. C#で自然にサーバーとクライアントを繋げる 機能として提供するものはシンプルなRPCのみ あとはアプリケーションの作り込みで何でも作れる Unityにも依存しないことであらゆる使い方ができる(サーバーtoサーバーなど) 一つのシンプルなやり方で応用が効く(土管にもなるし土管以外もOK) サーバープログラムを透明にしない どちらにも平等に配置できることを意識したフレームワーク サーバーもクライアントもどちらも大事 適切な場所に適切なコードを書くことで、サーバー/クライアント全体を通し たアーキテクチャの最適化を支援する
  52. 52. LogicLooper https://github.com/Cysharp/LogicLooper MagicOnionのデフォルトはイベント駆動 (クライアントからの命令を起点に サーバーが結果を返す) LogicLooperはMagicOnion用の拡張で ティックレートベースの駆動で動かせる こちらのほうがゲーム向きな動きが可能 (AIが自動行動したり、 複数コマンドを溜めてバッチ処理したり)
  53. 53. エコシステムには全部乗る 未来で償却する
  54. 54. エコシステムには全部乗る 未来で償却する
  55. 55. 現実的にはホスティングに困る ステートフルサーバー
  56. 56. ゲームセッションとコンテナが1:1
  57. 57. ゲームセッションとコンテナが1:1
  58. 58. Other Components
  59. 59. 管理画面やお知らせウェブビューなど ウェブもなんだかんだで重要 ASP.NET Core MVC 普通の、フルセットのMVCフレームワーク ミドルウェアがありテンプレートエンジンがありORMがあり…… C#ユーザーは皆これを使うので、フレームワーク選びに悩まない 情報も豊富だしコンポーネントも揃っている(認証連携など) ASP.NET Core Blazor C#だけでSPAを実装できるキワモノ とはいえ、管理画面の実装などには便利
  60. 60. バッチ量産のためのフレームワーク https://github.com/Cysharp/ConsoleAppFramework ASP.NET Coreと同じ土台に乗って、 MVCフレームワーク的にCLIアプリケーションが作れる // Foo.exe hello “world” のように書ける class Program : ConsoleAppBase { static async Task Main(string[] args) { await Host.CreateDefaultBuilder() .RunConsoleAppFrameworkAsync<Program>(args); } [Command(“hello”)] public void Hello([Option(0)]string name) { Console.WriteLine($"Hello My ConsoleApp from {name}"); } [Command(“Echo”)] public void Echo(string name) { Console.WriteLine(name); } }
  61. 61. Conclusion
  62. 62. (当たり前)
  63. 63. 完全統合形フレームワークという理想の現実化 クライアントとサーバーを、APIとリアルタイムを 全てをC#で統合するという理想を具現化するのがMagicOnion ゲームサーバーの未来へ ゲーム x サーバーはニッチなところがあり、 どの言語もパーツ(ライブラリ)が揃いきっていない場合も多い CysharpはC#を最高のゲーム開発環境とすべく、 MagicOnionだけでなくあらゆるライブラリの提供で実現する そしてそれは国内ローカルではなく、ワールドスタンダードを自分 達が作るという気概でやっていきます……!

×