view Paper/riono-sigos.tex @ 32:102de90587f5

update
author riono <e165729@ie.u-ryukyu.ac.jp>
date Thu, 06 May 2021 23:37:19 +0900
parents 575b1e144749
children
line wrap: on
line source

%%
%% 研究報告用スイッチ
%% [techrep]
%%
%% 欧文表記無しのスイッチ(etitle,eabstractは任意)
%% [noauthor]
%%

%\documentclass[submit,techrep]{ipsj}
\documentclass[submit,techrep,noauthor]{ipsj}



\usepackage[dvipdfmx]{graphicx}
\usepackage{latexsym}
\usepackage{url}
\usepackage{listings}
\usepackage{caption}

\def\Underline{\setbox0\hbox\bgroup\let\\\endUnderline}
\def\endUnderline{\vphantom{y}\egroup\smash{\underline{\box0}}\\}
\def\|{\verb|}
%

%\setcounter{巻数}{59}%vol59=2018
%\setcounter{号数}{10}
%\setcounter{page}{1}

\lstset{
  language=java, 
  tabsize=2, 
  numbers=left,
  frame=single, 
  basicstyle={\ttfamily\footnotesize}, % 
  identifierstyle={\footnotesize}, % 
 commentstyle={\footnotesize\itshape}, % 
  keywordstyle={\footnotesize\bfseries}, % 
  ndkeywordstyle={\footnotesize}, % 
  stringstyle={\footnotesize\ttfamily}, 
  breaklines=true, 
  captionpos=t, 
  columns=[l]{fullflexible}, % 
  xrightmargin=0zw, % 
  xleftmargin=1zw, % 
  aboveskip=1zw, 
  numberstyle={\scriptsize}, % 
  stepnumber=1, 
  numbersep=0.5zw, % 
  lineskip=-0.5ex, 
}

\renewcommand{\lstlistingname}{Code}

\begin{document}


\title{継続を使用する並列分散フレームワークのUnity実装}

%\etitle{How to Prepare Your Paper for IPSJ SIG Technical Report \\ (version 2018/10/29)}


\affiliate{KIE}{琉球大学大学院理工学研究科情報工学専攻}
\affiliate{IE}{琉球大学工学部工学科知能情報コース}

\author{安田 亮}{Ryo Yasuda}{KIE}[riono210@cr.ie.u-ryukyu.ac.jp]
\author{河野 真治}{Shinji Kono}{IE}[kono@ie.u-ryukyu.ac.jp]

\begin{abstract}
 FPSやMMORPGなどのゲームにおける通信方式には、クライアントサーバ方式とp2p方式の2つが考えられる。クライアントの負荷軽減やチート対策などを理由にクライアントサーバ方式が主流である。しかし、データの同期にはサーバを経由するため低速である。
そこで本研究室で開発している分散フレームワークChristieを用いることで、高速かつ、安全に、データの同期を行いたいと考えた。
本研究ではChristieをゲームエンジンUnityに対応するため、C\#への書き換えを行う。
\end{abstract}


%
%\begin{jkeyword}
%情報処理学会論文誌ジャーナル,\LaTeX,スタイルファイル,べからず集
%\end{jkeyword}
%
%\begin{eabstract}
%This document is a guide to prepare a draft for submitting to IPSJ
%Journal, and the final camera-ready manuscript of a paper to appear in
%IPSJ Journal, using {\LaTeX} and special style files.  Since this
%document itself is produced with the style files, it will help you to
%refer its source file which is distributed with the style files.
%\end{eabstract}
%
%\begin{ekeyword}
%IPSJ Journal, \LaTeX, style files, ``Dos and Dont's'' list
%\end{ekeyword}

\maketitle


\section{オンラインゲームにおけるデータ通信}

オンラインゲームはさまざまな回線を通じて複数のプレイヤーが関与する分散プログラムである。通信形態はクラウド上のサーバを
中心とした形態が多い。分散プログラムを正しく書くことは難しく、また、ゲームの場合はさまざまな攻撃が行われることが多い。
ネットワーク上のパケットを用いた攻撃やウイルスもそうだが、ゲームのルールに沿っていても、プレイヤーのデバイス上で
プログラムを用いたチートが行われる場合もある。

