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

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

【聖剣伝説3-ToM_mod】uassetとuexpファイルのバイナリ変更方法まとめ

スポンサーリンク

2020年9月19日追記:rngd_uasset_modify_for_trials_of_manaについて

nameテーブルへの要素の追加・変更・削除の際に、変更が必要となるアドレスの値を一括で増減するツール(rngd_uasset_modify_for_trials_of_mana) https://github.com/rinne-grid/rngd_uasset_modify_for_trials_of_mana


2020年5月上旬から現在まで、聖剣伝説3ToMのmod作成に夢中になっています。

今回、いわゆるシステム系のmodを作成する時の手順について、備忘録として本記事に残しておこうと思います。

目次

本記事で扱う内容

  • mod作成に必要となるuasset/uexpのアドレス変更位置

本記事で扱わない内容

必要なツール

nameテーブル要素の文字数変更

uassetファイルのnameテーブル要素の文字数を変更した場合に変更すべきデータアドレス一覧

No アドレス範囲
[1-1] 0x0018-0x001B(※1)
[1-2] (※1)で示された値を持つシリアル値(ファイルの下の方)
[1-3] 0x003D-0x0040
[1-4] 0x0045-0x0048
[1-5] 0x0049-0x004C
[1-6] 0x00A5-0x00A8
[1-7] 0x00A9-0x00AC
[1-8] 0x00BD-0x00C0
[1-9] nameテーブル要素の文字数

【例】 パーティにデュランがいなくても、「自由都市マイヤ」にデュランを出現させる

アプローチ: フラグの変更で対応する

対象ファイル:
Content\Game00\Data\Csv\NPCPram\NPCParamMaia.uasset

変更概要:

SAVE_DURAN_JOINというフラグ(nameテーブル要素)をev_2_raf_204_ENDに置換。
これによって、パーティにデュランがいなくても「ev_2_raf_204_END」というフラグがtrueであれば表示されるようになる

・SAVE_DURAN_JOIN : 15バイト  
・ev_2_raf_204_END : 16バイト  
    ->1バイト増えるので、[1-1]-[1-9]の値を1増やしてあげる必要がある

[1-1]
0x0018-0x001B: 49 4F 00 00(10進数で20297)なので、4A 4F 00 00(20298)を設定

[1-2]
20297を示す値を検索すると、0x004E4A-0x004E4Dが見つかる(複数見つかる場合もあるが、変更すべきはファイルの下の方の値)
-> 0x004E4A-0x004E4D:4A 4F 00 00(20298)を設定

[1-3]
0x003D-0x0040: 25 4E 00 00(10進数で20005)なので、 1を足した値 26 4E 00 00(20006) を設定

[1-4]
0x0045-0x0048: 71 2D 00 00(10進数で11633)なので、 1を足した値 72 2D 00 00(11634) を設定

[1-5]
0x0049-0x004C: 8D 4E 00 00(10進数で20109)なので、 1を足した値 8E 4E 00 00(20110) を設定

[1-6]
0x0049-0x004C: 91 4E 00 00(10進数で20113)なので、 1を足した値 92 4E 00 00(20114) を設定

[1-7]
0x00A9-0x00AC: DA 9A 01 00(10進数で105178)なので、1を足した値 DB 9A 01 00(105179)を設定

[1-8]
0x00BD-0x00C0: 95 4E 00 00(10進数で20117)なので、 1を足した値 96 4E 00 00(20118) を設定

[1-9]
nameテーブル要素の文字列 SAVE_DURAN_JOINをev_2_raf_204_ENDに置換

  • 0x2AB2-0x2AC0のSAVE_DURAN_JOINが置換&追加され、0x2AB2-0x2AC1にev_2_raf_204_ENDが入る
    • 0x2AB2の直前の4バイトを見てみると、10 00 00 00(10進数で16)になっている・・・これは、SAVE_DURAN_JOINという文字列自体の長さを示している。
    • 文字列の場合、最後は00(NUL)で終わるという仕様。したがって、SAVE_DURAN_JOINという15バイトと00(NUL)の1バイトで、16バイトというデータになっている
  • 今回、ev_2_raf_204_ENDという16バイトと00(NUL)の1バイトに変更したため、17バイトに変更する必要がある
    • 0x2AAE-0x2AB1: 10 00 00 00(10進数で16)なので、1を足した値 11 00 00 00 を設定

