2.7K Views
January 27, 20
スライド概要
2020/1/25に開催されたUnity道場京都スペシャル4の講演スライドです。
講師:河合 宜文(株式会社Cysharp)
Unityのイベント資料はこちらから:https://www.slideshare.net/UnityTechnologiesJapan/clipboards
リアルタイム3Dコンテンツを制作・運用するための世界的にリードするプラットフォームである「Unity」の日本国内における販売、サポート、コミュニティ活動、研究開発、教育支援を行っています。ゲーム開発者からアーティスト、建築家、自動車デザイナー、映画製作者など、さまざまなクリエイターがUnityを使い想像力を発揮しています。
河合 宜文 / Kawai Yoshifumi / @neuecc Cysharp, Inc. Cygames C#大統一理論 C#
https://github.com/Cysharp MagicOnion SlnMerge MasterMemory RuntimeUnitTestToolkit UniTask RandomFixtureKit
https://github.com/Cysharp ConsoleAppFramework ValueTaskSupplement LitJWT Ulid Difference
https://github.com/neuecc UniRx MessagePack-CSharp ZeroFormatter Utf8Json LINQ to GameObject SerializableDictionary CloudStructures Open on GitHub
Unified Realtime/API Engine https://github.com/Cysharp/MagicOnion 特徴
全てのロジックをC#サーバー上で実行 AI・演算・結果処理など全てサーバー側で処理
Realtime Network
P2P Realtime Server Unity Native App Browser Microser vices API Server
P2P Realtime Server Unity Native App Browser Microser vices API Server
P2P Dedicated Server
P2P Dedicated Server
Realtime Server Unity Native App Browser Microser vices API Server
⚫ ⚫ ⚫ ⚫ ⚫ ⚫ ⚫ Unity Connected Games Photon Engine Monobit Engine DIY - WebSocket + Server App DIY - WebSocket + mBaaS DIY - TCP(UDP) + Server App DIY - TCP(UDP) + Unity Headless
Unity Connected Games
Photon Engine Monobit Engine
WebSocket + ServerApp WebSocket(TCP/UDP) + mBaaS(mobile backend as a Service)
TCP(UDP) + ServerApp TCP(UDP) + Unity HeadlessApp
TCP(UDP) + ServerApp TCP(UDP) + Unity HeadlessApp
About MagicOnion
C#の型が通信定義となる単方向/双方向RPC
// 自然な書き味で、タイプセーフにRPC(Remote Procedure Call)を実現
// C#のasync/await構文により、非同期通信も自然に見える
var client = MagicOnionClient.Create<ITestService>(channel);
var result = await client.Sum(100, 200);
public class TestService : ITestService
{
public async UnaryResult<int> Sum(int x, int y)
{
return x + y;
}
}
クライアントもサーバーも自
然に繋がっているように見え
る(デバッガもサーバー/クラ
イアント共有でステップ実行
で繋がって動いていく)
Call)を実現
C#の型が通信定義となる単方向/双方向RPC
// 自然な書き味で、タイプセーフにRPC(Remote Procedure
// C#のasync/await構文により、非同期通信も自然に見える
var client = MagicOnionClient.Create<ITestService>(channel);
var result = await client.Sum(100, 200);
public class TestService : ITestService
{
public async UnaryResult<int> Sum(int x, int y)
{
return x + y;
}
}
リアルタイム通信のための双方向の型付き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);
}
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);
MethodType t;
il.Emit(OpCodes.Ldfld, serializerOptionsField);
string requestType;
il.Emit(OpCodes.Newobj, (typeof(MarshallingAsyncStreamReader<>).MakeGenericType(def.ResponseType).GetConstructors().Singl
string responseType;
il.Emit(OpCodes.Ldarg_0);
ITypeSymbol unwrappedOriginalResponseType;
il.Emit(OpCodes.Ldfld, serializerOptionsField);
ExtractRequestResponseType(y, out t, out requestType, ou
resultType2 = typeof(DuplexStreamingResult<,>).MakeGenericType(def.RequestType,
var id =def.ResponseType);
FNV1A32.GetHashCode(y.Name);
il.Emit(OpCodes.Newobj, resultType2.GetConstructors()[0]);
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 =>
{
C#で自然にサーバーとクライアントを繋げる 機能として提供するものはシンプルなRPCのみ あとはアプリケーションの作り込みで何でも作れる Unityにも依存しないことであらゆる使い方ができる(サーバーtoサーバーなど) 一つのシンプルなやり方で応用が効く(土管にもなるし土管以外もOK) サーバープログラムを透明にしない どちらにも平等に配置できることを意識したフレームワーク サーバーもクライアントもどちらも大事 適切な場所に適切なコードを書くことで、サーバー/クライアント全体を通し たアーキテクチャの最適化を支援する
エコシステムには全部乗る 未来で償却する
エコシステムには全部乗る 未来で償却する
All in Oneではない RPCしかない
API Services
Realtime Server Unity Native App Browser Microser vices API Server
Realtime Server Unity Native App Browser Microser vices API Server
PROS CONS
中間言語からコード生成する サーバーコード (PHP/Ruby/Go/C#/etc...) IDL(JSON/XML/proto/etc...) クライアントコード (C#/Swift/JavaScript/etc...)
PROS CONS
protoはC#/* 任意の言語 */ではない
C# as a Schema C#に固定することで 通信定義そのものをC#で表現する
言語の違うREST Response型を別々 に書く APIクライアント を手書きする (ザ・マイクロ サービスみたいな 構成) 中間IDLを書く そこからクライア ント・レスポンス 型自動生成 (←を嫌う時によ くある構成、一番 メジャー) サービスを普通に 書く、そこからク ライアントを自動 生成、リクエス ト・レスポンス型 はC#のDLLとして 共有 サービスを普通に 書く、クライアン トはそのプロジェ クト参照から実行 時動的生成
認証、課金、クエスト、ミッション、etc...
https://logmi.jp/tech/articles/322333
適切なコードを適切なところに書く 作り込みを現実のものにする
適切なコードを適切なところに書く 作り込みを現実のものにする
MagicOnion is Unified Realtime/API Engine
Realtime Server Unity Native App Browser Microser vices API Server
サーバーとクライアントの距離が限りなく近い
ConsoleAppFramework
https://github.com/Cysharp/ConsoleAppFramework
引数の自動割当
複数コマンドのルーティング
コンフィグ処理
ロギング処理
ライフサイクル管理(Daemon)
class Program : ConsoleAppBas
{
static async Task Main(string[] args)
{
await Host.CreateDefaultBuilder()
.RunConsoleAppFrameworkAsync<Program>(args);
}
public void Run(string name, int repeat = 3)
{
for (int i = 0; i < repeat; i++)
{
Console.WriteLine($"Hello from {name}");
}
}
などCLIの面倒ごとに対応
}
API Service Realtime Unity
API Service Realtime Unity
Conclusion
時代の変わり目を超える リアルタイム通信がほぼ必須だったり、5Gが迫っていたり 旧来のフレームワークから変わっていくタイミング 一歩先の理想形へ クライアントとサーバーを、APIとリアルタイムを 全てをC#で統合するという夢想を具現化するのがMagicOnion ただの旧来のXXの置き換えなどではなく、 誰も見たことのない究極的な理想の形に近づけていく 銀の弾丸はないので、相応の困難は発生するかもしれないけれど ぜひ一緒に乗り越えていきましょう!→お、コンタクトフォームが https://cysharp.co.jp/contact/