TCP/IPが現状のインターネットの標準的なプロトコルであり、その上に、信頼性はないがコネクションなしにデータを転送できる
Datagram と、信頼性を保証する通信路である TCP の二種類のトランスポート層が用意されている。しかし、
より高いレベルの通信ライブラリにより、攻撃に強く、柔軟にゲームの通信プロトコルを拡張できるフレームワークが
望まれている。例えば、Windows 上のDirect Xなどにはそのようなもの搭載されている。Unity ゲームフレームワークでも
さまざまな通信ライブラリが存在する。

当研究室では初代PlayStation用に作成した Federated Linda を拡張して、CodeGear / DataGear を用いた分散フレームワークを
開発中である。これは Java で書かれており、Unity 上で直接動かすことはできない。そこで、C\# で再実装することにより
Unity 上のゲームの通信ライブラリとして使用できるようにする。

従来の通信ライブラリと異なり、型のあるDataGear をタプル空間(DataGearManger/DGM)に Key を持つストリームとして
格納する方式をとっている。DGM は自ノードには local なものがあり、自ノードのスレッド間での通信に用いられる。
他のノードは、このDGMの proxy を持ち、proxy に書き込むことで自ノードとの通信を行う。

DGMの構成はトポロジーマネージャーにより自動的に構成される。ゲームノードは、まず、トポロジーマネージャと通信し、
自分が接続するべきノードを知らされる。自分が指示されたノードに接続し、DGMを持つ。ゲームプログラム自体は、
複数の名前のついたDGMを知っていればよく、IP addressなどを知る必要はない。

DGMは proxy であり、DataGearのコピーをそこに持っている。なので、ネットワーク接続の切断があっても、
ゲームの動きを止めることなく対応が可能となっている。ゲームノードは直接接続される対象が何かを
直接知ることはできないので、チートに対する耐性がある。例えば、まず、チートがあるかどうかを調べる
ノードに接続するなどの工夫が可能となっている。

本論文では Java で書かれた Chirstie と C\# で書かれたものの説明し、その機能と実装の差について考察する。

