気ままなタンス*プログラミングなどのノートブック

プログラミングやRPGツクール、DTM等について、学んだことや備忘録をアウトプットとして残し、情報を必要としている誰かにとって「かゆいところに手が届く」ブログとなることを願いながら記事を書いています。

【聖剣伝説3-ToM_mod】uassetとuexpの関係、確認方法概要について

スポンサーリンク

こんにちは。

2020年5月上旬から聖剣伝説3ToMのmod作成に夢中になり、色々と調査や検証を行ってきました。

以前とある方より「"すべての店に武器・防具を追加するmod"や"すべての店に秘薬やクラスチェンジアイテム追加するmod" ってどんなアプローチで作ったの?」という質問を頂きました。

英語での質問だったため、Google翻訳に頼りつつ、 uassetとuexpの関係や、自分自身のアプローチについてざっくりと書いて回答しました。 今回、回答した内容の日本語版をブログ記事として残しておきたいと思います。

目次

利用ツールについて

本記事では下記のツールを利用しています。
各種利用方法は割愛します。

はじめに

  • 通常の手順を試したができなかった
    • uasset+uexpの結合とJSON化
    • JSONの値変更と変更後のJSONのuasset化

まず、mod製作者の皆さんが使っているSerializerを用いて、uasset+uexpをJSONにしました。

しかしショップのファイルは、変更したJSONからbinに変換しても、内容が適用されず、通常の手順では不可能でした。 Serializerのみで編集完了するファイルは少ないようで、別のアプローチが必要になりました。

そこでnamesファイルとJSONファイルを元にuassetおよびuexpの16進数の並びを解析し推測しながら16進数を追加・変更することにしました。 (namesファイルはSerializerのuassetからJSONを出力するバッチ「1 - uasset to JSON--dumpnames.bat」を利用することで取得できます。)

加えて、別のSerializerであるJohnWickParseのソースコード(※1)からuassetのHEX情報を得ました。

※1 JohnWickParse/blob/master/src/assets.rsの435行目~470行目付近

上記の情報をもとに、推測と検証を行った結果、以下のことを理解することができました。

[1]uassetのnamesとuexpの関係
[2]namesキーの変更方法
[3]namesキーの追加方法
[4]uexpの配列と構造体のHEX列

uassetとuexpの関係

それではuassetとuexpの関係について具体的に確認していきましょう。
uexpは、namesのインデックスとその値(整数や浮動小数点数、names)で構成されているようです。 (例外があるかもしれませんが、DataTableとよばれるオブジェクトに関しては、この構成のようです。)

ShopItemDataCsv.uassetを用いた解析アプローチ例

ShopItemDataCsv.uasset (Content\Game00\Data\Csv\ShopData)を例にします。 これをSerializerでJSONにすると、下記のようなデータが得られます。 f:id:rinne_grid2_1:20201227110718p:plain

上記画像の1219行目に注目してみます。 "ItemId_24_320FB4CD4865E046DDF62B80E83DE9FD": "EItemType::ITEM_ID_CHOCO", と書かれているようです。

上記JSONの「キー:値」がバイナリエディタ上では、どのようになっているのか?
これを解析していきます。

1 - uasset to JSON--dumpnames.batで得られたShopItemDataCsvNames.namesではItemId_24_320FB4CD4865E046DDF62B80E83DE9FDは以下のとおりになっています。 f:id:rinne_grid2_1:20201227110752p:plain

79行目に注目してください。 この場合、ItemId_24_320FB4CD4865E046DDF62B80E83DE9FDは79行目にありますが、インデックスは0始まりなので行数から1を引く必要があります。

79-1=78、つまり78がItemId_24_320FB4CD4865E046DDF62B80E83DE9FDのインデックスということになります。

78を16進数(32bit)で表現すると、00 00 00 00 00 00 00 4Eです。

しかし、uexpの16進数はリトルエンディアンで表現されるため、 下記のとおりになります

4E 00 00 00 00 00 00 00

