# HG changeset patch # User Kazuma Takeda # Date 1486578760 -32400 # Node ID d129603159925becd7229b7d16031e7af056bbc3 # Parent 82cf63664f430093040da4623d2d3be3f281b5ee Add Image, delete subsection. diff -r 82cf63664f43 -r d12960315992 paper/images/GameTree.pdf Binary file paper/images/GameTree.pdf has changed diff -r 82cf63664f43 -r d12960315992 paper/images/craft.png Binary file paper/images/craft.png has changed diff -r 82cf63664f43 -r d12960315992 paper/images/craft_1.png Binary file paper/images/craft_1.png has changed diff -r 82cf63664f43 -r d12960315992 paper/main.pdf Binary file paper/main.pdf has changed diff -r 82cf63664f43 -r d12960315992 paper/main.tex --- a/paper/main.tex Wed Feb 08 16:36:39 2017 +0900 +++ b/paper/main.tex Thu Feb 09 03:32:40 2017 +0900 @@ -78,7 +78,7 @@ % 1章では研究目的を書かない(もったいない) \chapter{ゲームエンジンにおけるデータベース} -この章ではデータベースのあり方と問題点を提議し、解決方法を提案する。 +この章ではデータベースのあり方と問題点を提議する。 \section{インピーダンスミスマッチ} @@ -86,6 +86,7 @@ プログラム中のデータ構造とRDBの表構造のズレによりインピーダンスミスマッチという問題がある。 例えばRPGゲーム中のユーザが持つアイテムという単純なものでも、RDBではユーザとアイテムの組をキーとする巨大な表として管理することになる。 +% ネストを許さないのは第一正規形だけ プログラム中では、ユーザが持つアイテムリストという簡単な構造を持つが、第一正規形を要求するRDBではネスト構造を許さない。 ORMapperではデータベースのレコードをプログラム中のオブジェクトにマッピングし扱うことができる。 @@ -146,9 +147,11 @@ Jungleはcommit logを持ち、それを他のノードやディスクに転送することにより、分散構成と持続性を実現する。 -\section{JungleDatabaseのAPI} +\chapter{JungleDatabaseのAPI} -\subsection{Jungleの木} +本章ではJungleDatabaseのAPIを記述する。 + +\section{Jungleの木} Jungleは複数の木の名前を利用し、管理しており、名前により生成、編集を行う。 以下にJungleクラスが提供している木の生成、管理を行うAPI(表\ref{jungleTree})に記述する。 @@ -156,15 +159,15 @@ \begin{table}[htb] \begin{center} \caption{Jungleに実装されているAPI} -\begin{tabular*}{\textwidth}{|l|l|} \hline +\begin{tabular}{|p{14em}|p{14em}|} \hline {\tt JungleTree createNewTree(string treeName) } & Jungleに新しく木を生成する。木の名前が重複した場合、生成に失敗しnullを返す。 \\ \hline {\tt JungleTree getTreeByName(string treeName)} & JungleからtreeNameと名前が一致するtreeを取得する。名前が一致するTreeがない場合取得は失敗しnullを返す \\ \hline -\end{tabular*} +\end{tabular} \label{jungleTree} \end{center} \end{table} -\subsection{TreeNode} +\section{TreeNode} Jungleが保有する木は、複数のノードの集合で出来ている。 ノードは、自身の子のList、属性名と属性値の組のデータを持つ。 @@ -173,7 +176,7 @@ \begin{table}[htb] \begin{center} \caption{TreeNodeに実装されているAPI} -\begin{tabular}{|p{8em}|p{14em}|} \hline +\begin{tabular}{|p{14em}|p{14em}|} \hline {\tt Children getChildren()} & ノードの子供を扱うChildrenオブジェクトを返す。\\ \hline {\tt Attribute getAttribute()} &ノードが保持しているデータを扱うAttribteオブジェクトを返す。 \\ \hline \end{tabular} @@ -181,7 +184,7 @@ \end{center} \end{table} -\subsection{Either} +\section{Either} jungleでは例外処理を投げる時にEitherクラスを用いて行う。返って来たEitherのオブジェクトに対して、{\tt isA() }で{\tt Error}かどうかをチェックする。 {\tt Error}でない場合は{\tt b()}で対象のオブジェクトを取り出す事ができる。 @@ -196,14 +199,14 @@ \end{lstlisting} -\subsection{ChildrenとAttribute} +\section{ChildrenとAttribute} Childrenクラスへのアクセスは表\ref{Children}に記述されているAPIを、Attributeクラスへアクセスは表\ref{Attribute}に記述されているAPIを用いて行う。 \begin{table}[htb] \begin{center} \caption{Childrenに実装されているAPI} -\begin{tabular}{|p{8em}|p{14em}|} \hline +\begin{tabular}{|p{14em}|p{14em}|} \hline {\tt int size()} & 子供の数を返す。\\ \hline {\tt at(int num)} &ノードが持つ子供の中から、 変数{\tt num}で指定された位置にある子ノードを返す。 \\ \hline \end{tabular} @@ -214,7 +217,7 @@ \begin{table}[htb] \begin{center} \caption{Attributeに実装されているAPI} -\begin{tabular}{|p{10em}|p{12em}|} \hline +\begin{tabular}{|p{14em}|p{14em}|} \hline {\tt T get(string key)} &ノードが持つ値から、属性名 {\tt key}とペアの属性値を{\tt Generic}型で返す。 \\ \hline {\tt string getString(string key)} &ノードが持つ値から、属性名 {\tt key} とペアの属性値を{\tt string}型で返す。 \\ \hline \end{tabular} @@ -222,7 +225,7 @@ \end{center} \end{table} -\subsection{NodePath} +\section{NodePath} Jungleでは、木のノードの位置を{\tt NodePath}クラスを使って表す。 {\tt NodePath}クラスはルートノードからスタートし、対象のノードまでの経路を、数字を用いて指し示すことで対象のノードの場所を表す。また、ルートノードは例外として-1と表記される。 @@ -235,7 +238,7 @@ \end{center} \end{figure} -\subsection{木の編集} +\section{木の編集} Jungleの木の編集は{\tt JungleTreeEditor}クラスを用いて行われる。 {\tt JungleTreeEditor}クラスには編集を行うために、表\ref{editor}に記述されているAPIを用いて行う。 @@ -243,7 +246,7 @@ \begin{table}[htb] \begin{center} \caption{Editorに実装されているAPI} -\begin{tabular}{|p{8em}|p{14em}|} \hline +\begin{tabular}{|p{14em}|p{14em}|} \hline {\tt Either addNewChildAt( NodePath path, int pos)} & 変数{\tt path}で指定した場所にある、ノードの子供の変数{\tt pos}で指定した位置子ノードを追加する\\ \hline {\tt Either deleteChildAt( NodePath path, int pos)} & @@ -305,7 +308,6 @@ これにより、インスタンスをJson化することができる。 しかし、変数名をKeyとしてValueを取り出すといったことは出来ない。 - \chapter{Jungle-Sharpの実装} JavaとC\#はよく似た言語であり、移行はそれほど難しくない。 @@ -316,9 +318,9 @@ Jungleの木の変更(commit)はCAS(Check and Set)を用いてatomicに行われる。競合している書き込み中に自分の書き込みが成功した場合に関数\verb+success()+が成功する。 -JavaではAtomicRefarenceが標準であるがC\#にはなかったためAtomicRefarenceのClassを新たにつくった。 +JavaではAtomicRefarenceが標準であるがC\#にはなかったためAtomicRefarenceのクラスを新たにつくった。 -\begin{itembox}[l]{AtomicReplace} +\begin{itembox}[l]{AtomicRefarence.cs} \scriptsize{ \begin{verbatim} // C# @@ -417,6 +419,8 @@ \end{itembox} Eitherをチェックしつつデータを格納する例を以下に記述する。 + +% サンプルのコードを簡単なものに変更 \begin{itembox}[l]{DataSaveTest.cs} \scriptsize{ \begin{verbatim} @@ -522,8 +526,49 @@ \section{Attributeの格納するデータの型} -UnityではGameObjectクラスがシーンを構成する。 +C\#の再実装を行った際にJavaのJungleに沿ってデータの型、つまりByte Arrayで設計を行っていた。 +データの格納を行うたびにByte Arrayへのキャストを行う必要がある。 +しかし、キャストの処理は軽くはない。 + +そこで、シーンを構成するObjectをそのまま格納するに仕様を変更した。 +C\#ではObjectクラスのエイリアスとしてobject型が使える。 + +object型を使うことによってユーザーが定義した任意の変数を代入することができる。 +以下にその使用例を記述する。 + +\begin{itembox}[l]{SaveData.cs} +\scriptsize{ +\begin{verbatim} +Player player = new Player (); +either = either.bind ((JungleTreeEditor arg) => { + return arg.putAttribute ("Player", player); +}); +Enemy enemy = new Enemy (); +either = either.bind ((JungleTreeEditor arg) => { + return arg.putAttribute ("Enemy", enemy); +}); +\end{verbatim} +} +\end{itembox} + +% as演算子はbyte arrayにするよりも早いのでOK?か? +データを取り出すにはGenericで型を指定する、もしくはas演算子を用いてキャストを行う。 +以下に取り出す例を記述する。 + +\begin{itembox}[l]{SaveData.cs} +\scriptsize{ +\begin{verbatim} +Player player = attr.get ("Player"); + +Enemy enemy = attr.get ("Enemy") as Enemy; +\end{verbatim} +} +\end{itembox} + +データの型の再設計を行ったことによりシーン内のオブジェクトをそのまま格納が可能になった。 +格納の際にByte Arrayに変換する必要がない。 +分散構造や、ネットワークで必要な時だけ変換する。 \chapter{ベンチマーク} @@ -535,6 +580,8 @@ 同じオペレーションでJavaとC\#で計測する。オペレーションは以下に記述する。 なお、1回目の処理はキャッシュを作り処理が遅くなるため、計測は行わず、2回目以降から行う。 +%% これは変更する必要がある +%% この例題はわかりにくい!!! \begin{itembox}[l]{Benchmark.cs} \scriptsize{ \begin{verbatim} diff -r 82cf63664f43 -r d12960315992 presen/slide.md --- a/presen/slide.md Wed Feb 08 16:36:39 2017 +0900 +++ b/presen/slide.md Thu Feb 09 03:32:40 2017 +0900 @@ -1,137 +1,19 @@ -title: PC画面配信システムTreeVNCの NAT への対応 -author: Tatsuki IHA +title: ゲームエンジンにおけるJungleDatabaseの提案 +author: Kazuma Takeda profile: lang: Japanese code-engine: coderay -# 画面共有を利用したコミュニケーション -- 授業やゼミ等で、それぞれが PC 端末を持っている場合では、PC の機能を活かした コミュニケーションが可能である -- 画面配信システム TreeVNC は参加したクライアントをバイナリツリー状に接続し、配信コストを分散させる 仕組みを取っている。そのため, 多人数が参加しても処理性能が下がらない -- ツリー のルートが参照している VNC サーバーを変更することで、ケーブルの差し替えなしに画面の切替が行える - -# TreeVNC の問題点 -- TreeVNC を実際に使用していく中で様々な問題が発生 -- 講義等を大学外の遠隔地から受けたい場合がある -- TreeVNC は NAT を越えた接続が行うことができない - -# TreeVNC の問題点 -- ゼミ等で発表者毎に画面切り替えを行う際、デュアルディスプレイを使っている学生がいた -- その際 VNC サーバーからはすべての画面データが送信されており、発表とは関係ない画面も配信されていた - -message - -# この発表は -- TreeVNC の概要 - - 構造 - - 原理 - - 画面切り替え -- 今回の改良 - - NAT 対応 - - マルチディスプレイの対応 -- TreeVNC の評価 - - 画像データ送信の遅延 - - ネックになってるノードへの対処 +# ゲームエンジンのデータベース +- ゲームエンジンUnityではデータベースとしてSQLite3やPlayerPrefsが挙げられる。 -# TreeVNC -- TreeVNC は本研究室で開発している VNC を利用した画面配信システム -- 配信コストを分散させることで大人数でも画面配信が可能 -- スムーズな配信画面の切替を行う - -# VNC -- VNC(Virtual Network Computing) は RFBプロトコルを用いて遠隔操作を行うソフトウェア -- サーバー側とクライアント側に分かれており、サーバーを起動し、クライアントがサーバーに接続を行うことで遠隔操作を可能とする - -message - -# RFB プロトコル -- RFB(Remote Frame Buffer)プロトコルは VNC で用いられているプロトコル -- 自身の画面をネットワーク越しに他者の画面に表示する -- Framebuffer と呼ばれるメモリ上に置かれた画像データを使用して画面表示を行う -- サーバーは Framebuffer が更新されるたびにクライアントに対して変更部分だけを送信する。 - -# TreeVNC の構造 -- Java で作成されたTightVNC(Tight Virtual Network Computing) を元に作成されている -- 様々なメッセージで通信を行う -- クライアント同士をバイナリツリー状に接続する -- バイナリツリーのルートのノードをRoot Nodeと呼び、 Root Node に接続されるノードを Node と呼ぶ -- Root Node が参照している VNC サーバーから FrameBuffer を取得して、 木構造を辿って Node に送信する。 - -message - -# TreeVNC の原理 -- ポート一本あたりの負荷 - - 従来のVNC : Node数 * データ量 - - TreeVNC : (2(子供の数) + 1) * データ量 -- 従来のVNCはNode数に比例 -- TreeVNCはNode数に関係なく一定 - -message +## ゲームのデータの種類 -# 共有画面切り替え -- TreeVNC の Root Node は配信者の VNC サーバーと通信を行っている -- 画面を配信されている側のビューワにある Share Screen ボタンが押す -- Root Node に SERVER\_CHANGE\_REQUEST を木構造を辿りながら送信 -- Root Node は Share Screen ボタンを押したクライアントの VNC サーバーと通信を開始 - -# Direct Connection -- NATを越えたネットワークからの接続は直接配信側の Root Node に接続を行うことで実現する -- Direct Connection した Node はそのネットワークの Root Node になる -- Direct Connection された Root Node では NAT を越えたネットワーク先の Node の管理を行わない - -message - -# マルチディスプレイ -- 画面切り替えの際のSERVER\_CHANGE\_REQUESTに共有するディスプレイの座標を付加する -- Root Node は 接続した VNC サーバーから画像データを要求する FRAME\_BUFFER\_UPDATE\_REQUEST に受け取った座標を付加する -- VNC サーバーは要求された座標内の画像データを FRAME\_BUFFER\_UPDATE で Root Node に送信する - -message - -# TreeVNC の評価 -- 木の深さによる画像データの遅延を調べる -- 実験環境 - - 実際に講義を受講している学生が TreeVNC を使用 - - 約20名の接続 - -# 実測方法 -- Root Node は 送信時間と画像データを持った CHECK\_DELAY を 末端 Node まで木構造を辿りながら伝達する -- CHECK\_DELAY を受け取った各 Node は 付加された送信時間を CHECK\_DELAY\_REPLY に付加し、 Root Node に送信する -- CHECK\_DELAY\_REPLY を受け取った Root Node は CHECK\_DELAY の送信にどれだけ時間がかかったかの計算を行う - -message +- シーン内のオブジェクトが持つパラメーター +- セーブデータ +- ネットワーク時のデータ +などがあげられる。 -# 深さ1, 2 -message -message - -# 深さ3, 4 -message -message - -# 結果から -- 画像データの伝達はほぼ1秒以内に収まっている -- 容量が小さい場合でも時間がかかる場合がある。 それはその送信の前に大容量の画像を送信した後の回線の遅延が残っているためだと考えられる -- 深さ3が遅い原因として1つの Node がボトルネックになっている事が判明した。 -- ネックになった Node をそのままにするとその子Nodeに影響を及ぼしてしまう。 そのためその Node に何らかの対応を行う必要がある - -message -message +# ゲームエンジンのデータベース の問題点 +- ORMapperを必要とする -# ネックになっているノードへの対処 -- CHECK\_DELAY\_REPLY で Root Node は ネックかどうかのを判断をする -- ネックになっているなら、その Node を木構造のリストから削除 -- 最後の Node を削除した Node の場所に移動 -- ネックになったところは三分木になる - -message - -# まとめと課題 -- 今回TreeVNCの様々な問題点の解決を行った - - NAT - - マルチディスプレイ - - 画面切り替えの安定化 - - エラー通知 - -- NATを越えた画面切り替え -- 音声配信等の共有機能の追加 -