Synamon’s Engineer blog

Synamonはリアルとデジタルの融合を加速させるため、メタバース領域で法人向けにサービス提供を行うテックカンパニーです。現在開発を進めている「メタバース総合プラットフォーム」をはじめ、メタバース市場の発展に向けた事業展開を行っています。このブログでは、メタバース技術とその周辺の技術、開発全般に関してエンジニアがお話しします。

SYNMNのマルチプレイの仕組みについてちょっと紹介

本記事は Synamon Advent Calendar 2022 の5日目の記事になります。

adventar.org


エンジニアの岡村です。

Synamonが現在ベータ版として提供している新しいアプリ「SYNMN」。皆さん触ってみましたか?

今回は、そんなSYNMNのマルチプレイ処理をちょっと紹介しようと思います。

SYNMNの同期概要

SYNMNのマルチプレイは主に2種類の仕組みを使って実現しています。1つが状態ベースの同期処理、もう一つはトリガーです。

状態の同期

ルーム内にある1個の同期オブジェクトがあったとして、そのオブジェクトにはかならず持ち主となるプレイヤーがいます。持ち主の世界での状態がそのオブジェクトの正しい状態として定義されており、同期システムによって監視されています。同期システムは一定間隔でオブジェクトの状態をチェックし、更新があれば新しい値を他のプレイヤーの世界のオブジェクトに送信します。

状態の監視と送信は自動で行われており、単純にオブジェクトの状態が変化したときだけでなく、プレイヤーの入室時の同期も自動的に行われます。状態にはラベルを付けて分類することができ、座標だけの同期やそれ以外の細かい同期を分けて行うことも出来ます。

また、オブジェクト自体の状態が変化したタイミングでイベントが発火するようになっており、自分のオブジェクトかそうでないかに関わらず(判別することも可能)、イベントを読むことでビューへの反映が出来るようになっています。

トリガーの送信

状態だけでは持ち主以外のプレイヤーがオブジェクトに対して状態の変更をさせたい時に不便です。なので、そんな時の為に、トリガーを持ち主側に送る処理もあります。 トリガーは持ち主以外のプレイヤーから呼び出され、持ち主の世界のオブジェクトに届けられる経路を主とします。

トリガーは特定のプレイヤーに送ることは出来ず、必ず特定の属性(オブジェクトの持ち主やそれ以外など)を指定して送る必要があります。PhotonにおけるRPCのRPCTargetのような形ですね。PhotonではPlayerを直接指定してRPCを送信できますが、SYNMNではできません。 ここは後述の仕組みを実現する為にあえて制約を設けている部分でもあります。

意図と強み

以前までのSynamon製のアプリでは、同期システムはPUN2をベースにした同期システムを使っていました。これは自由度が高く、凝った同期ロジックを組むことが出来たのですが、SYNMNではオブジェクト側の同期ロジックの自由度をあえて削り、不便な状態にしています。これは、以下のようなメリットがあると判断したためです。

同期処理をシステム側で制御できる

SYNMNで採用している同期システムは、同期されるオブジェクトそのものに同期のタイミングや相手を制御する権限がありません。一応トリガーはありますが、他のプレイヤーの入室をオブジェクト側で検出できないので、どのタイミングで送ればトリガーで同期できるのかわかりません。

これは裏を返せば、同期のタイミングや相手の制御はすべて同期システム側が持っているということになります。こうすることで、負荷が上がった時や同期ロジックに大幅な変化があったとしても、各オブジェクトに対する改修が最小限で済みます。

オブジェクト側で同期用のコードを書く量が最小限になる

オブジェクト側でハンドリングできることは少ないので、必然的にオブジェクト側で書くことになる同期コードの量も減ります。今までの同期システムでは、各オブジェクトのロジック中に他のプレイヤーが入室したときの同期処理を書かなければなりませんでした。これはコードの肥大を招くと共に、オブジェクト自身のロジックが同期ロジックに隠されて読みづらくなる原因となっていました。SYNMNでは状態の同期は同期システムが勝手に行うので、オブジェクト内に書く同期ロジックは最小限になりました。同期したい状態を定義すること、状態を変えること、状態が変わった時に正しくビューなどに反映することがオブジェクト側に残った責務になります。

同期用のコードがマルチプレイ以外にも使える

同期ロジックから他のプレイヤーの存在などを排除し抽象化したことで、同期ロジックをマルチプレイ以外にも使うことが出来るようになりました。例えばローカルでオブジェクトを2つ用意してのデバッグや、リプレイ機能、動きをマルチプレイのルームの外へ配信することなどが、オブジェクト内のコードを弄ることなく実現できます。

弱み

SYNMNの大人数まで対応できるユースケースに合致しているため、今回はこのような仕組みを採用しました。当然これはすべてのプロダクトに適用できるものではなく、ユースケースによって採用する同期の仕組みは異なってくるはずです。今回の仕組みはそれっぽく同期してみんなと繋がる、コミュニケーション特化のメタバース向けの仕組みと言えるでしょう。なので、例えば格闘ゲームのような細かい同期ズレが致命的なユースケースではこの仕組みは使えません。

技術的な弱みもあります。オブジェクト同士が相互作用を行うとき、SYNMNの同期システムでは他のオブジェクトが同期されているかどうかが保証されていないので、最悪の場合、特定のプレイヤーの世界では存在しないオブジェクトに依存するオブジェクトが生成されることがあります。その場合の辻褄の合わせかたはオブジェクト自体のロジックに依存しています。 他にはやはり同期システムが一元管理しているため、オブジェクト内で特殊な同期処理を行うのが難しいです。例えばNEUTRANSのAirCanvas(空中に絵を描くことのできるペン)はかなり特殊な同期処理をし、描画のほぼリアルタイムな同期を実現していました。そのようなことはSYNMNの同期システムでは実現できないので、代替手段を考える必要があります。

おわりに

以上、SYNMNで採用している同期の仕組みをざっくりと紹介しました。この仕組みはUNetやNetCode for GameObject, Photon Fusion等でも似た仕組みが採用されており、今後のメタバースにおける同期システムのトレンドになりそうな気がしています。SYNMNもまだそのポテンシャルを100%引き出し切れていないので、引き続き開発を頑張っていきます。

ここまで読んでいただきありがとうございました。良いクリスマスを!