nameテーブルへの要素の追加

uassetファイルのnameテーブルの要素の追加方法と、その場合に変更すべきアドレス

No アドレス範囲
[2-1] 0x0018-0x001B(※2)
[2-2] (※2)で示された値を持つシリアル値(ファイルの下の方)
[2-3] 0x003D-0x0040
[2-4] 0x0045-0x0048
[2-5] 0x0049-0x004C
[2-6] 0x00A5-0x00A8
[2-7] 0x00A9-0x00AC
[2-8] 0x00BD-0x00C0
[2-9] 0x0029-0x002C:nameテーブルの要素数

nameテーブルの要素のバイト列は以下のようになっている

バイト範囲 項目の示す意味 例(※3)
最初の4バイト 文字数 16 00 00 00(リトルエンディアンで22)
それ以降の00(NUL)まで 文字列全体 6D 73 67 5F 62 61 74 5F 73 6B 69 6C 6C 5F 6E 61 6D 65 30 30 31 00(msg_bat_skill_name001)
00(NUL)の次の2バイト non_case_preserving_hash 5A 81
その次の2バイト case_preserving_hash 7C 99

(※3) Content\Game00\Data\Csv\SkillData\SkillDataEditTableDEF.uassetファイルのmsg_bat_skill_name001の場合

f:id:rinne_grid2_1:20200724144048p:plain

したがって、uassetのnameテーブルの要素を追加する場合、 文字数を示す(4バイト) + 文字列本体 + NUL(1バイト) + 末尾のハッシュ(2バイト+2バイト)をセットで追記する必要がある。

【例】 ラベル表示内容の置き換え

変更概要:

Content\Game00\Data\Csv\SkillData\SkillDataEditTableDEF.uasset内のmsg_bat_skill_name001というName要素を
Content\Game00\Data\Csv\SkillData\SkillDataEditTableATK.uassetに追加し、
SkillDataEditTableATK.uasset側のmsg_bat_skill_name004をmsg_bat_skill_name001に差し替える

