バグ: 一部の条件を満たしたテキストセルを表示した後に非表示にするとセーブ時に異常終了

Issue #1047 resolved
tachi gigas created an issue

お疲れ様です。
β1のリリース後に本当に申し訳ございませんが、詰まったのでご教示をお願い致します……。

コモン変数を用い、再表示時の処理が「状態変数値を更新する」となっているテキストセルを表示した後に非表示にすると
セーブ時に異常終了する現象を確認しました。
検証に用いたシナリオを添付します。
最初は使用したカード名をテキストセルにした時に起きるかと思っていましたが……。

cw.sprite.background.TextCellDatanamelistにて、dataメンバは存在するがnameメンバがNoneであるためアサーションエラーとなります。
テキストセルを非表示する際の画面再構築コンテントで背景がリロードされ、_add_textcell関数が呼ばれるのですが、
そこで再表示時の処理が「状態変数値を更新する」となっていて、フラグ・ステップ・コモンであるnamelistのアイテムについて
nameメンバのみがNoneに書き換えられているためです。
いつもご迷惑をおかけする所ではあるのですが、僕は内部仕様に詳しくないので、この場合はどう修正すれば良いのでしょうか。

Comments (11)

  1. k4nagatsuki repo owner

    namelistすなわちNameListItemのリストはテキストセルやメッセージに表示される特殊文字の内容をリスト化して記録したものですが、その構造は基本的には

    • item.nameには実際に表示される文字列が入る
    • item.dataにはその文字列の由来となったデータ(#M#Rなら該当キャラクターのインスタンス、状態変数値ならフラグやステップのインスタンス、等)が入る

    ……となっています。

    が、コモンの場合は少々ややこしく、なぜそうしたのか自分でもよく分からないのですが(型情報が必要という事なのだろうが今見るとテキストとして表示するだけのデータの型情報を記録する必要が無さそうに思えるので単なる判断ミスの可能性もある)、コモンの場合は例外としてitem.nameにコモン値そのもの(数値だったり真偽値だったりする)が入っており、そしてそれを型情報と共にセーブデータに保存しています。

    テキストセルをいちど表示したあと消すと、そのセルの設定にもよりますが、セルに表示されているコモン値は存在しない状態、すなわちNoneになります。これがセーブ処理の想定から抜けていた部分で、バグの原因です。

    これを解決するにはNone値をきちんとセーブデータに書き出す仕様が必要です。

    cw.xmlcreater.create_scenariolog()から問題のアサーションを削除し、

                        elif isinstance(item.data, cw.data.Variant):
                            e_name.set("type", "Variant")
                            e_name.set("variant", item.data.name)
    
                            if isinstance(item.name, list):
                                cw.data.Variant.value_to_element(item.name, e_name, typeattr="valuetype")
                            elif isinstance(item.name, bool) or not isinstance(item.name, int)
                                e_name.set("valuetype", cw.data.Variant.value_to_type(item.name))
                                e_name.text = cw.data.Variant.value_to_str(item.name)
                            else:
                                assert item.name is None
    

    のように変更して、valuetypeを書き出さない場合は値はNoneである、という事にするのがよさそうに思えます。

    読み出し側(cw.sprite.background.BackGround._create_textcelldata()では:

                        elif vtype == "Variant":
                            name2 = e_name.getattr(".", "variant", "")
                            if e_name.getattr(".", "valuetype", None):
                                name = cw.data.Variant.value_from_element(e_name, "valuetype", None)
                            else:
                                name = None
                            if name2 in cw.cwpy.sdata.variants:
                                data = cw.cwpy.sdata.variants[name2]
                            else:
                                data = None
    

    のようになるでしょうか(valuetypeがなかったらnameNoneにする)。

  2. tachi gigas reporter

    ご多忙の中、ご教示頂いた上、コードまで提示頂きまして誠に恐縮です。手許でも正常な動作を確認いたしました。
    お手隙の際にご確認をよろしくお願いいたします。

    pull request #279

  3. tachi gigas reporter

    それで、すみません……今、非常に混乱しているのですが、
    今朝方確認したところ、直っておりません。僕は一体昨日何を見たんだ。
    後でエラーログも念の為もうひとたび添付いたしますが、
    コードの場所を移動させたassert item.name is not Noneでアサーションエラーになります。

    item.nameNoneとして書き出すべきという話でしたが、
    str(None)"None"となるため、文字列"None"を書き出す必要があるのでしょうか。
    その場合、実際のコモン変数の中身として"None"が入っている場合、見分けがつかないので、どうしたものでしょう。

    申し訳ございませんがご助力お願いいたします……。ちょっと頭冷やしてきます。

  4. k4nagatsuki repo owner

    ありゃ、アサーションの条件が逆になってますね。ここに来る場合、item.nameNoneのはずです。

  5. tachi gigas reporter

    時間があき、申し訳ありません。

    件のアサーションの部分は、`item.Name`が`None`の時も実文字列がある場合も通る箇所であり、アサーションというよりif文にした方がよいという形と認識しております。こうする事で、Noneが入る際も中身のないxmlになると思います。こんな時間で恐れ入りますが、お手隙の際にご確認いただきますよう、お願いいたします。

    pull request #281

  6. k4nagatsuki repo owner

    上記マージしました。ありがとうございます。

    構造体対応の問題があったので私の方で追加で修正しておきます。

  7. tachi gigas reporter

    お疲れ様です。時間が経ちまして恐れ入りますが本件解決済み&投稿者が僕につきクローズ操作いたします。

  8. Log in to comment