雑用担当の備忘録

技術的な話のみになります。翻訳データそのものはありません。 カテゴリ>その他>注意事項を必ず参照してください

カテゴリ:解析 > UE4

フォント

今までの情報で豆腐では無く日本語が表示されているはずですが(1)にも書いたようにCJK互換で中国のグリフが表示されたり文字の上部が若干欠ける不具合があります。
対処方法はフォント置換なんですがやり方は2通りあります。
  1. Slate の ttf ファイルを置き換える。
  2. uasset のフォントデータを置き換える。
1は簡単なんですがこのゲームでは文字の上部は欠けたままです。そんなに気にならないとは思うので気にしないという人は1で良いと思います。
2はUE4自体が必要ですが文字の上部も欠けずにちゃんと表示されます。

Slate 置換
対象ファイル Engine\Content\Slate\Fonts\DroidSansFallback.ttf
を日本語フォントに置き換えるだけファイル名はそのまま DroidSansFallback.ttf にする。
この情報はこちらのスレの130さんからの情報です。有難うございます。

uasset 置換
対象ファイル EthanCarter\Content\Gameplay\Assets\Fonts\MenuFonts.uasset
UE4でこのファイルを作成していきます。UE4のバージョンは4.8.3を使うとうまくいきます。
まず MenuFonts.uasset の中身をバイナリエディタで見ます。
/Game/Gameplay/Assets/Fonts/MenuFonts
こんな部分があると思います。これを元にUE4で作成していきます。
UE4起動して
UE4_Font01
このようなフォルダ構成にして ユーザインタフェース>フォント で MenuFonts を作成する。
UE4_Font02
フォントを追加でインポートする ttf ファイルを選択する。この状態で保存

後はパッケージングするだけなんですが、パッケージ設定で Packaging:Use Pak File のチェックを外して pak ファイルにまとめないようにするとアンパックの手間がいらないので良いです。

後は出来た MenuFonts.uasset ファイルを元の EthanCarter\Content\Gameplay\Assets\Fonts\MenuFonts.uasset と置き換える。

このゲームはヘッダにカスタマイズ等無いようなので、置き換えるだけでゲーム起動します。

locres 編集

翻訳すべきデータは EthanCarter\Content\Localization\Game\en\Game.locres にある。

locres の構造
struct Locres {
    namespace_count: i32,
    namespaces: Vec<Namespace>,
}
struct Namespace {
    namespace: FString,
    key_count: i32,
    entry: Vec<Entry>,
}
struct Entry {
    key: FString,
    source_string_hash: i32,    // crc32
    localized_string: FString,
}

01 00 00 00
namespace_count = 0x1

FB FF FF FF 47 00 61 00 6D 00 65 00 00 00
FString
0xFFFFFFFB = -5 なので UTF-16-LE で5文字つまり10バイトで末尾に Null 付加されている。
47 00 61 00 6D 00 65 00 00 00
したがって
namespace = "Game"

A3 02 00 00
key_count = 0x2A3

0x2A3ぶん entry を読み込む
entry[0]
FB FF FF FF 4E 00 6F 00 6E 00 65 00 00 00
FString だから key = "None"

C5 0D 18 71
source_string_hash = 0x71180DC5

F0 FF FF FF 3D 00 3D 00 3D 00 3D 00 20 00 4D 00
45 00 4E 00 55 00 20 00 3D 00 3D 00 3D 00 3D 00
3D 00 00 00
FString だから localized_string = "==== MENU ====="

こんな感じで読み込めるから、これを元にエクスポート処理を実装すればよい。

インポートはオフセット値とか気にする必要はないので、上記の処理の反対を頭から繰り返すだけで可能

アンパック

pak ファイルにデータはまとめられている。展開した状態でゲーム起動は可能。

pak ファイルは 4G 超えていますので、大容量のデータを取り扱えるバイナリエディタでないとデータは見れません注意してください。

struct PakInfo {
    magic: u32,
    version: i32,
    index_offset: u64,
    index_size: u64,
    index_hash: [u8; 20],
}
まず PakInfo なんですがこれは pak の末尾にあります。
offset, size は u64(4G超可能) なんで注意 8 バイトです。
magic は末尾から seek(-44) です。

index_offset ここに index があるのでそこへ seek
3F 89 CF 4F 01 00 00 00 = 0x14FCF893F

struct Pak {
    mount_point: FString,
    num_entries: i32,
    entries: Vec<PakEntry>,
}
struct PakEntry {
    file_name: FString,
    offset: u64,
    size: u64,
    uncompressed_size: u64,
    compression_method: i32,
    hash: [u8; 20],
    compression_blocks: Vec<PakCompressedBlock>,
    bencrypted: u8,
    compression_block_size: u32,
}
PakCompressedBlock は今回の non commpres では取り扱いません。comppresed のゲームの時に書きます。

まず FString について
struct FString {
    legth: i32,
    string: Vec<u8>,
}
length の値が < 0 の場合 string は UTF-16LE で > 0 の場合は ANSI
String は null 終端
path は ANSI なので length は正の値

0A 00 00 00 2E 2E 2F 2E 2E 2F 2E 2E 2F 00
length = 10, String = "../../../"

mount_point = "../../../"

となります。後は num_entries 分 PakEntry を読み込むcompression_blocksは無いものとして考えてください。

後は実際のアンパック処理なんですが
file_name, offset, size がわかっているので
offset へシークして size 分読み込んだものを file_name として出力するだけ。

追記:
忘れていました。offserへシークした場所に PakEntry の file_name を除いた他の要素が付加されていますので。それを読み込んでその次のデータから取り扱うが正解です。

TVECR 解析

概要:
  • フレームワークは UE4、ローカライズは UE4 の機能を使用。つまり locres バイナリデータの編集が必要。
  • pak は non compress、展開した状態でゲームが起動できるためリパックの必要はない。
  • Font は EFontCacheType::Runtime のため uasset のフォントに無い文字コードの場合は slate の font が使われる。
UE4の基本形といった所でしょうか。
まぁ、UEは内部のバージョンによって細々としたところが変わっていくので、今後色んな派生形が出てくると思います。

locres 編集した状態
EthanJP

フォントは置換していないが Runtime なので豆腐では無く日本語が表示される。
ただし、この場合若干の不具合も発生します。
最の字を見てみると、若干上の方が欠けています。
あとこのフォントでは CJK 互換の部分で C つまり中国のグリフが表示されます。

追記:移転後、フォント置換後の画像を表示していました。フォント置換前の画像に戻しました。

↑このページのトップヘ