\section{Christie のC\#への書き換えについて}
Christie\cite{christie} はAlice\cite{alice} というプロジェクトで開発が行われていた。しかしAlice には様々な問題点があった。データを管理しているlocalDataGear をシングルトンで設計してしまい、local で接続を行う際には複数のアプリケーションを立ち上げる必要がある。また、データを受け取る際にObject 型で受け取っている影響で何の型が送信されるか不明瞭である点などがあり、再設計を行う必要性が発生した。それらの問題点を解消するためにAlice を再構築したものがChristie である。
Christie はAlice の機能や概念を維持しつつ、Alice で発生していた問題点やプログラムの煩雑さなどを解消している。

今回Chrstie をC\# へ書き換えを行う。これは、ゲーム制作において多くの開発者に使用されているUnity に対応するためである。Unity はC\# でプログラミングが可能であり、C\# とjavaは比較的書き方が似ているため、書き換えが行いやすいと判断した。
C\# への書き換えの方針は、java 版との互換性を保つために極力同じ動作をするAPI を用いて実装を行った。


\section{Christieの基礎概念}
Christieは当研究室で開発している分散通信フレームワークである。同じく当研究室で開発している GearsOSのファイルシステムに組み込まれる予定があるため、GearsOSを構成する言語 Continuation based Cと似た概念を持っている。 Christieに存在する概念として以下のようなものがある。

\begin{itemize} %箇条書き
\item CodeGear 
\item DataGear
\item CodeGearManager (以下CGM)
\item DataGearManager (以下DGM)
\end{itemize}

以下はjava版のChristieについて解説を行う。
CodeGearはクラスやスレッドに相当する。
DataGearは変数データに相当し、CodeGear内でannotationを用いて変数データを取得する。CodeGear内に記述した全てのDataGearの中にデータが格納された際に、初めてそのCodeGearが実行されるという仕組みになっている。
CGM はノードであり、CodeGear、DataGear、DGMを管理する。
DGMはDataGearを管理するものであり、putという操作により変数データ、つまりDataGearを格納できる。DGMのput操作を行う際にはLocalとRemoteのどちらかを選び、変数のkeyとデータを引数として渡す。
Localであれば、LocalのCGMが管理しているDGMに対しDataGearを格納していく。Remoteであれば、接続したRemote先のCGMが管理しているDGMにDataGearを格納できる。

図 \ref{fig:christieclass} は、Christie を同一プロセスで複数のインスタンスを立ち上げた際のDGM やCGM の接続の構造を示している。
全てのCodeGearManger はThreadPool と他のCGM をList として共有している。ThreadPool とはCPU に合わせた並列度でqueue に入ったThread を順次実行していく実行機構である。ThreadPool が増えると、CPU コア数に合わない量のThread を管理することになり並列度が下がるため、1つのThreadPool で全てのCGM を管理している。
また、CGM のList を共有することでメタレベルで全てのCodeGear/DataGear にアクセス可能となっている。

\begin{figure}[h] %PDF
\begin{center}
\includegraphics[width=10cm]{fig/ChristieClass.pdf}
\caption{Christie の複数インスタンスの立ち上げ}
\label{fig:christieclass}
\end{center}
\end{figure}

put操作を行った後は、対象のDGMの中にqueueとして保管される。DataGearを取り出す際には、CodeGear内で宣言した変数データにannotationをつける。DataGearのannotationにはTake、Peek、TakeFrom、PeekFromの4つがある。


\begin{description}
\item[Take] 先頭のDataGear を読み込み、そのDataGear を削除する。DataGearが複数ある場合、この動作を用いる
\item[Peek] 先頭のDataGear を読み込むが、DataGear が削除されない。そのため、特に操作をしない場合は同じデータを参照し続ける。
\item[TakeFrom (Remote DGM name)] Take と似ているが、Remote DGM nameを指定することで、その接続先(Remote) のDGM からTake 操作を行える。
\item[PeekFrom (Remote DGM name)] Peek と似ているが、Remote DGM name を指定することで、その接続先(Remote) のDGM からPeek 操作を行える。
\end{description}


\section{TopologyManager}
TopologyManager とは、Christie 上でのNetwork Topologyを形成するために参加を表明したノード、TopologyNode に名前を与え、必要があればNode 同士の配線も自動で行う機能である。TopologyManager のTopologyの形成方法として、静的Topology と動的Topology の2つがある。静的Topology はCode \ref{code:ring} のようなdot ファイルを与えることで、Node の関係を図 \ref{fig:ring} のように構築できる。静的Topology はdot ファイルのNode 数と同等のTopologyNode があって初めて、CodeGear が実行される。

\lstinputlisting[caption=ring.dot, label=code:ring]{src/ring.dot}

\begin{figure}[h] %PDF
\begin{center}
\includegraphics[width=6cm]{fig/ring.pdf}
\caption{Code \ref{code:ring} の図示}
\label{fig:ring}
\end{center}
\end{figure}

\section{プログラムの例}
Code \ref{code:javaSHW} 、Code \ref{code:javaHWC} 、Code \ref{code:javaFHW} はChristie の機能を使用してhello world を出力する例題である。

\lstinputlisting[caption=java StartHelloWorld, label=code:javaSHW]{src/StartHelloWorld.java}
\lstinputlisting[caption=java HelloWorldCodeGear, label=code:javaHWC]{src/HelloWorldCodeGear.java}
\lstinputlisting[caption=java FinishHelloWorld, label=code:javaFHW]{src/FinishHelloWorld.java}

Code \ref{code:javaSHW} ではCGM を作り、setup(new CodeGear) を行うことで各CodeGear に記述されたDataGear の待ち合わせを行う。全てのDataGear が揃った場合にCodeGear が実行される。CodeGearaManager の作成方法はStartCodeGear を継承したものから、createCGM(port) を実行することにより、CGM が作成できる。

Code \ref{code:javaSHW} の11、12行目はput(key, data) を行うことでDGM のqueue にデータを格納することができる。key はstring 型のみで格納したい変数名を指定する。11、12行目のput ではCode \ref{code:javaHWC} のフィールド変数helloWorld を指定し、データは"hello" と"world" を逐次的に格納している。

Code \ref{code:javaHWC} 、Code \ref{code:javaFHW} がCodeGearにあたる。それぞれのフィールド変数には@Take annotation が付いており、DGM に格納されたkey を参照してデータを取得する。その後DataGearManger に格納されたデータは破棄される。

Code \ref{code:javaHWC} では最初にフィールド変数 helloWorld にstring 型の"hello"を取得、print を行い、再びkey hello、data "hello" をDGM にput している。また8行目で自らをsetupしているため、再帰的にHelloWorldCodeGear が再実行される。2回目の実行ではフィールド変数 helloWorld に"world" の格納と出力がされ、key world、data "world" がDGM に格納される。Code \ref{code:javaHWC} でput した"hello" と"world" は最終的に、Code \ref{code:javaFHW} の同名のフィールド変数に格納される。
2回目の実行でもsetup しているが、DGMにはkey helloWorld のデータが無いため、3回目以降は実行されない。

Code \ref{code:javaHWC} の2回の実行後、Code \ref{code:javaHWC} のローカル変数hello とworld が全て揃ったことによりCode \ref{code:javaHWC} が実行されプログラムは終了する。



\section{Christie \#}
Code \ref{code:csSHW}、Code \ref{code:csHWC}、Code \ref{code:csFHW}、はCode \ref{code:javaSHW} 、Code \ref{code:javaHWC} 、Code \ref{code:javaFHW} の例題をC\# に書き換えたものである。

\lstinputlisting[caption=C\# StartHelloWorld, label=code:csSHW]{src/StartHelloWorld.cs}
\lstinputlisting[caption=C\# StartHelloWorld, label=code:csHWC]{src/HelloWorldCodeGear.cs}
\lstinputlisting[caption=C\# StartHelloWorld, label=code:csFHW]{src/FinishHelloWorld.cs}

java とC\# はクラスや変数などの記述方法が似ているため、書き換えの際の大きな変更は少ない。
C\# ではjava のannotation はなく、attribute を利用する。attribute の使用方法はCode \ref{code:csHWC} の5行目のように、attribute を付与したい変数の前に[Take] などつけることで使用可能である。


\section{Unity}
Unity\cite{unity} はUnity Technologies が開発を行っている、ゲームエンジンである。世界で最も使用されているゲームエンジンであり、ゲーム制作に必要な機能が揃っており、個人でもゲーム開発が可能になっている。
主な特徴としては、様々なプラットフォームに対応可能であり、PC、iOS、Androidやその他コンシューマも開発可能である。また非常に軽いことも特徴であり、スペックが低いノートPC でも十分ゲーム開発が可能である。

プログラミング言語はC\# が使用でき、C\# 既存のAPI やUnity 用に拡張されたAPI なども使用可能である。
拡張性も高く、開発に必要な機能を作成しUnityのメニューから実行することも可能である。


\section{Unityでの動作}
Code \ref{code:unityHW}、 Code \ref{code:unitySHW}はCode \ref{code:csSHW}、Code \ref{code:csHWC}、Code \ref{code:csFHW}をUnity 上で動作させるための実装である。

\lstinputlisting[caption=Unity HelloWorld実行クラス, label=code:unityHW]{src/UnityHelloWorld.cs}
\lstinputlisting[caption=Unity StartHelloWorld, label=code:unitySHW]{src/UnityStartHelloWorld.cs}

Unity ではMain 関数が実行されないため、MonoBehaviour を継承してStart 関数を呼び出す必要がある。
2行目のStart はゲーム開始時に1度だけ呼ばれる関数である。

2行目でCGM を生成し、3行目でCode \ref{code:unitySHW} のインスタンスを生成、引数にCGM を渡している。
実行される関数 RunCodeGear はCode \ref{code:csSHW} のMain 関数とほぼ同等の処理である。

\section{Take annotation の実装}
java 版ではDataGear を取得する際に、annotation という java の機能を用いて行った。C\#には annotation はなく、代わりにattribute を利用して DataGear の取得を行っている。
以下のCode \ref{code:javaTake}、Code \ref{code:csTake}はjava とC\# におけるTakeの実装である。

\lstinputlisting[caption=java における Take annotation の実装, label=code:javaTake]{src/Take.java}

\lstinputlisting[caption=C\# における Take attribute の実装, label=code:csTake]{src/Take.cs}

java でannotation を自作する際には、 @interface で宣言する。また、Code \ref{code:javaTake} の2行目ではannotation情報をどの段階まで保持するかを指定しており、Take の場合 JVMによって保存され、ランタイム環境で使用できる。3行目ではannotationの適用可能箇所を指定しており、フィールド変数に対して適応可能となっている。

C\# でattribute を作成する際には、 System.Attributeを継承する必要がある。attribute の適用可能箇所については、Code \ref{code:csTake} の4行目でフィールド変数を指定している。

\section{MessagePackの相違点}
Christie ではデータを送信する際に、MessagePack\cite{mspack} を使用してデータを圧縮し、送信している。java 版で使用しているMessagePack はバージョンが古く現在はサポートされてない。そのためMessagePack の最新版とは記述方法が異なっている。Code \ref{code:javamspackEx} はMessagePack の使用方法を示したものである。

\lstinputlisting[caption=java におけるMessagePack の使用方法, label=code:javamspackEx]{src/MessagePackEx.java}

MessagePack を使用するには圧縮するクラスに対して @Message annotationをつける必要がある。これにより、クラス内で定義したpublic変数が圧縮される。
Code \ref{code:javamspackEx} の17 - 21行目は圧縮解凍の例であり、MessagePackのインスタンスを作成後、msgpack.write(data) を行うことでbyte[] 型にdataを圧縮できる。
解凍にはmsgpack.read を使用し、圧縮されたbyte[] 型と圧縮対象のクラスを渡すことで解凍できる。


C\# のMessagePack は複数存在しており、java と同様な書き方をするMessagePack-CSharp\cite{csmessage} を選択した。

\lstinputlisting[caption=C\# におけるMessagePack の使用方法, label=code:csmspackEx]{src/MessagePackEx.cs}

MessagePack-CSharp ではjava 版と同様にクラスに対して圧縮を行うためCode \ref{code:csmspackEx} の1行目で MessagePackObject attribute を追加している。また、圧縮する変数に対してkey を設定することができ、int やstring を指定することができる。


データの圧縮にはMessagePackSerializer.Serialize (data) を使用し、byte[] 型に圧縮される。解凍にはMessagePackSerializer.Deserialize$<$T$>$(data) を使用する。Deserializeはジェネリスク関数であるため、$<>$内に解凍するデータのクラスを指定する。
Code \ref{code:csmspackEx} の21行目では、変数それぞれにkey を設定していることでjson に展開することが可能である。

 
\section{CodeGear 実行時のThreadPool からTask への変更}
java 版ではCodeGearの実行にThreadPool を使用していた。C\# では書き換えの際にThreadPool よりも高機能なTask で書き換えを行った。

\lstinputlisting[caption=java におけるCodeGear を処理するThreadPool の実装の一部, label=code:javaExecutor]{src/ThreadPoolExecutor.java}

Code \ref{code:javaExecutor} はjava 版におけるCodeGear を実行するThreadPool の実装の一部である。java では独自にThreadPool を作成する際には ThreadPoolExecutor を継承する。また優先度の機構が実装されており、CodeGear 実行時に優先度を決めることが可能になっている。
CodeGearの実行には17行目のexecute を呼び出すことで、実行される。

\lstinputlisting[caption=C\# におけるCodeGear を処理するThreadPool の実装, label=code:csExecutor]{src/ThreadPoolExecutor.cs}

Code \ref{code:csExecutor} はCode \ref{code:javaExecutor} をC\#に書き換えを行ったものである。 
CodeGear の実行には14行目の Execute を呼び出し、Task で実行を行っている。Task はC\# のThreadPool を拡張したもので、内部にThreadPool と実行待ちQueue を持っている。スケジューラーを自作することも可能である。
実装の優先度が低かったため、今回はCodeGear のpriority による実行順変更については実装を行わなかった。

\section{Unity で使用されている通信ライブラリとの比較}
Unityで主に使用されている通信ライブラリにPhoton Unity Networking 2\cite{pun2} (以下PUN2)と、公式サポートされたMLAPI\cite{mlapi} の2つとChristie \# の比較を行う。

PUN2 はUnity でオンラインゲームを作成する際に最もよく使用される通信ライブラリの1つである。Photon Cloud というサービスがあり、自前でサーバを用意せずともサーバを使うことが可能である。サーバクライアント方式であり、TCPで通信を行っている。ネームサーバ、マスターサーバ、ゲームサーバの3つのサーバがあり、Photon Cloud に接続するとネームサーバに入り、接続している地域からマスターサーバが自動で選択される。マスターサーバではマッチメイキングが行われ、完了するとルームが作成されているゲームサーバに転送される。
Unity の実行は各クライアントで行われ、サーバには同期に必要なデータが送信される。また送受信できるデータはUnity 用に適応されており、コードを書かなくても座標であるTransform や物理演算のRigidBody などは同期が可能になっている。


MLAPI はUnity 公式サポートされた通信ライブラリである。こちらもサーバクライアント方式であり、サーバはPUN2 とは異なり自ら立てる必要がある。同期可能なデータはUnityの Transform やAnimation やVector、Ray、QuaternionなどUnity のプリミティブな型である。またRPC が提供されており、attribute をつけるだけでRPC に対応可能である。サーバやクライアントなどの接続先の指定にはIPアドレスなどが必要である。


Christie では送信データをobject 型に変換した上で圧縮、送信を行っている。そのためプリミティブ型、およびユーザーが定義したクラスのインスタンスごとデータを送信することが可能である。
PUN2 やMLAPI などでは開発を行いやすいようにInspector 拡張などが行われており、Christie では未対応な部分があるが、通信の信頼性、特にノードの接続先が直接記述されていない点が優れている。


\section{チート対策について}
オンラインネットワークゲーム開発にはチート対策が必須になっている。チートの種類には、サーバへ送信するデータをクライアント側で改竄を行うもの、メモリ上の値を書き換えるものなど多岐にわたる。

通常のオンラインゲームでのチート対策としては、クライアントをモニタリングする、ダメージ計算などを全てサーバ側で処理する、ゲームをプレイしている他のプレイヤーからの通報などがある。
しかし、チート開発とチート対策はいたちごっこになっているというのが現状である。

Christie では従来の通信ライブラリとは異なり、型があるDataGear をタプル空間であるDGM にkey を持つストリームとして格納する方式をとっている。他のノードとの通信にはDGM のproxy に書き込むことで可能としており、DGM の構成にはTopology Manager が自動的に構成される。そのためクライアントはどこに接続を行っているかを直接知ることなく、IPアドレスなどの余計な情報なしに通信が可能となっている(図 \ref{fig:anticheat})。


\begin{figure}[h] %PDF
\begin{center}
\includegraphics[width=9cm]{fig/AntiCheat.pdf}
\caption{label を使用したデータ通信}
\label{fig:anticheat}
\end{center}
\end{figure}


\section{実装の現状}
今回、Local DGM を使用してUnity 上でデータ通信を行うことができた。

Socket とMessagePack を用いた通信に関しては書き換え途中であり、Topology Manager を使用した通信に関しても今後書き換えを行なっていく予定である。

書き換えの予定としては、上記の2つに加え、Christie の他の例題、Alice からChristie に書き換えた際に書き換えが行われなかった機能や例題の洗い出しを行なっていく。

Unity ではChristie の検証として FPS を作成する予定である。

\nocite{*}
\bibliographystyle{ipsjunsrt}
\bibliography{riono-sigos}



\end{document}