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を作成する時の手順について、備忘録として本記事に残しておこうと思います。
目次
- 目次
- 本記事で扱う内容
- 本記事で扱わない内容
- 必要なツール
- nameテーブル要素の文字数変更
- nameテーブルへの要素の追加
- uexpファイルのバイト列フォーマットについて
- バイナリ編集で作ったシステム系のmod
本記事で扱う内容
- mod作成に必要となるuasset/uexpのアドレス変更位置
本記事で扱わない内容
- バイナリエディタの使い方
- uasset/uexpの抽出方法、pak化の方法
- わかりやすくて素晴らしい記事があります(http://hal51.click/game/tom_modding)
- UassetSerializerの使い方
- リンク先(https://discord.com/channels/707365628830416946/722886515851788339/725305372314828860)
- (Hex) Edit Trials of Mana
- Serializer Fix
- リンク先(https://discord.com/channels/707365628830416946/722886515851788339/725305372314828860)
必要なツール
- バイナリエディタ(おすすめ…HxD - Freeware Hex Editor and Disk Editor | mh-nexus)
- UassetSerializer(bloodstained-tools/UAsset_Serializer_KZ_0.2a--plus-batch-scripts.zip at master · ithinkandicode/bloodstained-tools · GitHub)
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の場合
したがって、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バイト)
SkillDataEditTableATK.uasset
・0x36DDにコピーしたバイト列を追記
・[2-1]-[2-8]に30を加算
・[2-9]に1を加算・・・407→408(nameテーブルに要素を追加したため)
・msg_bat_skill_name004のインデックス:271
→SkillDataEditTableATK.uexpをバイナリエディタで開き、271の値を検索し、該当部分を408に置き換え
これで、追加した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の知識もないため、見当違いのことを書いていたらすみません。
ケヴィンのボイスをデュランに変更する
Change Kevin's Attack voice to Duran at Trials of Mana Nexus - Mods and communityまんまるドロップを「風の太鼓」で置き換えて、序盤で自由にワールドマップ移動ができるようにする
Change Shop Item Drop to Wind Drum at Trials of Mana Nexus - Mods and communityパーティに参加していないメンバーを町に出現させる(6人で旅してる気分になれる)
Spawn All Heroes in Town at Trials of Mana Nexus - Mods and community全ての町の道具屋で、ステータスアップアイテム、クラスチェンジアイテム、種アイテムを購入可能にする
Add Items To All Shop - potions and class change items and seeds at Trials of Mana Nexus - Mods and community