Open yumetodo opened 7 years ago
@S-H-GAMELINKS まだ怖くてデバッグできていないのでマージしないでください。多分大丈夫と思いたいですが・・・。
KeyState&
と引数の型がなっている場合はキー操作との同期が発生するが、関数を抜けるまでにflushとupdateがされた状態で関数を抜ける
が実現できていない箇所がある可能性があり、その場合明確なバグです。何回もチェックはしているのですが、変更が多すぎて正直脳内がパンクしそうです。
ソースコード内のTODO:
コメントにも書きましたが、多くの関数がKeyState
クラスを受け取る仕様になっているのはもともとの関数分けが下手くそだからで(viewとlogicが混ざっている)、そのせいで若干無駄にflushせざるを得ない部分も生じているのでキー操作が絡むものはもっと呼び出し階層が浅いほうに持っていきたいのですが、それをするとdiffが仕事しなくなるのと私の脳が破裂するのでひとまずPull Requestを出しました。
恐る恐るデバッグボタンを押したら・・・うーん、あーもーだめだー(AMD)。取り除いたらあかんsleep処理かflush処理を取り除いてしまっているなこれ・・・
一通りチェック致しました。
一回、マージして実機で動作させて修正していく方がいいかもしれませんね……。
KeyState::flush_stream
の中の比較処理が意外と処理コストがかかっているのでSIMD化しないとだめですねこりゃ(それよりも管理人さんにお願いしてキー判定がなくなるまでwaitする関数をつくってもらうべきかもしれない、DxLib::GetHitKeyStateAll
のコストも馬鹿にならない・・・)。
とりあえず、動作確認してみました。
キーが押されてる間、ずっと式が成立しているようですね……。かなりのスピードでカーソルが……
あー、処理コストかかってますか……。
お願いするのが、いいかもしれませんね
実際に動作させてる中で、以下の二点もわかりました
・クリック待ち処理がEnterキー二回押すことで終了している? ・セーブ/ロード時に「セーブ/ロードしました!」のメッセージ後にDebug Assertion Failedと出ている。
とりあえず管理人さんにはお願いしてきました
http://dxlib.o.oo7.jp/cgi/patiobbs/patio.cgi?mode=view&no=4158
ありがとうございます。
今のところ、先ほどの二点が確認されたのみで、そのほかは問題なく動作しているようです。
セーブ/ロード時に「セーブ/ロードしました!」のメッセージ後にDebug Assertion Failedと出ている。
手元では再現しないですね・・・。Debug Assertion Failedで再試行してやるとVSのデバッガに飛べるのでそれでまずどのアサートに引っかかっているのかがわからないと・・・
デバッガで見てみたところ stdthrow.cpp
の_CrtDbgBreak()
で例外がスローされたようですが…。
ちなみに、こちらが実際の画面です。
いや、コールスタック張ってくれないとなにもわからないですって・・・。そのDebug Assertion Failed
のウィンドウで再試行
を押してコールスタックの部分を見てください
……申し訳ない、こちらでよかったですかね…
@S-H-GAMELINKS それはmaster
(04d7f9233c0708e385588dd100d84a6c6895d51c)では再現しないですか?そのへんはいじっていないはずなので・・・
試してみたんですが、再現しないです……
試しに、releaseでビルドしたもので動作確認したんですが、問題なく動作してますね……
string subscript out of range で調べてみるとこんなものが見つかりました。
もしや、こちらのデバッグ設定の問題かもしれません……。
試しに、releaseでビルドしたもので動作確認したんですが、問題なく動作してますね……
それは当たり前です。C++11からstd::stringが文字列を格納する領域の連続が保証されています。また、std::basic_string::data
関数がある以上、std::stringが文字列を格納する領域はNULL文字終端します。つまりstd::basic_string::operator[]
にstd::basic_string::size
の結果を渡した場合、領域外アクセスですが、多くの実装では\0
を返します。Debugでだめなのは領域外アクセスを検知するからですね。
つまりアサートが出る時点でCP==String[SP].size()
となっています。
…はあ、そういう事だったんですか…
だから余計につらいです・・・うーむ。
いっそ範囲外アクセスはstd::basic_string:at
を使って例外飛ばして補足して握りつぶしてしまおうか・・・
その手になりそうですよね…
しかしmaster
で発現しないのは本当に不思議・・・
うーむ。debugで引っかかるわけですし、何らかの設定が変更された…?
いや、それならyumetodoさんの方でも同じ現象が確認されてるでしょうし…
わからんですね…
また別の現象発見・・・
マウスが有効の状態でタイトル画面にいると、マウスとキーボード両方で制御を取り合う・・・というよりキー操作が無効にならない・・・
マウス有効時のキー操作が無効にならない現象、こちらでも確認できました。
すみません、3.00のソースと見比べていて気付いたんですが、もしかしたらキー操作関連の関数に
if (ConfigData.mouse_key_move == 0)
がないのが原因かもしれません……
@S-H-GAMELINKS でもなぜかmasterでは再現しないんですよね・・・ 対応策としてはご指摘のとおり、キー操作系関数でそれを見るようにすることですが。
……そのことなんですが、先ほどのPull request(#29)をマージ後に同様の現象がmasterでも発生しました……
……何なんでしょうかね、これ。
えー、それらしい箇所が判明しました。
ウインドウ風とサウンドノベル風の下記の部分がどうも影響していた模様です。
if (SP != 0) {
SP = SP - 1;
CP = EOF;
}
どうも、CP = EOF
とわたっている部分がassertに引っかかってるのではないかと……。
反応遅れました。
あああ!リファクタリング初期に「なんでEOFが・・・?」と思っていましたが、すっかり忘れていました。
たぶん、ゲームメニューから戻る際に、実装した部分ですね、これ……。
確か、ゲームメニューから戻る際に最後に表示していた行を描画するためだったかと……
vectorで動的配列に変更した際に、この部分がassertに引っかかったんでしょうね……。
いや、申し訳ない……。
これEOF
が-1
を想定していますよね?するとstd::vector
じゃなくてもそれをoperator[]
に渡すのはUBなので仕様変更しないといけないですね・・・
またそもそもEOF
が-1
とは規定されていないのでそもそもアウトですね。
対応策は一応、なんとか用意できました。
SP - 1
CP = EOF
この部分の SP - 1
を取り除いて、 CP = 0
のみに変更することで問題ないと思われます。
一応、手元のbranchでテストしてみましたが、問題なく動作するようです。
@S-H-GAMELINKS その手元のbranchをmasterに反映していただけますか?こっちにも取り込みたいので
こちらのコミットで修正してあります。よろしくお願い致します。
@S-H-GAMELINKS WINDOWNOVEL
関数の方も修正が必要かと思っているんですがどうでしょうか・・・?
とりあえず、修正しておきました
あと、fmtのsub module バージョン上げておきましょうか?
ちょうど、4.0.0もリリースされているみたいですし
そうですね。Change log見る限り影響はなさそうですし、上げてコンパイルが通ればmaster反映お願いします。
@S-H-GAMELINKS とりあえずstd::string::operator[]
のassertに引っかかる件は解決でいいですかね?
はい。これで解決できたと思います。
memo: 東方輝針城では1200msキー移動にラグ
キー操作の速さに関してなんですが、物の試しにKeyState::updateのreturnの前に
std::this_thread::sleep_for(70ms);
を追記してみたところ、キー操作の遅延に成功しました。
あとは、数値をうまく変更してやれば、キー操作の速さはうまくいくかもしれません。
やっぱりそういう方向の解決策ですよねぇ。ちょっとやってみます。
やはり、こういう方法になりそうですね…。
よろしくお願いします。
@yumetodo さん
お忙しいようでしたら、一回こちらでPRをマージしてキー操作の遅延処理を実装しましょうか?
あー、いや、完全にこれやるのを忘れていました・・・。 10/7までに終わるめどが立たなかったら再度書き込みます・・・
あ、いえ、大丈夫ですよ
承知しました。
あと、本当にお忙しくて難しいようでしたらおっしゃってください。 こちらで実装しますし
MessageBox
系関数にKeyState
クラスを渡し、確実に入力がflushされるように( try to resolve #20 )基本方針
KeyState
クラスを介して行うMessageBox
でのこるキー判定を削除するためにこれをラップする関数にKeyState
クラスを渡すKeyState
クラスを受け取るconst KeyState&
と引数の型がなっている場合はKeyState
クラスにキャッシュされたキー入力を見るKeyState&
と引数の型がなっている場合はキー操作との同期が発生するが、関数を抜けるまでにflushとupdateがされた状態で関数を抜けるIssue
std::string::operator[]
のassertに引っかかる => 55f4a291f7f0c26c906b3a0049e5375d44698288, 04c420198596f7d7ae8334343d969a3da5786b67ref:
20
21