言語ゲーム

とあるエンジニアが嘘ばかり書く日記

Twitter: @propella

Croquet2D システムの理論と実装

近く公開が予定されている Croquet2D ですが、かなり判りにくくしかもちゃんと動かないので、本当はこういう風に動く「はず」だという事を書きます。また実装とパフォーマンスについての考察を書きます。

画面共有システムとしての Croquet2D の位置づけ

画面共有システムとしては、VNC が有名ですし、Squeak にも Nebraska というシステムが付属しています。これらはある一つのパソコンのマウスやキーボードを複数の場所で操作し、その画面表示結果を送信するという動作形態になっています。一方で Croquet2D では、まず接続開始時に共有するシステムの内部をすべて同じ状態にします。その後イベントのみを送信しあう事で画面結果の情報をまったくやり取りする事無しに同じ画面を共有するという仕組みになっています。

設計

おおまかに、アイランド、コントローラ、ルータが存在します。アイランドとコントローラはそれぞれのホストに存在し、ルータはサーバに置いてあります。以下では「メッセージ送信」の事を「イベント」と書きます。

  • アイランド - ある時刻の世界の内部状態を保持しています。
  • コントローラ - アイランドの時刻を進め、内部状態を変化させます。
  • ルータ - イベントを各コントローラに配布します。

動作手順は以下の通りです。

  • ユーザはキーボードやマウスの操作を行います。
  • コントローラはイベントを受け取り、ルータに伝えます。
  • ルータには複数のコントローラが繋がっています。
    • ルータはあるコントローラからイベントを受け取ります。
    • ルータはイベントに現在の時刻を記録します。
    • ルータは繋がっているすべてのコントローラにイベントを送信します。
  • 各コントローラはルータからイベントを受け取り、アイランドに伝えます。
  • 各アイランドはイベントに従って内部状態と時刻を変化させます。

特徴

  • アイランドの持つ時刻は、ルータ(サーバ)の時刻であり、マシン自体が知っている時刻とは関係ありません。
  • アニメーションを見せるためには、ルータはアイランドの時刻を進める為に適当な間隔で空のイベント(ハートビート)を送信する必要があります。

構造

Croquet2D を実現させるための内部システムです。運良くバグに遭わなければ future 以外使う必要はありません。

  • future メッセージ - すべてのアイランドに同時に実行されるイベント
  • syncSend メッセージ - 外部からアイランドの内部にアクセスするために内部的に使用される。ユーザは直接使いません。
  • datagram - イベントをネットワークで送信する為に内部的に使用される。ユーザは使いません。

内部実装

あるアイランドの内部状態を変化させるには以下のようにします。

Car future forwardBy: 100.

これは次のようにコンパイルされます。

Car futureSend: #forwardBy: at: 0 args: {100}.

メッセージはまず、TMessageData としてシリアライズされます。

そして、sendMessage: の中で、さらに TDatagram にカプセル化されます。TDaragram に含まれる facet とは、ルータにこのメッセージをどうして欲しいのかをあらわし、この場合ルータの中で send:from: が送られます(このメカニズムはとても複雑です)。TDatagram の data は TMessageData をバイト列にした物です。

TDatagram はネットを通じてルータの send:from: に送られます、そこで TMessageData に戻され、タイムスタンプが与えられ、もう一度 TDatagram に直して各コントローラに送られます。この時の facet は recvFacet (recv:from:) です。

各コントローラの recv:from: に到着した TDatagram は再び TMessageData に解凍され、最終的に decodeScheduleAndExecute: に到着します。ここで最初のイベントが復活して、アイランドのイベントキューに送られます。同時に、イベントの持つタイムスタンプまでアイランドの時刻を進めます。

各アイランドは、キューに保存されたイベント列を、アイランドの時刻まで実行します。