日数かけすぎたけど、設定ファイルに関数のシンボル情報を書かないようにする対応できた。
*
その変更に対応するように、sucroseとかへびゲームとかを修正すれば完了。
次はパッケージパスを利用してパッケージ内のファイルにアクセス、という本来やるべきだった作業に戻ろう。
モジュール初期化時に情報を引数で渡すのはできた。
*
ちょっと考えていたが、ゲームとベースシステムの情報を独立させているのはそのままでよかった。
モジュール内に記述してしまうと、ショートカットファイルに記述する際にもモジュール名が必要になり、よくない。
もう一方の関数のシンボル情報に関しては、予定通り進めよう。
ひとまずテストの作成から。
*
何を焦っていたのか知らないが、テストも作らずに始めようとしていた。
なので、ひとまずテストを作った。
明日にはそのテストを通す処理を実装するとしよう。
久しぶり。
*
まだ体調は不完全だが、今日無理しなければ明日には万全になるだろう。
*
今更ながら、パッケージ情報ファイルの構成がおかしい気がする。
おかしい点は2つ。
1つは、パッケージ内のゲームとベースシステムの情報を独立させていること。
まとめてあることで、見た目は分かりやすいが処理はしにくかった。
それがどのモジュールに入っているのかという情報があるが、そもそもモジュール情報内に書いておけば済むことだ。
もう1つは、ゲームやベースシステムの情報に関数のシンボル情報を含めていること。
設定ファイルに記述する情報としては、ちょっと低レイヤーすぎる。
設定ファイルには関数のシンボル情報を含めない形にした方がいいかもしれない。
*
ちなみに、モジュール初期化時に渡すパッケージ情報に関するどうのこうの、もまだ終わっていない。
正直、渡す内容についても再度検討するべきではと考えている。
いっそ、パッケージ情報ファイルの中身も渡してしまった方が分かりやすいような。
ひどくやる気が出ない。
*
しかし、このままではまずいので直近でやるべきことをリストアップし、とりあえずfgに関数の宣言を追加した。
明日はcandymakerにその関数の実装を追加するのをやろう。
軽く熱が出ている。
*
最近気温の変化が激しいので、それにやられたのかもしれない。
作業しようにも頭が痛くてうまく思考がまとまらない。
とりあえずいくつかファイルを追加したが。
*
モジュール初期化時に渡すパッケージ情報に関する型を追加して、関数も追加しようと思ったけど、手順違うかも。
パッケージ情報に含む情報として、パッケージディレクトリのパスがあるが、これもただの文字列とかでなく型を作る予定。
なので、そっちの方を先にやるべきだろうな。
やる気が出ない。
*
とりあえず、関数の仕様だけまとめるプロジェクトとしてfgを作った。
過去に作ったプロジェクトと同じ名前。
ここに最初に追加するものは、やはりcandymaker内で使用する関数や構造体の宣言だろうな。
sucroseのものについても宣言を追加するけど、量が多いし今やったら絶対だれる。
そういうのは後回し。
cmmainの記述を整えて、candymakerも試しにライブラリ化して動作するところまで確認。
*
関数の仕様だけまとめたプロジェクトも必要な気がしてきている。
今のままでは、モジュール初期化時にファイル読み込みをするためだけに、candymakerのヘッダファイルを読み込む必要があるし。
コアライブラリのダミーを作って、それをロードし、関数が呼び出されるところまで確認。
*
cmmainはとりあえずこんなところだろうな。
明日からcandymakerの方を修正していく。
やる気絶不調。
*
とりあえず、cmmainとかいうプロジェクトを作った。
あともう少しでコアライブラリのロードまでできる。
昨日の時点で実験は済んでいる。
*
今日から作業に入ろうとしたのだけど、どのように構成するのが最適なのか、色々考えていた。
まず、candymakerのほぼ全てをライブラリ化したものとそれを読み込むメインプログラムは、別のプロジェクトにするべきなのか?
前者はモジュール側から参照されることはあるが、後者にはそれがないため、分けるべきかもしれない。
しかし、その場合双方の名前はどうしよう。
そもそもcandymakerとかいう名前、あんまかっこよくないし別のに変えたい気もする。
名前空間がcandymakerだとなかなか長いので、もうちょい短めので。
*
少し考えたが、プロジェクトの分割はやろう。
メインプログラムの方は、一度作ったら多分ほぼ修正しない感じになりそう。
コアライブラリのロードと、メイン関数の呼び出しくらいしかやることないし。
確実にやる気落ちてる。
*
方針変更。昨日のはなし。
candymakerのほぼ全てを共有ライブラリ化する。
これにより、モジュールからcandymakerの関数を参照可能にする。
*
こっちの方が、昨日の案よりずっと現実的だと思う。
そういった構成が可能なのか、簡単なコードで実験しなければと思うのだが、まだやってない。
明日にはやってしまう予定。
思ったよりも大規模な変更が必要になりそう。
*
モジュールロード時の初期化関数に渡すデータは、仮にパッケージコンテキストと呼称することにした。
このパッケージコンテキストは、ゲームの初期化関数にも引数として渡す。
そうしないと、ゲーム内からパッケージのファイルにアクセスする場合に、必ずモジュール初期化関数を用意しなければならず、面倒だ。
*
と、そこまではいい。
問題は、モジュールのロードを行うcandymakerで生成したデータの内部に、モジュール側からどうやってアクセスするのか、ということだ。
パッケージコンテキストの仕様は後々変更することはもちろんあると思うので、メンバを直接アクセスするなんてのは現実的ではない。
ではパッケージコンテキストに関するモジュールを作って、ってやるとそのモジュール初期化時にパッケージコンテキストを渡せないではないか。
*
現在の構成として、candymakerは完全に独立している。
ゲームやベースシステムは、candymakerが一方的にモジュールをロードし、関数を呼び出すだけであって、その呼び出された関数の中からcandymaker内のデータにアクセスするような仕組みを作っていない。
なので、その仕組みを作る必要が出てきたな、という感じ。
具体的には、candymaker内のデータにアクセスするための、ラッパーのようなモジュールを作ろうと思う。
モジュールロード後に、ラッパーモジュール内に用意した初期化関数を呼び出し、candymaker内の関数にアクセスできるようにする。
パッケージコンテキスト内のデータを参照するには、ラッパーモジュールの関数を呼び出し、その関数を経由してcandymaker内の関数にアクセス、データを参照する、といった流れ。
*
さて、そんなに都合よくできるかどうか。
パッケージ内のファイル読み込み方法考え中。
*
ゲーム内で使うテクスチャであれば、BaseContextにパッケージのパスを追加しておけばいいかー、と思ったけど違う気がする。
BaseContextは、読み込んだモジュールすべての関数が参照する可能性のあるものだ。
パッケージが違っていても関係ない。
そういう性質のものに対して、1パッケージのみに関係する情報を乗っける、というのは違和感がある。
*
モジュールロード時のデータを追加するべきかもしれない。
現状のモジュールロードは、初期化関数が指定されていれば、引数のないその関数を呼び出すだけ。
これに対し、引数を付け加えるべきかも。
その引数のデータとして、そのモジュールが属するパッケージのパスなどを乗っける。
*
しかしその場合、そのデータはどうやって管理しよう。
実体はモジュールをロードしたところに置いておいて、初期化関数でポインタをモジュールのグローバルに配置する、というのがセオリーだろうか。
できるだけグローバルとか使いたくないんだけど、さすがにこれは仕方ない気がするなぁ。
まずファイル入出力に対応することに決めた。
*
セーブをできるようにするにも、テクスチャや音声を扱うにも、まずはファイルに対する入出力ができないことには始まらない。
差し当たっては、どれを実現する目的で作ろうかな。
音声はまだ無理だし、テクスチャかセーブデータか。
現状、この前作ったへびゲームは、スコア表示が存在しない。
描画が面倒だったので。
比較的簡単にスコア表示を行なうために、テクスチャ読み込みに対応してもいいかもしれない。
そしてハイスコアを保存するために、セーブデータに対応する、という形はどうだろう。
*
まだセーブデータという概念自体作ってないわけだから、先にテクスチャに対応するのは道理かも。
テクスチャはパッケージのディレクトリに置けばいいだけだし。
ウィンドウクローズイベントハンドラ追加。
*
ベースシステムに、メインウィンドウのクローズイベントの対応を追加し、メインウィンドウが閉じたら正常終了するようにした。
付随して、起動中はwhile(1)によってCPU1コアの使用率が100%になってしまっていた状態も解消。
きりがいいと思ったので、sucroseをv0.9.0とした。
*
次はどこを進めようか。
一度よく考えるべきだろうな。
過去の記事を見直せば、ある程度計画のようなものも出てくるかもしれない。
メインウィンドウやゲームパッドマネージャに対するイベントハンドラの設定方法を変更。
*
これにより、とりあえずゲーム側のソースコードが50行少なくなった。
まぁそれはおまけ程度であり、割とどうでもいい。
*
メインウィンドウやゲームパッドマネージャに対し、特定のイベントハンドラの設定を阻止できるようにインターフェースを変更した。
メインウィンドウのウィンドウを閉じる時のイベントハンドラなんかは、ゲーム側から触らせたくなかったので、想定通りに変更できて満足。
*
とりあえず、ウィンドウを閉じるイベントに対応しようと思う。
今のベースシステムは、ウィンドウを閉じた時の不正終了で落ちているので気に食わない。
*
ちなみに、体の描画に付け足したい要素が、とかいうのは土曜に片付けておいた。
体の描画と、衝突による進行停止、つまりゲームオーバーも作った。
*
これで、とりあえずゲームとしての体裁は整ったはず。
もうちょい、体の描画に付け足したい要素があるので、来週の頭にそれをやって、0.1.0としよう。
*
実際にゲームを作ってみて、ベースシステム側の改善点も少し見えた。
来週はその辺から手を付けていくか。
へびが動くようになった。
*
餌の配置と、餌を食って体が伸びるようになった。
しかし、体の描画処理を行なっていないため、見た目にはほぼ反映されていない。
そのせいもあって、食った後の挙動がこれで合ってるのか、ちょっと判断がつかない。
*
でも体を描画するためのデータはできているわけだし、明日体の描画処理を作る。
そして衝突判定も作り、明日中の完成を目指す。
本格的に描画を開始した。
*
とりあえず、へびと外壁を描画。こんな感じ。
テクスチャとかまだまともに使えるようにしてないし、というよりも面倒なので見た目がしょぼいのは仕方がない。
緑色のがへび。
左側の、ぱかっとなってる方が口。
コントローラによる向き変更にも対応している。こんな感じ。
体の描画はまだなので、頭としっぽが千切れそうになってるのは仕方がない。
*
それに、向き変更が可能なだけであってまだ動くこともできない。
その処理はなんとか今日作ったので、明日動かしてみる予定。
それがうまくいけば餌を食べて体を伸ばす処理と、餌の配置処理。
最終的に外壁や体との衝突判定処理も追加する。
そして、衝突でゲーム停止、つまりゲームオーバーになるようにすれば一段落といったところかな。
ソースを機能ごとに分割した。
*
へびの描画を先にやってから、それに対してコントローラ動かした時の挙動を付けていく形にしようとしたが、うまく行かず。
どうも作る順を間違えたらしい。
コントローラでどのようにデータを変動させるか決めないと、そもそもどのようなデータを用意するべきか、がはっきりしない。
なのでコントローラの挙動の方が先だな。
背景黒く塗ることはできた。
*
別にそれ自体、全然難しくないんだけど。
すぐにソースが肥大化しそうで、どうやって機能分割したものかと考えていた。
しかしそれも大体見えてきたので、明日にはもっと機能分割し、手を付けやすくする予定。
ゲームパッドイベントハンドラの設定処理も完了。
*
次からイベントハンドラの中身を詰めていくわけだけど。
基本的には、ゲームパッドの操作→描画処理、という流れになると思うけど、なにもしてなくてもへびを動かす処理も必要になる。
なので、ゲームパッドとは別に待機処理を動かしておいて、一定時間ごとにへびを動かす→描画、という流れも必要になるだろう。
ウィンドウ描画イベントについては、単に描画処理流すだけで問題ないはず。
*
ゲーム自体の処理はそんな感じだけど、ゲームオーバーになったら処理の流れを変える必要があるだろうな。
ゲーム開始前の画面は、とりあえずは省いてしまってもいいだろう。
起動と同時に開始、ゲームオーバーでもう動かなくなる、みたいな感じ。
あとから、タイトル画面とゲームオーバー時になんか押すとタイトルに戻る、といった処理を追加するか。
やる気びみょうだけど、感覚はだいぶ戻ってきた。
*
とりあえずウィンドウイベントハンドラ設定処理は書いた。
描画イベントの処理は空っぽだが。
ちゃっちゃとゲームパッドイベントの方も設定処理書いて、中身を詰めていきたい。
そろそろcandymakerの開発に戻る。
*
簡単なゲームを作ってみようと思う。
現状、フォントファイルを読んで文字を出すとかできないし、かといって自分で線引いて文字書くのもめんどくさい。
というわけで、そういった表示が必要なさそうなゲームを作る。
*
思いついたのは、なんていうの?
へびが餌食ってどんどん伸びていくあれ。
あれなら得点などの表示がなくても問題ないし。
あれ作る。
というわけで中継ツールを作った。
*
xlinkkaiだとゲームスピードが落ちてしまうゲームも、ローカル内での中継ではさすがにスピードが落ちなかった。
ネット越しの中継をした場合どうなるかは、まだ確認していない。
*
xlinkkaiでどうしようもないくらい遅延していたゲームは、ローカルでの中継の時点で既にどうしようもないくらい遅延してた。
もしやデータ到着順が入れ替わったりとかいう、UDPで起きるらしい現象が頻発してこんなことになっているのでは、と思いTCP版を作ってみたが変わらず。
他のゲームの場合、ローカル内で中継する限りではUDP版とTCP版、どちらでもこれといった違いは見られなかった。
なんなんだろう。
pspautoconnector2は想定通りに動いているようだ。
*
しかし、一部のゲームでゲーム性が変わってしまう程度にゲームスピードが遅くなってしまうのが気に食わない。
これはpspautoconnector2ではなくxlinkkaiの問題だと思うけど。
というわけで、xlinkkaiの代わりのツールを簡単に作ってみようかと。
*
昨日試した限りでは、パソコンに無線LANアダプタを2つ差して、2台のPSPとそれぞれ通信し、単純にデータを中継すれば、チャンネルが違っていても通信が可能ということが確認できた。
その中継を行なうために作ったプログラムに多少手を加えれば、遠隔地とP2P通信するためのツールにできるはずだ。
*
とはいえ、xlinkkaiもおそらくP2P通信なんだよなぁ。
ポート開放が必要なのも、きっとそのためだし。
しかし、その通信部分の処理が甘くて処理遅延の原因になっているとすれば、改善の余地があるかもしれない。
まぁ、やるだけやってみよう。
今日1日で完成させられると思うし。
無理なダイエットはよくないと思った。
*
pspautoconnector2がきちんと動作していない原因が判明。
無理に環境全体のサイズを小さくしようとした環境を使っていたことが原因のようだった。
ようだった、というのはそうでない環境を使ったらきちんと動作するようになった、というだけなので、他の原因ということも考えられる。
しかし、その2つの環境の相違点は、より多くのプログラムをbusyboxへのシンボリックリンクに差し替えていることが大きいので、やはりその辺が原因かな、と。
他にも、xlinkkaiのエンジンの停止でこけるなどしていたので、無理に小さくしようとした環境は今後使わないようにする。
必要がなくなったらすぐ消そう。
*
起きたら、新たに作ったmicroSDの動作確認をする予定。
過去にやったことをすっかり忘れていた。
*
カーネルモジュールのソースに修正を加えていた件について忘れていたこともあり、あまり進まなかった。
とりあえずカーネルモジュールは使えるようになった、はず。
*
しかし、pspautoconnector2がきちんと動作していない。
いや、期待通りの動作はしていると思うのだが。
SSIDとチャンネルはきちんと設定されているので、そこに至るまでにPSPのネットワークも検索しているはずなのだが、既存のネットワークに繋がず新しいネットワークを作っていて接続できていない。
アドレスを指定する処理も必要なんだろうか。
とりあえず明日追加してみるけど、それでうまくいくのかどうか。
今日設定ファイルいじくったので1.0.0にした。
*
pspautoconnector2はとりあえず一区切り。
次は自動生成したgentooの小型化するスクリプトを作るつもり。
だけど、とりあえず前に作ったやつを差し替えて試してみようかな。
正直、そんなに簡単にできるような作業でもないと思うのだ。
なかなかに期限も迫っているし。
*
pspautoconnectorについては、また新たな問題が浮上した。
SSIDが変動する一部のゲームで、接続がうまくいかない。
PSPのSSIDを変動させる前に、対象のSSIDを検索する処理を行なっているらしく、PSPが変動後のSSIDに変わらないのだ。
簡単に言えばpspautoconnectorと同じ動きをしている。
双方、変動後のSSIDを探そうとするけれど見つからないので、接続がうまくいかない。
解決するには、パソコンの無線LANアダプタのSSIDを変更する必要がある。
*
一番簡単な手段としては、手動変更だろう。
しかし、それを自動化したくてpspautoconnectorを作ったわけで、それをしては意味がない気もする。
とはいえ、それすらも自動化したい、となると、pspautoconnector同士で通信を行なう必要が出てくる。
親のPSPについては、子のPSPが接続するために自動でSSIDが変動する。
それを検知したpspautoconnectorは、他のpspautoconnectorに通知し、SSIDを変更させる、といった具合だ。
でもそれをするとなると、中継するサーバーを何かで作るとかか、P2P通信するとかが必要になって、かなり大掛かりになる。
難しいところだ。
大きな勘違いをやらかしていたため修正。
*
疲れた。
設定ファイルの要素をいじくったら1.0.0にする予定。
休日はできるだけ作業しないようにしているが、明日にやってしまおうかな。
*
しかし、めちゃくちゃな作り方したのでソースがとても汚ない。
次からは絶対こんなことしないよ。
設定ファイル読み込み処理を作って、0.1.0とした。
*
明日は特定のゲーム向けの、より迅速なSSID変更処理を追加する予定。
明日中に完成までできればいいのだが。
昨日の時点で、初回の接続がうまくいかない問題については解決済み。
*
接続前に、接続用アダプタで対象のネットワークが見つかるまでネットワーク検索をかけ、見つかり次第接続する形で対応。
前バージョンよりも短い時間で接続できるようになった気がする。
比較するために前バージョンでも試そうとしたんだけど、うまく動いてなかった。
設定値がおかしいのかもしれないが。
*
今日から、設定ファイル読み込み処理を作っている。
前バージョンでは、設定値をコマンドライン引数で直接設定していた。
しかし今回はコマンドライン引数で設定ファイルのパスを指定し、それを読み込む形にする。
後々、多少複雑な設定値を扱えるようにするためにはその方がいいと判断した。
で、設定ファイルの記述形式はcandymakerのものと同じ物、つまり簡易的なJSONにする。
これであればマップやリストを利用できるし。
何より、すでに作ってあるので手間が省ける。
というわけで、candymakerから必要なソースを持ってくるところまではやった。
明日中に、設定値をハードコーディングしている部分を全て差し替えたいところ。
前回接続時から一定時間経過しないと再接続できない仕組みは追加した。
*
で、今は初回の接続がうまくいかない原因を探っていて、大体把握できた。
大まかに言えば、アダプタを2つにしたのが原因だった。
接続用のアダプタが、接続先のネットワークの存在を把握できていないのがいけない。
把握するための方法は、ネットワークの検索。
検索用と接続用に分け、接続用のアダプタではネットワークの検索をしていなかったからいけなかったのだ。
接続前にネットワーク検索をかけて、ネットワークの存在を把握してから接続、という形にすれば多分いける。
となると、処理の流れ自体に手を加えるべきかもしれない。
やる気がびみょう。
*
ネットワーク検索時の重複を消す処理は追加した。
他にも、PSPの検索を開始した後にSSIDを変更した場合、接続失敗にせず再度PSPの検索をする処理も追加した。
現在のSSIDと同じSSIDに再度接続しようとする問題については、ちょっと考え中。
前回接続時の時間を記録しておいて、一定時間経たないと再接続できない仕組みを追加しようかと考えている。
その仕組みを追加したとしても、ネットワークが変わらない場合再接続を禁止する処理は必要だと思うけど。
*
もしくは、接続できなかった場合はSSIDを空にしておくことで対応するべきだろうか。
前バージョンはアダプタが1つだから問題なかったけど、今回は2つなので、SSIDをそのままにしておくと検索に引っかかってしまう。
ネットワークが消滅してから10秒程度経たないと検索から消えてくれないので、今すぐ追加したところで効果は確認できないが。
金曜の時点で、とりあえず動作する状態にはなった。
*
まだまだ完成ではないが。
コマンドライン引数か設定ファイルから設定するデータがハードコーディング状態だったりとか。
現在のSSIDと同じSSIDに再度接続しようとしてしまうのもよくない。
前バージョンならそれほど問題でもなかったかもしれないが、今回は違う。
ネットワーク検索用アダプタで検索をかけた時に出てくるSSIDが増えてしまうのだ。
全く同じSSID、チャンネルのネットワークが複数検出される。
検出時に被りがある場合は無視する処理も追加する予定だが、ネットワークが変わらないのに接続しようとすることに意味はないので、こちらも処理を追加して抑制する。
*
色々試していて気がついたのだが、同じメーカーのチップセットで同じカーネルモジュールを使っていても、チップセットが違うと細かい動きが違う気がする。
xlinkkaiを使うためralinkのアダプタを使っているが、古いアダプタと新しいアダプタで違いが出ている。
アドホック接続をするためにSSIDとチャンネルを設定すると、新しいアダプタの場合は既に存在するネットワークに接続しようとするので問題ない。
古いアダプタの場合、既にネットワークが存在しても、とりあえず新しいネットワークを作る。
それからちょっと経つと、既に存在するネットワークに接続する。
いや、もしかしたら既に存在するネットワーク側がアダプタのネットワークに擦り合わせているのかもしれない。
そこまでは確認していない。
とにかく、そのような動作をしているため、古いアダプタだと素早いネットワーク接続に向いていないのでは、と思っている。
SSID変動型のゲームでうまくいかない場合があるのもそのせいなのでは、と思っている。
ネットワーク接続処理を作った。
*
PSP検知処理はまだまだ。
最終的な作りは見えた感じ。
ネットワークへの接続とPSP検知処理を別々のスレッドでやるので、次に接続するネットワークの決定をどうするか、が問題だった。
古いバージョンの処理は列挙、接続、検知を順々にやっていたので、列挙したネットワークに順番に接続するだけで済んでいた。
しかし今回は別々のスレッドなので、ループで順々にネットワークに接続しては検知、という手段は使えない。
そこで、接続したネットワークの履歴を残す、という方法を考えた。
一度ネットワークに接続したら、そのネットワークの情報を履歴リストにつっこんでいく。
次にネットワークに接続する時には履歴リストを参照し、今まで接続したことがないネットワークに優先的に接続する。
全て接続済みの場合は一番古いものを優先。
一度接続したことがあるネットワークに接続した際には、そのネットワークの情報を一番上に持ってくる。
この方法であれば、同じネットワークばかり接続しようとしてしまう、というようなことにはならない。
*
実際には、今接続しているネットワークと同じゲームのネットワークが出現したら、すぐさまそのネットワークに切り替える、という機能も作る予定。
SSIDが切り替わるタイプのゲームで、タイムアウトがかなり短いゲームへの対策だ。
それでうまくいくのかどうかは分からないが。
古い処理から引っ張ってきて、周囲のネットワークの列挙処理を作った。
*
ネットワークの列挙とネットワークへの接続はそれぞれ別のアダプタでやることもあり、スレッドで処理している。
色々試して気付いたことには、あまり短すぎる間隔で処理を呼び出しまくるとおかしくなる、という点だ。
大雑把に試してみた感じだと、100ミリ秒間隔が限界点。
それよりも短い、10ミリ秒間隔以下で呼び出すと、新たに出現したネットワークを検知できなかったり、消滅したはずのネットワークがいつまでも検知されたり。
そもそも、前に作った時は検知開始してからデータが取れるまでに1秒程度かかってた気がするのだが。
まぁいいか。
*
次は検知したネットワークに接続する処理を作ろう。
今回作った処理と同じく、スレッドで処理する。
それが出来たら、その次はネットワーク内のPSP検知処理だな。
windows10インストール完了。
*
使う機会はずっと後になると思うが。
*
pspautoconnector2の開発開始。
基本的には既存のソースから引っ張ってくるので、そんなに時間かからないと思うのだけど。
設定項目が多少増えるから、コマンドライン引数で与えるのではなく設定ファイルを作った方がいいかもしれない。
でもそうなると面倒が増えるから、とりあえずはコマンドライン引数からにするか。
設定ファイルにするかどうかは、メインの処理が出来上がってからでも遅くはない。
アップグレードの期限が迫っているので、そろそろwindowsを10にしようかと思っている。
*
で、今日ちゃっちゃとアップグレードしようとしたのだが、結果から言えばまだできていない。
1つのパソコンに2環境作ってあるため、とりあえずインストールディスクを作ろうとしたのだが、まずそこがうまくいかない。
ツールを使って落とそうとしたが、Cドライブに8GBの空きが必要などと言われた。
Cドライブは基本的に、必要最低限の領域しか確保しないため、そんなに空きがないのだ。
Dドライブなら余裕があるのに。
クリーンインストールするのだし、と色々消してみたが7.8GB程度までしか空きができない。
windowsアップデート関連のファイルをクリーンアップすれば空きが10GB程度になりそうだが、再起動しないと消せないようだった。
で、再起動してみたらログイン画面から画面真っ黒。
マウスポインタだけは見える状態。
セーフモード起動もできない状態になってしまった。
*
仕方ないのでgentooを起動して調べてみたら、公式サイトからディスクイメージをダウンロードできるとか。
もっと早く言ってほしかった。
*
そんな感じでまごまごしていたので、本日は全然進んでいない。
実は昨日、騙し騙しカーネルインストールスクリプトを書いていたので、とりあえずそれを追加しておいた。
この後rootfsインストールスクリプトも書いてしまうか。
それができたら軽量化などと言っていたが、正直めんどくさいので、先にpspautoconnectorの新バージョンの方をやろうと思う。
最悪、軽量化などできなくてもいいのだ。
とりあえずrootfs生成まで完了。
*
次はカーネルインストールだが、これも過去のスクリプトから持ってくればすぐできるはずだ。
そこまでできたら、実際にrootfsとカーネルをSDカードにインストールし、動かしてみる。
特に問題ないようなら、その次は軽量化か?
必要ないパッケージのファイルの除去などを、スクリプトでまとめてできるようにする。
昨日の時点で、必要なファイルのダウンロードとカーネルビルド処理まではできた。
*
あとはrootfs生成について。
そこまでは、過去に組んだスクリプトを参考にして進められる。
*
過去のスクリプトでは、rootfs生成時にカーネルのインストールもやっていたけど、今回のは別にしようと思っている。
カーネルは複数インストールすることもあるんだし、それをシェルスクリプトで対応させるのはなかなかめんどうだ。
特に今回の場合はraspberrypiなので、1用と2用で別のカーネルを積む予定だ。
場合によって1のみ、あるいは両方、あるいは1用のを複数、などというのを1つのスクリプトで全パターン網羅する、というのは困難を極める。
それなら、1つのカーネルをインストールするスクリプトを作っておいて、それを自分で複数回動かした方が分かりやすそうだ。
8月中旬頃までは別の作業することにした。
*
raspberrypiで動作するgentooの自動生成関係をやる。
それが済んだら、pspautoconnectorの新バージョンを作る。
それをraspberrypiに乗っけて出来上がり。
candymaker-0.12.0完成。
*
前に作ったpainttestとかgamepadtestで試したが、いい感じ。
sucroseを別パッケージに分離したが、ちゃんと動作している。
結構それっぽくなってきた感じがある。
*
気になった点としては、設定ファイルの記述ミスの場所が分かりにくいというところか。
エラーログの内容を変えることで対応できると思うけど。
同パッケージ内の依存解決完成。
*
古い処理も片付けた。
これで他に何もなければ、明日バージョンを確定させよう。
*
次はどうしよう。
とりあえず、今回の追加で複数のパッケージを扱えるようになったわけだな。
candymakerに何か追加するとしたら、設定ファイルマネージャやモジュールマネージャとかその辺だろうな。
しかし、それらは現状必須ってわけでもないし。
いよいよ簡単なゲームでも作ってみるか?
同パッケージ内の依存解決の目処は付いた。
*
明日完成させる。
そこまでできたら、古い方の構成は削除するとしよう。
それでとりあえずバージョンを確定させるか。
基礎はできたかも。
*
細部はまだできていないが、インターフェース情報と依存情報、そして有効モジュールリストを使い、適切なモジュールを検索する処理を作った。
山場は越えたのでは、と思うけど、ちょっと処理がぐちゃぐちゃな気がするんだよなぁ。
強引に解決した箇所もあるし。
しかし、その箇所は小手先の修正では解決できない気がする。
きちんと書くには、新たな仕組みを追加するべきだろう。
*
まぁ、その辺りはやはり後回しで。
やる気はいまいちだが順調だと思いたい。
*
先週の時点では、またしてもうっかり忘れていた部分の機能追加のみだった。
やはり先週末で完成は無理だった。
現時点で、完成までの目処は立った感じがある。
うまくいけば明日には完成するのでは、と思っている。
*
しかし、インターフェース情報と依存情報、どちらもパッケージ情報に固定データとして書かれてるのはどうなんだろう。
ちょっと融通が効きにくそう。
すぐに追加する必要はないと思うけど、パッケージ設定によって調整できるようにするべきか。
インターフェース情報を追加、あるいは変更をできるようにしたりとか。
うっかり忘れていた。
*
パッケージ情報ファイルの依存モジュール情報の記述方法を、他パッケージへの依存に対応したものに変更するのを忘れていた。
なので、今日はとりあえずそこを作った。
ちなみに、現時点では古いものもまだ消していない。
現状ではそれで動いているわけだし、消したら消したでめんどうなので。
*
やる気が残念なことになっていたので、そこまでしかできなかった。
明日は金曜日だし、明日で完成させたいところではある。
しかし、大きく違う処理を新規に作ることになるわけだし、そう簡単にいくかどうか。
パッケージ情報ファイル読み込み処理に、インターフェース情報についての処理を追加した。
*
これでとりあえず下準備はできた感じか。
これらの情報を元に、他パッケージへのモジュール依存の解決を可能にする。
パッケージ設定ファイル解析処理を作った。
*
インポート機能は未対応。
そのうちやる。
忘れないように、課題管理に追加しておいた。
*
次はパッケージ情報ファイルへの記述追加対応。
インターフェース情報の読み込みに対応する。
昨日は既存処理を整えていた。
*
で、今日からパッケージ設定ファイルに入ろうとしたのだが、昨日書いたのは多分間違ってる。
時間が経ちすぎたため、当初の構成を忘れてしまっていたようだ。
*
パッケージ設定ファイルで依存モジュールのマッピングはしない。
依存モジュールの解決は、パッケージ情報ファイルのモジュール情報に記載する実装済みインターフェース情報と、パッケージ設定ファイルのモジュール使用許可リストで行なう。
他パッケージへの依存モジュールの指定はインターフェース名で行なう。
モジュール使用許可リストから、そのインターフェースが実装されているモジュールを探し出す形。
*
そんなわけで、パッケージ情報ファイルにも手を加える必要がある。
どこから手を付けたものだろうか。
パッケージ情報ファイルの依存モジュール情報かな、と思ったがこれは最後か?
少なくともインターフェース情報がなければ動作しないし。
インターフェース情報より先に、パッケージ設定ファイルを作るべきか?
その2つは直接的な関わりはないから、どっちから手を付けても大丈夫かな。
*
インターフェース情報とパッケージ設定ファイルを作って、それを元に依存モジュール情報の内容を変更、最終的にモジュールロード処理らへんを変更する感じか。
しかし、同パッケージについても依存モジュールの指定をインターフェース名でやるべきかと思ったが、正直二度手間な気がする。
インターフェース名でやることによるメリットもあるため可能にはしたいが、モジュール名の直接指定でもできるようにしたい。
パッケージ設定ファイルを先に作るべきでは、という気がしてきた。
*
今のところの問題は、他のパッケージのモジュールへの依存モジュール指定ができないという点だ。
これを、依存パッケージを直接指定して解決する、というのは分かりやすいが、最終的な構成とは割と異なる。
そこから最終的な形に持っていこうとすると、設定ファイルの記述から変えていかなければならない気がする。
それなら、そこはまだ現状のままにしておいて、パッケージ設定ファイルを追加した後に対応した方が楽なのでは、という気がしている。
*
パッケージ設定ファイルには何を書くんだったか。
とりあえずはモジュールの使用許可リストと、依存モジュールのマッピングか?
他のパッケージ設定ファイルを参照したりするから、それも書くか。
後々、パッケージとセーブデータディレクトリの関連付けも書く。
*
この中の、最低限必要なものはどれだろうか。
モジュール使用許可リストは後回しでいいだろう。
他の設定ファイルの参照、つまりインポートも後でいい。
そうなると、依存モジュールマッピングだけか。
依存モジュールマッピングの後に、インポートも対応しよう。
*
依存モジュールマッピングの記述方法はどうしよう。
細かい指定方法と、大まかな指定方法、少なくともその2種類は用意したい。
具体的には、細かい指定方法というのはモジュールレベルのマッピング。
多まかな指定方法というのはパッケージレベルのマッピングだ。
その中間もあれば、より便利だろうな。
やる気減退がかなりやばい。
*
しかし、とりあえず0.11.0確定まではやった。
次は他のパッケージにあるモジュールに対し、依存モジュール指定をできるようにする。
そこまでできれば、とりあえずcandymakerは一段落だろう。
昨日はうっかり書き忘れた。
*
wafのタスク生成がよく分からんので、昨日1日では完了できなかった。
なんとなく分かってきた上で、多分明日までかかりそうだな、といった感じ。
現在のビルドルールが、C++のソースファイルをコンパイルする、という作業を前提に書かれているため、融通が効かない。
そこから修正していく必要がある。
*
しかしモチベーションが上がらない。
モジュール参照を作った。
*
それをパッケージ情報ファイルで使うようにした。
結果、パッケージ情報ファイル内のモジュールのパス指定が、パッケージ内の相対パスになった。
これで、ベースシステムとゲームに必要なパッケージに加え、ショートカットファイルを1つのディレクトリにまとめることで、candymakerにショートカットファイルを読み込ませればゲームが動作するようになった。
*
どうしよう、きりがいいしここで0.11.0としてしまうべきか。
しかしながら、開発上の問題点が新たに浮上している。
自動テストで使用するパッケージ情報ファイルの位置と、モジュールの位置が噛み合わないため、自動テストが失敗してしまうのだ。
一応、ビルド後に自分でモジュールをコピーして、テストが通ることは確認したものの、こんなこと毎回やりたくない。
毎回やってたら、いずれコピーし忘れとかで問題が出てくるだろうし。
何よりめんどくさい。
*
wscriptに手を加えて、その辺を対応してから0.11.0とすることにしよう。
パッケージ参照を作った。
*
それをショートカットファイルで使うようにした。
結果、ショートカットファイルからのベースシステム、ゲームのパッケージ指定が、ショートカットファイルからの相対パスになった。
今まではcandymakerからの相対パスで、実用度は皆無だったため、これは大きな進歩だ。
現状の構成からすると、ショートカットファイルの内容は完成したと言っていいはずだ。
*
しかしながら、パッケージの参照についてのみ対応したのであって、それ以外は未対応だ。
例えば、パッケージ情報ファイルのモジュール指定なんかは、まだcandymakerからの相対パスで指定しなければならない。
できるだけ早く対応してしまいたいが、パッケージ参照ができたということはモジュールの依存関係にそれを使用できるということだ。
どちらを先にやるべきか、悩ましい。
*
前者は型の変更であって、処理の流れ自体は変わらない。
後者は型の追加に加え、それを利用した処理の追加、となるだろう。
であれば、負荷の軽いモジュール指定の記述、つまりモジュール参照型の作成を先にやってしまうか。
早まらなくてよかったかもしれない。
*
煮詰まってはいるんだが、よく考えたら始まりから間違っていたのかも。
ショートカットファイルのベースシステム参照について、パッケージパスの記述を色々考えていたんだが、想定では、
{ "base" : "基点ディレクトリ名", "path" : [ "ディレクトリ名", "ディレクトリ名", "パッケージディレクトリ名" ] }
といった感じの記述で、基点ディレクトリからの相対パスを表現しようとしていたんだけど。
しかし、基点ディレクトリから見ても深い階層に配置することなんてないよなぁ、と考え、
{ "base" : "基点ディレクトリ名", "path" : "パッケージディレクトリ名" }
こうでいいよな、と思った。
更に、これならいっそのこと、
{ "at" : "基点ディレクトリ名", "name" : "パッケージディレクトリ名" }
という感じにキーの名前を変えた方が分かりやすそうだな、と。
で更に、この構成は既存のベースシステム参照やゲーム参照の構成と酷似している。
ならば、これはパスというより参照情報という括りで扱った方がよさそうだな、と思った。
*
ゲーム中で使用する素材なんかは、ある程度区分けされてるディレクトリ構成を扱えた方がいいだろうから、パスの概念が必要になると思う。
しかしながら、現状ではそこまで自由度の高い要素は必要ないのでは、という話。
少し希望が見えてきたかもしれない。
確実にやる気減退している。
*
今日も全然進んでない。
このままではよくないので、candymakerのソースを眺めていたが、ちょっと整理した方がいい気がしてきた。
なんとなくでファイルを置いてしまっている感じがある。
特に設定ファイル周り。
ショートカットファイルの要素、ベースシステム参照とゲーム参照の定義が、ベースシステム側やゲーム側に置かれてるのが違和感ある。
設定ファイル側、あるいはどちらにも属しない独立したディレクトリに置くべきでは。
生成時の引数として、設定ファイルの要素を渡すことになると思うから、設定ファイル側でいいとは思うけど。
*
その辺から、ソースファイルの配置を整えるところから始めようかな。
どこを進めるべきか考えていた。
*
ひとまずsucroseはここで中断しておく。
設定ファイルのパスの扱いをどうにかしようと思う。
現状では、ベースシステムとゲーム、どちらも1つのパッケージで完結してなければならないという制限がある。
パッケージをまたぐ依存関係を解決できないためだ。
しかし、ゲームやベースシステムが汎用的なパッケージを利用する、などというのはよくあることだと思うので、できないと非常に困る。
というわけで、依存モジュールの指定にパスを含めるようにする。
付随して、今まで環境依存の文字列として扱ってきたパスを、共通的に扱うべく書式を定めようと思う。
*
しかし、一気に全部をやろうとしてもうまくいかないと思うので、段階的に作っていく。
まずやるべきは、型の関係だろうな。
後に回せば回すほど、影響箇所が増えて面倒になるし。
なので、まずはパスの型を作る。
次に、設定ファイルのパスの箇所について対応し、これで一段落。
その次はどうするか。
最終的には、パッケージ設定ファイルを追加することになるけど、さすがにそこまで一気にはやりたくないなぁ。
パッケージからパッケージに、直接依存する形を取るか?
現状の依存モジュールの記述は、
{ "deps" : [ "依存モジュール名" ] }
といった具合だが、ひとまず
{ "deps" : [ { "path" : パス型(依存モジュールのパス), "name" : "依存モジュール名" } ] }
という形にするか。
で、最終的には
{ "deps" : [ { "package" : "依存パッケージ名", "name" : "依存モジュール名" } ] }
という形にするかな。
実際のモジュールとのマッチングは、パッケージ設定ファイルでやる感じ。
*
今回の作業の最終的な落としどころも考えておこう。
ショートカットファイルと必要なパッケージ群を1つのディレクトリにまとめた上で、
candymaker ショートカットファイルパス
と実行すれば、ディレクトリがどこに配置してあってもゲームが動かせる、といったところか。
それを実現するには、前述した作業以外にも工程が必要になるが、やりたいことはつまりそういうことだろう。
ショートカットファイルを基点とするファイル配置への対応。
現時点では、candymakerを実行したティレクトリを基点とした配置にしか対応できてないし。
むしろそんなものはなんの役にも立たないし。
休みだし、久々にraspberrypi関係をやっている。
*
raspberrypiで動作するgentooの自動生成をスクリプトにまとめようとしている。
とりあえず、最新のstage3をダウンロードするスクリプトを書いた。
昔書いたスクリプトでは、落とすstage3のパスを直書きしていたので、stage3が新しくなったら修正が必要だった。
今回はサーバーにあるlatest-stage3なんちゃらファイルを参照して、現在の最新版をダウンロードするようにした。
おまけで、stage3の最新版がダウンロード済みで、最新版が更新されていない場合にダウンロードをスキップする処理も追加した。
*
休日に地道に進めて、起動後ディスクレス化する環境の自動生成までやりたいところ。
スクリプトを使って試行錯誤し、最終的に生成できた、というのは昔やったんだけど。
手動で手を加えたことも色々あって、今ではどうやったら確実に生成できるか覚えてないので。
0.8.0確定。
*
sucroseの.hと.cppの総行数が1万を越えた。
試しに、バージョン毎のファイル数と行数を簡単なシェルスクリプトで出力したところ、
バージョン | ファイル数 | 行数 |
---|---|---|
v0.1.0 | 16 | 495 |
v0.2.0 | 39 | 2676 |
v0.3.0 | 40 | 2810 |
v0.3.1 | 40 | 2810 |
v0.4.0 | 40 | 3032 |
v0.5.0 | 40 | 3253 |
v0.6.0 | 88 | 8790 |
v0.6.1 | 91 | 8685 |
v0.7.0 | 105 | 9449 |
v0.8.0 | 129 | 13001 |
こんな具合だった。
0.3.0から0.5.0にかけてファイル数が一向に増えてないのは、ウィンドウ周りの機能追加をするたびにバージョンを上げてたんだろう、多分。
過去の記述を見返したら、0.6.0でゲームパッドがどうたら言ってて、行数も一気に倍以上増えてるので多分そう。
*
0.8.0で追加したスレッドプールとタスクにより、非同期処理が多少書きやすくなった、はず。
しかし、タスクマネージャ書いてる時にデッドロック見つけちゃってやばかった。
スレッド内でロックしてるmutexをロックしながらjoinしようとしてた。
やはり非同期処理で厄介なのは、バグが再現しないことがある、という点か。
今回の件も、たまたまjoinの方が早くロックを取得すると発生するのであって、毎回起きるわけじゃないし。
また、停止してしまうだけで不正終了はしないから、どこで止まってるのかも特定が面倒だし。
久々にgdbとか使って停止箇所特定などしようとしたが、久々すぎてうまく使えず。
結局printfデバッグで発生箇所を特定し、解決した。
まだどこかにバグが潜んでいそうで怖い。
ゲームパッドの対応も完了。
*
しかし、0.8.0はまだ確定しない予定。
タスク管理の共通化のアイデアがひらめいたので。
明日それを作ってから確定する予定。
*
問題となっていたのは、タスクを括る必要がある、という点だった。
どういうことかと言えば、
{
bool ended;
タスク
タスク
タスク
Ender ender;
}
これで伝わるかどうかは謎だが。
排他制御関係やEnderの定義を省いて簡略化しているが、タスクを管理する構造体の定義だ。
endedは終了フラグで、trueの場合タスクの実行できなくなる。
それにより、各タスクが他のタスクに遷移することなく終了する。
enderは、破棄のタイミングでendedをtrueに設定する。
この構成によって、構造体を破棄すれば安全にタスク群を破棄できるのだ。
不用意にタスクを破棄しようとすると、まだ動いているタスクから破棄済みのタスクに遷移しようとして死ぬ、などということが起きる可能性がある。
*
これをどう共通化したものか、いい案が浮かばなかった。
仮に、TaskManagerというものを用意して、そこにタスクを登録していく形、とすると各タスクのメンバ名が消えるようなものなので、タスクの遷移がやりにくくなりそうだ。
自分で生成したものの破棄を他でやる、という構成も気に食わない。
*
早い話が、endedに2回破棄処理をかける必要があるのが問題なのだ。
1回目の破棄でendedをtrueに設定、2回目で物理的に破棄、つまりメモリ領域の解放。
そこで思い付いたのが、
{
TaskManagerBegin taskManager;
タスク
タスク
タスク
TaskManagerEnd taskManagerEnd;
}
このような構成だ。
実際にはBeginとEndをユニークポインタで管理するだろうが、それ以外に違いはない。
TaskManagerBeginに、終了フラグや排他制御関係のものを持たせる。
TaskManagerEndは、生成時にTaskManagerBeginの参照を要求する。
TaskManagerEndの破棄時に、TaskManagerBeginの終了フラグを設定する。
といった具合だ。
他にも、WaitTaskCancellerみたいなものをBeginとEndの間に配置することで、待機タスクをキャンセルによって終了させる、ということもできるようにする予定。
待機スレッドプール完成。
*
出来たそれを使って、早速ウィンドウの処理に待機タスクを追加した。
ゲームパッドマネージャの処理も、タスクで処理するように書き換えた。
あとはゲームパッドだけ。
それが完了したら0.8.0として確定するか。
*
現時点で、スレッドプールで稼働しているスレッドが1つでも、ウィンドウとゲームパッドマネージャがきちんと動作することを確認している。
待機スレッドプールを作る前は、どちらかのタスクが待機を行なっている間、もう片方のタスクを処理できなかった。
…はず。
残念ながら確認したわけではない。
絶対やばいよなぁ、ということで対応したので。
*
ウィンドウとゲームパッドマネージャのタスクの管理部分は、ほぼ同じ構成になった。
共通化できそうな気がするが、そううまくいくだろうか、とも思う。
うまく共通化できれば、かなり有用なものになりそうなのだが。
ゲーム側のタスク管理にも使えるし。
普通のスレッドプールのタスクについても破棄処理が間違っている気がする。
*
現状、タスクの破棄処理は未稼働タスクの削除と稼働中タスクの待機をした後に行なっている。
しかし、未稼働タスクの削除はいらないのではないか?
確かにタスクの破棄までの時間が短縮されるが、そもそも稼働させたいから未稼働タスクに蓄積されているのだ。
それを稼働させずに消してしまう、というのはおかしい気がする。
それに、普通のスレッドプールは待機が発生することがないのだから、ちょっと待てばすぐ終了するはずだ。
なので、未稼働タスクと稼働中タスク、どちらからも破棄対象のタスクがなくなるまで待機するのが正しいかな、と。
待機スレッドプール、まだ出来てないが構成ははっきりした感じ。
*
pthread_cancel()で待機を強制的に切って終了させる、というのは多分やらない方向になる。
pthread_cancel()による強制終了処理自体は用意するが、それはあくまで例外的な処理であり、通常は待機が終わるまで待って終了させる。
そもそも、pthread_cancel()を使わざるを得ない状況というのがあまりないのだ。
read()やpoll()などの、条件を満たさなければ処理が進まない、というような関数を使う場合にのみ使うべきだ。
例えばミューテックスと条件変数によるwait()であれば、notify()で起こしてやればいい。
破棄したい場合には、例えば終了フラグなどをセットしてから起こしてやれば上出来だろう。
そんなわけで、昨日書いた想定は間違い。
*
待機スレッドプールは、私が考えていた以上に便利な面もありそう。
pthread_cancel()を使う場合、今までのやり方では想定しているポイント以外でキャンセルが発生しないか不安に思っていた。
それが、待機スレッドプールを使うことにより、pthread_cancel()の影響する範囲を待機タスクの部分のみに絞ることができる。
普通のスレッドプールで処理する範囲に関しては、pthread_cancel()でキャンセルがかかることは絶対になくなったわけだ。
この安心感は大きい。
*
しかし、今作ってるこれ、動作的にはファイバのようなものだな。
固定数のスレッドと、それを利用する無数の処理の断片、という構図になるので、効率的に処理を回せそうな雰囲気はある。
でも、処理と処理を繋ぎ合わせてるのは実質的にgotoのようなものなんだよな。
あまり複雑な繋ぎ方はしない予定だけど、やろうとすれば簡単にスパゲティ化するだろうし、ちょっと怖い。
ゲームパッドのスレッドについては後回しにした。
*
だって現状が中途半端すぎるもんで。
ウィンドウのイベント読み込み待機中、スレッドプールの1スレッドを占有してしまうのが痛い。
処理の詰まりを分かりやすくするために、スレッドプールは1スレッドのみで動かしていて、その1スレッドがメインウィンドウのイベント処理だけに使われちゃってもうだめ。
スレッドプールでは待機無しの処理だけを流すので、待機処理は待機スレッドプールというのを別に用意し、そこでやろうと考えている。
*
待機スレッドプールは、プールっていうよりキャッシュなんだけど。
待機処理が必要になった時にスレッドを起動し、そのスレッドで待機処理をする。
待機処理を終えたスレッドはそのまま保持しておき、別の待機処理に使い回す。
*
とまぁ、そんな具合。
スレッドプールのタスクは待機が発生しない処理だけを流すので、破棄は処理が終わるのを待ってからにしている。
一方、待機スレッドプールのタスクはpthread_cancel()で待機を強制的に切って終了させる予定。
pthread_cancel()で終了したスレッドは使い回せないので、joinしてから破棄、という流れになるだろうな。
*
待機スレッドプールについてはまだちょっともやもやしてるんだよなぁ。
きちんと作れるのか不安だ。
普通のスレッドプールと比べて、違うのは内部、つまり実装だけで、インターフェース自体はほぼ同じになる予定ではあるのだが。
ひとまず、ウィンドウから使うところまではできた。
*
ゲームパッドの方についても、ちゃっちゃとやってしまう予定。
とりあえず、スレッドプール以外にstd::threadを使用している箇所が無くなるようにする。
*
タスクの引数に、そのタスクの参照を追加したのはいいのか悪いのか。
タスクの処理の最後でそのタスクを再度開始させることで、ループ処理をするために追加した。
これが無い場合、タスクをなんらかの構造体のメンバとして追加したりしないと、自身の参照を得るのが困難だったからだ。
しかしながら、実際の運用を考えた場合、自身を再度開始させることなんてないのでは?という気もしている。
処理の待機が存在しないタスクを回し続けたらCPUの稼働率が無駄に高くなってしまうし。
処理の待機は別の種類のタスクで処理する予定なので、それを利用すると処理タスク→待機タスク→処理タスク→…となるので、自身は参照しない。
それにその場合、循環参照になるため全タスクをなんらかの構造体にメンバとして追加することになると思うし。
とはいえ、今はウィンドウの処理で使ってるから、そこで使わなくなったらさっさと消してしまうかな。
構成失敗したかも。
*
スレッドプールの件。
とりあえずできたので、実際に使おうとしたのだがうまくいかない。
スレッドタスクというものを作り、それをプールに投げて実行する、という形を取っているのだが、処理が終了したかどうか確認できないという問題が浮上した。
タスクを破棄したくても、まだ処理中かもしれないし、破棄しても大丈夫なのかどうかが判断できないのだ。
プールが1つならまだどうにかできるかもしれないが、現在の仕様上だとタスクはプールに投げる時に対象のプールを指定する形を取っており、やろうとすれば複数のプールに投げることもできる。
その場合、こっちのプールではどうだ、あっちのプールでは、といった感じの処理が必要になり、収拾つかなくなる感じがある。
実際には、複数のプールを生成することに意味は全く無いので、そのようなことはやらないが、そうなる可能性があるという時点で構成が間違ってる気がするのだ。
*
私が想定している運用からすると、タスクを生成するタイミングで、そのタスクを処理するプールを指定しておく形がいいのかもしれない。
そうすれば、タスクを処理するプールが1つに固定されるので、処理の終了チェックなどがやりやすくなるはずだ。
*
他の問題としては、あるタスクの処理内で、他のタスクをプールに投げる、とかについてか。
通常時は問題ないと思うが、これまたタスクを破棄するタイミングで、タスクをプールに投げようとしたらそのタスクはすでに破棄済みでメモリ例外、なんてのは起きそうなものだ。
どちらかといえばプールやタスクの問題というより、そもそもマルチスレッド処理だから起きる問題という感じなので、その辺考慮した記述をすれば問題ないのだろうけど。
*
本当なら、今の構成を作るのは昨日中に終わってた気もするんだけど、やる気減退してたのか終わらなかった。
終わってたところで、今日同じ問題にぶち当たって頭抱えてたか。
さて、どのように修正加えていくかくらいは目星を付けておくか。
とりあえず0.7.0は完了。
*
スレッドプールについては、waitをどう処理するかまだ考えてないのだった。
そこを考えるのは後回しにしてもいいような気がするけど。
*
スレッドプールで動かす処理についても、イベントハンドラと同じ形にしようかと思っている。
ファンクタを引数にスレッドプールハンドラとでも言うべきものを生成する。
スレッドプールにそれを登録することで、プールしてあるスレッドで処理する。
そう考えると、同じハンドラを複数回登録するのもありかな、と考えている。
*
というのも、現状ではウィンドウやゲームパッドのイベントハンドラは、同じものを複数回登録できない仕様にしているのだ。
この制限も、正直あまり意味がないので撤廃するべきかもしれない。
ベースシステムデータの変更については完了したと言える。
*
ゲームパッドのイベントからウィンドウの再描画要求出せるようになった。
ゲームパッドいじくるとウィンドウに描画している三角形の色が変わっていい感じ。
しかしながら、ウィンドウやゲームパッドマネージャのスレッド開始についても変更しておかないとまずい。
その変更が完了したら、0.7.0としようと思う。
*
0.8.0はどうしよう。
スレッドプールの追加が妥当だろうか。
しかし、それがないと困る、というレベルでも…なくはないか?
イベント処理をスレッドプールでやるようになれば、描画イベントの処理遅延も改善できるはずだし。
*
他の候補としては、sucroseではなくcandymakerの方か。
ファイルパスの扱いをはっきりさせる。
その辺ができれば、設定ファイルがより実用的になる。
現状では、絶対パスもしくは作業ディレクトリからの相対パスしか指定できないからなぁ。
ファイル入出力なども作り始めることができるようになるはずだ。
ゲームパッドのイベント内でウィンドウの参照を取得できるように対応中。
*
ベースシステムデータの中身を2つに分けることで対応することにした。
片方は従来のものからデータ参照機能を取り除いたもの。
もう片方は従来のもののデータ参照機能と、ウィンドウなどの実行中のデータ参照機能を合わせたもの。
スレッド処理に関しては、とりあえず自前で実行する形にしようと思う。
スレッドプールについてはまた今度。
多分今やってるのが完了したらやる。
*
今日中に2つに分割する作業は完了したいところだったが、ちょっと厳しそう。
明日中には。
色々考えた結果、やはり音は後回しにすることにした。
*
位置付けとしては、テクスチャ、というより画像ファイルに近い感じがするのだ。
あれば便利だろうけど、今すぐに必要というわけでもない。
それに、音に関してはどのように構成するべきなのか、まだよく分かっていないのだ。
その試行錯誤に時間を使ってしまうよりも、別のところを進めるべきかな、と。
*
差し当たっては、ゲームパッドのイベントからウィンドウの再描画要求をするのが困難、という点をどうにかしよう。
ゲームパッドの入力が即座に画面に反映されないので、これではゲームにならない。
しかし現状、ウィンドウ生成時にイベント処理スレッドを開始しているのが問題になるか?
ゲームパッドマネージャでも、生成時にイベント処理スレッドを開始している。
全てのイベント処理が始まる前に下準備をしておく、ということができなさそうだ。
今回の件では、ゲームパッドのイベントからウィンドウを参照できるようにしておく、というのがそれに当たる。
対処方法としては、単純に考えて生成とスレッド開始を別々にしておき、準備が完了した後にスレッドを開始する、となるんだろうけど。
しかしそれはあまりスマートじゃないなぁ。
今はまだウィンドウとゲームパッドマネージャだけ、2つだからいいけど、今後スレッドを起動する要素が増えていったら大変そうだ。
*
そこで、スレッドはスレッドプールで管理する、という方法を考えている。
スレッドプールの生成と開始を別々にしておく。
スレッド処理が必要な要素は、生成時にスレッド処理をスレッドプールに登録する。
スレッドプールのスレッド開始命令で、登録されている処理を一斉に開始する。
しかしながら、私はスレッドプールというものについて、言葉と大体のイメージしか知らんので、そんなにうまくいくものだろうか、という不安がある。
できれば、イベント処理1つ1つについても、スレッドプールに投げてスレッドで処理したいのだけど。
それによって、描画処理の垂直同期による、ウィンドウイベントの処理遅延も解決できる気もするし。
*
さて、どこから手を付けるか。
ひとまず、スレッドプールは置いといて、ゲームパッドのイベントからウィンドウの再描画要求ができるように、構成を変更するか。
0.6.1できた。
*
ウィンドウ生成とかに追加した、いらんデータの削除と、課題管理に上げてた2件を対応。
*
次からは音と思っていたけど、うーん。
音を扱うということは、まずファイル読み込みを使うことになりそうな気がする。
ウィンドウやゲームパッドはそんなことないけど。
*
別のところを進めるべきか。
土日にじっくり考えてみよう。
ぐーたらやってたら遅くなってしまったが、0.6.0できた。
*
ゲームパッドを扱う簡単なプログラム、gamepadtestを作って思ったことには、ウィンドウを参照しにくいという点だ。
ちょっと前に作った描画を行なう簡単なプログラム、painttestの時は、ウィンドウを参照するのが描画イベント内であり、イベントデータからウィンドウの参照が得られるため問題なかった。
しかし今回は、ゲームパッドのイベント内からウィンドウの再描画リクエストをしようとしたけど、現状ではできていない。
ウィンドウの参照を得られないからだ。
そんなわけで、ゲームパッドの抜き差しやボタン押下などに反応して、描画色を変えるようにしているのだけど、ウィンドウを一旦隠すとかして、手動で再描画させないと色が変わらない感じ。
実行中のベースシステムデータ、みたいなものを用意して、今動いてるベースシステムのデータ、つまりウィンドウの参照などを取得できるようにするべきか。
*
とりあえず、細かい修正をやってしまおう。
ウィンドウの生成時やら描画イベントやらに足してしまった、ベースシステムデータの参照削除と、あとは課題管理に追加してある件を何件か、といったところか。
想像以上に疲れた。
*
ゲームパッドIDの対応は完了した。
やはり仕様変更は疲れる。
テスト駆動でやってるからか、きちんとできてそうな実感があるのはいいのだけど。
今回のは、さすがに最初に横着しすぎただろうか。
最初からゲームパッドIDを文字列でなく独立した型にしていれば、こんなことには。
処理内容だったらともかく、型についてはできるだけ後から変更をかけないようにしないといけないな。
*
とりあえず、ベースシステムデータにゲームパッドのイベントハンドラを設定できるようにして、メインでゲームパッドマネージャを起動するところまでは書けた。
なので、ゲームパッドを使用する簡単なプログラムを作りたいところだけど、いかんせん疲れた。
明日でいいかなーという気がしている。
プログラムが問題なく動くなら0.6.0として確定させるから、できれば今日やりたい気もするんだが。
*
明日は金曜日か。
明日中に0.6.1を作れればきりがいいな。
簡単なプログラムの作成と細かい修正、これらをまとめて明日中に…やれるか?
ゲームパッドの扱い、ほぼ完成。
*
ゲームパッドIDに関してはまだ生の文字列のままなので、明日直そう。
それができたら0.6.0とする。
*
次はゲームパッドに関するものをベースシステムに追加するとしよう。
で、簡単なゲームを作る。
あー、ウィンドウのイベントにベースシステム関係の参照追加しちゃったのも直すか。
他にも細かい修正したらそれを0.6.1とするか。
*
以前の記述を見直したら、ゲームパッドの次は音って書いてるな。
それもそうか。
音までやって、ゲームパッドで動かせて音も出るゲームを作れたら、中途半端にしてる部分もどうにかしていくべきだろうな。
さすがに昨日の今日で本調子とは行かないか。
*
とりあえず、ゲームパッド接続・切断に関しては出来上がった。
ゲームパッドIDはただの文字列ではなく型を作るべきとは思うが、使えないこともないし今はこれでいいだろう。
次はゲームパッドの入力だ。
接続イベントを済ませた後にゲームパッドの入力を扱うオブジェクトを作り、切断イベントの前に破棄、という形になるだろうな。
先週中にゲームパッド対応は終わらせたかった。
*
でもそれはさすがに無茶だったようだ。
金曜開始時点で、ゲームパッドの入力の扱いに関してはノータッチだったし。
*
で、今日。
体調が優れないのと、キーボードの調子が悪いのダブルパンチで作業はかどらず。
キーボードのEnterキーが、1回押しただけなのに2回入力される現象が稀に発生していた。
しかし、前に壊してしまった同じ型のキーボードからパーツを拝借したところ、どうやら改善できたようだ。
*
明日こそ本気出す。
evdevは地雷だったかもしれない。
*
とりあえずわけがわからない。
ゲームパッドのボタン数取得方法からしてもうだめ。
かろうじて分かったことは、どうもそんなのなさそう、という空気だけ。
evdevでのゲームパッドの扱いは多分、windowsのxinputに近いんじゃないかなと思う。
決まった仕様にゲームパッドを当てはめていく感じ。
xinputの方はまだいい。
ゲームパッドのボタン数とかも仕様のうちに入っているため、ボタン数や軸数が固定だから。
evdevの場合、とりあえずいくつか用意しておいたボタンのうち、接続したゲームパッドだとこのボタンとこのボタンと…が使えるよ!!みたいな情報を得てどうのこうのとか、なにやらすごいめんどくさい。
多分evdevだと、ボタンが100個とか付いてるゲームパッドに対応できないんじゃないかな。
そんなもの扱う予定などないが、古い仕様やDirectInputにはできた。
evdevとxinputにはそれができなさそう。
もうフォースフィードバックとかどうでもいいんで、古い仕様の方を使うとしよう。
ゲームパッドが振動するみたいな機能、私基本的に嫌いだし。
*
結構な時間とやる気を無駄にしてしまった。疲れた。
ゲームパッド切断については、昨日すぐ作った。
*
で、pthread_kill()もちょっと扱いめんどうそうだな、というのも大体理解した。
というわけで、今日はゲームパッドの入力の扱いに入ろうとしている。
のだが、いまひとつまとまらないような。
*
過去のプロジェクトの構成とは、これまた少し変える予定。
過去のプロジェクトでは、ゲームパッドの初期状態に関してもボタンや軸の状態変化イベントを呼び出していたが、これはやめる。
ボタンの初期状態の通知と、ボタンの状態変化の通知というのは別物にするべきだと思うからだ。
具体的には、初期状態についてはゲームパッド接続イベントのイベントデータから取得できるようにする。
状態変化については変えなくてもいいと思う。
過去のプロジェクトと同じく、変化があったものについてどう変化したかのみ通知する。
ボタン数、軸数の取得については、過去のプロジェクトのやり方はさすがに頭が悪すぎる。
要求があった時にゲームパッドから取得して返す、とかちょっと。
ゲームパッドを扱うならまず使用するデータなんだし、接続時にゲームパッドから取得する。
*
あと、今回は状態変化イベント、ということでボタンと軸の区別をなくそうと思っていたけど、やっぱりだめかも。
変化したものだけ通知する場合、やはりこれは別々の方がいい。
1つにするとなると、例えば変化したのがボタンなのか軸なのか、といったフラグのようなデータが必要になるし。
あるいは、ゲームパッドのボタンや軸の状態を全て記録しておく形か。
しかしそれは扱いにくそう。
どのボタンもしくは軸に変化があったのか知りたい場合、直前のイベントデータと比較しなければならないわけだし。
なにより、そのようなことがしたければイベントハンドラでやればいいと思う。
提供する機能は、必要最低限にしたいのだ。
*
まとめると、イベントで扱えるデータは、まず共通的なものが
・ゲームパッドID
接続時に扱えるデータが
・ボタン数
・軸数
・ボタンの初期状態
・軸の初期状態
状態変化時に扱えるデータが
・変化のあったボタンもしくは軸
・値
こんな具合だと思っている。
ちなみにゲームパッドIDというのは、一意であればなんでもいい。
デバイスのパスのようなデータになると思うが。
あー、ゲームパッド名も接続時、もしくは共通データとして保持するべきか?
ボタンと軸の数についても、接続時以外でも見られた方が便利だろうか。
それなら、接続イベント時にどっかに退避しておく、というのをイベントハンドラでやればいいとも思っているのだけれど。
*
さて、どこから手を付けるか。
やはり接続時に参照できるデータから追加していくべきか。
ゲームパッド接続検出処理ができた。
*
過去のプロジェクトよりはましになった気がする。
過去のプロジェクトでは、pthread_cancel()でスレッドをキャンセルして終了させるために、そのスレッド内では動的なメモリ確保を行なわないようにしていた。
pthread_cancel()で終了するスレッドと、そのスレッドからデータを受け取って処理するスレッド、2つのスレッドを走らせていたのだ。
*
今回は、とりあえず起動するスレッドは1つにした。
スレッド内で使用するデータに関しては、スレッド起動前に生成し、sucrose::GamepadManagerに持たせるようにした。
*
しかし、pthread_kill()を使えばもっとスマートにできるのではないか?
使ったことないから確証はないが、スレッドに対してシグナルを投げられるので、poll()を起こすのに使えるかな、と。
それがうまく行くなら、sucrose::GamepadManagerにメンバとしてデータを持たせる必要がなくなりそう。
*
ひとまず、切断検出を先にやってからにしよう。
とりあえずは動いてるわけだからな。
ちょっとやる気減退してきているような。
*
主にudevが悪いと思う。
でも、なんとか初回のゲームパッド接続検出処理はできた。
過去のプロジェクトを参考にしつつ、多少処理は変えた。
デバイスがゲームパッドかどうかのチェックを簡略化した感じ。
しかし、evdevか。
そんなのもあったな、っていう気持ち。
1つのデバイスについて、/dev/input/jsXと/dev/input/eventXの2つが出てくるからなんだろうと思ったら、後者はevdevのデバイスらしい。
過去のプロジェクトでは、確か見た目だけで判断して前者を使ってたんだけど、どうもこっちは古いらしい。
evdevの方がフォースフィードバックにも対応してるとかなんとか。
なので、今回はevdevの方を採用することにした。
*
明日中には、少なくともリアルタイムのゲームパッド接続検出を仕上げてしまいたい。
切断についても、同じ処理の中に含ませられると思うし、やってしまいたいところ。
で、接続・切断ができたら次はゲームパッドの状態変化検知だけど、これは多少時間かかるだろうな。
デバイスをオープンしてどうの、という処理が必要になってくるわけだし。
sucrose::GamepadManagerの作成に入り始めた。
*
ゲームパッド接続イベントについて、イベントハンドラとかイベントデータとかイベントハンドラ集合とかを作ったのでいよいよ本体。
しかし、午後に野暮用で出かけたせいか、暑かったせいもあり以降やる気出んで途中まで。
なんとか、ただGamepadManagerを生成する部分までは書いたので、明日はその中身。
udevを利用して、ゲームパッドの接続を検出する。
多分、その辺は過去のプロジェクトのソースを流用できるはず。
参考にして手早く済ませたい。
昨日の変更は失敗だったかもしれない。
*
ゲーム固有データ初期化時に、ベースシステムデータを参照できないので、描画イベント内でベースシステムデータ→ゲーム固有データ→OpenGLコンテキストが参照できない、のが問題だったんだけど。
改めて考えてみたら、イベントハンドラにはラムダ式を使えるようにしているので、描画イベント生成前に生成しているOpenGLコンテキストの参照を描画イベント生成時に渡せばそれで見られるわ。
ラムダ式のような構文を使えない、あるいは使いにくい言語とかのために作った、と考えれば全く使い道がないわけでもないか?
それに、ラムダ式の参照だけだと、相互に参照し合う、みたいな状態への対応が難しいか。
いや、そんな構成にすること自体よくないんだが。
*
あとは、ベースシステム起動時に使うデータが、実行中常に触れる状態になってるのもなんか気になる。
実装済みのデータで言えば、ウィンドウのイベントハンドラ。
これはベースシステム起動時に生成するウィンドウで使用するためのものなので、それ以降は必要がなくなる。
しかし、実行中もsucrose::setWindowEventHandlers()を呼び出せてしまう。
意味は全くないが。
しかし意味がないものを呼び出せるというのはなんだか気持ちが悪い。
*
そこで、ベースシステム起動時にのみ使用するデータと、実行中も使用するデータの2つに分ける、という案を思い付いた。
前者はBaseArgs、後者はBaseContextとかそんな名前で。
例えばゲーム固有データは実行中も使用するので、後者に格納される。
ゲーム側からは、BaseArgsはゲーム初期化時には参照できるが、以降は参照できなくなる。
今までベースシステムデータの参照を必要としていた部分は、BaseContextの参照に置き換わるような感じ。
*
せっかくbitbucketに課題管理システムがあるのだから、活用するべきかもしれない。
少なくとも今のプロジェクト作ってからは一度も使っていない。
思い付いた案をここに書いておくだけでも、書かないよりましだとは思う。
しかし、そのうちどこに書いたのかとか、むしろ書いたこと自体忘れてしまうだろう。
そうなる前に、課題として投稿しておくべきだろうな。
ゲームパッドの入力取得の構成を考えている。
*
古いプロジェクトで作ったやつをそのまま使えば楽なのでは、と思いもしたのだが。
前に作ったやつは、いい加減にもほどがあるような構成だった気がする、と思って検索してみた。
古いプロジェクト全てに対しfindでファイルを検索したところ、どうやらdp時代に作ったものが最後だったようだ。
それより後のプロジェクトでは、そこに辿り着く前に作り直してたんだな。
*
ファイル構成をぱっと見て記憶を探ったが、確かこんな感じだったはずだ。
・ゲームパッド接続管理(GamePadManager)で、ゲームパッドの接続、切断を検知
・接続、切断時には、ゲームパッドに結び付くデータ(GamePadKey)がイベントハンドラの引数として得られる
・GamePadKeyを引数に、ゲームパッド1つを表現するオブジェクト(GamePad)を生成することで、対応するゲームパッドの状態変化(ボタンを押した、離したなど)を検知できるようになる
*
GamePadがおかしい。
ゲームパッドは人の手で自由に接続したり切断したりできるのに、それをプログラムが任意に生成できるオブジェクトとして表現するのは違和感がある。
ゲームパッドが切断されているのにGamePadが存在し続けることができるし、逆にゲームパッドが接続されているのにGamePadが存在しないことにもできる。
そういう不自然な構成は、実際に利用しようとすると扱いにくく感じることが多いのだ。
*
そんなわけで、少なくとも物理的なゲームパッドに直接結び付く低レイヤー部分では、任意に生成可能なゲームパッドを表現するオブジェクトなんてのは用意しない方がいいだろうな。
GamePadManagerにゲームパッドの接続、切断検知以外に、ゲームパッドの状態変化についてもイベントを処理させる形がいいかもしれない。
GamePadManager周りについては、古いプロジェクトの処理を参考にしてもいいかもしれないな。
それと、GamePadはGamepadと記述することにしよう。
描画イベントハンドラ内で、ゲーム固有データを参照できるようにした。
*
具体的には、描画イベントデータの中にベースシステムデータを追加した感じ。
描画イベントデータからベースシステムデータの参照を取得し、そこからゲーム固有データの参照を取得する。
これで、昨日の時点で問題になっていた部分は解決した。
2つ関数を呼ばないとゲーム固有データの参照を取得できないとか、なんかめんどうな気もするけど、どうにかするとしたら後でいいだろう。
取得できないよりはずっとましだ。
*
他に目についた問題点といえば、描画処理に関する点だ。
ウィンドウのサイズを変更すると再描画要求が発生し、再描画のために描画イベントハンドラが呼び出される。
イベントハンドラ内で動作確認用のログをstd::printf()で出力しているのだが、ウィンドウサイズをぐりぐりと変更した後、サイズ変更をやめても少しの間ログが出続ける。
垂直同期するような処理はまだ入れてないはずなのに、描画で処理遅延が出るというのは違和感あったので、調べてみたらどうも垂直同期が行なわれていたようだ。
これはなにか対処すべきか、と思ったけど普通に考えて描画イベント内で描画処理をしなければいいだけなんだよなぁ。
変にイベントをまとめたりしてもおかしなことになりそうだし。
*
一段落した感触がある。
次はどこを進めようかな。
ゲームとして最低限必要なもの、と考えた場合、操作系を作るべきか。
マウスやキーボード、そしてゲームパッド。
ゲームパッドをメインに据えたいところだけど、ゲームパッドは個体ごとの仕様がばらばらすぎて、うまく管理したいけどまだいい案がないんだよなぁ。
まぁ、管理部分については後回しでもいいだろう。
低レイヤーなものでも、ゲームパッドが扱えればゲームパッドを動かすと画面に変化が出る、ということができるようになる。
今後上に何か被せるとしても、そのまま使えそうな根底部分の処理を作っていこう。
*
入力ができたら、次は音かな。
画面への描画、プレイヤーの入力処理、音声出力。
この3つができれば、ゲームと呼んでいいものが作れるだろう。
ゲーム固有のデータを扱えるようにした。
*
結局、ベースシステムデータに対し設定する関数を作り、それをゲーム初期化関数内から呼び出す形を取った。
設定ファイルに関数名を記述する形にしなかったのは、簡単に言えばそこまでする必要はないと思ったからだ。
ベースシステムデータの場合は、ベースシステムメイン関数を呼び出す前にゲーム初期化関数が呼び出され、その時点でベースシステムデータが必要になるため、ベースシステムメイン関数とは別に用意しておかなければならないという事情があった。
しかし今回の場合は、似たような形を取ったところでゲーム初期化関数に入った時点ですでにゲーム固有データが生成されている、初期化関数内では生成する処理を書かなくて済む、程度の恩恵しか得られない。
たかがその程度のことのために設定ファイルの要素を増やすこともないだろう。
プログラムに記述する形であれば記述ミスなんかはコンパイラがエラーにしてくれるけど、設定ファイルの場合はその辺も自分でどうにかする必要があるから面倒だし。
*
さて、まだ問題は解決していない。
というより、大きな修正が必要になりそうな別の問題が出てきた。
今日作った機能を使い、昨日作った表示プログラムを修正した。これ。
valgrindでメモリ解放漏れがないか確認したいが、OpenGLを使っているためかこけてしまう。
想定では解放漏れはないんだけど。
その点はともかく、描画イベント中にベースシステムデータを参照することができないという問題が新たに出てきた。
OpenGLコンテキストはベースシステムデータ内のゲーム固有データの中に持たせてあるため、素直にやろうとするとOpenGLによる描画ができないのだ。
なので、今はその場しのぎな処理で対応している。
ゲーム初期化時にゲーム固有データのポインタをグローバルに配置し、描画イベントでグローバルに配置したゲーム固有データのポインタを参照、OpenGLコンテキストを使用する、といった具合だ。
こんな見苦しいやり方は、解放漏れ並みに容認できないので早急に修正したい。
ぱっと思い付く解決法としては、ウィンドウ生成関数、つまりsucrose::newWindow()に引数としてベースシステムデータの参照を追加し、それをイベントハンドラに渡す、という方法だ。
あらゆる箇所でそんなことをすればベースシステムデータへの依存度がやばくなりそう、とは思うものの、そもそもベースシステムありきのシステムなのだから、むしろよく今までやらずにやってこれたもんだな、とも思う。
ソースの色々な場所に、std::printf()によるデバッグログ出力を記述しているが、これも将来的にはベースシステムデータの中にログ出力用データを配置して、それを使ってログ出力したいとも考えているし。
とりあえず、描画イベントの件については上に書いた通りの方法でやってみるか。
他の方法も思いつかないし、あったところでどうせ余計にトリッキーになるし。
とりあえず表示プログラムできた。これ。
*
今のところソースファイルは1つだけ。これ。
ゲーム初期化処理でウィンドウイベントハンドラを生成し、それをベースシステムデータに設定してるだけ。
OpenGLコンテキストの生成もしてるが、ウィンドウ自体の生成はしていない。
構成としては想定通りだ。
しかし、現時点ではの話とはいえゲーム自体にデータを持たせられないのはやはり問題だった。
おかげで、OpenGLのコンテキストとかイベントハンドラの実体とか、そういうのはグローバルに置いてしまっていて、解放処理もしていない。
ゲーム固有データをベースシステムデータに設定する処理を早急に作るべきか。
どのように構成するべきかな。
作ってみた感触としてはゲーム固有データはほぼ必須になる気がするし、ベースシステムデータみたく設定ファイルにイニシャライザ、ファイナライザの関数名を記述する形にするか?
それで、ゲーム初期化処理の関数内に来た時にはすでにデータは生成されている、みたいな。
あるいは上に書いたように、ゲーム初期化関数内で、ベースシステムデータに設定する形にするか。
この場合設定するのは任意となる。
よく考えて構成を決めるべきポイントだろうな。
よく考えてみることにしよう。
XInitThreads()の呼び出しとモジュール分割、両方完了。
*
それに、ベースシステムデータにデータを1つ追加した。
ウィンドウイベントハンドラだ。
設定関数も作った。
ゲーム側からベースシステムデータにウィンドウイベントハンドラを設定すれば、ゲームのメインウィンドウ生成時にそのイベントハンドラが使われる。
明日は今日作った機能を使って、ウィンドウに表示を行なうプログラムでも作ってみるか。
しかし現時点ではゲーム自体にはデータを持たせられないんだよなぁ。
やるべきことはたくさんある。
どこから手を出したものか。
モジュールの初期処理、終了処理の対応ができた。
*
次は、この機能を使ってsucrose側でXInitThreads()の呼び出しを追加するとしよう。
モジュールの依存関係解決機能も使って、モジュール分割もするべきだろうな。
それらが済んだら、いよいよベースシステム側とゲーム側の通信についても取りかかるか。
いや、その前にまだやっておくべきことがあるか。
現状ではベースシステム側とゲーム側とではモジュールの管理が別々になっている。
そのため、両方で使われるモジュールがある場合、初期処理と終了処理が2回呼び出される可能性がある。
だから、モジュールを集中管理するための仕組みを追加するべきかもしれない。
とはいえ、現時点ではあまり初期処理や終了処理に頼らないため、まだ必要ないかも。
XInitThreads()も、2回くらい呼び出しても多分平気だし。
将来的には、多くのモジュールで初期処理と終了処理を使うことになるかもしれないけど。
やる気出てる気がする。
*
というわけで、モジュールの依存関係解決をやっつけた。
今回の追加では、別パッケージのモジュールに依存するようなことはできない。
あくまで同パッケージ内のみ。
別パッケージのモジュールの指定方法をまだ決めてないから仕方がない。
でもまぁ、これでもある程度はやれるはずだ。
というわけで明日からは、初期化処理と終了処理の対応に入る。
ゴールデンウィーク明けからやる気増してきた感ある。
*
イベントハンドラについて大体処理の追加ができて、あとは実際にイベントが発生した時にイベントハンドラを呼び出すくらいになった。
しかし、現在の仕様ではそろそろ限界な感じがある。
モジュールの初期化処理が存在しないため、XInitThreads()を呼び出せていないので、記述自体は合っていてもX11をマルチスレッドで扱おうとしてこけたりしている。
イベントハンドラが完了したら、モジュールの初期化処理と終了処理の対応を追加するべきか。
いや、それをするにはモジュールの依存関係解決をやってからか?
悩ましい。
ベースシステム内で、OpenGLによる描画ができる、というところまで確認できた。
*
次は描画処理をゲーム側で処理させたいところだが、それには多少手間がかかるな。
流れとしては、ベースシステムデータにメインウィンドウに設定するイベントハンドラを用意し、ゲームの初期処理で描画イベント発生時の処理をイベントハンドラに追加、ベースシステムメイン関数でイベントハンドラを元にメインウィンドウを生成、となるんだろうけど。
まず、イベントハンドラとかを作っていない。
ウィンドウに関しても、イベントを全く処理していない。
なので、作ってしまうとしよう。
これらを作り終えたら、次はモジュールの依存関係の解決をやるか?
現状、ゲームとベースシステム、それぞれ1モジュールしか読み込めないし不便だ。
ベースシステムのライブラリに、ウィンドウの処理もOpenGLの処理も全て含めてしまっている状態だし。
必要な処理はきちんと書かれていて、それ以外は書かれてなかったり手抜きだったりのいい感じのソースが書けた。
*
というわけで、ウィンドウを表示するベースシステムが一応はできた。
一応というだけあって、本当に表示するだけでそれ以外何もできないんだけど。
おまけに表示を維持するために無限ループを回しているため、起動しているとCPU1コアの使用率が100%になる。
しかしこれは大きな前進だ。ようやく表示まで漕ぎ着けた。
次はOpenGLに対応させたいところだ。
それができれば、ウィンドウ内に何かを書いて表示することができるし。
それに関しても、とりあえずはベースシステム内で完結させるか。
ゲーム側で描写処理をしたいところではあるが、それにはベースシステムとゲーム間のやりとりについて固めなくてはいけないので多少めんどうだし。
それがない状態で、とりあえずOpenGLが使えるようになるところまでを、先に確認するべきだろうな。
まぁ、OpenGLについても、基本は古いプロジェクトのソースを参考にすればどうにかなるはずだ。
ウィンドウと同じように、参考にした上で簡略化や省略をして、暫定的なものを小さくまとめて実装するとしよう。
とりあえずウィンドウを作らんと始まらぬ、と古いプロジェクトのソースを見たがなんだこれは。
*
本当に私が書いたのか?とコミットログを見たところ、ウィンドウ周りのソースをいじっていたのは2年くらい前のようだ。
無駄に複雑になってるのはこの際無視するとしても、なんだか構成が頭悪い。
std::unique_ptrの扱いにまだ慣れてなかったのだろうか?
自前のデリータを作ればもっと分かりやすく書けそうな処理を見つけ、もやもやとした気分になった。
自前のデリータが使えることを知らなかったわけではなさそうだ。
ウィンドウの他のデータに関してはそれを使っているところもある。
やはり、昔の自分のソースは他人のソースなのだな。
わけがわからないよ。
困ったな、どっから作り始めたものか。
*
やはりベースシステムメイン関数か?
データはどういう処理にするのかが決まらんことには構成しようもないし。
データに対する処理はベースシステムデータ構築時と、ゲームによる初期処理の2つあるが、それは後にするべきだろうな。
とりあえず表示に関する部分から始めるべきか。
ウィンドウ生成処理を古いプロジェクトから持ってきて構成するか。
さくっとできそうだったから、ベースシステムメイン関数についての修正は昨日のうちに終わらせた。
*
で、今日はゲームの初期化処理についての修正をやった。
とりあえずこれを0.8.0とする予定だけど、テストで使用するモジュールとか、その辺もうちょい整えたいな。
明日それをやってから0.8.0としてpushし、先に進もう。
もやもやが多少消えたからか、やる気出てきた気がする。
*
既存のゲームデータ生成、破棄処理をほぼそのまま引っ張ってきて、ベースシステムデータ生成、破棄処理を追加した。
次はベースシステムメイン関数の引数にベースシステムデータを参照を追加し、利用できるように修正しよう。
現状ではmain()でcandymaker::Basesystem内のベースシステムメイン関数を直接呼び出しているが、ベースシステム実行関数を別に作った方がいい気がする。
main()でベースシステムデータを直接参照するのはレイヤーが違うと思うし。
それが終わったらゲームの初期処理についてか。
こっちは、今の構成は破棄して新しい構成にするわけだから、まずは別のソースファイルに作った方がいいだろうな。
さすがにモジュールの扱いを段階分けするのは完了している。
*
しかしモジュールの依存情報の解釈についてはまだ。
というより、色々考えてたらこれもう後回しでいい感じがしているので放置。
ゲーム生成処理をベースシステム関数内でやるとかいうのもありえんのでやらない。
それしたところで、大した違いもないだろう。
*
最近は、ゲームとベースシステムの構成が間違っているのではないかと考えている。
ゲームはベースシステムにアクセスする必要があるが、そのうまい方法を思いつかない、というのが現時点での大きな問題点だ。
色々考えた結果、ベースシステムがメイン関数のみの構成なのがいけないのだ。
ベースシステムは処理だけでなくデータも持つべきだ。
逆に、ゲームの方は初期処理だけでいい。
ゲームにデータなど必要ない。
そのように変更する場合、処理の大まかな流れは以下のようになる。
*
1.ベースシステムデータ生成
2.ゲームの初期処理
3.ベースシステム実行
4.ベースシステムデータ破棄
*
2は引数としてベースシステムデータの参照を受け取り、それに対して処理を行なう。
3はゲームが動作している段階で、4はゲーム終了後の後処理となる。
*
さて、どのように作業を進めたものか。
まずはベースシステムデータの生成、破棄を進めるべきか。
これ自体はただの処理追加なので、楽にできるだろう。
むしろそれを先にやっておかないと、他の変更はベースシステムデータの存在が前提なので作業を進めにくくなりそう。
ベースシステム関数の引数にベースシステムデータの参照を追加するのもそうだし、ゲームの初期処理についてもベースシステムデータの参照を引数として渡す。
それらが完了したら、ゲームからベースシステムにアクセスできるようになるわけだし、いい加減ゲームやベースシステムの方の作成に移ろう。
candymakerをいじくるのはうんざりしてきているのだ。
モチベーションが一向に上がらない原因はそこだと考えている。
書こうとして、またも違和感。
*
設定ファイルに関係する処理が置かれているディレクトリの方にソースを配置すると言ったが、それもおかしい。
設定ファイルの解析処理に関係する処理なんて書かんのだから、そんなところに配置するのは不自然だ。
設定ファイルについては、解析結果を参照するだけだ。
ならば設定ファイルのソースが配置されているディレクトリと同列辺りに配置するのが筋だろう。
昨日は違うか、と言っていた方が正しいような気がしている。
やはり頭が茹で上がるとまともな思考にならん感じある。
多少時間がかかっても、深く考えを巡らせるべきだろうか。
そんな考えを認めてしまうと、考えるだけで無駄に時間が過ぎる気がするから、認めたくはないのだが。
*
ふと思いついて、linuxのインストールCDに含まれているメモリチェックツールを使ったところ、やはりメモリがもうだめな雰囲気だった。
gccがSEGVで死ぬのはおそらくそれが原因だろう。
むしろ、それ以外ではほぼ問題が起こっていない理由が分からない。
並列コンパイルとか高負荷の処理を流さん限り使わないような箇所がおかしくなっているのだろうか。
ともあれ、運が悪いとemergeがこけるというのがいい加減嫌になってきたし、原因がメモリであろうことも特定できたので、交換することにした。
今使ってるのは、安いからという理由だけでよく知らんメーカーのメモリを使っていたので、今回はトランセンドにする。
これまた比較的安い気がする、というのも決めた理由の一つだけど。
どうにもうまくまとまらんと思ったら、モジュールの扱いが低レイヤーすぎるのがいけないんだろうな。
*
パッケージ情報ファイルに依存情報の追加はしたのだが、それをどう扱ったものか考えていた。
現在、モジュールのロードについては、モジュールのパスを引数にして行なっている。
依存情報を扱うなら、例えば依存情報も引数として渡し、そっちのロードを先にやる、という形になるだろうが、現状だとそれはまず無理だ。
モジュールのパスというのはつまり、設定ファイルの内容を解釈した後のものだ。
モジュールのロード処理中では、設定ファイルを解釈するような処理を行なっていない。
依存情報というのは設定ファイルレベルの情報なので、そんなものを渡したところで扱いようがないのだ。
ならばモジュールのパスではなく、設定ファイルレベルのモジュール名やら設定ファイルの内容やらを渡せばいいかもしれないが、それはしたくない。
少なくとも、最終的には現在存在するモジュールのロード処理とかは必要になるのだ。
それをわざわざ壊して複雑化させるなど間違っている。
*
というわけで、モジュールの扱いについて、現在作ってある処理を利用する、より設定ファイル寄りの処理を追加するべきなのだろう、という結論に達した。
結論に達するのが遅い気がする。やはりやる気が足りてない気がする。
間に土日を挟んだり、健康診断で血を抜かれたりしたからといって、もうちょい早くその結論を出せたはずだ。
それはともかく。ソースを見直したところ、現在あるモジュールを扱う処理だが、これはモジュールと言うよりローダーと言った方が正しい気がする。
この辺は将来的にモジュール化して、様々な形式のモジュールを扱えるようにしたい箇所だし。
だから名前を変えて、これから作る処理を新たなモジュールを扱う処理に…と思ったが、それもちょっと違うか。
これから作るのは、設定ファイルの内容を解釈したりといった処理が入るから、そこに置くべきではないな。
置くなら設定ファイルに関係する処理が置かれているディレクトリの方だ。
危ない危ない。全く、先が思いやられる。
やはり想定が甘い。
*
モジュールの扱いのライブラリ化についてやるなら、暫定的、の部分をもっと細かく考えないと進められないな。
依存関係解決についても、きちんとやるならパッケージ設定ファイルとか必要になるし。
こちらも機能を限定した、暫定的なものから作っていくべきだろうな。
やはり依存関係解決から作っていこう。
パッケージ情報ファイルに依存情報を追加し、同一パッケージ内のみ対応、といった感じか?
ベースシステムのメイン取得→ゲーム生成→ベースシステム実行という流れが違う気がしてきた。
*
ゲーム生成関数の引数に、ベースシステムで使用するデータを渡すということは、そのデータを生成する必要があるけど、そのデータ生成どうすんの、という話だ。
そこで考えたことには、ゲームの生成はベースシステムを実行してから、その中でやるべきか、ということ。
これなら、ゲーム生成関数に渡すデータはベースシステム関数内で生成できる。
しかし、ゲーム生成・破棄関数の取得までは定型処理だし、ベースシステム関数内でやるべきではないだろう。
でも、それで本当にいけるか?ゲーム生成関数のシンボル名はベースシステムに依存するわけだし、関数の取得もベースシステム関数内でないとできないのでは?
となると、モジュールのロードをしてからモジュールの参照をベースシステム関数に渡す?
ということは、モジュールの型や関係する関数はライブラリ化する必要がありそうだなぁ。
ライブラリ化については後回しにしたいところだが、それでできるだろうか?
そもそも現時点での実装では、モジュールの依存関係解決などやっていないのだ。
ライブラリだけ作ってもどうしようもない。
*
色々と問題点が浮かび上がってきたな。とりあえずまとめてみよう。
a.ゲーム生成処理の呼び出しをベースシステム関数内に移動
b.モジュールの扱いをライブラリ化
c.モジュールの依存関係解決
こんな感じ?
aを実現したいが、そのためにはbとcが必須。
bは実現したところでcがないと活用できない。
cは前提条件なし。
bかcから始めよう。
bはとりあえず暫定的なものでいいだろう。想定ではかなり簡単にできるはずだ。
問題はcか。前のプロジェクトで似たような処理は作ったはずだから、それを活用できれば早いか?
*
とりあえず現在の状態を0.6.0としてしまおう。
ゲームの生成まではできた。
*
しかし、このままでは生成ができるだけで、ベースシステムとはなんの通信もできない。
どうするかなぁ。通信インターフェースを作るのまで含めるか、それともこの辺で、ソースを整えて0.6.0とするか。
ソースを整えるのはやるとしよう。
*
ベースシステムとゲームの通信はどうしよう。
ベースシステムのメイン取得→ゲーム生成→ベースシステム実行としているが、ベースシステム実行時に生成したゲームを引数として渡すか?
今の構想ではそれは向かないように思える。
ベースシステムからゲームに対してアクションをかけるということは、ゲーム側に決まった関数でも定義しておかなければ難しいだろう。
そして、ゲームにはできれば決まった関数というのは用意したくない。
ゲーム側の必須関数は生成と破棄だけにしたいのだ。
ゲーム側の生成関数の引数に、ベースシステムで使用するデータを渡し、そこにイベントハンドラを設定していく、という形になるだろうか。
この形なら、決まった関数はベースシステム側に作られ、それを介してベースシステム側からゲーム側を操作できるようになるはずだ。
お腹きゅうきゅうする。
*
raspberrypiはそろそろもういいかなという感じ。
というよりやりすぎた感じ。
やりすぎちゃって、軽く燃え尽きちゃってる感じある。
このままではいかんと思い、candymakerのソース眺めたりなどしていた。
戻らねば。
*
やりすぎたかいもあり、なかなかのものができた、と思うんだけど、最新の修正を適用したものの動作確認がまだ。
1人では動作確認できないのが厳しいところだ。
理論的にやってできないことはないはずなのだが、なぜかうまくいかなくて困る。