月曜日, 11月 02, 2009

Tokyo Railways コンピュータ版のバグ修正

 昨日と今日は「Tokyo Railways コンピュータ版」の障害修正を集中的にやってます。特に今日は、先日にpumpCurryさんがたくさん報告してくれた件をまとめて直していて、コメントにあった2、3、4、8、9をつぶしました。
 この中で一番苦労したのが3番。コメントにあった「保存後読み込み直した時「プレイヤーさんの番です」と出たあと、なにかのはずみでフェイズが1つ進む時があります」というやつです。これは最初は「プレイヤーさんの番です」というダイアログの閉じるボタンのクリックイベントが2回以上入っておきているのだと思ったが、実は違っていた。ダイアログボタンの閉じるボタンのクリックイベントでは、ダイアログを閉じる以上のことは何一つやってなかった。連打はこの問題を引き起こす状態を作り出しやすいが、かならずしもボタンの連打とは関係ない現象だった。
 データをロードしたときの処理は、実は通常のセーブデータと自動セーブデータではちょっとだけ違っている。
 通常のセーブは移動フェイズか建設フェイズで行われるが、自動セーブデータはターン終了フェイズというタイミングでやっている。通常セーブしたデータをロードすると、セーブしたときのフェイズの初期処理をやってから、途中の状態の操作を再実行している。だが自動セーブデータの場合、通常セーブの処理の前にターン終了フェイズを完了させてターンを進行させている。問題の核心は、フェイズの初期処理とフェイズの終了処理はいずれもロード処理とは別のスレッドを作成して実行している点にあった。
 つまり、自動セーブデータのロード処理では以下の2つのスレッドを順番に実行している。
  (1)ターン終了フェイズの終了処理スレッドの生成・実行
  (2)現在のフェイズの初期処理スレッドの生成・実行
 この中で(1)のスレッドは非常に処理が短く終わり、(1)と(2)の間の処理は少しだけ重たい処理なので、通常ならば(2)が始まる前に(1)が終わる。つまり(1)のターン終了処理で次のターンに進んで、次のターンプレイヤーの移動処理の初期処理が走る。
 ところが、何らかの理由で(1)で生成されたスレッドが実行される前に(2)が始まってしまう場合がある。その場合には、(2)の現在のフェイズがまだターン終了フェイズのままだったりする。このとき、ターン終了フェイズの初期処理はもう一度データの自動セーブを行った後、そのまま現在のフェイズの終了処理を行ってしまう。そうすると、フェイズ終了処理が2回行われ、2度目の処理の時にはすでに移動フェイズに進んでいて、移動フェイズの終了処理が走ってしまっていた。
 この現象を起こす何らかの理由としては、沢山のスレッドを生成・実行している時というのが一番考えられるが、実はマウスクリック処理は、仕組上、クリックのたびにスレッドを生成・実行している。だからマウスクリックを連打すると沢山のスレッドが生成されてその順番待ちが発生し、(1)で生成されたスレッドの実行が遅れて、(2)に先に到達してしまうのだと思う。
 この現象はCPUコア数が少なければ発生しやすく、シングルコアのPCが一番発生しやすいと思うのだが、実は開発やテスト環境のPCはすべて2つ以上のコアをつんでたりする。だから私が発見できなかったのだと思う。
 で、対策なのだが、実は自動セーブデータのロードの際には(1)の処理は必要なのだが、(2)はいらなかったのだ。だから(2)をスキップすればそれで解決。要するに自動セーブデータと通常セーブデータで条件をきりか分けて処理を分けていたのだが、ちゃんと切り分けきれてなかったというだけの問題だった。それが、こんなスレッドがらみの面倒な不具合につながっていたとはちょっと最初はわからなかった。

 なにはともあれ、解決できてよかった。この問題を報告してくれたpumpCurry様に改めて感謝します。

 

3 件のコメント:

pumpCurry さんのコメント...

たびたび申し訳ないです...

10.相模原マップの青山の矢印が左右逆

11.起動時背景画像の2倍以上にウインドウサイズを大きくすると、白いエリアにメニューが表示されてどうすることもできなくなる :D

12.自分の移動フェイス終了後、建設フェイズ前にイベントが発生したのにも関わらず、イベント発生後即保存して再度読み込むと、1プレイヤー分か、または1フェイズ前で発生したことになって自分の移動フェイズまでイベントが持たないことがある(ちょっと詳しく調べて再報告しますです)

s-jima さんのコメント...

pumpCurry様、いつもありがとうございます。
10の件ですが、すぐに対応して追加マップの最新版をリリースします。
複数人で数えきれないほどテストプレーしているのに、意外と気がつかないものですねえ・・・

11の件、確認しました。開発環境では簡単に対策できたので、次のバージョンで修正版をリリースします。
 できれば起動画面のウィンドウサイズは変えてほしくないけど、サイズを変えられなくするのはなんとなく嫌なのですよねえ。1600x1600くらいの解像度があれば、理論上は起動画面以外でも同様の問題は起きるわけなので、ちゃんと対応します。

12の件ですが、こちらでも調べてみますが、pumpCurryさんの方で何か分かったら、続報をお願いします。

いつもいつも、ご報告感謝します。

s-jima さんのコメント...

12.の件、現象を確認しました。
単純なバグでした・・・
発生中のイベントはセーブデータ内の"activeevent"というタグの"turnplayer"という属性値で発生プレイヤーを保存しているのですが、これを読み取るプログラムでは"turnPlayer"になってました("p"と"P"の違い)。
この結果として、発生中イベントをロードするとイベント発生プレイヤーが正しく読み込まれず、ターンの第1プレイヤーになってしまいます。
これはちょっと痛い不具合ですねえ・・・なんで今まで気がつかなかったのか。