セーブデータに埋め込まれたスクリプトをお手軽にクリーニングできるツール

みんな待ってた?
このツール!
 
 
バイナリエディタを使って無理やり全てのスクリプトをクリアする方法を以前、記事に書きました。
あの方法だと、本来クリアしちゃいけないデータもまるっとクリアしちゃうので、様々な弊害が発生する可能性が大いにありました。
特定のMODだけを確実に狙い撃ちしてクリアするのはとてもハードルが高く、正直、「めんどくさすぎてやってられない」レベルです。

ここでもう一度おさらいしておきたいと思います。

何故、セーブデータに埋め込まれたスクリプトをクリーニングする必要があるのか?


MODを無効にしても、そのMODが使っていたスクリプトの情報がセーブデータに残る場合がある…からです。

じゃあ、何故、それが問題なんでしょうか?


MODは既に無効になっているのに、セーブデータに残ったスクリプト情報を使ってスクリプトを動かそうとします。
このとき、エラーが出たり、CTDを起こしたりします。
エラーはPapyrusログに記録されるため、意味不明な内容でPapyrusログが汚れ、処理する必要のない処理がメモリ空間とPapyrusのコールスタックをいつまでも占有し、処理しなければならないスクリプトの邪魔をします。


親切なMOD作者なら、セーブデータにスクリプトが残らないようなアンインストールの手順をMODのダウンロードページなり、MODに付属しているテキストなりに書いていますが、全てがそうなっているとは限らず、また、MODを使う側もきちんと作者が書いたアンインストール方法を読んで、手順通りにアンインストールするとは限りません。


ということで、うっかりセーブデータにスクリプトが残っちゃったときに捗るツールです。

使い方に関しては、MODデータベースさんに書かれている説明で十分ですから、セーブデータにスクリプトが残ってしまう状況をわざと作って、このツールでクリーニングし、どうなるか見てみましょう。


MODの準備

Creation Kitを使い、ロード直後にスクリプトが走るMODを作ります。
詳しい手順は重要じゃないので割愛。

MODに仕込んだスクリプトは以下。

ScriptName Test_Script extends ReferenceAlias

auto state FirstState
event OnPlayerLoadGame()
Debug.Trace("Test_Script : OnPlayerLoadGame")
Debug.Notification("Test_Script : OnPlayerLoadGame")
RegisterForUpdate(10.0)
GotoState("SecondState")
endevent
endstate
state SecondState

endstate

event OnUpdate()
Debug.Trace("Test_Script : OnUpdate")
Debug.Notification("Test_Script : OnUpdate")
endevent

セーブデータをロードした直後かニューゲームした直後に OnPlayerLoadGame() が実行されます。
このとき、Papyrusログと、ゲーム画面の左上に Test_Script : OnPlayerLoadGame というメッセージが表示されます。

次に、10秒毎に OnUpdate() を呼び出す処理と、次回ロード時は OnPlayerLoadGame() を実行しないようにする処理が書かれています。

現実の時間で10秒経過するごとに、OnUpdate() が実行され、Papyrusログと、画面の左上に Test_Script : OnUpdate というメッセージが表示されます。

なので、ゲーム画面にこのメッセージが出たら、このスクリプトの処理が走ってるということが分かります。

0 test script.esp という名前でMODを作成し、Creation Kit を終了。


Vanillaでゲームを進めておく

まだ 0 test script.esp は使いません。
公式の Update.esm 以外、一切MODを使わない状態でゲームを進めておきます。
とりあえず、オープニングのゴタゴタが終わって、リバーウッドで一息つくところまで進めてセーブ。



一旦、ゲームを終了。

Alternate Start 使ってるから、久しぶりにオープニング見たわぁw


スクリプトを走らせる

スカイリムランチャーを起動して、0 test script.esp を有効にします。



MODを有効にした状態でセーブ→ロードしないと、OnPlayerLoadGame() が実行されない場合があります(現在の私のPCではそうです)。
なので、さっきセーブしたデータをロードし、更に新規でセーブ。
ゲームを再起動して、新規セーブしたデータをロード。



OnPlayerLoadGame() が実行されたことを確認。
10秒待ちます。



OnUpdate() が実行されたことを確認。
これ以降は、10秒毎に Test_Script : OnUpdate のメッセージが表示され、仕込んだスクリプトが問題なく動作していることを確認できました。

新規セーブしてゲームを終了。


MODを無効にした状態でスクリプトが走るか確認してみる


0 test script.esp を無効にします。

さっきセーブしたデータをロード。