(リトルエンディアンについては、申し訳ありませんがここでは説明を割愛します。Web検索等ですぐに出てくるので、検索をおすすめします。)

試しに、HxDツールでShopItemDataCsv.uexpを開き、この16進数の値4E 00 00 00 00 00 00 00で検索してみると、160件のデータがマッチします。Serializerで出力したJSONで ItemId_24_320FB4CD4865E046DDF62B80E83DE9FDを検索すると同様に160件であり、個数が一致していることがわかります。

続いて、検索結果のうちの一つであるアドレス0x00000164の16進数に着目してみましょう。 f:id:rinne_grid2_1:20201227110819p:plain

4E 00 00 00 00 00 00 00 46 00 00 00 00 00 00 00 08 00 00 00 00 00 00 00 0F 00 00 00 00 00 00 00 00 1B 00 00 00 00 00 00 00

これらの16進数を上記で説明した方法でnamesと照合していきます。

16進数 10進数 namesキー(10進数に対応するインデックス)
4E 00 00 00 00 00 00 00 78 ItemId_24_320FB4CD4865E046DDF62B80E83DE9FD
08 00 00 00 00 00 00 00 8 CameraId_26_4BE91328489B42F5B11C5E8894E1EF3A なんだか関係なさそうなキー。
0F 00 00 00 00 00 00 00 00 15 EItemType
1B 00 00 00 00 00 00 00 27 EItemType::ITEM_ID_DROP

さて、 08 00 00 00 00 00 00 00をnamesとマッチングした結果、 CameraId_26_4BE91328489B42F5B11C5E8894E1EF3Aという関係なさそうなキーが出てきました。

このようにたまに突拍子もない値が登場することがあります。 これは、値の型を示す識別子の後に挿入されるケースが多いです。 (IntProperty FloatPropertyなどの型識別子, EItemType EItemType::ITEM_ID_DROPなどのEnumProperty) この場合、namesキー値ではなく、値そのものであると考えた方が良いです。

しかしこれで、 “ItemId_24_320FB4CD4865E046DDF62B80E83DE9FD”: “EItemType::ITEM_ID_DROP”が示す16進数の値が判明しました。

  • “ItemId_24_320FB4CD4865E046DDF62B80E83DE9FD”: “EItemType::ITEM_ID_DROP”が示す16進数の値
    • 46 00 00 00 00 00 00 00 08 00 00 00 00 00 00 00 0F 00 00 00 00 00 00 00 00 1B 00 00 00 00 00 00 00

では、目的のEItemType::ITEM_ID_CHOCOを探すにはどうすれば良いでしょうか。

46 00 00 00 00 00 00 00 08 00 00 00 00 00 00 00 0F 00 00 00 00 00 00 00 00 1B 00 00 00 00 00 00 00 のうち、1B 00 00 00 00 00 00 00の部分(10進数27)が、 namesのEItemType::ITEM_ID_DROPのインデックスと一致していました。

つまり、この部分をEItemType::ITEM_ID_CHOCOのインデックスである 14 00 00 00 00 00 00 00(10進数20)に置換すれば良いのです。

  • “ItemId_24_320FB4CD4865E046DDF62B80E83DE9FD”: “EItemType::ITEM_ID_CHOCO”が示す16進数の値
    • 46 00 00 00 00 00 00 00 08 00 00 00 00 00 00 00 0F 00 00 00 00 00 00 00 00 14 00 00 00 00 00 00 00

この16進数で検索をしてみると、15件のデータが出てきました。 JSONでEItemType::ITEM_ID_CHOCOを検索してみると、同様に15件であり一致していることがわかります。 このようにして、各種データの解析や変更を行うことができます。

nameキーの変更方法、追加方法や、uexpの配列と構造体のHEX列については、 下記の記事をご参照ください。

【聖剣伝説3-ToM_mod】uassetとuexpファイルのバイナリ変更方法まとめ - 気ままなタンス*プログラミングなどのノートブック