2012年12月31日月曜日
Star Wars The Force Unleashed II
日本語化
archive: 普通のzip
font: .dds, a2f and swf
pak2.lp/Game/Disc/UI/Hud/Fonts/PCDX/ .dds , a2f
pak3.lp/Game/Global/UI/Flash/fonts_en..gfx (swf)
text: utf-8 plain
pak3.lp/Game/Global/UI/GlobalText.utf8 , GlobalTextPC.utf8
一部フォントは文字コードにアイコンを振ってるのでフォント作成時に混ぜる必要アリ
2012年12月30日日曜日
2012年12月29日土曜日
Star Wars The Force Unleashed
日本語化可能と思われ
整合性チェックとかなければ。
archive: *.utf16_pc.lp http://forum.xentax.com/viewtopic.php?f=10&t=3823
text: utf-16 tsv
font: .dds/.a2f
Tahoma14.dds
ru_Tahoma14.dds
ここでロシア語用のフォントにLatin-1とロシア文字の両方が含まれている。
このことから1byte文字の切り替えではなく、Unicode対応であることがわかる。
もちろんテキストデータを見るのが確実だが。
整合性チェックとかなければ。
archive: *.utf16_pc.lp http://forum.xentax.com/viewtopic.php?f=10&t=3823
text: utf-16 tsv
font: .dds/.a2f
hdr: char magic[8] // "2D2Rtlum" char unk[8] // 0 fill char type[4] // "font" char unk2[12] // 0 fill float tex_w float tex_h int unk // font width? int unk // font height? int num int unk // 34 int n_glyph int dataofs // glyph start dataofs + x10 short indexes[num] // map charcode=>glyph short pad[] // 4byte align struct glyphs[n_glyph] float u0,v0 float u1,v1 float u2,v2 float u3,v3 (u0,v0) (u3.v3) +--------+ | | | | | | +--------+ (u1,v1) (u2,v2) ※codeが255までしか無いの(Tahoma14.rtf)はちょっと違うが気にしないことにする
Tahoma14.dds
ru_Tahoma14.dds
ここでロシア語用のフォントにLatin-1とロシア文字の両方が含まれている。
このことから1byte文字の切り替えではなく、Unicode対応であることがわかる。
もちろんテキストデータを見るのが確実だが。
7.62 mm: High Calibre
かな化可能と思われ。
archive: packer/unpacker
text: 暗号化plain text de/encriper (同上) .txt .ini
font: BMP/fonts .ttf .fnt
.fnt:
header:
int unk // 0
int unk // 256
int unk // 256
struct glyphs[0xe0] // 20-ff
int w
int h
data:
まだしらべてないお
archive: packer/unpacker
text: 暗号化plain text de/encriper (同上) .txt .ini
font: BMP/fonts .ttf .fnt
.fnt:
header:
int unk // 0
int unk // 256
int unk // 256
struct glyphs[0xe0] // 20-ff
int w
int h
data:
まだしらべてないお
2012年12月27日木曜日
2012年12月25日火曜日
Death to Spies
日本語化可能
Death to Spies (初代)
- Death to Spies
- Death to Spies: Moment of Truth
- Death to SpiesをMoment of Truthで動かすMOD
- Death to Spies: Moment of Truthの中文化MOD
- それを利用したDeath to Spies:Moment of Truthの日本語化MOD
を利用してさらにトリッキーなことをすれば日本語化可能。
ツール整備が面倒なので訳す人がいれば用意する。
日本語化MODを公開する(2)
ゲーム日本語化 Advent Calendar 2012
日本語化リクエスト募集で募集したリクエストの中から
Deep Blackです。
∧∧
ヽ(・ω・)/ ズコー
\(.\ ノ
、ハ,,、  ̄
本命はSyndicateです。
Syndicate
日本語化可能。
日本語化MOD
font: The Chronicles of Riddick: Escape from Butcher Bayと同じ
text:
archive: see below
日本語化MOD
font: The Chronicles of Riddick: Escape from Butcher Bayと同じ
text:
archive: see below
All.xcd: FOOTER: int num struct ent[num] int ofs int zero1 // maybe ofs hi int size int zero2 // maybes size hi int namelen char name[namelen] char pad[0-3] // x20 fill 4byte align int footer_pos END OF FILE each file: hdr: char magic[16] // 'MOS DATAFILE2.0\0' int v0 //0 int v1 //0 int v2 int v3 int v4 int v5 int num int v7 // struct ent[num-1] char typename[16] int v0 int next int unk0 int pos int size int num2 // used at data int unk2 typename: XCD_ATTRIB XCD_INDEXES XCD_DATA XCD_SOUNDNAME XCD_AICATEGORY XCD_INDEXES: struct idx[num2] int id; // incremental int ofs; // ofs in XCD_DATA short size short unk XCD_DATA: struct msg[] short zero // 0 short flg // if 1, leads msg short len short zero[2]; // 0 short strz[len-3] // null terminated UTF16
日本語化MODを公開する
ゲーム日本語化 Advent Calendar 2012
日本語化リクエスト募集で募集したリクエストの中から
Deep Blackです。
メタスコア39点
何千本あるかわからないSteamの中でワースト14 (15はShellshock 2)
見つかったレビューが
結論:糞ゲーだった。返金を要求するレベル。普通なら
こんなの訳す奴いねえwwww
とスルーするところだが、
製品版には日本語リソースが含まれているという噂なので解析してみた
まず "Deep Black xentax" でぐぐると
XeNTaX • View topic - Deep Black Game Localization File (global.pack)
がトップに出てくる。
まあわざわざ英語版ゲームをやろうって人は読めるだろうが
誰かこのファイルunpack/repackしてくんね?
一日後
ほいよ。unpackするquickbms scriptだお
二ヶ月後
まだ要る人おるかもしれんから
テキストの変換とpackerおいとくわ
Deep Black: Reloaded (DEMO)
日本語化可能
日本語化MOD
archive:
http://forum.xentax.com/viewtopic.php?f=35&t=7214
http://forum.xentax.com/viewtopic.php?f=10&t=8675
http://aluigi.altervista.org/papers/bms/biart7.bms
text: global.pack/ localization_db.loc *.bsrt
format: http://forum.xentax.com/viewtopic.php?f=10&t=8675
import/exporter http://forum.xentax.com/viewtopic.php?f=35&t=7214
font: CommonGuiSceneSet.pack .dds .abc
abc font format:
日本語化MOD
archive:
http://forum.xentax.com/viewtopic.php?f=35&t=7214
http://forum.xentax.com/viewtopic.php?f=10&t=8675
http://aluigi.altervista.org/papers/bms/biart7.bms
text: global.pack/ localization_db.loc *.bsrt
format: http://forum.xentax.com/viewtopic.php?f=10&t=8675
import/exporter http://forum.xentax.com/viewtopic.php?f=35&t=7214
font: CommonGuiSceneSet.pack .dds .abc
abc font format:
int ver // 6 int unk // 1 float f1 // width? float f2 // 0 float f3 // 0 float f4 // width? int num short indexes[num]; // charcode-1 to glyphs map int num2 struct glyphs[num2] float u0 // tex coord 0.0..1.0 float v0 float u1 float v1 short xofs // -1 .. 4 short w short h short zero // always 0
2012年12月22日土曜日
中華MODのしくみ
ゲーム日本語化 Advent Calendar 2012
前回、ゲームプログラムには元々日本語(マルチバイト文字)表示に対応しているものと、Latin-1(1バイト文字)表示にしか対応していないものがあり、対応するにはプログラムの変更が必要という話をした。
ソースコード(実行ファイルの元)がある場合は、ソースコードを変更してそのソースから変更版の実行ファイルを作ればよいが、無い場合はどうするか。
ゲームプログラムの実行ファイルから、文字表示に関する部分を突き止め、その部分を乗っ取って自作のマルチバイト対応コードに置き換える、ということをする。
実行ファイルを書き換える。
Morrowind Code Patch
とかたぶんそう。
通常、エクスプローラからメニューやダブルクリックすると、ゲームプログラムをメモリにロードして実行する。
しかし特殊なローダを使うと、ロードだけして実行しない。
ここで無理やりDLLを読み込ませ、さらにメモリ上のゲームプログラムの文字表示関連部分を変更して、それから実行する。
ゲームが開始してパラメータやイベントなど文字表示を行う処理になると、変更された文字表示処理に飛ぶ。
ゲームプログラムを改変する、というとなんだか怖そうだが、怪しいMODを使わない人でも、実は使ったことがあるはず。
Steamで販売されているゲームには、元々Steamに対応しているものと、していないものがある。
また、「ゲームを追加/非Steamゲームを追加」すると、非steamゲームをsteamのリストに登録してsteam経由でプレイできる。
steam経由でプレイすると、右下にsteamアイコンが出て、画面キャプチャやチャット等のsteam機能を使えるようになる。
これはsteamが特殊ローダとして働き、非steamゲームを改変してsteam機能を追加している。
例えばキー入力を乗っ取ってSHIFT+TABでsteamモードに入ったり、画面描画完了を乗っ取ってsteamアイコンを表示してから本当の画面描画完了をしていると思われる。
※コメントで指摘されましたがOrignの勘違いでした。
※と思ったけどやっぱsteamにもDLLいました
中華MODの中には、XXXX.dll を XXXX.dllとXXXX_ori.dllとかに差し替えるものがある。
ゲームプログラムは通常、Windows DLLやDirect X DLLなど、外部のDLLをロードするように作られている。
差し替えた状態でゲームプログラムがDLLをロードする時、本来のDLLではなく偽DLLを読む。
このタイミングで偽DLLの初期化が呼ばれるので、ここでメモリ上のゲームプログラム本体を書き換える。
また、オリジナルのDLLをロードして、オリジナルDLL内の関数の場所を調べておく。
ゲーム中にDLLが呼ばれたら、偽DLLはオリジナルのDLLの該当関数に飛ばす。
ここでのポイントは「元々ゲームプログラムがロードするDLL」という点である。
どのDLLを差し替えるかはさしたる問題ではない。
「ゲーム中にDLLが呼ばれたら、オリジナルのDLLの該当関数に飛ばす」処理を書くのが、関数がたくさんあるDLLだと面倒なので、関数が少ないDLLが好まれる。
Direct X のDLLを差し替えているからといって、 Direct X の機能を変更しているとは限らない。
これらの「ゲームプログラム改変MOD」は、技術的にはウィルスの類と同じである。
乗っ取った後、キー入力や通信を盗み見たりの悪さをするか、文字を表示するかの違いでしかない。
改変してプロテクトやDRMのチェックを無効にするのも同様である。
他にも書き換える手段はあるが、ウィルスと異なり、見つからないようこっそり書き換えたり、書き換えたあと存在を隠すことが目的ではないので、詳細は述べない。
「ゲームプログラムの実行ファイルから、文字表示に関する部分を突き止め、その部分を乗っ取って自作のマルチバイト対応コードに置き換える」と言ったが、
日本にもそこまでやっている人が何人かいる(逆に言えば何人かしかいないと思われ)。
TObject
Obvilion日本語化パッチ
FOJP
俺はヘタレなので、置き換え場所を探すのが簡単なものしかやったことは無い。
ところでFOJPのソースコードが公開されていた。
ゲームプログラムの文字表示部分を突き止めるのではなく、変態(ほめ言葉)的なことをしている。
前回、ゲームプログラムには元々日本語(マルチバイト文字)表示に対応しているものと、Latin-1(1バイト文字)表示にしか対応していないものがあり、対応するにはプログラムの変更が必要という話をした。
ソースコード(実行ファイルの元)がある場合は、ソースコードを変更してそのソースから変更版の実行ファイルを作ればよいが、無い場合はどうするか。
ゲームプログラムの実行ファイルから、文字表示に関する部分を突き止め、その部分を乗っ取って自作のマルチバイト対応コードに置き換える、ということをする。
EXE書き換え
実行ファイルを書き換える。
Morrowind Code Patch
とかたぶんそう。
特殊ローダ
通常、エクスプローラからメニューやダブルクリックすると、ゲームプログラムをメモリにロードして実行する。
しかし特殊なローダを使うと、ロードだけして実行しない。
ここで無理やりDLLを読み込ませ、さらにメモリ上のゲームプログラムの文字表示関連部分を変更して、それから実行する。
ゲームが開始してパラメータやイベントなど文字表示を行う処理になると、変更された文字表示処理に飛ぶ。
通常 +------------+ | | | ゲーム.exe | | | | 本体 | | | | | | | | テキスト | | | | | 1文字取出 | | | | | | | | 文字表示 | | | +------------+ ローダー経由 +------------+ | | | ゲーム.exe | | | | 本体 | | | | | | | | テキスト | | | | | *------------+ | | | | | | | | | *---------+ | | | | | +------------+ | | |自作DLL | | | | | | | | 文字表示 --|--+ | | | | | 1文字取出--|-----+ | | +------------ *を書き換える
ゲームプログラムを改変する、というとなんだか怖そうだが、怪しいMODを使わない人でも、実は使ったことがあるはず。
Steamで販売されているゲームには、元々Steamに対応しているものと、していないものがある。
また、「ゲームを追加/非Steamゲームを追加」すると、非steamゲームをsteamのリストに登録してsteam経由でプレイできる。
steam経由でプレイすると、右下にsteamアイコンが出て、画面キャプチャやチャット等のsteam機能を使えるようになる。
これはsteamが特殊ローダとして働き、非steamゲームを改変してsteam機能を追加している。
例えばキー入力を乗っ取ってSHIFT+TABでsteamモードに入ったり、画面描画完了を乗っ取ってsteamアイコンを表示してから本当の画面描画完了をしていると思われる。
※コメントで指摘されましたがOrignの勘違いでした。
※と思ったけどやっぱsteamにもDLLいました
偽DLL
中華MODの中には、XXXX.dll を XXXX.dllとXXXX_ori.dllとかに差し替えるものがある。
ゲームプログラムは通常、Windows DLLやDirect X DLLなど、外部のDLLをロードするように作られている。
差し替えた状態でゲームプログラムがDLLをロードする時、本来のDLLではなく偽DLLを読む。
このタイミングで偽DLLの初期化が呼ばれるので、ここでメモリ上のゲームプログラム本体を書き換える。
また、オリジナルのDLLをロードして、オリジナルDLL内の関数の場所を調べておく。
ゲーム中にDLLが呼ばれたら、偽DLLはオリジナルのDLLの該当関数に飛ばす。
通常 +------------+ | | | ゲーム.exe | | | | | +--- DLL呼出1 | | | | +-+--- DLL呼出2 | | | | | | | +------------+ | | | DLL | | | | | | | | *初期化 | | | | | | +-- DLL関数1 | | | | +---- DLL関数2 | | | +------------| * はロード時に自動で呼ばれる 偽DLL +------------+ | | | ゲーム.exe | | | | | +--- DLL呼出1 | | | | +-+--- DLL呼出2 | | | | | | | +------------+ | | | 偽DLL | | | | | | | | *本体改変 | | | | 元DLLロード | | | | | +----------------+ +--------------------+ | | | | +------------| | | | 元DLL | | | | | | | | *初期化 | | | | | | | | DLL関数1 ----+ | | | | | DLL関数2 ------+ | | +------------|
ここでのポイントは「元々ゲームプログラムがロードするDLL」という点である。
どのDLLを差し替えるかはさしたる問題ではない。
「ゲーム中にDLLが呼ばれたら、オリジナルのDLLの該当関数に飛ばす」処理を書くのが、関数がたくさんあるDLLだと面倒なので、関数が少ないDLLが好まれる。
Direct X のDLLを差し替えているからといって、 Direct X の機能を変更しているとは限らない。
これらの「ゲームプログラム改変MOD」は、技術的にはウィルスの類と同じである。
乗っ取った後、キー入力や通信を盗み見たりの悪さをするか、文字を表示するかの違いでしかない。
改変してプロテクトやDRMのチェックを無効にするのも同様である。
他にも書き換える手段はあるが、ウィルスと異なり、見つからないようこっそり書き換えたり、書き換えたあと存在を隠すことが目的ではないので、詳細は述べない。
「ゲームプログラムの実行ファイルから、文字表示に関する部分を突き止め、その部分を乗っ取って自作のマルチバイト対応コードに置き換える」と言ったが、
- 既存プログラムの該当処理部分を突き止める、つまりDRMクラックできる技量と、
- さらにそれを乗っ取る、つまりウィルスを作れる技量と、
- 自作のマルチバイト対応コードを書く、つまりゲームプログラム(の一部)を作れる技量とを併せもっている必要があり、
- なおかつ、ゲーム本体のバージョンが変わると置き換える場所も変わるので、面倒くさい。
日本にもそこまでやっている人が何人かいる(逆に言えば何人かしかいないと思われ)。
TObject
Obvilion日本語化パッチ
FOJP
俺はヘタレなので、置き換え場所を探すのが簡単なものしかやったことは無い。
ところでFOJPのソースコードが公開されていた。
ゲームプログラムの文字表示部分を突き止めるのではなく、変態(ほめ言葉)的なことをしている。
2012年12月21日金曜日
The Secret of Monkey Island: Special Edition
かな化できそうな予感
archive: http://forum.xentax.com/viewtopic.php?f=10&t=8183
font: monkey2.pak/fonts .png .font
text: localization uitext.info Latin-1 binary
archive: http://forum.xentax.com/viewtopic.php?f=10&t=8183
font: monkey2.pak/fonts .png .font
text: localization uitext.info Latin-1 binary
Planet Alcatraz
かな化可能
archive: http://forum.xentax.com/viewtopic.php?f=16&p=32441
text: .csv (plain)
font: .efn and .dds
archive: http://forum.xentax.com/viewtopic.php?f=16&p=32441
text: .csv (plain)
font: .efn and .dds
char magic[4] // 'BMFN' int fontnamelen char fontname[fontnamelen+1] // zero terminate int texnamelen char texname[texnamelen+1] // zero terminate int ver // 1 = version? int height // int width // struct font[256] short x short y char w char xofs // -1 .. 1 char h char yofs // -1 .. 1
2012年12月20日木曜日
文字表示のしくみ
ゲーム日本語化 Advent Calendar 2012
ゲームプログラムがテキストから文字を取り出すとき、1byte系の言語なら1byteが1文字と簡単である。
しかしCJK対応するには、1byteの文字なのか、後続のデータを含めて2-3byteで1文字なのかを判定して取り出す必要がある。
また、フォント処理でも、1byte系言語なら256の表を用意して
'A' => 文字コード41h => 表の41h番目のフォント
という簡単な処理だが、CJK対応には、たくさんの文字から適切にフォントを探すようなプログラムが必要になる。
1byte対応ゲームである
DOOM 3 のソースコードが公開されているので、具体例を見てみる。
ここでは元のフォント情報内部形式はそのままに、
neo/renderer/myfont.h
neo/idlib/Str.hneo/idlib/Str.cpp
activeFont->GetScaledGlyph( scale, textChar, glyphInfo )
neo/renderer/Font.cpp
というわけで変更点はだいたい似通っている。
ゲームのソースコードは商売のタネなので基本的には公開されることはないのだが、
デベロッパによっては古いゲームのソースコードをファンサービスで公開することがある。
(それ以上非公開にしていても利益を生むことは無いという判断?)
元々マルチバイト対応してないゲームでも、ソースコードが公開されていれば(そしてライセンス上の問題が無ければ - 普通は問題無い形で公開されている)、表示できるように改造することで日本語化可能になる。
FreeSpace 2/日本語化プロジェクト
Aquaria 日本語化
元々1byteにしか対応していないものを日本語化するにはこのようなプログラムの変更が必要となるので、海外ゲームの日本語版が割高になるのは翻訳も含めてやむを得ない面もある。
しかし元々日本語化可能なゲームであるにもかかわらず、英語版のまま割高で国内販売してるのはフサケンナって思う。
ゲームプログラムがテキストから文字を取り出すとき、1byte系の言語なら1byteが1文字と簡単である。
しかしCJK対応するには、1byteの文字なのか、後続のデータを含めて2-3byteで1文字なのかを判定して取り出す必要がある。
また、フォント処理でも、1byte系言語なら256の表を用意して
'A' => 文字コード41h => 表の41h番目のフォント
という簡単な処理だが、CJK対応には、たくさんの文字から適切にフォントを探すようなプログラムが必要になる。
1byte対応ゲームである
DOOM 3 のソースコードが公開されているので、具体例を見てみる。
DOOM3
フォントデータや、テキストから1文字を切り出す部分が1byte(文字コード0-255)を前提としたつくりになっている。
フォント情報の内部形式
const int GLYPH_START = 0; const int GLYPH_END = 255; const int GLYPH_CHARSTART = 32; const int GLYPH_CHAREND = 127; const int GLYPHS_PER_FONT = GLYPH_END - GLYPH_START + 1; typedef struct { int height; // number of scan lines int top; // top of glyph in buffer int bottom; // bottom of glyph in buffer int pitch; // width for copying int xSkip; // x adjustment int imageWidth; // width of actual image int imageHeight; // height of actual image float s; // x offset in image where glyph starts // テクスチャ座標 float t; // y offset in image where glyph starts float s2; float t2; const idMaterial * glyph; // shader with the glyph char shaderName[32]; } glyphInfo_t; typedef struct { glyphInfo_t glyphs [GLYPHS_PER_FONT]; // 256文字固定 float glyphScale; char name[64]; } fontInfo_t;
フォントのロード
フォントデータには個数や文字コード情報がなく、コード順に256文字並んでいることを前提にしている
bool idRenderSystemLocal::RegisterFont( const char *fontName, fontInfoEx_t &font ) {
...
fileSystem->ReadFile( name, &faceData, &ftime );
fdOffset = 0;
fdFile = reinterpret_cast<unsigned char*>(faceData);
for( i = 0; i < GLYPHS_PER_FONT; i++ ) { // 256文字固定
outFont->glyphs[i].height = readInt();
outFont->glyphs[i].top = readInt();
outFont->glyphs[i].bottom = readInt();
outFont->glyphs[i].pitch = readInt();
outFont->glyphs[i].xSkip = readInt();
outFont->glyphs[i].imageWidth = readInt();
outFont->glyphs[i].imageHeight = readInt();
outFont->glyphs[i].s = readFloat();
outFont->glyphs[i].t = readFloat();
outFont->glyphs[i].s2 = readFloat();
outFont->glyphs[i].t2 = readFloat();
int junk /* font.glyphs[i].glyph */ = readInt();
//FIXME: the +6, -6 skips the embedded fonts/
memcpy( outFont->glyphs[i].shaderName, &fdFile[fdOffset + 6], 32 - 6 );
fdOffset += 32;
}
...
}
テキストの表示
int idDeviceContext::DrawText(float x, float y, float scale, idVec4 color, const char *text, float adjust, int limit, int style, int cursor) { ... while (s && *s && count < len) { if ( *s < GLYPH_START || *s > GLYPH_END ) { s++; continue; } glyph = &useFont->glyphs[*s]; // 1byte取り出し // 文字コード -> 文字形(glyph) は単純な表参照 ... float yadj = useScale * glyph->top; PaintChar(x,y - yadj,glyph->imageWidth,glyph->imageHeight,useScale,glyph->s,glyph->t,glyph->s2,glyph->t2,glyph->glyph); if (cursor == count) { DrawEditCursor(x, y, scale); } x += (glyph->xSkip * useScale) + adjust; s++; count++; // 1byte進める } } ... }
日本語化MOD
このように1byteコードのみにしか対応していないゲームは、基本的にかな化はできるが漢字日本語化はできない。
しかしソースコード(プログラムの元)が公開されている場合、プログラムを変更することによって日本語表示が可能になる。
フォント情報の内部形式
ここでは元のフォント情報内部形式はそのままに、
glyphs[0-254] は元のまま、
glyphs[255] に 独自のmy_glyphs_tをぶち込むという
少々トリッキーなことをしている。
neo/renderer/myfont.h
typedef struct { int height; // 文字コードとして代用 int top; // top of glyph in buffer int bottom; // bottom of glyph in buffer int pitch; // width for copying int xSkip; // x adjustment int imageWidth; // width of actual image int imageHeight; // height of actual image float s; // x offset in image where glyph starts float t; // y offset in image where glyph starts float s2; float t2; const idMaterial * glyph; // shader with the glyph int id; //char shaderName[32]; } my_glyphInfo_t; typedef struct { int num; // グリフ数を管理 my_glyphInfo_t* glyphs; } my_glyphs_t;
フォントのロード
neo/renderer/tr_font.cpp
fileSystem->ReadFile( name, &faceData, &ftime ); fdOffset = 0; fdFile = reinterpret_cast<unsigned char*>(faceData); int mw = 0; int mh = 0; if (memcmp(fdFile,"BMF\x03",4)==0) { // Bitmap Font Generator形式に対応 ... my_glyphInfo_t* myglyphs = (my_glyphInfo_t*)Mem_ClearedAlloc(sizeof(my_glyphInfo_t)*num); int n=0; float inv_w = 1.0f/scaleW,inv_h = 1.0f/scaleH; for(;p < next;p+=20) { int id = get32(p); int x = get16(p+4); int y = get16(p+6); int w = get16(p+8); int h = get16(p+10); int xoffset = get16(p+12); int yoffset = get16(p+14); int xadvance = get16(p+16); int page = p[18]; int xSkip = xadvance; my_glyphInfo_t* glyph = (id < GLYPH_END)?(my_glyphInfo_t*)&outFont->glyphs[id]:&myglyphs[n++]; // 0-254はそのまま、それ以上はmyglyphsに入れる glyph->id = id; glyph->height = h+yoffset; glyph->top = base-yoffset; glyph->imageWidth = w; glyph->imageHeight = h; glyph->xSkip = xSkip; glyph->s = x*inv_w; glyph->t = y*inv_h; glyph->s2 = (x+w)*inv_w; glyph->t2 = (y+h)*inv_h; glyph->glyph = materials[page]; // shaderName not used if (mw<xSkip) mw=xSkip; } my_glyphs_t* t = (my_glyphs_t*)&outFont->glyphs[GLYPH_END]; t->glyphs = myglyphs; // &outFont->glyphs[255] にmyglyphsをぶち込む
t->num = n;
テキストの表示
neo/ui/DeviceContext.cpp
while (s && *s && count < len) { if ( *s < GLYPH_START ) { s++; continue; } .... int ch = *s; int l=1; if (utf8) { if (ch<0x80) { } else if (ch<0xc0) { } else if (ch<0xe0) { if (!is_leading(s[1])) break; ch = ((ch&0x1f)<< 6) | (s[1] & 0x3f); l=2; } else { if (!is_leading(s[1]) || !is_leading(s[2])) break; ch = ((ch&0x0f)<<12) | ((s[1] & 0x3f)<<6) | (s[2] & 0x3f); l=3; } // 1文字取り出してbyte数をlに代入 } glyph = get_glyph(useFont, ch); // 対応する文字画像を取り出す float yadj = useScale * glyph->top; PaintChar(x,y - yadj,glyph->imageWidth,glyph->imageHeight,useScale,glyph->s,glyph->t,glyph->s2,glyph->t2,glyph->glyph); // 文字画像表示部分は元のまま if (cursor == count) { DrawEditCursor(x, y, scale); } x += (glyph->xSkip * useScale) + adjust; s+=l; count+=l; // 1文字分進める
DOOM3 BFG
最近DOOM3 BFG Editionのソースコードが公開されてたので、どう変更されたか見てみる。
(ところでid softwareは最初にDOOMのソースコードを公開してから毎回クリスマスに公開してたのだが、Bethesda Softworksに買収されてから時期が関係なくなった)
(ところでid softwareは最初にDOOMのソースコードを公開してから毎回クリスマスに公開してたのだが、Bethesda Softworksに買収されてから時期が関係なくなった)
フォント情報の内部形式
struct fontInfo_t {
struct oldInfo_t {
float maxWidth;
float maxHeight;
} oldInfo[3];
short ascender;
short descender;
short numGlyphs; // 個数を管理している
glyphInfo_t * glyphData;
// This is a sorted array of all characters in the font
// This maps directly to glyphData, so if charIndex[0] is 42 then glyphData[0] is character 42
uint32 * charIndex;
// As an optimization, provide a direct mapping for the ascii character set
char ascii[128];
const idMaterial * material;
};
フォントのロード
bool idFont::LoadFont() {
....
fd->ReadBig( fontInfo->numGlyphs ); // フォントデータから個数を読んでいる
fontInfo->glyphData = (glyphInfo_t *)Mem_Alloc( sizeof( glyphInfo_t ) * fontInfo->numGlyphs, TAG_FONT );
fontInfo->charIndex = (uint32 *)Mem_Alloc( sizeof( uint32 ) * fontInfo->numGlyphs, TAG_FONT );
fd->Read( fontInfo->glyphData, fontInfo->numGlyphs * sizeof( glyphInfo_t ) );
for( int i = 0; i < fontInfo->numGlyphs; i++ ) {
idSwap::Little( fontInfo->glyphData[i].width );
idSwap::Little( fontInfo->glyphData[i].height );
idSwap::Little( fontInfo->glyphData[i].top );
idSwap::Little( fontInfo->glyphData[i].left );
idSwap::Little( fontInfo->glyphData[i].xSkip );
idSwap::Little( fontInfo->glyphData[i].s );
idSwap::Little( fontInfo->glyphData[i].t );
}
...
}
テキストの表示
int idDeviceContext::DrawText(float x, float y, float scale, idVec4 color, const char *text, float adjust, int limit, int style, int cursor) {
...
while ( charIndex < len ) {
uint32 textChar = drawText.UTF8Char( charIndex ); // マルチバイトを考慮してcharIndexから1文字取りだし、charIndexを1文字分(1-3byte)進める。
... scaledGlyphInfo_t glyphInfo; activeFont->GetScaledGlyph( scale, textChar, glyphInfo ); // textCharのUnicodeの文字情報をscale倍してglyphInfoに読み込む。 prevGlyphSkip = glyphInfo.xSkip; PaintChar( x, y, glyphInfo ); // 1文字表示 if (cursor == charIndex-1) { DrawEditCursor(x, y, scale); } x += glyphInfo.xSkip + adjust;drawText.UTF8Char( charIndex )
neo/idlib/Str.hneo/idlib/Str.cpp
activeFont->GetScaledGlyph( scale, textChar, glyphInfo )
neo/renderer/Font.cpp
というわけで変更点はだいたい似通っている。
ゲームのソースコードは商売のタネなので基本的には公開されることはないのだが、
デベロッパによっては古いゲームのソースコードをファンサービスで公開することがある。
(それ以上非公開にしていても利益を生むことは無いという判断?)
元々マルチバイト対応してないゲームでも、ソースコードが公開されていれば(そしてライセンス上の問題が無ければ - 普通は問題無い形で公開されている)、表示できるように改造することで日本語化可能になる。
FreeSpace 2/日本語化プロジェクト
Aquaria 日本語化
元々1byteにしか対応していないものを日本語化するにはこのようなプログラムの変更が必要となるので、海外ゲームの日本語版が割高になるのは翻訳も含めてやむを得ない面もある。
しかし元々日本語化可能なゲームであるにもかかわらず、英語版のまま割高で国内販売してるのはフサケンナって思う。
The Testament of Sherlock Holmes
日本語化可能。
FrogwareのSherlock Holmesシリーズと同じ。
追記:
-フォントが微妙に違った
日本語化
font4:
FrogwareのSherlock Holmesシリーズと同じ。
追記:
-フォントが微妙に違った
日本語化
font4:
char magic[4] // fa d4 9a 23 int fontsize? float font_w float font_h+a int zero // 0 int num struct glyphs[num] float u0 float u1 float v0 float v1 float w // pixels float h // pixels float adj // 0 or -0.xx // AVX_jw int code int num2 struct blocks[num2] int startchar int endchar int startidx int endidx font1 - 512x512 font1_big 1024x2048 megafont2 1024x1024 italic font_dialog 1024x256 u0,v0 +---------------+ | ** | | | * * | | | * * | | |********|h | |* *| | |* *| | |* *| | |--------+ | | w | +---------------+ (u1,v1)
2012年12月19日水曜日
日本語化リクエスト募集
日本語化してほしいゲームのリクエストを募集します。
で
コメント欄に書いてください。
同じゲームは最初のコメントの返信にぶら下げてください
翻訳したい人だとポイント高いです
メタスコアと俺の趣味でポイント(俺のモチベーション)が上下します
12/25に公開予定なので〆切りはお察しください
リクエストが無ければ普段通り適当に公開します。
追記: 正月まで(ホリデーセールが終わるまで)延長します。
- - DEMO版がある、または
- - Indie bundleに入ってた
- - 1C Complete Packに入ってた
- - その他俺が持ってるもの
- -
6650%引以上でセール中 - - giftする
で
- - 日本語表示とツール公開までです。翻訳はシラネ
- - かな化までとか日本語化困難とわかるだけの場合もあります
- - ↑なのでgiftは慎重に
コメント欄に書いてください。
同じゲームは最初のコメントの返信にぶら下げてください
翻訳したい人だとポイント高いです
メタスコアと俺の趣味でポイント(俺のモチベーション)が上下します
リクエストが無ければ普段通り適当に公開します。
追記: 正月まで(ホリデーセールが終わるまで)延長します。
2012年12月18日火曜日
文字コードの話
ゲーム日本語化 Advent Calendar 2012
ゲームの多言語の対応は大きく4つに分けられる。
ゲームプログラムがテキストから文字を取り出すとき、1byte系の言語なら1byteが1文字と簡単である。
しかしCJK対応するには、1byteの文字なのか、後続のデータを含めて2-3byteで1文字なのかを判定して取り出す必要がある。
また、フォント処理でも、1byte系言語なら256の表を用意して
'A' => 文字コード41h => 表の41h番目のフォント
という簡単な処理だが、CJK対応には、たくさんの文字から適切にフォントを探すようなプログラムが必要になる。
日本語化する上で、ゲームがどこまで対応した作りになっているかが重要になる。
このタイプは日本語化は難しい。英字(大文字26+小文字26)を潰して全て「かな」または「カナ」にすることはできなくはないが、英字が使えなくなるので完全に訳す必要がある。
古いゲームやindieの一部に見られる。
ドイツ・フランスなど西ヨーロッパの国々は共通の文字コードを使っている。
言い換えると西ヨーロッパの国々が共通して使える文字コードを決めた、と言える。
Steamで 言語: English*, ドイツ語, フランス語, イタリア語, スペイン語
などと特定国に偏っているのは、市場規模の理由もあるが、プログラム対応コストをかけずに翻訳コストだけで対応できるからでもある。
世界展開・マルチプラットフォーム展開する大手のものを除き、多くはここまでの対応である。
ドイツ語化MODが存在する場合、アーカイブ形式とメッセージ形式が解析されたことを意味する。
これに加えてフォント形式を解析すれば、かな化は可能である。
かなの他に、数文字までなら漢字を使うこともできる。古いファミコンゲームで一部だけに漢字が使われてたのと同じ。
ロシア語化MODが存在する場合、2.に加えてフォント形式が解析されたことを意味する。
元々ロシア産のゲームは、1byte文字で対応している場合と、unicodeで対応している場合がある。
前者はかな化、後者の場合は日本語化できる可能性がある。
ゲームが元々マルチバイトに対応しているか、ゲームプログラムを変更して無理やり表示させているMODもある。
中文化MODが存在する場合、アーカイブ形式、メッセージ形式、フォント形式が全て解析されており、マルチバイト文字の表示が可能なことを意味する。
ただし、中文化MODは改変結果のみが配布されており、解析情報は公開していないか公開しているけれども中国語だから見つけにくいのか、
存在するだけでは「表示可能であることが実証された」という意味程度で、日本語化するには改めてフォント形式などを解析する必要がある。
データ上では、Unicodeを1-3byteのマルチバイトに割り当てたもの(UTF-8)と、常に2byte使うもの(UTF-16)がある。
UTF-16はさらにUTF-16LE(Little Endian)とUTF-16BE(Big Endian)のものがある。
メモ帳(notepad)で文字コード指定での保存時に「Unicode」とあるのがUTF-16LEである。
PCゲームのUTF-16は殆どの場合UTF-16LEであるが、ゲーム機からの移植等でまれにUTF-16BEの場合もある。
この中でどのような対応しているかは、テキストの文字コードで判断できる。
ASCII,Latin-1,utf-8は、英数字の部分(20-7f)は同一なので、テキストを見ても区別が付きにくいことがある。
Steam等で再インストールなしで言語を簡単に切り替えられる場合は、試しにドイツ語やフランス語に変えて、ドイツ語用のデータを追加ダウンロードしてみる。
英語しかない場合、テキストに著作権表記の©や、商標権表記の®が含まれていれば、そのコードがLatin-1かutf-8かで判断できる。
フォント画像がtgaやDDSなどの形式で簡単に確認できる場合は、フォント画像からも推測できる。
画像にラテン文字しかない場合はLatin-1である可能性が高い。
つまりかな化できる可能性が高い。
ラテン文字とそれ以外の文字が1枚の画像にある場合は、Unicodeである可能性が高い。
つまり日本語化できる可能性が高い。
Unicode対応していても一筋縄でいかない場合がある。
Unicode一覧を見ると1fffくらいまでで、CJKを除くほとんどの言語をカバーしていることがわかる。
ゲームによってはこの範囲の多言語化しか想定しておらず、CJK文字は3000くらいから始まるので、漢字やかなのメッセージを食わせるとぶっ飛ぶことがある。
このような場合、unicodeテキストの読み込み自体は実装されているので、
100-1fffあたりに漢字やかなを割り当てた「俺コード」をデッチあげて、それに沿ってフォントを作成したりテキストを変換すればよい。
unicode テキストを編集する際に気をつける点が2つある。
テキストエディタによっては、BOM(Byte Order Mark)という見えない文字がくっつくことがある。
ゲームによってはBOMが有る/無いと動かないことがあるので、元データにあわせる。
BOMは
UTF-16LEなら ff fe
UTF-8なら ef bb bf
である。
素のテキストファイルだから簡単に変更できるのでは?と思って変更したら動かなかった、と言う場合は、
目grepとかわかんね、という人も先頭数バイトくらいは確認してみよう。
ゲームによっては、未使用領域や外字領域を、ボタンや矢印等のアイコンの文字コードとして使っている場合がある。
これは通常のエディタでは見えないので、編集時に注意するか、コンバータで置換するようにする。
ゲームの多言語の対応は大きく4つに分けられる。
- 1. 英語のみ(ASCII)
- 2.ドイツ・フランス語などラテン文字の言語(Latin-1,ISO-8859-1)
- 3. ロシア・チェコ語などその他の1byte(224以内の)文字の言語(ISO-8859-X)
- 4.中国、日本、韓国など、それ以上の文字数(マルチバイト)の言語(Chinese, Japanese, KoreanをまとめてCJKと呼ぶ) Unicode
ゲームプログラムがテキストから文字を取り出すとき、1byte系の言語なら1byteが1文字と簡単である。
しかしCJK対応するには、1byteの文字なのか、後続のデータを含めて2-3byteで1文字なのかを判定して取り出す必要がある。
また、フォント処理でも、1byte系言語なら256の表を用意して
'A' => 文字コード41h => 表の41h番目のフォント
という簡単な処理だが、CJK対応には、たくさんの文字から適切にフォントを探すようなプログラムが必要になる。
日本語化する上で、ゲームがどこまで対応した作りになっているかが重要になる。
1.英語のみ
このタイプは日本語化は難しい。英字(大文字26+小文字26)を潰して全て「かな」または「カナ」にすることはできなくはないが、英字が使えなくなるので完全に訳す必要がある。
古いゲームやindieの一部に見られる。
2. ドイツ・フランス語など
ドイツ・フランスなど西ヨーロッパの国々は共通の文字コードを使っている。
言い換えると西ヨーロッパの国々が共通して使える文字コードを決めた、と言える。
などと特定国に偏っているのは、市場規模の理由もあるが、プログラム対応コストをかけずに翻訳コストだけで対応できるからでもある。
世界展開・マルチプラットフォーム展開する大手のものを除き、多くはここまでの対応である。
ドイツ語化MODが存在する場合、アーカイブ形式とメッセージ形式が解析されたことを意味する。
これに加えてフォント形式を解析すれば、かな化は可能である。
かなの他に、数文字までなら漢字を使うこともできる。古いファミコンゲームで一部だけに漢字が使われてたのと同じ。
3. ロシア・チェコ語など
ロシア語化MODが存在する場合、2.に加えてフォント形式が解析されたことを意味する。
元々ロシア産のゲームは、1byte文字で対応している場合と、unicodeで対応している場合がある。
前者はかな化、後者の場合は日本語化できる可能性がある。
4. 中国語・韓国語など
ゲームが元々マルチバイトに対応しているか、ゲームプログラムを変更して無理やり表示させているMODもある。
中文化MODが存在する場合、アーカイブ形式、メッセージ形式、フォント形式が全て解析されており、マルチバイト文字の表示が可能なことを意味する。
ただし、中文化MODは改変結果のみが配布されており、解析情報は公開していないか公開しているけれども中国語だから見つけにくいのか、
存在するだけでは「表示可能であることが実証された」という意味程度で、日本語化するには改めてフォント形式などを解析する必要がある。
Unicode
マルチバイトの文字コードには、国(言語)ごとに違うコード(Shift-JIS等)と、世界共通コード(Unicode)があるが、現在のゲームは殆どがUnicodeである。
データ上では、Unicodeを1-3byteのマルチバイトに割り当てたもの(UTF-8)と、常に2byte使うもの(UTF-16)がある。
UTF-16はさらにUTF-16LE(Little Endian)とUTF-16BE(Big Endian)のものがある。
メモ帳(notepad)で文字コード指定での保存時に「Unicode」とあるのがUTF-16LEである。
PCゲームのUTF-16は殆どの場合UTF-16LEであるが、ゲーム機からの移植等でまれにUTF-16BEの場合もある。
この中でどのような対応しているかは、テキストの文字コードで判断できる。
ASCII,Latin-1,utf-8は、英数字の部分(20-7f)は同一なので、テキストを見ても区別が付きにくいことがある。
Steam等で再インストールなしで言語を簡単に切り替えられる場合は、試しにドイツ語やフランス語に変えて、ドイツ語用のデータを追加ダウンロードしてみる。
英語しかない場合、テキストに著作権表記の©や、商標権表記の®が含まれていれば、そのコードがLatin-1かutf-8かで判断できる。
フォント画像がtgaやDDSなどの形式で簡単に確認できる場合は、フォント画像からも推測できる。
画像にラテン文字しかない場合はLatin-1である可能性が高い。
つまりかな化できる可能性が高い。
ラテン文字とそれ以外の文字が1枚の画像にある場合は、Unicodeである可能性が高い。
つまり日本語化できる可能性が高い。
Unicode対応していても一筋縄でいかない場合がある。
Unicode一覧を見ると1fffくらいまでで、CJKを除くほとんどの言語をカバーしていることがわかる。
ゲームによってはこの範囲の多言語化しか想定しておらず、CJK文字は3000くらいから始まるので、漢字やかなのメッセージを食わせるとぶっ飛ぶことがある。
このような場合、unicodeテキストの読み込み自体は実装されているので、
100-1fffあたりに漢字やかなを割り当てた「俺コード」をデッチあげて、それに沿ってフォントを作成したりテキストを変換すればよい。
unicode テキストを編集する際に気をつける点が2つある。
BOM
テキストエディタによっては、BOM(Byte Order Mark)という見えない文字がくっつくことがある。
ゲームによってはBOMが有る/無いと動かないことがあるので、元データにあわせる。
BOMは
UTF-16LEなら ff fe
UTF-8なら ef bb bf
である。
素のテキストファイルだから簡単に変更できるのでは?と思って変更したら動かなかった、と言う場合は、
目grepとかわかんね、という人も先頭数バイトくらいは確認してみよう。
外字
ゲームによっては、未使用領域や外字領域を、ボタンや矢印等のアイコンの文字コードとして使っている場合がある。
これは通常のエディタでは見えないので、編集時に注意するか、コンバータで置換するようにする。
2012年12月17日月曜日
ゲーム日本語化 Advent Calendar 2012
ゲーム日本語化 Advent Calendar 2012にMODとか日本語化とか色々や洋ゲーMODメモで様々な日本語化をされているのJpMod Zzzさんが参加してくれました
tsxbinの紹介
ありがとうございます
ネタが切れる前でよかった
tsxbinの紹介
ありがとうございます
ネタが切れる前でよかった
2012年12月16日日曜日
unpackerの探し方
ゲーム日本語化 Advent Calendar 2012
まず最も重要なのは xentax である。
とりあえず
xentax ソフト名
xentax アーカイブの拡張子
xentax アーカイブのシグネチャ文字列
などで検索すればなんとかなる場合もある。
例えば、GOGでinquisitorというソフトがあるが、
inquisitor xentax
でぐぐると
Zork Nemesis/Grand Inquisitor
という別のゲームがヒットするので
inquisitor xentax dat
で絞ってぐぐると
http://forum.xentax.com/viewtopic.php?f=8&t=3886
が見つかる。この記事にある
http://aluigi.org/papers/bms/inquisitor.bms
はリンク切れなので、適当に変更すると
http://aluigi.altervista.org/papers/bms/inquisitor.bms
からunpackerがgetできる。
ここで使われてるのは
quickbms
というソフト用のスクリプトで、
(最近は著作権的に危ういのは消しているようだが)、
誰かがmegauploadあたりに
「このアーカイブわかんね?」
と上げると、
「これでextractできんじゃね?」
と誰かがquickbms script形式でunpackerをあげていることがある。
(スルーされることのほうが多いが)
古いゲームだと
Dragon Unpacker
Game Extractor
gobread
ADVに強いununpakke
などが、マルチフォーマットのunpackerの代表的なもので、
「XXXというゲームのunpackはどーすんの?」
という質問の答えによくあげられる。
gobreadは32bit windowsでしか動かないポイので、Windows x64ユーザは仮想マシンか何か用意しておきたい。
(あとTowWorld関連のWD PackagerもXP 32bitでしか動かないポイので)
その他、比較的新しいゲームについては
Rick’s Game Stuff
ただし、コレで見つかるのはpacker機能のないunpackerだけのことが多く、日本語化するにはさらにpacker, font形式、message形式などが必要になる。
2次元エロゲならunpackしてエロ画像見えたらうれしいだろうが、
一般洋ゲの場合、ゲーム中でいかにエロっぽいキャラクターであろうと、テクスチャだけ見てうれしいものではない。テクスチャを○色に差し替えてrepackできて初めて意味がある。
またunpackerと称するものの中には、アーカイブ形式を理解せず、単にシグネチャを目印に音楽や動画を切り出すだけのものもある。indie bundleでOSTがオマケにつく場合もあるから音楽を抜き出したいというニーズがあることはわかるが、このような似非unpackerでは、日本語化の役には立たない。
packerを作るには、初心者でも使えるGUIのunpackerのようなものよりも、xentax bbsや Game File Format Centralのquickmbs scriptや構造説明のほうがが参考になる。
quickbmsの最新版では、unpackerだけでなくpacker機能も付いたようなので、
quickbms scriptを元にpackerを改めて作る必要も無くなったかも。
重要な点として、同じ開発会社(販売会社ではない)は同じアーカイブ形式もしくはその派生したものを使っていることが多いので、開発会社を調べて、そこが過去に出したゲームのunpakerが使えないか調べてみる。
開発会社は検索の他、steamやgamersgateなどでの購入時にもわかる。
例えば Sniper Elite V2 はRebellion開発なので、同じ会社の過去の作品であるAliens vs. Predatorのpacker/unpackerと日本語化手法がほぼそのまま使える。
(Shellshock 2やRogue Warriorも同様に日本語化できるが、メタスコアが伝説レベルのクソゲーなので、翻訳する酔狂な人はいないと思われ)
当然と言えば当然なのであるが、英語ゲームのローカライズ(○ ○ 語化)のニーズがあるのは英語圏以外なので、ローカライズ手法に関する情報も英語圏以外にあることが多い。ロシアとか中国とか。
xentaxからリンクするような投稿をだれかがしてれば発見できるが、いまのところいい発見方法を見つけていない。
詳しい話は後で述べるか、文字種や文字コードの関係で
中文化 = 日本語化 > ロシア語化 = かな化 > ドイツ語・フランス語 > 英語のみ
理論上、中文化可能であれば、漢字含む日本語化が可能である。
しかし、中文化MODを探す上で、元のゲームに中文化パッチを当てた状態で著作物全体がp2pに流れてたりして、legalな中文化パッチのみを入手するのはむずかしいというか区別が付きにくい。
迂闊に検索すると(日本の著作権上)ヤバイ物をダウンロードしかねない。
俺の観測では
3dmgameやchinaAVG(ADV専用)
追記: ali213 と そこの中文化チーム
が中文化MODのみを配布してるようだ。
検索方法が良くわからんので一覧を目視してる。
汉化 というのが中国語化(Chinese localization)という意味らしい。
ココにあるソフトは、日本語化できる可能性が高い。
まず最も重要なのは xentax である。
とりあえず
xentax ソフト名
xentax アーカイブの拡張子
xentax アーカイブのシグネチャ文字列
などで検索すればなんとかなる場合もある。
例えば、GOGでinquisitorというソフトがあるが、
inquisitor xentax
でぐぐると
Zork Nemesis/Grand Inquisitor
という別のゲームがヒットするので
inquisitor xentax dat
で絞ってぐぐると
http://forum.xentax.com/viewtopic.php?f=8&t=3886
が見つかる。この記事にある
http://aluigi.org/papers/bms/inquisitor.bms
はリンク切れなので、適当に変更すると
http://aluigi.altervista.org/papers/bms/inquisitor.bms
からunpackerがgetできる。
ここで使われてるのは
quickbms
というソフト用のスクリプトで、
(最近は著作権的に危ういのは消しているようだが)、
誰かがmegauploadあたりに
「このアーカイブわかんね?」
と上げると、
「これでextractできんじゃね?」
と誰かがquickbms script形式でunpackerをあげていることがある。
(スルーされることのほうが多いが)
古いゲームだと
Dragon Unpacker
Game Extractor
gobread
ADVに強いununpakke
などが、マルチフォーマットのunpackerの代表的なもので、
「XXXというゲームのunpackはどーすんの?」
という質問の答えによくあげられる。
gobreadは32bit windowsでしか動かないポイので、Windows x64ユーザは仮想マシンか何か用意しておきたい。
(あとTowWorld関連のWD PackagerもXP 32bitでしか動かないポイので)
その他、比較的新しいゲームについては
Rick’s Game Stuff
ただし、コレで見つかるのはpacker機能のないunpackerだけのことが多く、日本語化するにはさらにpacker, font形式、message形式などが必要になる。
2次元エロゲならunpackしてエロ画像見えたらうれしいだろうが、
一般洋ゲの場合、ゲーム中でいかにエロっぽいキャラクターであろうと、テクスチャだけ見てうれしいものではない。
またunpackerと称するものの中には、アーカイブ形式を理解せず、単にシグネチャを目印に音楽や動画を切り出すだけのものもある。indie bundleでOSTがオマケにつく場合もあるから音楽を抜き出したいというニーズがあることはわかるが、このような似非unpackerでは、日本語化の役には立たない。
packerを作るには、初心者でも使えるGUIのunpackerのようなものよりも、xentax bbsや Game File Format Centralのquickmbs scriptや構造説明のほうがが参考になる。
quickbmsの最新版では、unpackerだけでなくpacker機能も付いたようなので、
quickbms scriptを元にpackerを改めて作る必要も無くなったかも。
重要な点として、同じ開発会社(販売会社ではない)は同じアーカイブ形式もしくはその派生したものを使っていることが多いので、開発会社を調べて、そこが過去に出したゲームのunpakerが使えないか調べてみる。
開発会社は検索の他、steamやgamersgateなどでの購入時にもわかる。
例えば Sniper Elite V2 はRebellion開発なので、同じ会社の過去の作品であるAliens vs. Predatorのpacker/unpackerと日本語化手法がほぼそのまま使える。
(Shellshock 2やRogue Warriorも同様に日本語化できるが、メタスコアが伝説レベルのクソゲーなので、翻訳する酔狂な人はいないと思われ)
また、FPSやADV等は、他の開発会社が作成した基本プログラム(ゲームエンジン)を利用していることがあるので、拡張子やシグネチャに見覚えがあったら、他の開発会社のゲームエンジンを使っているか、その会社のゲーム用のunpackerが流用できないか確認してみよう。
当然と言えば当然なのであるが、英語ゲームのローカライズ(○ ○ 語化)のニーズがあるのは英語圏以外なので、ローカライズ手法に関する情報も英語圏以外にあることが多い。ロシアとか中国とか。
xentaxからリンクするような投稿をだれかがしてれば発見できるが、いまのところいい発見方法を見つけていない。
詳しい話は後で述べるか、文字種や文字コードの関係で
中文化 = 日本語化 > ロシア語化 = かな化 > ドイツ語・フランス語 > 英語のみ
理論上、中文化可能であれば、漢字含む日本語化が可能である。
しかし、中文化MODを探す上で、元のゲームに中文化パッチを当てた状態で著作物全体がp2pに流れてたりして、legalな中文化パッチのみを入手するのはむずかしいというか区別が付きにくい。
迂闊に検索すると(日本の著作権上)ヤバイ物をダウンロードしかねない。
俺の観測では
3dmgameやchinaAVG(ADV専用)
追記: ali213 と そこの中文化チーム
が中文化MODのみを配布してるようだ。
検索方法が良くわからんので一覧を目視してる。
汉化 というのが中国語化(Chinese localization)という意味らしい。
ココにあるソフトは、日本語化できる可能性が高い。
2012年12月15日土曜日
技術メモ: 実践 目grep
ゲーム日本語化 Advent Calendar 2012
実際に解析してみる。
The Real Texasを例にする。
(以下数値は16進数)
フォルダを見るとglobというサイズの大きいファイルがある。
他にゲームデータらしきファイルは無い。globがアーカイブと思われる。
軽くダンプしてみる
0000010に 78 9c が見える。たぶんzlibヘッダ。
2つのアーカイブを見比べる。
共通のシグネチャやバージョン番号らしきヘッダはないことがわかる。
サイズの一番小さいworld.globを調べる
先頭付近と末尾付近をざっと眺める
どこにもファイル名らしきものは見当たらない。
先頭の
e5 f9 2b 00
be 00 00 00
はよくわからない。後者をファイル数と仮定する。
zlibヘッダの直前に
4c 00 00 00
2c 4e 00 00
が見える。前者がファイルサイズ、後者が展開後サイズとあたりをつける。
ここからバイナリエディタでまじめに見る
int size
int origsize
char data[size]
と仮定して、dataの先頭にsizeを足して飛んでみる
5c にきた。
なんかズレてるので、sizeはデータサイズではなく、origsizeの4byte分を含めたサイズとわかる
int size
int origsize
char data[size-4] // zlib compressed
とりあえずこの仮定でunpackerを作ってみる。
ファイル名は適当に連番をつける。
$fp = fopen($file,'r'); $unk = fgetint($fp); $num = fgetint($fp); for($i=0;$i<$num;$i++) { $size = fgetint($fp); $origsize = fgetint($fp); $data = fread($fp,$size-4); $data = gzuncompress($data); $outfile = $dir.sprintf("%04d.dat",$i); file_put_contents($outfile,$data); printf("%d %x %d %d %x\n",$i,$pos,$size,$origsize,ftell($fp)); } fclose($fp);
実行してみる。
うまく展開されているようだ。
アーカイブ名がworld.globなのでマップデータか何かだろう。
ただし、最終位置がアーカイブのサイズと会わない。ヘッダの値をファイル数と仮定したのは間違いだったようだ。
最後まで処理するようにする。
for($i=0;true/*$i<$num*/;$i++) { $pos = ftell($fp); if ($pos>=$filesize) break;
最後のファイルだけなんか大きいので覗いてみる。
どう見てもファイル名っぽい。
先頭の4a 1e 00 00はファイル数ぽい。
次の20 00 00 00は、ファイル名の長さっぽい。
解説してなかったが、文字列はたいてい
長さ 文字....
文字.....0
のいずれか。
長さ 文字...0
の場合もある。
あるいは、長さちょうどのサイズではなく、4byte等でalignされるように末尾にpaddingが付くこともある。
20 00 00 00 の直後の world... 文字列に20を加えてみると、うまく文字列の末尾になった。
次の文字列開始30 までの間に、
e3 0d 10 00
cc 00 00 00
30からの文字列末尾の次にも、
19 0a 10 00
24 00 00 00
が見える。
ためしに 100de3に飛んでみる
size origsize zlibヘッダ
と圧縮されたファイルの先頭ぽいので、これはオフセットとわかった。
もう一つの値 cc 00 00 00 はよくわからん
int num struct entry[num] int len char name[len] int ofs // offset to file int unk
改めてファイルの先頭を見てみると
E5 F9 2B 00
BE 00 00 00
と、ofs,unkと同じ構造をしていることがわかる。
2BF9E5に飛んでみると、これは先ほど解析した最後のファイルである、エントリ情報を指しているとわかる。
2BF9E5 はファイルサイズより小さいので、アーカイブ内の何かを指すオフセットだ、と 最初に気づいていれば、先にファイルエントリ情報を見つけられたはずだが、まあこういうこともある。
ここまでの情報をもとに、アーカイブを先頭から読んで連番ファイルに出力するのではなく、ファイルエントリ情報を読んでファイル名を付けて出力するように変更する。
$fp = fopen($file,'r'); $entpos = fgetint($fp); $unk0 = fgetint($fp); $data = read_data($fp,$entpos); $st = new BinStream($data); $num = $st->getint(); echo $num,"\n"; for($i=0;$i<$num;$i++) { $namelen = $st->getint(); $name = $st->read($namelen); $ofs = $st->getint(); $unk = $st->getint(); printf("%x %x %s\n",$ofs,$unk,$name); $data = read_data($fp,$ofs); savefile($dir.$name,$data); } fclose($fp); function read_data($fp,$pos) { fseek($fp,$pos,SEEK_SET); $size = fgetint($fp); $origsize = fgetint($fp); $data = fread($fp,$size-4); $data = gzuncompress($data); return $data; }
うまくいった。
data.globを展開してみる
なんかエラーだって
エラー部を見てみると
sizeが0の場合はorigsize,dataが続かず、すぐ次のファイルになっていることがわかる。
int size // if 0 , no origsize,data
int origsize
char data[size-4] // zlib compressed
size == 0 の特殊処理を入れる。
function read_data($fp,$pos) { fseek($fp,$pos,SEEK_SET); $size = fgetint($fp); if ($size==0) return '';
もう一度展開してみる。
うまくいった。完成。
The Real Texas unpacker
The Real Texas
かな化できんこともない
0-7fの英数字しか想定してない気がする
achive: 独自形式 zlib圧縮 unpacker
font: data.glob内 data/font/*.png と *.lua(座標)
text: data.glob内 data/ luaスクリプトに埋め込み
0-7fの英数字しか想定してない気がする
achive: 独自形式 zlib圧縮 unpacker
font: data.glob内 data/font/*.png と *.lua(座標)
text: data.glob内 data/ luaスクリプトに埋め込み
int ofs // offset to file includes compressed entery int unk struct file int size // if 0 , no origsize and data int origsize char data[size-4] // zlib compressed uncompressed entry; int num struct entry[num] int namelen char name[len] int ofs // offset to file int unk
2012年12月14日金曜日
技術メモ: ゲームデータの特徴
ゲーム日本語化 Advent Calendar 2012
zipには先頭に'PK'というシグネチャがあるが、
アーカイブ内のゲームデータにも特徴がある。
PNG 89 'PNG' (SJISだと '臼NG')
DDS: 'DDS '
BMP: 'BM'
TGA; 00 00 20 00 (32bitの場合)
JPEG: ff d8 ff XX (JFIFの文字が見えることも)
シグネチャが無くても、非圧縮画像は00(黒)やFF(白)が多発するので見分けが付く。
アルファつき32bitなら 00 00 00 FF とか 4byteごとに規則的に並ぶ。
圧縮DDS(DXT5)は一見圧縮データぽいが、特徴的な00やffの並びが見られる。
画像ぽいデータなら、先頭あたりに画像サイズぽい値あがあるはず。
非圧縮なら、縦x横に1dotあたりのbyte数(1-4)を掛ければ(ヘッダサイズを除いた)ファイルサイズに近い値になるはず。
WAV: RIFF....WAVEfmt
OGG: OggS
が圧倒的に多い。日本語化には(どっかの暇人がアテレコでもしない限り)関係ないのでここではスルー。
plain textは普通に人間が読めるのでわかりやすい。
メッセージやスクリプトなど
バイナリ化されたメッセージやスクリプト、モデルなど。
4byte int や floatぽい値が並ぶなど、無秩序ではなく特徴がある。
メッセージがスクリプト中に埋め込まれている場合などは、メッセージぽいテキストが見える。
なんかゴチャゴチャしてたら、圧縮か暗号化されている。
zlib圧縮の場合、78 xx という zlibヘッダがある(ないこともある)
アーカイブ解析時に、ファイル情報部の「オフセットぽい値」に飛んでみて、これらファイルの先頭ぽい特徴が見えたら、ファイルの先頭と考えられる。
このオフセット値は、
- ファイル先頭からの絶対値
- ヘッダの直後からの相対値
- データ部の先頭からの相対値
などのバリエーションがある。
とりあえず飛んでみて、少しズレてたらヘッダ分の可能性が高い。2つのファイルでオフセット位置に飛んでみて同様にズレてたら確定。
また、動画やサウンドなら「ファイルサイズぽい値」が大きな値になってるはず。
ところで「デジタルフォレンジック」という分野がある。
「フォレンジック」とは「法廷」や「科学捜査」の意味で、
「デジタルフォレンジック」とは、(関連する部分だけ言えば)故意に隠したファイルやHDD上の痕跡から、証拠となるデータを復元することである。
その手の解析コンテストや勉強会に出てる人のスライドが公開されており、ゲームデータ解析にも通じるところがあるので必見。
zipには先頭に'PK'というシグネチャがあるが、
アーカイブ内のゲームデータにも特徴がある。
画像
PNG 89 'PNG' (SJISだと '臼NG')
DDS: 'DDS '
BMP: 'BM'
TGA; 00 00 20 00 (32bitの場合)
JPEG: ff d8 ff XX (JFIFの文字が見えることも)
シグネチャが無くても、非圧縮画像は00(黒)やFF(白)が多発するので見分けが付く。
アルファつき32bitなら 00 00 00 FF とか 4byteごとに規則的に並ぶ。
圧縮DDS(DXT5)は一見圧縮データぽいが、特徴的な00やffの並びが見られる。
画像ぽいデータなら、先頭あたりに画像サイズぽい値あがあるはず。
非圧縮なら、縦x横に1dotあたりのbyte数(1-4)を掛ければ(ヘッダサイズを除いた)ファイルサイズに近い値になるはず。
サウンド
WAV: RIFF....WAVEfmt
OGG: OggS
が圧倒的に多い。日本語化には(どっかの暇人がアテレコでもしない限り)関係ないのでここではスルー。
テキスト
plain textは普通に人間が読めるのでわかりやすい。
メッセージやスクリプトなど
動画
bink(BIK)かogm、mkv等が多い。その他
バイナリ化されたメッセージやスクリプト、モデルなど。
4byte int や floatぽい値が並ぶなど、無秩序ではなく特徴がある。
メッセージがスクリプト中に埋め込まれている場合などは、メッセージぽいテキストが見える。
圧縮データ
なんかゴチャゴチャしてたら、圧縮か暗号化されている。
zlib圧縮の場合、78 xx という zlibヘッダがある(ないこともある)
アーカイブ解析時に、ファイル情報部の「オフセットぽい値」に飛んでみて、これらファイルの先頭ぽい特徴が見えたら、ファイルの先頭と考えられる。
このオフセット値は、
- ファイル先頭からの絶対値
- ヘッダの直後からの相対値
- データ部の先頭からの相対値
などのバリエーションがある。
とりあえず飛んでみて、少しズレてたらヘッダ分の可能性が高い。2つのファイルでオフセット位置に飛んでみて同様にズレてたら確定。
また、動画やサウンドなら「ファイルサイズぽい値」が大きな値になってるはず。
ところで「デジタルフォレンジック」という分野がある。
「フォレンジック」とは「法廷」や「科学捜査」の意味で、
「デジタルフォレンジック」とは、(関連する部分だけ言えば)故意に隠したファイルやHDD上の痕跡から、証拠となるデータを復元することである。
その手の解析コンテストや勉強会に出てる人のスライドが公開されており、ゲームデータ解析にも通じるところがあるので必見。
目grep入門 +解説 from murachue
2012年12月13日木曜日
技術メモ: アーカイブを覗いてみる
ゲーム日本語化 Advent Calendar 2012
ゲームで使う画像、サウンド、テキスト、スクリプト等は
個別のファイルになっている場合もあるが、たいていは巨大な数個のファイルにまとまっている。
zipそのままで拡張子変えただけという場合もある。
とりあえず16進ダンプして'PK'で始まってたらzipだ。
そうでない場合、アーカイブ形式を調べる必要がある。
アーカイブ形式を自作するつもりになれば想像できるが、
どこかに
- ファイル数
- (ファイル名)
- ファイルサイズ
- データ位置
- (圧縮してるか)
- (展開後のサイズ)
という情報があるはず。
例えばzipではこういう構造になっている。
これらの情報がどこかにあるはず、という前提で16進ダンプを見ていく。
情報はたいてい32bitのlittle endianである。
ファイル数なら
2c 00 00 00
とか小さい値のはず。
オフセットなら
20 00 00 00
..
5e 03 00 00
..
1a 2c 00 00
のように増えていくはず。
ファイルサイズなら、アーカイブのサイズより小さいはず。
+--------------+ | ヘッダ | +--------------+ |ファイル1情報 | |ファイル2情報 | | ..... | |ファイルN情報 | +--------------+ | ファイル1 | +--------------+ | .... | +--------------+ | ファイルN | +--------------+
というのが最も良くあるパターンである。
ヘッダには識別符号(zipなら'PK')、ファイル数などが含まれる。
アーカイブのバージョンらしき数値があることもある。
ファイル情報はアーカイブ末尾にあることもある。
この場合、アーカイブ先頭のヘッダまたは末尾のフッタなど、たどれる場所に情報開始位置があるはず。
+--------------+ | ヘッダ | +--------------+ | 情報開始位置 | +--------------+ | ファイル1 | +--------------+ | .... | +--------------+ | ファイルN | +--------------+ |ファイル1情報 | |ファイル2情報 | | ..... | |ファイルN情報 | +--------------+または
+--------------+ | ヘッダ | +--------------+ | ファイル1 | +--------------+ | .... | +--------------+ | ファイルN | +--------------+ |ファイル1情報 | |ファイル2情報 | | ..... | |ファイルN情報 | +--------------+ | 情報開始位置 | +--------------+まれにファイル情報がまとまってない場合がある
+--------------+ | ヘッダ | +--------------+ |ファイル1情報 | | ファイル1 | +--------------+ | .... | +--------------+ |ファイルN情報 | | ファイルN | +--------------+
この場合、 オフセット 情報が無く、内部ファイル末尾がそのまま次のファイルの開始になっていることもある。
ファイル名ぽい文字列が手がかりになるが、ファイル名が無い場合がある。
一つは、ファイル名だけ別ブロックにまとまっていて、情報にブロック内のオフセットがある場合。
もう一つは、ファイル名に替わるIDらしき32bit値がある場合。
前述のようにファイルサイズやオフセットは小さい値だから、上位は00のはずである。
2a 4b cd a7
とか00を含まない値の場合、ファイルのチェックサムかファイルIDを疑ってみる。
Xentax Game File Format Central
には、ゲームアーカイブ形式の解析が数多く掲載されている。
2012年12月12日水曜日
技術メモ: 簡単なものをかな化してみる
ゲーム日本語化 Advent Calendar 2012
世間ではAdvent Calendarとかいうのが流行ってるようなので、この機会に日本語化について書いてみる。
最近indie bundleにあった Weird Worlds: Return to Infinite Space を例にする。
- ファイルはアーカイブされず素で入ってる
- フォントは普通の画像形式
- テキストは普通のテキスト
- 1byte英語文字コード(ISO-8859-1)決めうち
UnityやXNAを使わないエンジン自作のindieゲームにありがちなパターン。
- 無ければ全部見てく。(俺はIrfanViewを使用。DDS対応でフォルダ内まとめて見ることができる)
というわけで default\graphics\gui\font_16x32.tga が見つかった。
- 見ると文字が規則的に並んでいる。
- 文字幅が不規則な場合は、別に位置、幅、高さ等の情報を含む別ファイルがあることが多い。
- 下半分のウムラウト文字の余地が無く英数字だけの場合、かな化は困難かも。
ここでは文字が規則的なので終了。
- 適当な画面をキャプチャしてメッセージをメモる。ここでは[START]に注目
- そのメッセージを含むファイルをゲームフォルダから検索。(俺はサクラエディタを使用)
exe内の[START]はたぶんランチャ用で変更できない。
と言うわけで default\gamedata\string.ini が見つかった。
- メッセージを変更してみる
mainmenu_start START
を
mainmenu_start STARTス
とかにしてみる。
と言うわけで変更されたので合ってる。たぶん他の*.iniもテキストだろう。
英語文字コードでは記号やウムラウトになってる部分をかなにする。
半角カナで入力してもいいけど、かなとカナを含むフォントを用意して何かコンバータ作るのが吉。
汎用的なのが公開できればいいな。
この方法で かな化したのがCryostasis
コレを
こうすると
コレが
こうなる
世間ではAdvent Calendarとかいうのが流行ってるようなので、この機会に日本語化について書いてみる。
最近indie bundleにあった Weird Worlds: Return to Infinite Space を例にする。
- ファイルはアーカイブされず素で入ってる
- フォントは普通の画像形式
- テキストは普通のテキスト
- 1byte英語文字コード(ISO-8859-1)決めうち
UnityやXNAを使わないエンジン自作のindieゲームにありがちなパターン。
フォントの見つけ方
- フォルダ名やファイル名にfont とか gui とか interface とか含まれると怪しい。- 無ければ全部見てく。(俺はIrfanViewを使用。DDS対応でフォルダ内まとめて見ることができる)
というわけで default\graphics\gui\font_16x32.tga が見つかった。
- 見ると文字が規則的に並んでいる。
- 文字幅が不規則な場合は、別に位置、幅、高さ等の情報を含む別ファイルがあることが多い。
- 下半分のウムラウト文字の余地が無く英数字だけの場合、かな化は困難かも。
ここでは文字が規則的なので終了。
テキストの見つけ方
- 適当な画面をキャプチャしてメッセージをメモる。ここでは[START]に注目
- そのメッセージを含むファイルをゲームフォルダから検索。(俺はサクラエディタを使用)
□検索条件 "START"
検索対象 *.*
フォルダ f:\opt\Desura\Common\weird-worlds-return-to-infinite-space\
(サブフォルダも検索)
(英大文字小文字を区別する)
(文字コードセットの自動判別)
(一致した行を出力)
f:\opt\Desura\Common\weird-worlds-return-to-infinite-space\weird.exe(5183,452) [SJIS]:
(略)Mod Settings・・・Video Settings・・・START・・・MODS・・・・VIDEO SETTINGS・・・QUIT(略)
f:\opt\Desura\Common\weird-worlds-return-to-infinite-space\default\gamedata\strings.ini(76,17) [SJIS]: simulator_start START
f:\opt\Desura\Common\weird-worlds-return-to-infinite-space\default\gamedata\strings.ini(133,13) [SJIS]: start_start START
f:\opt\Desura\Common\weird-worlds-return-to-infinite-space\default\gamedata\strings.ini(143,16) [SJIS]: mainmenu_start START
4 個が検索されました。
exe内の[START]はたぶんランチャ用で変更できない。
と言うわけで default\gamedata\string.ini が見つかった。
- メッセージを変更してみる
mainmenu_start START
を
mainmenu_start STARTス
とかにしてみる。
と言うわけで変更されたので合ってる。たぶん他の*.iniもテキストだろう。
かなフォントを作る
英語文字コードでは記号やウムラウトになってる部分をかなにする。
テキストを訳す
半角カナで入力してもいいけど、かなとカナを含むフォントを用意して何かコンバータ作るのが吉。
汎用的なのが公開できればいいな。
作例
この方法で かな化したのがCryostasis
コレを
こうすると
コレが
こうなる
Weird Worlds: Return to Infinite Space
かな化可能と思われ
font: default/graphics/gui/font_16x32.tga
text: gamedata/*.ini
font: default/graphics/gui/font_16x32.tga
text: gamedata/*.ini
2012年12月4日火曜日
Port Royale 3
archive format: リンク
unpacker: Port Royale 3 Extractor (DL) repack不要で展開状態でも動く
font: swf
text: Patrician IVと同じ
日本語化
登録:
投稿 (Atom)