SkillDataEditTableDEF.uasset
・0x1F5E-0x1F7Bをコピー(計:30バイト 文字サイズ(4バイト) + 文字列全体(21バイト) + 文字終端(1バイト) + 末尾のハッシュ(2バイト+2バイト)

f:id:rinne_grid2_1:20200724144048p:plain

SkillDataEditTableATK.uasset
・0x36DDにコピーしたバイト列を追記

f:id:rinne_grid2_1:20200724150129p:plain

・[2-1]-[2-8]に30を加算
・[2-9]に1を加算・・・407→408(nameテーブルに要素を追加したため)
・msg_bat_skill_name004のインデックス:271
 →SkillDataEditTableATK.uexpをバイナリエディタで開き、271の値を検索し、該当部分を408に置き換え

f:id:rinne_grid2_1:20200724150554p:plain

これで、追加したnameテーブル要素を利用することができる。

[補足:nameテーブルの要素一覧の取得方法]
msg_bat_skill_name004という文字のインデックスが271であるということは、
1 - uasset to JSON--dumpnames.batを実行することによって取得できる、namesファイルで特定することができる。

namesファイルは、uasset内で利用されているname要素の一覧を表している。
なお、nameテーブルのインデックスは0から始まるため注意が必要。

例:
仮にSkillDataEditTableATK.uasset(結合済み)に対して、uasset to JSON--dumpnames.batを実行した場合 267行目:msg_bat_linkability_name043 →しかし、このname要素をuexp側で指定する場合は、行数の267ではなく、266(行数-1)を指定する必要がある

uexpファイルのバイト列フォーマットについて

uexpファイルは、(DataTableにおいては)nameテーブルのインデックスの組み合わせとその値が指定されているようです。

IntPropertyの場合

No バイト範囲 項目の示す意味
[3-1] 8バイト 整数のNameプロパティ(IntProperty)
[3-2] 8バイト 整数値

・仮に、Nameテーブルのインデックスが以下の値を示している場合
 ・IntPropertyのNameインデックス:86(0x56)

【整数値5を表すバイト列】
[3-1] 56 00 00 00 00 00 00 00
[3-2] 05 00 00 00 00 00 00 00

BoolPropertyの場合

No バイト範囲 項目の示す意味
[4-1] 16バイト 真偽値のNameプロパティ(BoolProperty)
[4-2] 1バイト 真偽値

・仮に、Nameテーブルのインデックスが以下の値を示している場合
 ・BoolPropertyのNameインデックス:5(0x05)

【true】(真)
[4-1] 05 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
[4-2] 01

【false】(偽)
[4-1] 05 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
[4-2] 00

ArrayPropertyの場合

No バイト範囲 項目の示す意味
[5-1] 8バイト 配列のNameプロパティ(ArrayProperty)
[5-2] 8バイト 配列全体のバイト数
[5-3] 9バイト 配列内の変数型のNameプロパティ
[5-4] 4バイト 配列の要素数
[5-5] 以降のバイト 配列要素数*4のバイト列が続く*1

・仮に、Nameテーブルのインデックスが以下の値を示している場合
 ・ArrayPropertyのNameインデックス:4(0x04)
 ・IntPropertyのNameインデックス:114(0x72)

【配列要素が存在しない時のバイト列】
[5-1] 04 00 00 00 00 00 00 00
[5-2] 04 00 00 00 00 00 00 00
[5-3] 72 00 00 00 00 00 00 00 00
[5-4] 00 00 00 00

【配列要素が存在する時のバイト列】(要素10(0x0A)が存在する場合)
[5-1] 04 00 00 00 00 00 00 00
[5-2] 08 00 00 00 00 00 00 00
[5-3] 72 00 00 00 00 00 00 00 00
[5-4] 01 00 00 00
[5-5] 0A 00 00 00

StructPropertyの場合

Content\Game00\Data\Csv\ShopData\ShopItemDataCsv.uexpの場合

No バイト範囲 項目の示す意味
[6-1] 8バイト 配列要素の種類(ItemListなど)
[6-2] 8バイト 配列のNameプロパティ(ArrayProperty)
[6-3] 8バイト 配列全体のバイト数
[6-4] 9バイト 構造体のNameプロパティ(StructProperty)
[6-5] 4バイト 配列の要素数
[6-6] 8バイト 配列要素の種類(ItemListなど)
[6-7] 8バイト 構造体のNameプロパティ(StructProperty)
[6-8] 8バイト 構造体のバイト数(※4)
[6-9] 8バイト 構造体の種類(StG00ShopCommonItemDataStructなど)
[6-10] 17バイト *2
[6-11] これ以降 データ本体

(※4) [6-3]から[6-5~6-10]までのバイト数を引いた値

つまり、StructPropertyの要素[6-11]を追加した場合、
[6-3],[6-8]のバイト数と[6-5]の配列要素数を増やす必要がある。

・仮に、Nameテーブルのインデックスが以下の値を示している場合

インデックス Name要素 16進数
4 ArrayProperty 0x04
79 ItemList_20_7AB86DFD4DFFC48B0EB0749BF5743529 0x4F
117 StG00ShopCommonItemDataStruct 0x75
119 StructProperty 0x77

[6-1] 4F 00 00 00 00 00 00 00 (ItemList_20_7AB86DFD4DFFC48B0EB0749BF5743529)

[6-2] 04 00 00 00 00 00 00 00 (ArrayProperty)

[6-3] 65 08 00 00 00 00 00 00 (配列全体で2149バイト)

[6-4] 77 00 00 00 00 00 00 00 00 (StructProperty)

[6-5] 08 00 00 00 (配列要素数8)

[6-6] 4F 00 00 00 00 00 00 00
(ItemList_20_7AB86DFD4DFFC48B0EB0749BF5743529)

[6-7] 77 00 00 00 00 00 00 00 (StructProperty)

[6-8] 30 08 00 00 00 00 00 00
(構造体全体のバイト数:2149-53=2096)

[6-9] 75 00 00 00 00 00 00 00
(StG00ShopCommonItemDataStruct)

[6-10] EA DA 43 AF 77 64 4B 46 89 FA 06 33 0B AF E2 25 00

[6-11] (~0x0BF7のアドレスまで)

バイナリ編集で作ったシステム系のmod

上記の情報は、以下のmod作成時に調べました。 ゲームmod作成は今までやったことがなく、Unreal Engine4の知識もないため、見当違いのことを書いていたらすみません。

*1:これに当てはまらないケースもあるかもしれない

*2:たぶんDataStructの識別子