*華和梨と栞ロードとゴーストキャッシュ [#i1a3a6ac] アリス「おかしいわ。おかしいわ。何だかとってもおかしいわ。」~ ボブ「HI! どうしたんだい、海老名グリーンみたいなことを口走って!」~ アリス「誰が海老名パーキングエリアよ。~ それより、ゴーストを作ってるんだけど、ゴーストを切り替えるたびにセーブデータがぽこぽこ増殖していくのよ。~ いったい、何がおこってるの?」~ ボブ「HAHAHA! そいつはゴーストキャッシュという名のSSPの仕掛けた恐るべきトラップなのさ。」~ アリス「どーにかする方法はないわけ?」~ ボブ「HAHAHA! まぁ、落ち着けよアリス。~ この問題を理解するにはゴーストキャッシュの挙動と栞ロード/アンロードのタイミングの理解が必要なのさ!」 *目次 [#v35704f4] #contents *栞ロード/アンロードとゴーストキャッシュ [#ycc19f44] 通常、ゴーストが起動/終了するとき、栞ロードと栞アンロードが発生します。~ ところが、SSPのゴーストキャッシュが有効である場合、ゴーストキャッシュからゴーストが起動したり、ゴーストキャッシュに入ったりする場合には栞ロードや栞アンロードが発生しません。~ これが華和梨的には由々しき問題なのです。 *栞ロード時とゴーストキャッシュからの起動時での挙動の差 [#m6f7308c] 栞ロードが発生したとき、華和梨は「エントリの初期化」と「スクリプト記述ゾーンのKISの実行」を実施します。~ ところが、ゴーストキャッシュからの起動ではこれらの処理が実施されず、「各エントリの前回終了時の状態の復元」が実施されます。~ この挙動の差が問題なのです。~ どういうこと?~ **ちょっとテスト [#r9104b77] kawarirc.kis に以下のようにだけ書いてゴーストを起動します。~ ほげ: 0 System.Callback.OnGET: $(.entry ev.${System.Request.ID}) ev.OnBoot: $(inc ほげ)\1\s[10]\0\s[0]${ほげ}\e ev.OnClose : \- ev.OnGhostChanging: \e まずはゴーストキャッシュを無効にして、このゴーストを起動します。~ 普通にゴーストが起動すれば起動時に「1」と喋ります。起動時に「ほげ」エントリの内容を話していますが、この「ほげ」エントリの初期値は「0」でOnBootイベント受信時に1増やしているので。~ もちろん、このゴーストを他のゴーストに切り替えて戻したり、他のゴーストから呼び出してみても起動時に「1」と話します。~ ところがゴーストキャッシュを有効にしてこのゴーストを起動してみると……。 最初の起動時こそ「1」と話しますが、他のゴーストに切り替えてすぐにもどしてみると「2」と喋り、もう一度やってみると「3」になりと、起動すればするほど喋る値、つまり、「ほげ」エントリの値が増えていきます。 ***どうしてこうなった?(AA略) [#adfb1227] ゴーストキャッシュからゴーストが起動される時、「各エントリの前回終了時の状態の復元」が実施されるので、「ほげ」エントリは「0」で初期化するのではなく、前回終了時の「1」という状態を復元されてしまっているのです。~ そのため、OnBoot受信の契機で「1」である「ほげ」エントリは$(inc ほげ)により更に1増えて「2」となるのです。 **倍増するエントリ [#raf0085b] 次はこんな感じで。 System.Callback.OnGET: $(.entry ev.${System.Request.ID}) ev.OnBoot: $( load sav.txt; inc 起動回数; )\1\s[10]\0\s[0]起動回数:$(join 起動回数 ",")\e ev.OnClose : $(save sav.txt 起動回数)\- ev.OnGhostChanging: $(save sav.txt 起動回数)\e まずはゴーストキャッシュを無効にして、このゴーストを起動します。~ ゴーストが起動すれば起動時に「1」と喋り、起動するごとに「2」、「3」と増えていきます。~ ゴースト終了時(OnCloseやOnGhostChanging)の契機で「起動回数」エントリをセーブし、ゴースト起動時(OnBoot)でそれをロードして1増やしているのですから当然ですね。 ところがゴーストキャッシュを有効にすると……。~ ゴーストを切り替えたりするごとに、起動時のトーク、つまり、「起動回数」エントリの中身が「1」→「2/1」→「3/1/2/1」とカオスなことに。 ***どうしてこうなった?(AA略) [#kfc4dc99] ゴーストキャッシュからゴーストが起動される時、「各エントリの前回終了時の状態の復元」が実施されるのはさっき述べた通り。~ そのため、OnBootイベントを受信したときには既に「起動回数」エントリには「1」という値が設定されています。~ ところが、OnBootイベントでさらにセーブデータのロードを実行することに「ほげ」エントリに「1」という単語がもうひとつ追加されて、「1」が「1,1」という2つの単語を持った状態になってしまうのです。~ で、OnBootイベントでの$(inc 起動回数)により、コレが「2,1」に。~ もちろん、この状態でゴーストを終了すればセーブデータには「2,1」という2つの単語を持った状態でセーブされ、再びゴーストキャッシュから起動されたときに「起動回数」は「2,1」の状態が復元された上にOnBootイベントでさらにセーブデータの内容を追加され「2,1,2,1」となり、$(inc 起動回数)されるので「3,1,2,1」と倍増していくのです。 *ゴーストキャッシュ対策 [#y4bfb14d] **セーブデータのロードはスクリプト記述ゾーンで [#g01e0713] 一番簡単な対策はスクリプト記述ゾーンにセーブデータのロード処理を書いてしまうこと。~ ゴーストキャッシュから起動するときにはエントリの内容は前回終了時の状態が復元されるのだから有難くそれを使わさせてもらうことにして、通常の栞ロードが発生した時だけセーブデータから値を読み込んで使いましょう。 これはこんな感じ。 =kis load sav.txt; =end System.Callback.OnGET: $(.entry ev.${System.Request.ID}) ev.OnBoot: $(inc 起動回数;)\1\s[10]\0\s[0]起動回数:$(join 起動回数 ",")\e ev.OnClose: $(save sav.txt 起動回数)\- ev.OnGhostChanging: $(save sav.txt 起動回数)\e **エントリの状態の初期化はOnCacheRestoreにも [#oc0d0a33] セーブデータが増えるのはこれでいいとして、前の方に出てきた「ほげ」エントリのようにセーブ対象ではないけれど起動時に初期化したいエントリはどうしましょう。~ 実は、ゴーストキャッシュからゴーストが起動されるとき、SSPはOnCacheRestoreというNOTIFYイベントを投げてきています。この中で値の初期化を実施しましょう。 こんな感じ。 ほげ: 0 System.Callback.OnGET: $(.entry ev.${System.Request.ID}) System.Callback.OnNOTIFY: $(.entry ev.${System.Request.ID}) ev.OnBoot: $(inc ほげ)\1\s[10]\0\s[0]${ほげ}\e ev.OnClose: \- ev.OnGhostChanging: \e ev.OnCacheRestore: $(setstr ほげ 0) どうせなら処理を共通化。 =kis function 初期化処理 $(.setstr ほげ 0); 初期化処理; =end System.Callback.OnGET, System.Callback.OnNOTIFY: $(get ev.${System.Request.ID}) ev.OnBoot: $(inc ほげ)\1\s[10]\0\s[0]${ほげ}\e ev.OnClose: \- ev.OnGhostChanging: \e ev.OnCacheRestore: $(初期化処理) これでめでたしめでたし……と思いきや。 *ゴースト起動中の栞リロードとか終了イベントを経由しないゴースト終了 [#zd9d50eb] 前にこのへんに書いた話ではダメだったので没にしますた。さーせんww 続きは[[そずべねぐ/セーブとロードのおはなし]]で。 このへんに書きたい話のネタ +ネットワーク更新時、栞を含むサプリメントインストール時、SSPでの\![reload,shiori]、\![reload,ghost]タグではゴースト起動中に栞リロードが発生する。 +ゴーストの起動時にゴーストの起動時刻を終了してゴースト終了時にそれを喋らせたいとする。 +ただ、kawarirc.kisのスクリプト記述ゾーンの中で起動時刻を取得するとゴースト起動中の栞リロード時に値が上書きされてしまう。 +じゃあ、通常終了時には起動時刻をセーブせず、ゴースト起動中の栞リロードでは起動時刻をセーブしよう。 +つまり、いつもセーブするエントリ群とネットワーク更新時だけセーブするエントリ群がある(OpenKEEPSで言うところのbackupparam) +ゴースト起動中の栞リロードに関係するイベントを拾ってフラグON、その後のOnUpdateCompleteとかOnInstallCompleteとかを拾ってフラグOFF。\![reload,shiori]に対応して、kawarirc.kis内での初期化処理でもフラグOFF。 +デバッグメニューでのSHIORIリロードはやっぱり非救済ってことで。 以下は別の話。別のページに書く? +関係ないけどOnVanishedって起動中にも来るよね。 +ということは起動イベント受信時に起動イベント受信フラグ立てて、ネットワーク更新時にはセーブしないと。 +起動時に起動イベント受信フラグを消してからデータロードすれば通常のゴースト起動では起動イベント受信時に起動フラグが存在しないし、起動中の栞リロード後は起動フラグが存在する状態になるね。 *参考リンク [#nfc8b163] -[[らくだ屋/華和梨メモ]] *コメント [#jb6b4e1f] - よく考えたらトーク中の![change,ghost,random]とか拾ってなかった。OnTranslateで拾おう。 -- [[そずべねぐ]] &new{2009-12-23 (水) 07:51:04}; #comment