リパック

このゲームはリパックが必要です。
すべての情報を生成できるので元ファイルのヘッダーを利用したりする必要が無いので割と簡単です。

アンパックの時の構造と同じですが、Entry.hash はファイル名の crc64 です。
struct Arch {
    magic: u32,
    name_size: u32,
    entry_count: u32,
    entries: Vec<Entry>,
    names: Vec<u8>,        // name_size
}
struct Entry {
    hash: u64,                    // ファイル名の crc64
    offset: u64,
    entry_size: u32,
    number: u32,                // テキストとスクリプトは 0、それ以外は entry_size と同じ
    name_block: u16,
    name_offset: u16,
}
余談:
crc64 とは言っても crc は派生形が多いし実際これも派生形です。
テーブルのシード値を検索しようとしましたが GPU を使って計算しても約5年…
しょうがないので実装はテーブル値埋め込み、実際の計算部分も若干違います。

本題に戻って
entries は hash でソートした順番(昇順)で格納
ファイルデータは name_offset でソートした順番(昇順)で格納

name_offset でソートはファイル名でソートした順番と同じ事になります。
ファイル名でソートした順に names を格納するため。

ファイルデータをすべて格納した後、ファイルサイズは 0x10000 で割り切れるように 0 でパディングします。

分かりにくいので実装の概略
パックするフォルダを検索してファイル名を取得する。この時ファイル名でソート。
ファイル名から names を生成しファイルサイズを取得する。
この情報から Entry が決定するのでファイル数分=エントリー分生成する。
Entry を hash でソートしヘッダー及び Entry と names を出力。
Entry を name_offset でソートして対象のファイルデータを読み込み出力ファイルに書き出す。
書きだした後パディング処理を行う。

重要:
某ツールではスクリプトを blowfish 復号した状態でリパックするようになっているのですが、MCSMのバージョンからはこれでは起動しなくなるので、暗号化されたままアンパックしたスクリプトをパックするようにしてください。

パックした状態ではまだ動きません。ヘッダー付加が必要
magic: u32,
pack_size: u64,
を付加します。

ここでファイルの説明
Nxxx: 無圧縮 上記のパックした状態のもの
Zxxx: Nxxx を deflate 圧縮したもの
Exxx: Zxxx を blowfish(カスタム) で暗号化したもの

Exxx がゲームのファイルなんですがここまで復元する必要はありません。
無圧縮状態でも動きます。

Zxxx は deflate 圧縮で元のバイナリと同じにはならないのですが miniz の level = 9 で圧縮した状態のもので起動は確認済みです。


前回のローカライズと今回のリパックでようやく豆腐が表示されるようになります。