Unity C#と.NET Core(MagicOnion) C#
そしてKotlinによるハーモニー
株式会社Cysharp 代表取締役
河合 宜文
2019-09-04 CEDEC 2019
講演者プロフィール
• 河合 宜文 / Kawai Yoshifumi / @neuecc
• Cysharp, Inc. – CEO/CTO
• 株式会社Cygamesの子会社としてC#関連の研究開発やコンサ
ルティングを行う
• メインミッションはC#大統一理論(サーバー/クライアント共にC#で
実装する)の推進
• 株式会社アプリボットの新規タイトル(タイトル未発表)におけ
るMagicOnionの導入と周辺の基盤開発を担当
2019/9/4
融和と統一1
MagicOnion
• Unified Realtime/API Engine for .NET Core and Unity
• https://github.com/Cysharp/MagicOnion/
• Cysharp開発のC#によるOSSのネットワークエンジン
• リアルタイム系もAPI系も両方OK
• HTTP/2 gRPCの上に構築され、高性能とスタンダードを両立
• .NET CoreによるLinuxホスティングと完全なコンテナ対応
• 現在GitHub Starが1000以上と、国内外でも注目度上昇中
• パフォーマンスとC#としての使い勝手にこだわって開発
• C#のエキスパートが最初からUnity C#も前提に組み立てているた
め、C#のためのエンジンとして高い品質を誇る
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);
クライアントもサーバーも自
然に繋がっているように見え
る(デバッガもサーバー/クラ
イアント共有でステップ実行
で繋がって動いていく)
Why not (plain) gRPC
• protoはC#ではない!!!
• 故に言語の持つ
• 全ての型(Primitive, Nullable, Dictionaryなど)が使えない
• 属性(Attribute, Annotation)付与ができない
• リクエスト毎に必ず一つの型が必要になる
• 故にIDE(Visual Studio, Rider, etc...)の持つ
• シンタックスハイライトが効かない
• コードレンズなどのコード追跡機能が効かない
• リファクタリング支援(名前一括変更など)が効かない
• サーバー/クライアント大統一ならクライアント/サーバー超えて変更
される!
C#がIDLなら
C# as a Schema
クライアント/サーバーの実装言語を
共にC#に固定することで、
通信スキーマそのものをC#で表現する
プロジェクト参照で済むので
IDLのバージョン管理が不要というのも運用上メリット
しかしいきなりC#は投げ込めない
• C#大統一理論
• そんな過激派な意見がいきなり通じるわけがない
• 良いゲームを作るための開発であってC#を使うための開発
ではない
• ↑私はC#を使うための(げふんげふん)
• 各社それぞれの都合に合わせた融和のための施策から始める
• そしてあわよくば(げふんげふん)
ざっくり通信系の整理
Microser
vices
Realtime
Server
Unity
API
Server
C#大統一理論
Microser
vices
Realtime
Server
Unity
API
Server
全部MagicOnionによってC#で繋
がって脳みそお花畑ハッピー!
現実解
Microser
vices
Realtime
Server
Unity
API
Server
API Serverは各社の得意な言語
(Ruby, PHP, Java, Go, Kotlin, etc…)
リアルタイムサーバーはMagicOnion
使うでいいんじゃないか
Agenda
• C#(Unity)と他言語(今回はKotlin)の付き合い方
• C#(Unity) to C#(.NET Core)のコード共有
• MagicOnionによるリアルタイムサーバー実装
• まとめ
2019/9/4
他言語間ロジック共有いろいろ2
C#とKotlinによるロジック共有
• ロジック(計算式など)をKotlinサーバーとUnityで共有したい!
• 例えば戦闘力や経験値算出などをクライアントで計算して表示
• 何かを消費するなどして適用する場合、サーバー側でもバリデーショ
ンとして計算して適用する
• などなど、同じ計算式が必要な場合はままある
• 共有方法を考える
• 案A. 手書きで両方に作る
• 変更耐性が低い!うっかり忘れが発生しても気づかなそう
• 案B. 中間定義からKotlin, C#のコードを作る
• よくわからないオレオレ中間言語は誰も書きたくない
C#とKotlinによるロジック共有
• ロジック(計算式など)をKotlinサーバーとUnityで共有したい!
• 例えば戦闘力や経験値算出などをクライアントで計算して表示
• 何かを消費するなどして適用する場合、サーバー側でもバリデーショ
ンとして計算して適用する
• などなど、同じ計算式が必要な場合はままある
• 共有方法を考える
• 案A. 手書きで両方に作る
• 変更耐性が低い!うっかり忘れが発生しても気づかなそう
• 案B. 中間定義からKotlin, C#のコードを作る
• よくわからないオレオレ中間言語は誰も書きたくない
MagicOnionならC#で書いたコードが
全てそのまま無条件でサーバーとク
ライアントで共有できてハッピー!
案C. C#内部ロジックサービスとの通信
Kubernetes Pod
Kotlin API
Server
C# Internal
Service
Unity C#
両方C#なのでコードを共有する
案C. C#内部ロジックサービスとの通信
Kubernetes Pod
Kotlin API
Server
C# Internal
Service
Unity C#
Kubernetesの同一Pod内にサイドカーと
して外部と通信するKotlinサーバーと、内
部のみのC#によるサービスを立ち上げ、
gRPC(Unix Domain Socket)で通信して
計算結果を取得
案D. C# to Kotlinでコード共有(採用)
• C#を正としてUnity側中心にロジックを書いてしまい、Kotlin
側はC#からのコードジェネレートで生成する
• MicroBatchFramework
• https://github.com/Cysharp/MicroBatchFramework
• C#(.NET Core)でCLIツール作るのに便利なフレームワーク
• Roslyn(Microsoft.CodeAnalysis.CSharp)
• C#によるC#コンパイラ
• C#のAbstract Syntax Treeが取れる
class Program : BatchBase
{
static async Task Main(string[] args)
{
await BatchHost.CreateDefaultBuilder().RunBatchEngineAsync<Program>(args);
}
public void Generate(
[Option("i", "入力するフォルダ")]string inputDirectory,
[Option("o", "出力するフォルダ")]string outputDirectory)
{
foreach (var inputFilePath in Directory.GetFiles(inputDirectory,
"*.cs", SearchOption.AllDirectories))
{
var tree = CSharpSyntaxTree.ParseText(File.ReadAllText(inputFilePath));
var parseInfo = Parse(tree);
foreach (var item in parseInfo)
{
var template = new KotlinTemplate
{
ClassInfo = item
};
var code = template.TransformText();
var outPath = Path.Combine(outputDirectory, item.ClassName) + ".kt";
File.WriteAllText(outPath, code, Encoding.UTF8); }
CSharpSyntaxTree.ParseTextで.cs
ファイルからSyntaxTreeを取得
テンプレートエンジン(T4)を使って
Kotlinコードを生成
MicroBatchFrameworkによる
CLI定義と実装
ASTを元にテンプレートに当ては
める情報を生成(自前実装)
MagicOnionならC#で書いたコードが
全てそのまま無条件でサーバーとク
ライアントで共有できてハッピー!
2019/9/4
Unity C#と.NET Core C#のコード共有いろは3
コード共有
• 最も分かりやすいクライアント/サーバーの言語統一の利点
• メリットを最大限に甘受できるプロジェクト構成にする
一つのソリューションファイルで
サーバーのcsprojもクライアントの
csprojもホストする
これによりIDEが両プロジェクトを認識して
・リファクタリングが統一的に効く
・参照のジャンプなどが効く
・デバッグ実行でサーバー/クライアントが繋がる
vs Unity .csproj
• UnityはUnityの管理下のソースコードのみ参照可能
• サーバーのcsprojは柔軟に記述できる
• よって共有するコードの実体をUnityのほうに置いて、サー
バー側ではコードリンクで参照する
<ItemGroup>
<Compile Include="..¥Unity¥Assets¥Scripts¥Shared¥**¥*.cs" />
</ItemGroup>
シンボリックリンクとか、ビルドしてマ
ネージドDLLを配置とかやるとトラブルの
元なので、シンプルな手段が一番
シェアするディレクトリはasmdef
で切っておくとより良い
Unity Shimsの実装
• Unity依存コードの除去
• 理想的には完全除去が望ましいが、特に開発中でUnity側主導でコード
ができあがっている場合、残ってしまっていることが多い
• ダミーの型を用意して回避するのが手っ取り早くは楽
namespace UnityEngine
{
public class ScriptableObject {}
public class MonoBehaviour {}
public sealed class SerializeFieldAttribute : Attribute
{
}
// etc...
}
意外と問題なく動いたり動かなかったり。
とりあえずコンパイル通す→動かして問題出た
とこを何とかする、で工数的にそんな多くかか
らず何とかなる、ことも少なくないかな、と。
2019/9/4
MagicOnionによるリアルタイムサーバー実装4
サーバーロジックを書くということ
• MagicOnionはサーバーにロジックを書くためのフレームワーク
• データを右から左に流すだけのものではないし、サーバーを「透
明にしない」ことをポリシーにしている
• ゲームを面白くするには、クライアントだけが主でもサーバーだ
けが主でもない、両方が協調して、乗せるべきコードを乗せるべ
き場所に適切に書いていくことが大事
• MagicOnionはそれを最もやりやすくするための選択(の一つ)
• C#による統一はサーバー/クライアント間の壁を透明にするための選択
イベント型とサーバーループ
サーバーがクライアントからのリクエス
トを受け取ったら
イベント型とサーバーループ
なにか処理をしたうえで(あるいは何も
処理をせずに)接続している各クライア
ントに配信するスタイル
イベント型とサーバーループ
サーバーがクライアントからのリクエスト
を受け取ったらキューにコマンドを蓄積
イベント型とサーバーループ
処理した結果を各クライアントに配信
大量クライアントのコマンドも、サーバー
で適正に処理してまとめて流すことで帯域
爆発などが防ぎやすい
C#アプリクライアント
Unityクライアント(1)とC#クライアント
(3)などの構成で、より開発しやすく、負
荷テストなども作りやすく
2019/9/4
まとめ5
MagicOnion is...
• High Performance
• gRPC(HTTP/2) + MessagePack-CSharp
• Modern Architecture
• .NET Core, Container, OpenTelemetry
• C# Friendly
• C# as a Schema
• Unity Friendly
• Runtime/CodeGen(for IL2CPP)
未来を構築する
• 新しい時代の新しいフレームワーク
• 今やゲームにおいてリアルタイム通信はほぼ必須
• 5Gも迫っていてフレームワークも変化しなければいけないタイミング
• ならばこそ、より大きな未来を描いていきたい
• 完全統合形フレームワークという一つの理想
• クライアントとサーバーを
• APIとリアルタイムを
• 全てをC#で統合するという夢想を具現化するのがMagicOnion
• 理想を理想のままにせず、現実の結果に残すためにCysharpはOSSに
よる公開から、開発サポートまで様々なことをしていきます!

Unity C#と.NET Core(MagicOnion) C# そしてKotlinによるハーモニー