Mercurial > hg > Papers > 2022 > riono-master
annotate Paper/chapter/2-RewriteCS.tex @ 51:9d71ffda7d97
update
author | riono <e165729@ie.u-ryukyu.ac.jp> |
---|---|
date | Thu, 10 Feb 2022 19:08:25 +0900 |
parents | 1402268d1eca |
children | ea7e856b50e8 |
rev | line source |
---|---|
51 | 1 \chapter{ChristieのUnityへの適応} |
18 | 2 |
3 \section{Unity} | |
51 | 4 Unity\cite{unity}はUnity Technologiesが開発、公開しているゲームエンジンである。 |
18 | 5 画像や3Dモデルの表示、物理演算、UIのイベント機能などゲーム制作に必要な機能が標準で備わっており、 |
6 個人でもゲーム開発が可能となっている。 | |
7 さまざまなプラットフォームに対応可能であり、PC、iOS、Androidやその他コンシューマ機器も開発可能である。 | |
8 また、非常に動作が軽いことも特徴であり、スペックが低いノートPCでも十分ゲーム開発が可能である。 | |
9 | |
10 プログラミング言語としてはC\#がサポートされている。 | |
11 最新バージョンである2021.2.8ではC\# 9がサポートされており、 | |
12 .NET Frameworkはバージョン4.6に対応している。 | |
13 C\#向けの既存のAPIや外部ライブラリ、Unity用に開発されたAPIなども使用可能である。 | |
14 拡張性が高く、開発に必要な機能を作成しUnityのメニューから実行することも可能である。 | |
15 | |
16 | |
17 本研究では、開発環境を整えるためのハードルの低さ、公開されている通信ライブラリの豊富さなどを考慮しUnityを採用した。 | |
39 | 18 %Unity上でChristieを動作させるために、Javaで記述されているChristieをC\#に書き換えを行う。 |
19 | |
20 | |
21 \section{Photon Unity Networking 2} | |
51 | 22 Photon Unity Networking 2\cite{pun2}(以下PUN2)はUnityで利用可能なネットワークライブラリである。 |
39 | 23 自動で他のClientへの接続や同期を可能とし、マッチメイキング機能なども備わっている。 |
24 | |
25 \begin{figure}[htb] | |
26 \begin{center} | |
40 | 27 \includegraphics[width=115mm]{images/PUN2Connection.pdf} |
39 | 28 \end{center} |
29 \caption{PUN2のServer接続} | |
30 \label{fig:PUN2serverconnect} | |
31 \end{figure} | |
32 | |
33 | |
34 | |
35 図\ref{fig:PUN2serverconnect}はPUN2でのGame Serverまでの接続の過程を表した図である。 | |
36 PUN2ではサーバクライアント型の通信を行っており、Photon CloudというCloud Serverに接続することで通信を可能にしている。 | |
37 ClientはPhoton Cloudに接続を行うと、始めにName Serverに接続される。 | |
38 Name Serverでは、そのClientが利用可能なリージョンを提供し、最低PingのMaster Serverへの接続が自動で行われる。 | |
39 Master Serverでは、ゲーム全体における接続しているプレイヤーや、作成されているルーム情報などの監視を行っている。 | |
40 マッチメイキングや、新しいRoomの作成、参加などが可能である。 | |
41 各リージョンのMaster Serverは完全に分離しており、マッチメイキングはそれぞれのMaster Serverでのみ可能である。 | |
42 Game Serverでは、Master Serverで作成された各ルームの管理が行われおり、実際にClient同士の通信を行ってゲームプレイを可能としているのはGame Serverである。 | |
43 | |
44 % 開発面でのできること アタッチするだけとか | |
45 % 制限面 20mucみたいな 500messageとか | |
46 % ネット環境がないとlocal通信すらできない | |
47 | |
48 開発面においてはUnity API対応がされており、座標や回転データなどを持っているTransform、アニメーション、 | |
49 物理演算のRigidbodyの同期にはコードを書かずに用意されているScriptをGameObjectにAttatchするだけで同期可能となっている。 | |
50 | |
51 \lstinputlisting[label=src:Pun2Example, caption=PUN2の使用例]{src/Library/Pun2Example.cs} | |
52 | |
53 ソースコード\ref{src:Pun2Example}は、PUN2でServerに接続を行いゲーム内にプレイヤーを生成する例である。 | |
54 Callbackの使用にはMonoBehaviourPunCallbacksを継承する必要があり、MonoBehaviourPunCallbacksにはUnityのMonoBehaviourを継承しているため、 | |
55 Startメソッドなどが使用可能である。 | |
56 Startメソッドでは、事前に設定したName ServerおよびMaster Serverへの接続を行っている。 | |
57 OnConnectedToMasterメソッドはMaster Serverへ接続した際に呼ばれ、Roomへ加入を試しなければ作成を行い、 | |
58 OnJoinedRoomメソッドではGameServerにあるRoomに加入後に呼ばれ、プレイヤーの生成を行っている。 | |
59 このようにPUN2では各Serverへの接続/切断時のコールバックが豊富に用意されており、柔軟に処理を記述することが可能である。 | |
60 | |
61 しかし開発時に検証を行う際にLocalマシンで通信を行う場合などでも、Photon Cloudへの接続が必須となる。 | |
62 そのためネット環境がなければLocal通信でもPUN2を利用した通信はできない。 | |
63 | |
64 | |
65 PUN2の基本料金は無料であるが、使用上の注意としていくつかの制限がある。 | |
66 \begin{itemize} | |
67 \item 同時接続人数が20人以下 | |
68 \item 1Roomの秒間Message数が500以下 | |
69 \item データの転送量が60GB以下 | |
70 \item etc ... | |
71 \end{itemize} | |
72 | |
73 これらの制限を超えて利用する場合には、別途料金や有料プランに加入する必要が発生する。 | |
74 | |
75 | |
40 | 76 |
39 | 77 \section{Mirror} |
51 | 78 Mirror\cite{mirror}はUnityで使用できるOSSのネットワークライブラリである。 |
39 | 79 PUN2と同様にPC間の同期を自動で行い、主にMMO規模のネットワークを想定して開発が行われている。 |
80 主な機能として、ServerとClientを自動接続するScript、GameObjectの位置やアニメーションの同期を行うNetworkTransfromやNetworkAnimator、 | |
81 Room機能などがある。 | |
82 | |
83 \begin{figure}[htb] | |
84 \begin{center} | |
85 \includegraphics[width=140mm]{images/MirrorConnection.pdf} | |
86 \end{center} | |
87 \caption{Mirrorの接続} | |
88 \label{fig:Mirrorconnect} | |
89 \end{figure} | |
90 | |
91 | |
92 図\ref{fig:Mirrorconnect}はServerとClientの接続を表したものである。 | |
93 Mirrorはサーバクライアント型の通信が行われている。 | |
94 HostではServerと同時にLocal Clientが立ち上がる。 | |
95 他のClinetはServerに接続を行うことで同期が可能となる。 | |
96 ClinetはServerに対して操作やデータを送信し、Serverでの処理がClientに同期され反映される仕組みになっている。 | |
97 | |
40 | 98 \newpage |
39 | 99 |
100 \lstinputlisting[label=src:MirrorExample, caption=Mirrorの使用例]{src/Library/MirrorExample.cs} | |
101 | |
102 ソースコード\ref{src:MirrorExample}はMirrorを使用して、プレイヤーを表示、操作する例である。 | |
103 NetworkBehaviourはMonoBehaviorを継承して作成されており、ネットワーク上で動作させる処理に継承させる必要がある。 | |
40 | 104 OnStertServerメソッドはServerでこのGameObjectが生成された際に実行される。 |
105 このような様々なcallbackがNetworkBehaviourには用意されている。 | |
106 また、フィールド変数にSyncVar attributeを付与することで自動的に変数を同期可能にしている。 | |
107 SyncVar attributeによってサポートされている型はC\#のプリミティブ型やstring、Unity APIから提供されているVector3やQuaternion、 | |
108 Mirrorから提供されているSyncListやSyncDictなどのリストや辞書である。 | |
109 | |
39 | 110 10行目のCommand attributeを関数に付与することで、ClientがServerに対してこの関数を呼び出すことが可能になる。 |
111 Server側で処理が行われ、その結果の状態がClientへ同期される。 | |
112 | |
40 | 113 |
114 Mirrorには上記のような通信フレームワークとして便利な機能が用意されており、OSSなためプロジェクトに合わせて自由に機能の拡張が可能である。 | |
115 一方で公式Serverなどのサービスが用意されていないため、自前でServerを用意する必要がある。 | |
116 そのため、LAN上で通信を行う場合には特に問題ないが、インターネット上に公開を手軽に行うことができない。 | |
117 | |
39 | 118 |
119 \section{ChristieをC\#に書き換える意義} | |
43 | 120 ChristieはJavaで実装されているが、Unity開発は基本的にC\#が使用される。 |
121 ここで、ChrsiteをJavaのまま利用するか、C\#に書き換えるかという疑問が生じた。 | |
39 | 122 |
43 | 123 Unityはandroidの開発向けにJavaで書かれたメソッドをC\#で呼び出せる機能がある。 |
124 JavaやJava VMを呼び出すためにJava Native Interface(JNI)を利用している。 | |
125 C\#側でJavaを呼び出すには、Unity APIが提供しているヘルパークラスを呼び出す必要があるが、stringを使用してリソースディレクトリから検索を行っているため、 | |
126 計算負荷が高い。 | |
127 そのため、ChristieをJavaから呼び出して使用するには不適合であると考える。 | |
39 | 128 |
43 | 129 また、C\#に書き換えた際にバージョン管理の問題がある。 |
130 書き換えを行ったとして、ChristieにはJavaとC\#の2種類あることになり、機能の実装などそれぞれに対応する必要がある。 | |
131 しかしJavaとC\#それぞれの対応はそこまで難しくないと考える。 | |
132 Javaの記法とC\#の記法は非常によく似ており、APIもほとんど同じ機能を持ったものがそれぞれ実装されている。 | |
133 そのため、Chrisiteに機能追加をする際にはJavaとC\#両方に対応することでバージョン間のすり合わせを行えると考える。 | |
134 | |
135 以上の理由により、ChristieをUnityでサポートされているC\#への書き換えを行う意義を見いだすことができた。 | |
39 | 136 |
18 | 137 |
138 \section{Christie Sharpの書き換えの基本方針} | |
139 Javaで記述されたChristieと区別するため、C\#で記述するChristieをChrisite Sharpとする。 | |
140 Chrisite Sharpではコードの保守性や、Christie設計時の意図などを守るため、Chrisiteと同じ挙動、同じ動作をする必要がある。 | |
141 初めにC\#単体で動作するように、Christieの核となる部分の書き換えを行った。 | |
142 | |
143 | |
144 ChristieはJava 9から開発されていたため、現在では非推奨なコードやバージョンアップが必要な箇所が存在する。 | |
145 そこで書き換えを行う際に、C\#に対応しつつ処理動作の向上や最適化を行うために以下の改良を行った。 | |
146 | |
147 \begin{itemize} | |
148 \item MessagePackの変更及びバージョンアップ | |
149 \item ThreadPoolからTaskへの変更 | |
150 \end{itemize} | |
151 | |
152 | |
153 \section{attributeの実装} | |
154 ChristieではDGを取得する際に、annotationを用いてTakeやPeekなどのコマンドを処理していた。 | |
155 Christie Sharpはannotationではなく、代わりにattributeを利用してコマンドの処理を行っている。 | |
156 | |
20 | 157 \lstinputlisting[label=src:JavaTakeImple, caption=JavaにおけるTake annotationの実装]{src/java/Take.java} |
158 \lstinputlisting[label=src:CSTakeImple, caption=C\#におけるTake attributeの実装]{src/cs/Take.cs} | |
18 | 159 |
160 ソースコード\ref{src:JavaTakeImple}はJavaにおけるTake annotationの実装である。 | |
161 Javaでannotationを自作する際には、\@interfaceで宣言を行う。 | |
162 1行目ではannotationの適用可能箇所を指定しておりフィールド変数に対して付与可能としている。 | |
163 また、2行目はannotationの情報をどの段階まで保持するかを指定しており、Takeの場合JVMによって保存され、ランタイム環境で使用可能となっている。 | |
164 | |
165 ソースコード\ref{src:CSTakeImple}はC\#におけるTake attributeの実装である。 | |
166 C\#でattributeを自作する際には、System.Attributeを継承する必要がある。 | |
167 attributeの適用可能箇所については、1行目にてフィールド変数を指定している。 | |
168 | |
20 | 169 |
170 attributeの使用方法はannotationと同じく変数の宣言の前に、[ ]内に使用するattributeを宣言する(ソースコード\ref{src:CSTakeExample})。 | |
171 | |
172 \lstinputlisting[label=src:CSTakeExample, caption=Take attributeの例]{src/cs/TakeExample.cs} | |
173 | |
18 | 174 |
175 | |
20 | 176 \section{TaskによるCodeGearの処理} |
177 ChrisiteではCGの実行にThreadPoolを利用していた。 | |
178 しかしThreadPoolは管理や生成が煩雑であり、コストパフォーマンスの低下につながりやすい。 | |
179 C\#にはThreadをより使いやすく高機能にしたTaskという機能がある。 | |
180 TaskはC\#のThreadPoolを拡張しており、内部にThreadPoolと実行待ちQueueを持っている。 | |
181 Task.RunメソッドやTask.Factory.StartNewメソッドで処理を実行でき、処理が渡されるとThreadPoolで処理されるため、Christieと同じ動作をすると考え、Christie SharpではTaskで書き換えを行った。 | |
182 | |
183 \lstinputlisting[label=src:JavaThreadPoolExecutor, caption=ChristieにおけるThreadPoolの実装の一部]{src/java/ThreadPoolExecutor.java} | |
184 | |
185 ソースコード\ref{src:JavaThreadPoolExecutor}はChristieにおけるCodeGearを処理するThreadPoolの実装の一部である。 | |
186 Javaでは独自にThreadPoolを実装する際にはThreadPoolExecutorを継承する。 | |
187 またThreadの優先度を変更する機能が実装されており、CodeGear実行時に処理の優先度を設定することが可能となっている。 | |
18 | 188 |
20 | 189 |
190 \lstinputlisting[label=src:CSThreadPoolExecutor, caption=Christie SharpにおけるThreadPoolの実装]{src/cs/ThreadPoolExecutor.cs} | |
191 | |
192 ソースコード\ref{src:CSThreadPoolExecutor}はソースコード\ref{src:JavaThreadPoolExecutor}をC\#に書き換えを行ったものである。 | |
193 CGの実行には14行目のExecuteを呼び出し、Taskで実行を行っている。 | |
194 | |
195 | |
196 Threadの優先度による実行順変更については、実装の優先度が低かったため今回は実装を行っていない。 | |
197 Taskのスケジューラーは自作可能であり、実行待ちQueueの処理順を変更することができるため実装可能である。 | |
198 | |
199 | |
200 \section{Socket通信用のThreadをTaskに変更} | |
27 | 201 Christieでは、Socket通信を行っている箇所もThreadを使用したMultiThreadで動作している。 |
21
866f4329e430
title fix and add Continuation section
riono <e165729@ie.u-ryukyu.ac.jp>
parents:
20
diff
changeset
|
202 こちらも可読性や保守性のためTaskへの書き換えを行った。 |
866f4329e430
title fix and add Continuation section
riono <e165729@ie.u-ryukyu.ac.jp>
parents:
20
diff
changeset
|
203 |
866f4329e430
title fix and add Continuation section
riono <e165729@ie.u-ryukyu.ac.jp>
parents:
20
diff
changeset
|
204 \lstinputlisting[label=src:JavaAcceptThread, caption=ChristieにおけるAcceptThreadの実装の一部]{src/java/AcceptThread.java} |
866f4329e430
title fix and add Continuation section
riono <e165729@ie.u-ryukyu.ac.jp>
parents:
20
diff
changeset
|
205 |
866f4329e430
title fix and add Continuation section
riono <e165729@ie.u-ryukyu.ac.jp>
parents:
20
diff
changeset
|
206 ソースコード\ref{src:JavaAcceptThread}はChristieにおけるSocket通信を行っているThreadの実行箇所である。 |
866f4329e430
title fix and add Continuation section
riono <e165729@ie.u-ryukyu.ac.jp>
parents:
20
diff
changeset
|
207 無限ループを行い、他nodeがSocketで接続される度にデータ送受信専用のThreadを作成する。 |
27 | 208 IncomingTCPConnectionではデータの受け取りを行っており、OutboundTCPConnectionではSocket通信が終了する際のコマンドの送信をそれぞれMultiThreadで行っている。 |
21
866f4329e430
title fix and add Continuation section
riono <e165729@ie.u-ryukyu.ac.jp>
parents:
20
diff
changeset
|
209 |
866f4329e430
title fix and add Continuation section
riono <e165729@ie.u-ryukyu.ac.jp>
parents:
20
diff
changeset
|
210 \lstinputlisting[label=src:CSAcceptThread, caption=Christie SharpにおけるAcceptThreadの実装の一部]{src/cs/AcceptThread.cs} |
866f4329e430
title fix and add Continuation section
riono <e165729@ie.u-ryukyu.ac.jp>
parents:
20
diff
changeset
|
211 |
866f4329e430
title fix and add Continuation section
riono <e165729@ie.u-ryukyu.ac.jp>
parents:
20
diff
changeset
|
212 ソースコード\ref{src:CSAcceptThread}はソースコード\ref{src:JavaAcceptThread}をC\#に書き換えを行ったものである。 |
27 | 213 Christieでは、MultiThreadでSocket通信を行っていた。 |
23 | 214 Christie SharpではCodeGearの処理で使用していたThreadPoolと同様にTaskへの書き換えを行った。 |
18 | 215 |
216 \section{MessagePackの変更} | |
25 | 217 Christieではデータを他Nodeに送信する際に、MessagePackを使用してデータをSerializeし、送信を行っている。 |
51 | 218 Chrisiteで使用しているMessagePackはmsgpack java 0.6.12\cite{mspack}を使用しており、現在はサポートされていない。 |
23 | 219 そのためJavaでサポート対象となっているmsgpack java 0.7.x以上のMEssagePakckとは記述方法が異なっている。 |
220 ソースコード\ref{src:JavaMspackExample}はChristieで使用してるmsgpack java 0.6.12の使用例である。 | |
18 | 221 |
23 | 222 \lstinputlisting[label=src:JavaMspackExample, caption=JavaにおけるMessagePackの使用例]{src/java/MessagePackExample.java} |
223 | |
25 | 224 MessagePackを使用するには、Serializeを行うクラスに対して明示的に@Message annotationを付ける必要がある。 |
225 これにより、クラス内で宣言したpublic変数がエンコードの対象となる。 | |
226 ソースコード\ref{src:JavaMspackExample}の14 - 18行目はSerialize/Deserializeを行う例である。 | |
227 MessagePackインスタンスを作成後、writeメソッドを使用することで引数に渡したオブジェクトをbyte[]型にSerializeできる。 | |
228 Deserializeにはreadメソッドを使用し、引数としてSerializeされたbyte[]型とDeserialize対象のクラスを渡すことでデコードできる。 | |
23 | 229 |
230 | |
51 | 231 C\#のMessagePackは複数存在しており、msgpack java 0.6.12とほぼ同様の記述方法を採っているMessagePack CSharp 2.3.85\cite{csmessage}を選択した。 |
23 | 232 |
233 | |
234 \lstinputlisting[label=src:CSMspackExample, caption=C\#におけるMessagePackの使用例]{src/cs/MessagePackExample.cs} | |
30
2a9f335e45bd
add source code and update Unity chapter
riono <e165729@ie.u-ryukyu.ac.jp>
parents:
27
diff
changeset
|
235 MessagePack CSharpではmsgpack javaと同様にクラスに対してSerializeを行うため、\ref{src:CSMspackExample}の1行目でMessagePackObject attributeを追加している。 |
25 | 236 また、Serializeする変数に対してkeyを設定することができ、indexesとしてのintやstringをkeyとして指定することができる。 |
23 | 237 |
25 | 238 データのSerializeにはMessagePackSerializer.Serializeメソッドを使用し、引数として渡したオブジェクトをbyte[]型にSerializeする。 |
30
2a9f335e45bd
add source code and update Unity chapter
riono <e165729@ie.u-ryukyu.ac.jp>
parents:
27
diff
changeset
|
239 DeserializeにはMessagePackSerializer.Deserializeメソッドを使用する。Deserializeメソッドはジェネリスク関数であるため、$<>$内にDeserialize対象のクラスを指定する。 |
23 | 240 ソースコード\ref{src:CSMspackExample}の22行目ではjson展開の例であり、変数それぞれにkeyを指定していることで展開可能となっている。 |
18 | 241 |
25 | 242 \section{送信パケットの修正} |
243 MessagePackのバージョンを更新した影響により、Remote nodeにデータを送信するパケットの形式を変更する必要がある。 | |
244 図\ref{fig:SendPackt}はChristieと、Chrisite Sharpにおける送信パケットの構成である。 | |
245 msgpack javaではreadメソッドの引数にClass$<$T$>$を渡すことでデコード可能であり、RemoteMessageのDeserializeにデータ長を指定する必要はない。 | |
246 DGはジェネリスクで記述しており毎回デコードするクラスが異なるため、デコードの際にデータ長を必要としている。 | |
18 | 247 |
21
866f4329e430
title fix and add Continuation section
riono <e165729@ie.u-ryukyu.ac.jp>
parents:
20
diff
changeset
|
248 |
25 | 249 しかしMessagePack CSharpでは、DeserializeメソッドにClass$<$T$>$を渡してデコードすることができないため、データ長も付属させてデータを送信する。 |
250 それぞれのSizeのデータ長はintで指定しているが、MessagePackでSerializeした際に最大で5byteになる。 | |
21
866f4329e430
title fix and add Continuation section
riono <e165729@ie.u-ryukyu.ac.jp>
parents:
20
diff
changeset
|
251 |
25 | 252 \begin{figure}[htb] |
253 \begin{center} | |
254 \includegraphics[width=150mm]{images/SendPackt.pdf} | |
255 \end{center} | |
256 \caption{送信パケットの構成} | |
257 \label{fig:SendPackt} | |
26 | 258 \end{figure} |
259 | |
260 | |
261 | |
262 \section{Chrisite SharpのDebug} | |
51 | 263 Christie Sharpの開発にはJetBrainsが開発・提供しているC\#向けのIDE、Rider\cite{rider}を用いている。 |
27 | 264 Christie Sharpは並列分散プログラミングを行っているため、MultiThreadでのDebugが必須である。 |
265 RiderにはDebugerの標準的な機能が搭載されているが、Christie Shapを開発する際、MainThread以外で処理をする箇所に対して張ったBreak point | |
266 でプロセスが停止しない状況に陥った。 | |
267 解決方法がないか調査を行ったが原因は不明であり、MainThreadにBreak pointを張った場合には正しく停止するのに対し、 | |
268 MultiThreadにBreak pointを張った際には停止できないと言うことがわかった。 | |
269 そのため非効率ではあるが、Debugを行いたい処理の箇所にPrint文を挟むことでDebugを行った。 | |
26 | 270 |
43 | 271 |
272 \section{Christie Sharpの記述方法} | |
273 ソースコード\ref{src:CSStartCGExample}、\ref{src:CSCGExample}、\ref{src:CSCountExample}はソースコード\ref{src:StartCGExample}、\ref{src:CGExample}、\ref{src:CounteObj}をChrisite Sharpで書き換えたものである。 | |
274 JavaとC\#は大きく記述方法は変わらず、annotationがattributeになっている点が一番の違いである。 | |
275 そのためChristieとChrisite Sharptには互換性があると言える。 | |
276 | |
277 \lstinputlisting[label=src:CSStartCGExample, caption=Chrisite SharpにおけるStartCodeGearの記述例]{src/cs/StartCountUp.cs} | |
278 \lstinputlisting[label=src:CSCGExample, caption=Chrisite SharpにおけるCodeGearの記述例]{src/cs/CountUpper.cs} | |
279 \lstinputlisting[label=src:CSCountExample, caption=Chrisite SharpにおけるDGとして送信されるオブジェクトのクラス]{src/cs/CountObject.cs} |