使っていたMODが無効になっているので、警告メッセージが表示されます。
0 test script.esp がきちんと無効化されていることが確認できました。

0 test script.esp は無効になっているわけですから、普通に考えたら、このMODに仕込んだスクリプトの処理も無効になるはず…ですが…。


OnUpdate() は実行されちゃう。

くどいようですが、0 test script.esp は無効になっています。
なのに、スクリプトは動いています。
頭をもいでも動き続ける昆虫のような気味の悪さ。

このように、スクリプトを仕込んだMODを無効にしても、セーブデータにはスクリプトの情報が記録されていて、勝手に動く場合があります。


さらに細かい話

スクリプトの本体は Data/Scripts フォルダにある pex ファイルで、セーブデータに記録されるのは、この pex ファイルに書かれているスクリプトにアクセスするための情報だけです。
MODを無効にしたとき、スクリプトの本体である pex ファイルも削除してしまえば、スクリプトの本体がなくなるので、スクリプトは動作しなくなります。
ただ、Papyrusログが「スクリプト呼び出せねーぞ!」というログで汚れます。

[01/15/2015 - 12:58:16PM] Cannot open store for class "Test_Script", missing file?
[01/15/2015 - 12:58:16PM] warning: Unable to get type Test_Script referenced by the save game. Objects of this type will not be loaded.
[01/15/2015 - 12:58:16PM] warning: Could not find type Test_Script in the type table in save

ロードする度にこのログが出ます。

いや、MODも無効にしたし、pex ファイルも削除して、スクリプトを呼び出せないことは、プログラム側で把握できているはず。
だったら、この状態でセーブすれば、スクリプトの情報もセーブデータから削除されてスッキリするんじゃないだろうか?
セーブデータをクリーニングするツールなんて必要じゃいんじゃないだろうか?

という発想に至るわけですが…

[01/15/2015 - 01:01:15PM] Cannot open store for class "Test_Script", missing file?
[01/15/2015 - 01:01:15PM] warning: Unable to get type Test_Script referenced by the save game. Objects of this type will not be loaded.
[01/15/2015 - 01:01:15PM] warning: Could not find type Test_Script in the type table in save

やっぱりエラーが出る。
セーブデータをクリーニングしない限り、スクリプトの情報がなくなることはありません。
なので、クリーニングするツールはあった方が良い。


セーブデータに残ったスクリプトをクリーニング

SaveGame Cleaner を起動。


右上の Open ボタンをクリック。


最後にセーブしたセーブデータを選択。


セーブデータを Open した直後の様子。

このツールの便利なところは、特定のスクリプトに関係する情報だけを表示できる点です。
左上の Scripts に、0 test script.esp で仕込んだスクリプトファイルの名前(test_script)を入力します。


すぐ下のリストボックスに表示されてた項目が減りました。
Test_Script と書かれた項目だけ抽出されているのが分かります。


Papyrusスクリプトでは、英語の大文字と小文字の区別をしないので、そこは気にする必要はありません。
test_script も Test_Script も TEST_SCRIPT も、全て同じものとして扱われます。


Test_Script のインスタンス
インスタンスが生成されることによってスクリプトが動く


多分、state の値


多分、OnUpdate の呼び出し情報

これらの値を個別に削除することもできますが、0 test script.esp が使っていたスクリプト情報をまるっと削除するのが目的です。
ボタンいっぱつで、まるっと削除する機能を使いましょう。


Mod editor ボタンを押す。


有効にしているMODの一覧が表示されるので、スクリプトの情報を削除したいMOD(0 test script.esp)を選択(チェックがついた状態にする)。


Delete selected mods scripts ボタンを押す。


Test_Script の情報が削除されたことが分かります。


この状態のセーブデータを作るため Save as ボタンを押す。


とりあえず、分かりやすいように editedSave.ess という名前で新規保存。


今回クリーニングしたセーブデータではSKSEを使っていないので .skse ファイルは作られませんが、SKSEを使っている場合は .skse ファイルも一緒に作られます。


クリーニングしたセーブデータをロード。


しばらくほったらかしにして見ましたが、メッセージは出なくなりました。
pex ファイルはまだ Data/Scripts に入っているので、もしクリーニングに失敗したのなら、メッセージが出るはずです。
メッセージが出ないので、きちんとクリーニングされたことが分かります。
 
この記事へのコメント
コメントを書く
お名前:

メールアドレス:

ホームページアドレス:

コメント:

認証コード: [必須入力]


※画像の中の文字を半角で入力してください。
※ブログオーナーが承認したコメントのみ表示されます。