雑用担当の備忘録

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

fuk リパック

fuk はアンパックした状態ではゲームが起動しない?ようなので
リパックする必要があります。

global.res(翻訳データ)リパックの仕方

global.res を data1.fuk にリパックする必要があります。

data1\locale\enus\global.res FileSize:190255, OrgFileSize:763086, Num0:701953, FileIdx:1371, FileOffset:7760670

これをもとにリパックしていきます。

まず、翻訳済みデータ global.res を data1.fuk の末尾にアペンドします。

アペンドする前の data1.fuk の末尾
09E6BF50: 87 E6 7F 03 55 79 07 CD 00 00 00 00 00 00 00 00

なので09E6BF60に global.res をアペンドする。
アペンドしたら末尾は上記の 09E6BF50 のように末尾まで XXXXXXXF まで 00 でパディングしてください。

0x9E6BF60  この値が新しい FileOffset になります。

翻訳済み global.res のファイルサイズを見ます。763,058 バイトだとします。

これからやることは上記のログを下記のようにするイメージ
data1\locale\enus\global.res FileSize:763058, OrgFileSize:763058, Num0:701953, FileIdx:1371, FileOffset:9E6BF60

まず FileSize 関連の変更

OrgFileSize:763086(0xBA4CE), FileSize:190255(0x2E72F)
LittleEndian で u32 なので CE A4 0B 00 2F E7 02 00 となるのでこのデータを検索して
global.res のファイルサイズ763058(0xBA4B2)から
B2 A4 0B 00 B2 A4 0B 00 に置き換える。
これで FileSize と OrgFileSize が変わった状態

次に FileOffset:7760670 を FileOffset:9E6BF60 に変更する。

offset は 0x7760670 / 0xF = 0x776067
67 60 77 00 の状態で格納されているのでこの値で検索、先頭データから検索する方が良いでしょう。
そこを 60 BF E6 09 に変更

これでリパックは完了です。

この状態だとフォントが置換されていないため豆腐で表示されると思います。


フォント置換

フォントは logic.fuk の locale\enus\font01.ttf と locale\enus\font01b.ttf を置換すると良い。
やり方は global.res と同じような感じ

これでも不具合が出る場合は logic.fuk locale\enus\font02.ttf
どこにあったか忘れましたが font00.ttf あるいは glyph_lib.swf も置換すると良くなるかも。

global.res 編集

文字データは data1.fuk の locale\enus\global.res に格納されている。
global.res はバイナリデータ

res の構造

struct Res {
    magic: u32,
    version: u32,
    entry_count: u32,
    entries: Vec<Entry>,
}
struct Entry {
    id: u32,
    offset: u32,
    size: u32,
}

export 処理:

entries[0] = 66 00 0D 00 80 18 01 00 36 00 00 00
offset = 0x11880, size = 0x36

シーク offset だが Res のヘッダー分(u32*3=0xC)もプラスする。
つまり 0x1188C から 0x36 バイト

3C 00 66 00 6F 00 6E 00 74 00 20 00 73 00 69 00
7A 00 65 00 3D 00 27 00 34 00 27 00 3E 00 3C 00
62 00 72 00 3E 00 3C 00 2F 00 66 00 6F 00 6E 00
74 00 3E 00 00 00

文字コードは UTF-16-LE で null 終端(00 00)
したがって "<font size='4'><br></font>" となる。
これを entry_count 繰り返す。

import 処理:

上記の文字列が "<font size='4'></font>" と変化した場合を考える。
"<br>" = 3C 00 62 00 72 00 3E 00 が削除なので

3C 00 66 00 6F 00 6E 00 74 00 20 00 73 00 69 00
7A 00 65 00 3D 00 27 00 34 00 27 00 3E 00 3C 00
2F 00 66 00 6F 00 6E 00 74 00 3E 00 00 00

となる。size が変わるということは、次以降の entry の offset が変わることに注意。

実装としては、文字列の size を計算しすべての offset を再計算してから
ファイルに出力すると良い。

fuk アンパック

まず fuk のフォーマット
格納は LittleEndian

struct Fuk {
    magic:u32,
    fuk_version:u32,
    entry_count:u32,
    file_count:u32,
    length:u32,
    flag:u32,
    entry:Vec<FukEntry>,                  // size entry_count
    entry_info:Vec<FukEntryInfo>,    // size entry_count
    offsets:Vec<u32>,                        // size file_count
    file_names:Vec<u8>,                   // null terminate * entry_count    ANSI
}
struct FukEntry {
    next_id:i32,
    child_id:i32,
    parent_id:i32,
    name_offset:u32,
}
struct FukEntryInfo {
    uncompressed_size:u32,
    size:u32,
    num0:u32,
}

実際のアンパック処理

entry[0]から開始
FF FF FF FF 0B 08 00 00 FF FF FF FF 00 00 00 00
child_id = 0x80B つまり子供が居るのでこの entry 自体はフォルダになる。
フォルダ名は name_offset = 0x0 なので file_names から
00
が取得される。Null 終端なのでフォルダ名は空き文字つまりルートフォルダ。
次に子供へ移行

entry[0x80B] = 0A 08 00 00 0E 08 00 00 00 00 00 00 BD BC 00 00
child_id = 0x80E, name_offset = 0xBCBD
file_names[0xBCBD] = 77 6F 72 6C 64 73 00
なので "worlds" を取得

entry[0x80E] = 0C 08 00 00 0F 08 00 00 0B 08 00 00 D3 BC 00 00
child_id = 0x80F, name_offset = 0xBCD3
file_names[0xBCD3] = 77 6F 72 6C 64 00    // "world"

entry[0x80F] = FF FF FF FF FF FF FF FF 0E 08 00 00 D9 BC 00 00
child_id = 0xFFFFFFFF(i32 なので -1), name_offset = 0xBCD9
file_names[0xBCD9] = 72 65 6E 64 65 72 70 69 70 65 2E 78 6D 6C 00    // "renderpipe.xml"
child_id = -1 つまり子供が無いのでこの entry はファイルを表す。
ここまでで path は worlds\world\renderpipe.xml になる。

ここで実際にファイルを書きだす処理
必要なのは offset, size, uncompressed_size
size と uncompressed_size は entry_info[0x80F] で取得可能
ここで問題になるのは offset で offsets にあるのだが entry_count と file_count は違う。
entry_count にはフォルダも含まれるが file_count はファイルしか含まれないため差異が生じる。
これに対応するには entry を読み込んだ時にファイルの index を振っておけばよい
let mut cnt = 0;
for ent in entry {
    if ent.child_id == -1 {
        ent.file_index = cnt;
        cnt += 1;
    }
}
3っつの値が判明したので offset へシークして size 分読み込んで path へ書き出せば良いのだが
ファイルはzlib圧縮されているものと非圧縮のものと混在しているのでそこを注意
if size !=  uncompressed_size {
    zilb 展開後にファイル出力
} else {
    そのまま出力
}

ここまでで1個のファイル出力は完了

entry[0x80F] = FF FF FF FF FF FF FF FF 0E 08 00 00 D9 BC 00 00
次に next_id = -1 つまり次が無いので親 parent_id = 0x80E に戻る

entry[0x80E] = 0C 08 00 00 0F 08 00 00 0B 08 00 00 D3 BC 00 00
next_id = 0x80C なので entry[0x80C] を処理する。

こんな感じでループしていくとすべてのファイルが展開されます。
再起で実装すると良いでしょう。

↑このページのトップヘ