Skyrim MOD製作:NexusModsでのファイル公開手順 (その2:イメージの登録)
NexusModsでのファイル公開手順 (その1:登録の開始)の続きです。
今回はイメージのアップロード方法を説明します。
関連記事
- NexusModsでのファイル公開手順 (その1:登録の開始)
- NexusModsでのファイル公開手順 (その2:イメージの登録) --- 本記事です
- NexusModsでのファイル公開手順 (その3:必要条件とファイルの登録)
- NexusModsでのファイル公開手順 (その4:その他の操作)
- NexusModsでのファイル公開手順(その5:Skyrim SE用のファイル公開)
- Nexus Mods:ドネーションポイントシステム開始に伴う変更点と操作方法
参考リンク:
- Skyrim MOD作成Wiki - MODの英語ページ --- MOD公開に関する英語のコツが書かれています
Skyrim MOD製作:NexusModsでのファイル公開手順 (その1:登録の開始)
自分で制作したMODをNexusModsで公開する手順をまとめてみました。
せっかく苦労して制作したMODだから全世界のプレイヤーに見てもらいたい。でも言葉の壁があって… という方は意外と多いのではないでしょうか。
結論から言えば英語が全然できなくても問題ありません。なんとかなるものです。でも押さえておくべきポイントがいくつかありますので、その辺も交えて説明します。
既にMODを公開されている方も一読されることをお勧めします。私自身、新たな発見がありました。
なお、公開手順はSkyrim以外(Skyrim SE/Fallout/Oblivion/The Witcher 3等)のMODでもほぼ同様ですので、Skyrim以外のMODを制作されている方の参考にもなると思います。
カテゴリ・ファイル分類などはゲーム毎に異なりますので読み替えてください。
関連記事:
- NexusModsでのファイル公開手順 (その1:登録の開始) --- 本記事です
- NexusModsでのファイル公開手順 (その2:イメージの登録)
- NexusModsでのファイル公開手順 (その3:必要条件とファイルの登録)
- NexusModsでのファイル公開手順 (その4:その他の操作)
- NexusModsでのファイル公開手順(その5:Skyrim SE用のファイル公開)
- Nexus Mods:ドネーションポイントシステム開始に伴う変更点と操作方法
参考リンク:
- Skyrim MOD作成Wiki - MODの英語ページ --- MOD公開に関する英語のコツが書かれています
謝辞:
本記事ではサンプルとして拙作のSkyrim Sleeping Bags - Japaneseのページを使用しました。
オリジナルMOD Skyrim Sleeping Bags - Sleep Under Blanketsの作者Hoamaiiさんにこの場を借りて御礼申し上げます。
このMODはSkyrimに「毛布をかけられる」寝袋を追加するものです。雰囲気作りだけではなく、Frostfall利用時に「温かさ」を得られる優れものです。是非チェックしてください。
Skyrim Mod導入トラブル事例:セーブデータのロード時に確定CTD(Papyrus文字列数上限65535問題)-2016/5/13追記
概要
ゲームをある程度進めると、セーブしたデータのロード時に確定CTDが発生する(少し前のセーブデータは問題なくロードできる)。
FNISの初期ロード時CTD問題とは異なり、一時的に問題のないデータをロードした後にロードしても、qasmokeやHaven Bag内でセーブしたデータをロードしても確定CTDする。
目次
原因
もしかしたらPapyrus文字列数上限65535問題に該当しているかもしれません。
この問題に該当する場合、そのセーブデータは破損しており、絶対にロードすることはできません。
Skyrimのセーブデータ(.ESS)には、Papyrusスクリプトの使用する文字列を格納する文字列テーブルがあります。ファイル形式上、文字列テーブルの配列数はunsigned shortで表現されており、65535(0xffff)が上限となります。
Papyrus文字列数の上限を超過しても、ある程度はプレイ続行でき、セーブすることも可能ですが、一度ゲームを再起動した後にそのセーブデータをロードすると確定CTDします(必要な文字列がすべて含まれていない不正なセーブファイルとなるようです)。
上限を超過した状態でプレイを続行するのも問題があるようです(参考記事をざっと見た感じ、一見問題がないように見えるが内部的には文字列テーブルがおかしくなっている可能性ありとのこと)。
参考記事によると、実験の結果、Skyrimのエンジンそのものは65535を超える文字を取り扱えるようであり、セーブデータの形式だけの問題らしいとのこと。
bcspさんによる参考記事:The Nexus Forums : Corrupt Saves - StrCount > 0xFFFF - CTD on load
問題の切り分け方法
Save game script cleanerを使う方法(初期切り分け)
Save game script cleaner by Hadoramでセーブデータを開いたとき、ツールがアプリケーションエラーとなる場合、本問題に該当する可能性が高いです。
TESV ESS Files Editorを使う方法(正確に判断)
TESV ESS Files Editor by fubrusを使って文字列数を正確に把握できます。
ツールを起動し「Open」ボタンを押してセーブデータを開きます。
左のツリーから「Global data table 3」を展開し、その下位にある「2.Papyrus」をクリックします。
右のツリーに表示されるStrings(数字)が現在の文字列数を示しています。65535からこの数字を引いたものが上限までの猶予となります。
「Range check error」ダイアログが表示された場合、既に文字列数上限を超過しています。
文字列数は状況によって1,000~2,000くらい増減することがあるようです。文字列数が超過していなくても63,000以上であれば「以前気付かぬうちに上限を超していた可能性がある」と考えたほうがいいでしょう。
ロードCTDするのに文字列数に余裕がある場合、残念ながら文字列数が原因ではありません。次のブログ記事を参考に他の原因を探ってください。
- Skyrimshot(tktkさん):スカイリムのCTD対策
- Skyrim箱庭DIY(くつみやさん):SkyrimでよくあるCTDの原因まとめ(ロード時に確定CTD)
拙作のStrCountToolを使う方法(まとめてチェック)
複数のセーブファイルを纏めてチェックできるツールを作成してみました。
Crash Fix v8の拡張形式にも対応しています。
ダウンロード:StrCountTool v0.1
解説ページ:Skyrim自作MOD: StrCountTool 利用ガイド (v0.1版) - Thinking Skeever
実行例:
ファイルが壊れている場合、赤枠のようにエラーメッセージが表示されます。
MS OfficeやOpen Officeなどの表計算ソフトを使って表示することを想定していますので列が揃いませんがご勘弁を。
対策方法
ベゼスダがファイル形式を改善するのが一番ですが、Skyrimでは期待できないでしょう。Fallout4でも同じ問題があるのか気になるところですね。
- 使用するMODを減らす(特に会話・スクリプト・アニメーションを大量に追加するもの)
- Dynamic Distant Objects LOD - DynDOLOD by Shesonのv1.47以前は文字列テーブルを大量に消費しますが、v1.48以上にアップグレードすることで消費を大幅に削減できます(下記に実績を書いておきました)。
- SL 1.61は文字列テーブルを大量に消費しますが、markdf氏のJContainersパッチを使って消費を大幅に削減できるそうです(要JContainer3.3)。
2016/05/04追記:
●meh321氏のMOD Crash Fix v8に文字列数超過時の対策が追加されました。
CrashFixPlugin.iniの説明の和訳:
; 情報:スクリプトが65535より多い異なる文字列を使うと、セーブデータは破損しロードできません。 ; これは文字数が65520より大きい場合のファイル保存形式をわずかに変更することにより修正します。 ; これは、このオプションを有効にして作成したセーブデータの形式が変更されるため、バニラのゲームやsave gameツールで開けなくなることを意味します! ; 逆もまた真なりで、文字数を65520以下にして再びセーブするとバニラの保存形式に戻ります。 ; 概要:https://forums.nexusmods.com/index.php?/topic/3924850-corrupt-saves-strcount-0xffff-ctd-on-load/ のための修正 ; アドレス:大体30箇所のコードにパッチを当てた。 StringCount32=1
文字列数が65520を超えて作成したセーブデータはバニラの形式とは異なるため、Crash Fix v8のインストールされていない環境やセーブデータを扱う各種ツールでロードできなくなることに注意してください。
●markdf氏によりRestringerの開発が進められています(テスト版あり)
・PEXファイル中の文字列をJsonファイルに吐き出し、Jsonファイル中の文字列を参照するようPEXファイルを書き換えることにより、文字数を減らすアプローチです。
・ENDPOINT(末端MOD)に対してパッチを当てることを想定。例えばCampfireは他のMODにより利用されるので末端ではなく、FrostfallやWearable Lanternは末端MODである。
・実行にはJavaが必要で、Mod Organizer使用時は32ビット版のJavaが必要とのこと。
詳細解説
以下、参考記事の和訳を交えて解説します。
文字列テーブルに格納される文字列
参考記事によると、文字列テーブルには次のものが格納されるとのことです。
- 関数が利用するローカル変数の定義。通常、関数が終了した後にテーブルから削除されるが、MCM関連の変数の一部は保持され続けるようです。
- スクリプトプロパティ。文字列テーブルの大半はプロパティのようです。(筆者注:スクリプトの文字列プロパティの代表例はMCMのページ名です。ゲーム進行途中でMCMページ名の訳を変更するとMCMページが表示されなくなるのはこれに起因します)
- スクリプト/フラグメント名(.pex含まず)。これらのスクリプト名はプロパティと同様のようです。文字列テーブルに含まれるスクリプト名が極めて少ないことがこれを説明しています。
文字列がすべてセーブデータに保存されるわけではなく、現在のセーブで使われているスクリプトの文字列が保存されるようです。従って、インストールしたMODの数や種類によっても変化しますし、ゲームの進行状況に応じたスクリプト環境の変化によっても増減します。
どういうMODが文字列数に悪影響を及ぼすのか(参考記事の和訳)
- 確実ではないですが、一般的な経験則によれば、スクリプトが多いほどプロパティの数も多くなります。これは大量に会話を追加するMOD(Inteesting NPCs)が大きな影響を及ぼす理由をうまく説明しています。私は会話系MODの専門化ではないですが、クエストステージを進めるためだけにスクリプトが必要となるようです。私に言わせれば、MOD制作者がロールプレイの会話を追加することで16ビットの制限を圧迫するベゼスダのやり方はとてもとてもマヌケに思えます。
- 大規模で複雑なMCMを持つMOD。MCMの各項目(スライダー、トグルボタンなど)それぞれに対して変数定義が必要です。文字列テーブルの内容を見ると"OID"を含みMOD作者の慣例に従ったネーミング規則を持つ変数名が大量にありました。MODが無意味なMCMを追加するのを見て私はため息をつきます。シンプルなままでいいよ。
- 沢山のプロパティが付いたスクリプト。プロパティは文字列テーブルの数に大きな影響を与えるようです。例えばですが、最近私は素晴らしい"Illustrious Cloaks Of Skyrim"をスクリプト版からクラフト版にダウングレードしました。スクリプト版ではスクリプト1つあたり230ほどのプロパティがあります。スクリプト版の方がはるかにエレガントで適切な実装ですが、クラフト版にはまったくスクリプトが含まれていません。
- アニメーションMOD。特に「その手のサイト(訳注:Lovers Lab)」のユーザーで問題になります。アニメーション毎にいくつかの文字列が追加されることが報告されています。
さらに詳しい情報について
bcspさんによる記事:The Nexus Forums : Corrupt Saves - StrCount > 0xFFFF - CTD on loadでは、解決方法に関する議論や各MODの使用文字列数調査が継続して行われています。
OP(最初の書き込み)にはMODの使用文字列数をまとめたgoogleスプレッドシートへのリンクもありますので参考にしてください(うっかり更新しないようにご注意を)。
Crash Fix v8について
Crash Fix v8を使って実際に文字列数が65535を超過したセーブデータを作成し、その仕組みについて調査してみました。
Papyrusにおける文字管理方式、破損の仕組みを説明したあと、Crash Fix v8の仕組みについて説明します。
Papyrusにおける文字管理方式(PEXファイルの場合)
次のスクリプトをコンパイルしてPEXファイルを作成したとします。
Scriptname TestScript extends ObjectReference Event OnActivate(ObjectReference akActionRef) Debug.MessageBox("Not enough money") EndEvent
PEXファイルには次のような情報が保存されます。保存形式はバイナリ形式ですし保存される情報はもっと多いですが、分かりやすいように簡略化しています。
文字列テーブル
文字列番号 | 文字列 |
---|---|
0 | testscript |
1 | ObjectReference |
2 | OnActivate |
3 | akActionRef |
4 | debug |
5 | MessageBox |
6 | Not enough money |
スクリプト中間コード:()内が文字列番号
Scriptname (0) extends (1) Functioon (2)((1) (3)) (4).(5)((6)) EndFunction
このように、スクリプトコード中の文字列はすべて文字列番号に置き換えられ、文字列本体は文字列テーブルにまとめられます。同じ文字列がある場合、大文字小文字を無視して文字列テーブルの1エントリにまとめられます。
PEXファイルの文字列テーブルの上限は65535(0xffff)ですが、1つのスクリプトファイルで巨大なコードを書くことはないため、この時点では何も問題ありません。
セーブデータに保存される文字列
セーブデータには次の文字列が保存されます(ただし保存のトリガとなる一定の条件がある模様)。
セーブデータ破損の仕組み
Skyrimのゲームエンジンに読み込まれたスクリプトの文字列はすべて1つの文字列テーブルに保存されます。ゲームエンジンでは65,535を超える文字列テーブルを取り扱えるようですが、ファイルに保存する際に16ビットに切り詰められてしまいます。
例えば文字列数が65,600の場合、16進数に変換すると0x10040となりますが、セーブデータには下位16ビットの0x0040が文字列数として保存されます。
調査した範囲では文字列テーブルは65,600個分すべてがセーブデータに保存されるようなので、次回読み込み時に「文字列数が0x0040なのにそれ以上の文字列が入っている」状態となり、データ形式不正=CTDとなります。
Crash Fix v8 StringCount32機能の仕組み
CrashFixPlugin.iniのStringCount32を1にすることで、セーブデータ中の文字列数および文字列番号を拡張することができます。
; 情報:スクリプトが65535より多い異なる文字列を使うと、セーブデータは破損しロードできません。 ; これは文字数が65520より大きい場合のファイル保存形式をわずかに変更することにより修正します。 ; これは、このオプションを有効にして作成したセーブデータの形式が変更されるため、バニラのゲームやsave gameツールで開けなくなることを意味します! ; 逆もまた真なりで、文字数を65520以下にして再びセーブするとバニラの保存形式に戻ります。 ; 概要:https://forums.nexusmods.com/index.php?/topic/3924850-corrupt-saves-strcount-0xffff-ctd-on-load/ のための修正 ; アドレス:大体30箇所のコードにパッチを当てた。 StringCount32=1
実際に文字列数が超過したセーブデータを作成し調査したところ、セーブデータ中の文字列数(UInt16)および文字列番号(UInt16)が次のように保存されていました。
- 数<=0xfff0の場合:UInt16形式(バニラと同じ)
- 数>0xfff0の場合:0xff + 0xff + UInt32形式(Crash Fix拡張)
データ読み込みの際は、値が0xffffなら続けてUInt32の値を読み込めばいい訳です。とてもスマートですね!
このセーブデータで継続的にプレイした訳ではありませんが、パッチ箇所に漏れがなければ上記の問題点を完璧に解決するものだと思います。
とはいえ、文字列数が超過したセーブデータをセーブクリーナなどで読み込めないのは不便なので、あくまでも保険として利用するのが賢いと思います。
実例(私の体験談)
最近新しい環境を作成してニューゲームしたのですが、全ホールドの従士になってDawnguardクエストを開始しセラーナを救出した直後に本問題が発生しました。
タイミングがタイミングなので諦めきれず、グーグル先生を使ってやっと参考記事を見つけた次第です。
どの程度のMOD構成でどれくらいPapyrus文字列数を消費するかの目安になるかもしれないので、私の環境とPapyrus文字列数を晒しておきます。
MOD環境
カスタムボイスフォロワー、イマージョン系MOD、景観・遠景改善を中心に構築しました。SLなどのLovers Lab系MODは入れていません。
低FPS(GTX760で28前後)でスクリプト遅延もひどく、あまり褒められた環境ではありません。他のブログ管理者様が「これを入れたら重くなる」というものがことごとく入っているはずなので注意してください(これでも大分減らしたんですが)。
Mod Organizerのplugin.txtの内容:
# This file was automatically generated by Mod Organizer. Skyrim.esm Update.esm Unofficial Skyrim Patch.esp Dawnguard.esm Unofficial Dawnguard Patch.esp HearthFires.esm Unofficial Hearthfire Patch.esp Dragonborn.esm Unofficial Dragonborn Patch.esp ApachiiHair.esm ApachiiHairFemales.esm ApachiiHairMales.esm RaceCompatibility.esm Campfire.esm HighResTexturePack01.esp HighResTexturePack02.esp HighResTexturePack03.esp Unofficial High Resolution Patch.esp Bethesda_Hi-Res_Optimized.esp SMIM-Merged-All.esp NoWaterStreamBug.esp RealShelter.esp FISS.esp SkyUI.esp FNIS.esp FNISspells.esp Frostfall.esp UIExtensions.esp Atlas Legendary.esp Atlas Compass Tweaks.esp Mystical Illumination - Glowing Signs with Point the Way.esp TheEyesOfBeauty.esp The Eyes Of Beauty - Elves Edition.esp EnhancedCharacterEdit.esp CharacterMakingExtender.esp USKP Patcher for RaceCompatibility.esp Alternate Start - Live Another Life.esp FollowerLivePackage.esp Convenient Horses.esp My Home Is Your Home.esp sandboxcylinderheight.esp dD - Realistic Ragdoll Force - Realistic.esp LPBards.esp Males of Skyrim.esp IB - All-in-One.esp SBF All In One + DLC.esp Gyot_NPCs.esp BTRH_Waifu.esp Bijin Warmaidens.esp BW Ria.esp Bijin NPCs.esp Bijin Wives.esp Serana.esp Valerica.esp MyWarmaidens.esp Eli's Coffee Mod.esp Auto Unequip Ammo.esp towConversation.esp 00FacialExpressions.esp GoToBed.esp Hide Those Futile Quests.esp hmkHotKeys.esp JaxonzEnhGrab.esp JaxonzZoom.esp PerksUI.esp jkjsenhancedhotpools.esp The Paarthurnax Dilemma.esp Customizable Camera.esp DetectLever.esp DG-NoAttacks.esp DragonBlood.esp Dual Hand Combo Hotkeys.esp No Magic Ninja Dodge - No DLC.esp Qasmoke Travel Spell.esp Upgrade Leveled Items Spell.esp Snotgurg Equipment HUD.esp FixCombatMusic.esp FCO - Follower Commentary Overhaul.esp PreventsAccidentPickUp.esp Immersive detection of NPC.esp jbNPCMap.esp MIDFollowMeCloser.esp SaveHotKeyMCM.esp SSAssist.esp ShowRaceMenuAlternative.esp SkySet.esp UnreadBooksGlow.esp Headtracking.esp TChomesHearth.esp EnhancedLightsandFX.esp ELFX - Exteriors.esp Skysan_ELFX_SMIM_Fix.esp ELFX - NoBreezehome.esp BreezehomeByLupus.esp FieldLab.esp MammothManor.esp Pinegrove Lodge.esp Bluthanch.esp Wynter.esp Vellamo.esp Various Hunter.esp Chaconne.esp Toccata.esp Vivace.esp GoddessDiana.esp OK_Noemie.esp OK_sela.esp OK_HumanBeastCaravan.esp OK_Rosalie.esp RosaFollower.esp Recorder Follower Base.esp SolitudeTheLuckySkeeverHome_Lite.esp Warmstone.esp RiftenGarret.esp Thornrock.esp Minerva.esp Holidays.esp WondersofWeather.esp BlackHorseCourier.esp Dig Site.esp WitchTent.esp alesCampBedrollsSupplies.esp SimplyKnock.esp WetandCold.esp WetandCold - Ashes.esp ArtOfTheCatch.esp PipeSmoking.esp FNISSexyMove.esp Kyne's Gate.esp bbDTP.esp EasyWheel.esp TKDodge.esp FacelightPlus.esp QuickLight.esp RealisticWaterTwo.esp RealisticWaterTwo - Legendary.esp Watercolor_for_ENB_RWT.esp Fantasy Soundtrack Project.esp Fantasy Soundtrack Project - Combat.esp AOS.esp AOS2_RealisticWaterTwo Patch.esp AOS2_WetandCold Patch.esp Hunterborn.esp Hunterborn_Campfire_Patch.esp Animallica.esp iNeed.esp Skyrim Flora Overhaul.esp SFO - Dragonborn.esp Vivid Weathers.esp Vivid Weathers - AOS patch.esp MX2BeWithHealer.esp Tiwa44_Minidresses_Standalone.esp Tiwa44_Minidresses_Standalone_DG&DB.esp UNP Spice Gear.esp Long lost smelters by Hyralux.esp Long Lost Smelters -Winterhold.esp AMB Glass Variants Lore.esp Differently Ebony.esp aMidianborn_Skyforge_Weapons.esp Mini Vamps.esp RUSTIC SOULGEMS - Unsorted.esp SL01AmuletsSkyrim.esp SL01AmuletsSkyrimDGDB_Outfit.esp Immersive Jewelry.esp SL99Exchanger.esp SL99Exchanger_Patch_Immersive Jewelry.esp Skyrim Particle Patch for ENB - Flame Atronach Fix.esp NoAnimalsReportCrimes-DG+DB.esp Enhanced Landscapes.esp Enhanced Landscapes - Solstheim.esp Enhanced Landscapes - Marsh Pines.esp Enhanced Landscapes - Oaks.esp Enhanced Landscapes - DLC Patch.esp Routa.esp HoamaiiClearskyHideout.esp WindPath.esp AddItemMenu.esp DynDOLOD.esp RSPatch.esp Bashed Patch, 0.esp
Papyrus文字列数の推移
#012 - 39,111 #015 - 44,706 DynDOLOD v1.47の導入 #031 - 45,055 #100 - 46,286 #210 - 50,303 #300 - 52,443 #400 - 59,663 #501 - 61,572 #600 - 63,793 #705 - 65,435 全ホールドの従士になった #706 - 65,507 ディムホロウ洞窟突入 #707 - 65,434 #708 - 65,473 #710 - 65,496 セラーナ救出 #711 - 65,515 #712 - ロードできない!! #713 - 41,207 DynDOLOD v1.49へのアップグレード後、屋外に出てセーブ(劇的に減った!) --- その後の経過 --- #719 - 41,294 セラーナをヴォルキハル城に送った後 #731 - 41,268 メリディアクエストクリア #745 - 41,206 ドーンガード砦、新たな命令クエスト開始 #756 - 41,156 ハエマールの不名誉、デイドラの親友クエスト完了 #765 - 41,136 クロンヴァングル洞窟、ガンマーと合流しクマ討伐完了 #890 - 41,383 ドーンガード砦、残響を追ってクエスト開始 #933 - 41,369 アルケイナエウム、霊魂の確認クエスト開始 #949 - 41,491 ソウル・ケルン、死の超越クエスト開始 #972 - 41,562 アイスウォーター桟橋、死の超越クエスト完了 #991 - 41,447 アルフタンド・アニモンキュロリー、霊魂の確認クエスト進行中
グラフにしてみました。
DynDOLOD v1.49導入以降、増加傾向はほとんどありません。この調子で全クエストクリアまで持ちそうです。
ちなみに、以前構築した2つの環境は、DynDOLODを使っていない以外この環境と似たようなMOD構成でしたが、文字列テーブル数は39,000程度でした。
最後に
Forumでアドバイスしてくださった元記事The Nexus Forums : Corrupt Saves - StrCount > 0xFFFF - CTD on loadの投稿者bcspさんと、速やかにDynDOLODを改善してくださったShesonさんにこの場を借りて御礼申し上げます。もちろんご両人にKudosを差し上げました!
Thanks bcsp and Sheson!!
また、Crash Fixの作者meh321さんにも感謝します。正直これはFiles of the MonthどころかFiles of the Yearに匹敵する偉業だと思います。もちろんKudosとVOTEを差し上げました!
Thanks meh321! You're a genius!
みなさんへのお願い:
クエストMODや比較的複雑な構造・機能を持つMODでは文字列を多く消費する傾向がありますが、決して作者様を責めないでください! どう考えても悪いのはベゼスダですから。
上記のグラフを見ていただければ分かりますが、MODそれぞれの(一度きりの)消費文字数はさほど問題ではありません(大規模MODを大量に導入する際に問題があるかもしれませんが)。オブジェクト増加に従って文字列消費量が増加するMODにさえ気をつければなんとかなると思います。
Skyrim自作MOD: StrCountTool 利用ガイド (v0.1版)
拙作のツール StrCountToolの利用ガイドです。
このツールを使えば、SkyrimセーブデータのPapyrus文字列数を確認したり、プラグインファイル/スクリプトファイル中の文字列を表示することができます。
ツールのダウンロードはこちら→:StrCountTool v0.1
StrCountTool 利用ガイド (v0.1版)
目次
- 目次
- 1. はじめに
- 2. 主な特徴
- 3. 必要条件
- 4. インストール方法
- 5. アンインストール方法
- 6. 基本的な使い方(一般プレイヤー向け)
- 7. 少し高度な使い方(MOD制作者/問題調査者向け)(作成中)
- 8. 表示項目一覧
- 本ガイドの改訂履歴
1. はじめに
Skyrimセーブデータの文字列数上限65535問題をご存知でしょうか?
セーブデータにはバニラやMODで追加されたスクリプトに関する情報が保存されます。
スクリプトで使われている文字列データはセーブデータ中の文字列テーブルにまとめて保存されるのですが、セーブデータの文字列テーブルには最大65535個(符号なし16ビット)という上限があり、総文字列数が上限を超えるとセーブデータが破損しロードできなくなるというものです。
※この問題の詳細については以下の記事を参照してください。
bscpさんによる元記事:http://forums.nexusmods.com/index.php?/topic/3924850-corrupt-saves-strcount-0xffff-ctd-on-load/
日本語による解説(本ブログ):Skyrim Mod導入トラブル事例:セーブデータのロード時に確定CTD(Papyrus文字列数上限65535問題)-2016/5/13追記 - Thinking Skeever
本ツールを使えば、文字列の超過が発生していないか、増加傾向はないかを比較的簡単に確認することができます。
また、セーブデータではなく、プラグインファイル(ESM/ESP)やスクリプトファイル(PEX)に含まれる文字列の情報も表示できます。プラグインファイルやスクリプトファイルに含まれる文字列の一部がセーブデータに保存されることが確認されています。どのMODが文字列数増加に影響を与えているか調査する一助となるはずです。
2. 主な特徴
共通操作
セーブデータ(ESS)ファイル表示
- 単一ファイル表示/複数ファイルをまとめて一覧表示
- 文字列数だけでなく、ヘッダ情報/ゲーム内時間/アクティブスクリプト/文字列テーブル内容も表示可能
3. 必要条件
動作環境
私はWindows XP/8/10を持っていないので動作検証できていませんが、恐らく.NET Framework 4.0以降がインストールされていれば動作します。
表計算ソフト(オプション)
本ツールの表示結果は表計算ソフトで表示することを意図しており、列揃えなどの調整を一切行っていません。
Microsoft Office、Apache OpenOffice、LibreOfficeなどの表計算ソフトを使うことで表示結果を見やすくしたり、グラフにしたりできます。
本ガイドではLibreOfficeを使った操作を紹介しています。
4. インストール方法
- ツールをダウンロードします。こちらからどうぞ→:StrCountTool v0.1
- ZIPファイルを回答し、StrCountToolごと任意のフォルダにコピーします。ただしゲームのフォルダ、Mod Organizer/NMMのフォルダ、Program Filesフォルダは避けてください。良く分からなければデスクトップ上でも問題ありません。
- 旧バージョンからのアップデート時には、単純にファイルを上書きコピーしてください。
- ツールを起動するにはStrCountTool.exeを実行します。
5. アンインストール方法
アンインストールする場合、インストールしたStrCountToolフォルダごと削除してください。レジストリは使っていませんのでクリーニングの必要はありません(厳密にはWindowsと.NET Frameworkによって少量のレジストリが作られているかもしれませんが、誤差の範囲だと思います)。
6. 基本的な使い方(一般プレイヤー向け)
セーブデータの文字列数が超過していないか確認する基本的な使い方を説明します。
ツールの起動とオプションの設定
文字列数を確認する(単一ファイル)
左右のテキストボックスのどちらかにセーブデータ(ESS)ファイルをドラッグ&ドロップします。
片方のテキストボックスが邪魔ですので、真ん中のセパレータを左右に動かして調整してください。
「globalDataTable3.Papyrus.strCount:」の数字が文字列数です。
文字列数が上限を超過している場合エラーとなります。
発生するエラーは不定で、「Error: インデックスおよびカウントはバッファー内の場所を参照しなければなりません。」エラーとなる場合もあります。
文字列数が上限を超過していても、Crash Fix v8以降を使っている場合は次のようになります。上限の65535を突破できているのがお分かりでしょうか?
文字列数の判断の目安は次のとおりです(私の個人的見解です)。
文字列数 | 判定 | 説明 |
---|---|---|
~45,000 | 安全 | まあ大丈夫でしょう。 |
50,000~55,000 | 警戒 | 上限超過に対する備えが必要です。文字列数が増加傾向にあるか監視すべきです |
55,000~60,000 | 危険 | そろそろ抜本的な対策が必要です。 |
60,000~ | 対策要 | このままプレイを続けるのは危険です。セーブデータのクリーニングが出来なくなってもよいならCrash Fix v8以降を導入しましょう。そうでなければ使用中MODの文字列数対策版を探すか、不要なMODを削除しましょう。 |
エラー | 南無 | このデータは破損しています。過去のデータにさかのぼってやり直してください。 |
文字列数を確認する(複数ファイルをまとめて)
テキストボックスにファイルをまとめてドラッグ&ドロップします。
セーブフォルダごとドロップしてもかまいません。また、拡張子.ESS以外のファイルは無視されますので、.SKSEファイルもまとめてドロップしても問題ありません。
ドロップすると進捗ダイアログが表示されます。
読み込みが終わると次のような一覧が表示されます。タブ区切りのテキストなので列が揃いませんがご勘弁を。
「Display Level」が「Summary」の場合、右から2つ目の数字が文字列数です。
文字列数が超過している場合、赤枠のようなエラーメッセージが表示されます。
表計算ソフトで開く
テキストボックスを右クリックして「Open as .csv」を選択すると、表計算ソフトで結果を表示できます。
Libre Officeがインストールされている場合、次のダイアログが表示されます。「区切る」「タブ」をチェックして「OK」ボタンを押します。
他の表計算ソフトでも同様のダイアログが表示されますので、読み替えて設定してください。
表計算ソフトで表示した様子です。列が揃って見やすくなりました。
ご注意:
表計算ソフトで開くcsvファイルはStrCountToolインストールフォルダのTempフォルダに作成されますが、StrCountTool終了時に自動的に削除されます。データを編集した場合、別名で保存しないと結果が失われます。
グラフを表示する
表計算ソフトで開いたらグラフを表示してみましょう。文字列数の増加傾向がビジュアルに見えるのでとても分かりやすいです。
strCount列(J列)全体を選択し、「挿入」-「グラフ」メニューを選択します。
「グラフウィザード」画面が表示されたら「完了」ボタンを押します。
これで単純な棒グラフが表示できました。
今度は横軸をゲーム内時間にして時系列で表示してみましょう。
今度はGameDaysPast列(I列)とstrCount列(J列)全体を選択し、「挿入」-「グラフ」メニューを選択します。
「グラフウィザード」画面が表示されたら好みのスタイルを選択して「完了」ボタンを押します。
ここでは「線のみ」を選んでみます。
時系列グラフが表示できました。
ゲーム内時間に比例して文字列数が増加している様子が分かります。ところどころMODの追加や更新で文字列数が急増しているのがよく分かりますね。
2つのセーブデータを比較する
文字列数の増加傾向がある場合、2つのセーブデータを比較して調査することで原因を突き止められるかもしれません。
本ツールではファイル比較ツールWinMergeを使って2つのセーブデータを比較することができます。、
ファイル比較ツールの準備
先にWinMergeをインストールし、WinMerge.exeのインストールされたフォルダをWindowsのPATH環境変数に追加しておいてください(パスを通しておいてください)。
パスを通したくない場合や、WinMerge以外の比較ツールを使う場合、StrCountToolのインストールフォルダ中のStrCountTool.iniを次のように修正してください。
[General]
winMergePath=winmerge.exe ← ここにファイル比較ツールのフルパスを指定する
ファイル比較ツール活用のススメ:
ファイル比較ツールはあらゆる場面で役立つとても便利なツールです。この機会に是非導入しましょう。
場面ごとの活用例:
- MOD制作:修正したファイルの洗い出しと点検、過去のリリースと比較してファイル過不足チェックなど
- MOD翻訳:過去訳との比較、翻訳対象MODの変更箇所洗い出しなど
- MOD利用:MODアップデート時の変更点の洗い出し、Skyrim.iniファイルの変更点の見直しなど
比較の手順
左のテキストボックスに古いファイルを、右のテキストボックスに新しいファイルをドロップします。
ファイルを開いたら「Compare Text」ボタンを押します。
ファイル比較ツールが起動します。
「*** Papyrus Strings (数字):」の下が、セーブデータ中に含まれる文字列の比較となります。
スクロールして追加された文字列を眺めてみましょう。「F7」「F8」キーで前の・次の差異のある行にジャンプできるので便利です。
このセーブデータの場合、ゲームが進行するごとに「c28042」「c28297」という文字が増えていきました。調査の結果、DynDOLODが生成する文字列であることが判明し、DynDOLODを最新版にすることで増加傾向を止めることができました。
比較のコツ:
セーブデータ中の文字列は実行中のスクリプト(アクティブスクリプト)の数・種類によってもめまぐるしく変化します。
ゲーム内時間がある程度離れたデータや、新しい土地に入る前後・新しいクエスト開始前後とったイベントまたがりののデータを比較した方が問題を特定しやすいと思います。
7. 少し高度な使い方(MOD制作者/問題調査者向け)(作成中)
(現在作成中です)
8. 表示項目一覧
セーブデータ(ESS)ファイル
Lvl ※1 | 表示項目 | 説明 | 表示例 |
---|---|---|---|
1 | header.version: | ファイル形式のバージョン | 9 |
1 | header.saveNumber: | セーブ番号 | 10 |
1 | header.playerName: | プレイヤー名 | Bowmore |
1 | header.playerLevel: | プレイヤーレベル | 1 |
1 | header.playerLocation: | プレイヤーの場所 | ラッキー・スキーヴァー |
1 | header.gameDate: | ゲーム内日時 | 001.35.36 |
1 | header.playerRaceEditorId: | プレイヤー種族 | NordRace |
1 | header.playerSex: | プレイヤー性別。女性は1 | 0 |
2 | header.playerCurExp: | 36.75 | |
2 | header.playerLvlUpExp: | 100 | |
1 | header.fileTime: | ファイル保存日時 | 2016/03/14 11:00:33 |
2 | formVersion: | 74 | |
1 | globalDataTable1.GlobalVariables.GameDaysPassed: | ゲーム内経過日数(Skyrim広域変数より) ※2 | 0.5688909 |
1 | globalDataTable1.GlobalVariables.TimeScale: | タイムスケール(Skyrim広域変数より) | 6 |
1 | gameDateString: | ゲーム内日時文字列(Skyrim広域変数より組み立て) | 4E 201/07/17 13:39 |
1 | GameHoursPassed (GameDaysPassed multiplied by 24): | ゲーム内経過時間(GameDaysPassed * 24) ※2 | 13.65338 |
1 | RealHoursPassed (GameHoursPassed divided by TimeScale): | 経過実時間(GameHoursPassed / TimeScale) ※2 ※3 | 2.275563 |
2 | globalDataTable3.Papyrus.header: | 4 | |
1 | globalDataTable3.Papyrus.strCount: | Papyrus文字列数。Crash Fixによる拡張形式の場合、末尾に(Crash Fixed)が表示される | 39164 |
2 | globalDataTable3.Papyrus.stringsSize (bytes): | Papyrus文字列テーブルのサイズ(16進表記) | 0x000EC0E9 |
2 | globalDataTable3.Papyrus.scriptCount: | スクリプト数 | 5421 |
2 | globalDataTable3.Papyrus.scriptInstanceCount: | スクリプトインスタンス数 | 55115 |
2 | globalDataTable3.Papyrus.referenceCount: | リファレンス数 | 0 |
2 | globalDataTable3.Papyrus.arrayInfoCount: | 1244 | |
2 | globalDataTable3.Papyrus.papyrusRuntime: | 0x00017AD0 | |
1 | globalDataTable3.Papyrus.activeScriptCount: | アクティブスクリプト数 | 4 |
2 | String Count used in Active Scripts: | アクティブスクリプトで使われているPapyrus文字列数 | 196 |
3 | globalDataTable3.Papyrus.FunctionMessageCount: | 3 | |
3 | globalDataTable3.Papyrus.SuspendedStackCount1: | 0 | |
3 | globalDataTable3.Papyrus.SuspendedStackCount2: | 0 | |
3 | globalDataTable3.Papyrus.Unknown0Count: | 0 | |
3 | globalDataTable3.Papyrus.QueuedUnbindCount: | 0 | |
3 | globalDataTable3.Papyrus.SaveFileVersion: | 5 | |
3 | globalDataTable3.Papyrus.ArrayCount1: | 0 | |
3 | globalDataTable3.Papyrus.ArrayCount1a: | 0 | |
3 | globalDataTable3.Papyrus.ArrayCount2: | 1 | |
3 | globalDataTable3.Papyrus.ArrayCount3: | 74 | |
3 | globalDataTable3.Papyrus.ArrayCount4: | 20 | |
3 | globalDataTable3.Papyrus.ScriptListCount: | 1 | |
3 | globalDataTable3.Papyrus.ArrayCount4a: | 0 | |
3 | globalDataTable3.Papyrus.ArrayCount4b: | 0 | |
3 | globalDataTable3.Papyrus.ArrayCount4c: | 0 | |
3 | globalDataTable3.Papyrus.ArrayCount4d: | 0 | |
3 | globalDataTable3.Papyrus.ArrayCount5: | 0 | |
3 | globalDataTable3.Papyrus.ArrayCount6: | 3 | |
3 | globalDataTable3.Papyrus.ArrayCount7: | 1 | |
3 | globalDataTable3.Papyrus.ArrayCount8: | 29 | |
3 | globalDataTable3.Papyrus.ArrayCount9: | 0 | |
3 | globalDataTable3.Papyrus.ArrayCount10: | 0 | |
3 | globalDataTable3.Papyrus.ArrayCount11: | 0 | |
3 | globalDataTable3.Papyrus.ArrayCount12: | 0 | |
3 | globalDataTable3.Papyrus.ArrayCount13: | 0 | |
3 | globalDataTable3.Papyrus.ArrayCount14: | 0 | |
3 | globalDataTable3.Papyrus.ArrayCount15: | 0 | |
2 | *** Active Scripts | アクティブスクリプトの一覧 | - |
3 | Local Variables | アクティブスクリプトで使われているローカル変数の一覧 | - |
3 | Papyrus Strings used in Function | アクティブスクリプトで使われているPapyrus文字列の一覧 | - |
3 | *** Papyrus Strings used in Active Scripts | アクティブスクリプトで使われているPapyrus文字列の一覧 (全アクティブスクリプト分) | - |
1 | *** Papyrus Strings | Papyrus文字列の一覧 | - |
※1:表示レベル(1=Summary / 2=Detail / 3=More Detail)
※2:メニュー表示中の時間はカウントされない。
※3:ゲーム途中でTimeScale値が変更された場合には不正確となる。
プラグイン(ESM/ESP)ファイル
Lvl ※1 | 表示項目 | 説明 |
---|---|---|
0 | プロパティ一覧 | プロパティ定義の一覧。Display LevelがSummaryの場合、文字列型プロパティのみ表示 |
1 | Script Names | プロパティ定義されたスクリプト名の一覧 |
1 | Property Names | プロパティ名の一覧 |
0 | Property Strings | プロパティで定義された文字列の一覧 |
※1:表示レベル(1=Summary / 2=Detail / 3=More Detail)
スクリプト(PEX)ファイル
Lvl ※1 | 表示項目 | 説明 |
---|---|---|
0 | String table | 使用されている文字列の一覧 |
※1:表示レベル(1=Summary / 2=Detail / 3=More Detail)